« 2007年4月 | トップページ | 2007年6月 »

2007年5月26日 (土)

WindowsアプリからWScript.exeのWScriptオブジェクトを利用する。

VB6、EXCEL VBA、IE、HTA、WScriptなどのWindowsアプリから、
WScript.exeを起こして、WindowsアプリからWScript.Sleep()や
WScript.CreateObject()を使い、
WScript.ShellのPopUp()の時間指定を使います。

WScript.VBS

WScript.exeのWScriptオブジェクト(IHost_Class)を提供する部品側のサンプルです。

Set Shell=CreateObject("Shell.Application")
For Each ie In Shell.Windows()
  If ie.hwnd=CLng(WScript.Arguments.Item(0)) Then Exit For
Next
ie.PutProperty "WScript",WScript
Do While TypeName(ie)="IWebBrowser2"
  WScript.Sleep 1000
Loop
MsgBox "Ended."&vbTab,vbInformation,WScript.ScriptName

[説明]

Windowアプリ側に渡すため、WScriptオブジェクトをIEに渡します。
受け渡し用のIEが存在する間、待ち合わせをします。
Windowアプリ側が終了すると、IEが終了するので、抜けます。
一応動作確認用に終了のMsgBoxを出していますが、動作確認が済めば不要です。

GetWScript.VBS

WScript.exeを利用するWindowsアプリ側のサンプルです。
VBSファイルですが、VB/VBAのコードに貼り付けても使えます。

Set ie = CreateObject("InternetExplorer.Application")
Set wShell = CreateObject("WScript.Shell")
wShell.Run "WScript.exe ""WScript.VBS"" " & ie.Hwnd
For k = 1 To 10
  If Not IsEmpty(ie.GetProperty("WScript")) Then
    Set W = ie.GetProperty("WScript")
    If TypeName(W) = "IHost_Class" Then Exit For
  End If
'  WScript.Sleep 100
'  Application.Wait Now + TimeSerial(0, 0, 1)
  wShell.Run "ping localhost -n 2",0,True
Next
Set wwShell = W.CreateObject("WScript.Shell")
wwShell.Popup TypeName(W) & vbTab, 5, "Popup 5秒で閉じます", vbInformation
t1=Timer
W.Sleep 100
MsgBox (Timer-t1)*1000, vbInformation, "Sleep 100 mSecの実時間"
If vbYes = MsgBox("WScript.Quit ?" & vbTab, vbYesNo + vbQuestion, "GetWScript") Then W.Quit
MsgBox "Exit OK ?" & vbTab & vbTab, vbQuestion, "GetWScript"
'ie.Quit

[説明]

WScriptオブジェクトを受け渡しするために、IEを利用します。
IEはウィンドウハンドルで識別します。
WScript.exe側を起動します。
WSH以外での利用を想定してWScript.Sleepをpingで代替しています。
WScriptオブジェクトをここでは変数[W]で受け取ります。
[WScript].CreateObject()でWScript.Shellオブジェクトを作成します。
このWScript.ShellオブジェクトのPopUp()では時間指定が有効です。
[WScript].Sleep()が使えます。
[WScript].Quit
すると、WScript.exeはすぐ終了します。
Windowsアプリ側が終了してIEの参照を解放するか、IEを終了すると、
それをWScript.exe側が検知して、終了します。

2007年5月22日 (火)

すべてのウィンドウを元のサイズに戻す。その3

もしExcelがあれば、以下のスクリプトで可能です。それに心配するほどに遅くはないですよ。

RestoreAllWindows.VBS

Const GW_HWNDPREV = 3
Const SW_RESTORE = 9

Set Excel=CreateObject("Excel.Application")
Tasks=Array()
hwnd=Excel.ExecuteExcel4Macro("CALL(""user32"",""FindWindowA"",""JCC"",""Progman"",""Program Manager"")")
Do
  hwnd=Excel.ExecuteExcel4Macro("CALL(""user32"",""GetWindow"",""JJJ"","& hwnd &","& GW_HWNDPREV &")")
  If hwnd=0 Then Exit Do
  If Excel.ExecuteExcel4Macro("CALL(""user32"",""IsWindowVisible"",""JJ"","& hwnd &")") Then
    If Excel.ExecuteExcel4Macro("CALL(""user32"",""IsIconic"",""JJ"","& hwnd &")") Then
      Push Tasks,hwnd
    End If
  End If
Loop

For Each hwnd In Tasks
  Excel.ExecuteExcel4Macro "CALL(""user32"",""ShowWindow"",""JJJ""," & hwnd & ","& SW_RESTORE &")"
Next

Sub Push(Items,Item)
ReDim Preserve Items(UBound(Items)+1)
Items(UBound(Items))=Item
End Sub

2007年5月21日 (月)

すべてのウィンドウを元のサイズに戻す。その2

もしWord 2002以降があれば、簡単です。でも、Wordって、遅いぃーっ。

RestoreAllWindows.VBS

Set Word=CreateObject("Word.Application")
For Each Task In Word.Tasks
  If Task.Visible Then If Task.WindowState=2 Then Task.WindowState=0
Next

2007年5月19日 (土)

CScript.exe強制実行

先の応用で、CScript.exeでしか動かないスクリプトが、
もし、WScript.exeで起動されたら、CScript.exeで起動し直します。

既存のVBSファイルの先頭に以下のコードを組み込むだけです。

Option Explicit

Sub RerunCScript 'ここから
Dim Args
Dim Arg
If LCase(Right(WScript.FullName,11))="wscript.exe" Then
  Args=Array("cmd.exe /k CScript.exe",""""&WScript.ScriptFullName&"""")
  For Each Arg In WScript.Arguments
    ReDim Preserve Args(UBound(Args)+1)
    Args(UBound(Args))=""""&Arg&""""
  Next
  WScript.Quit CreateObject("WScript.Shell").Run(Join(Args),1,True)
End If
End Sub
RerunCScript 'ここまで

'以下は既存コードのサンプル
WScript.StdOut.WriteLine WScript.FullName
WScript.StdOut.WriteLine WScript.ScriptFullName
WScript.StdOut.WriteLine WScript.Arguments.Count
Dim k
For k=1 To WScript.Arguments.Count
  WScript.StdOut.WriteLine WScript.Arguments.Item(k-1)
Next

2007年5月18日 (金)

WScript.ShellのExec()でコンソールアプリを非表示で実行する。その2

再帰呼び出しで一本化する例です。

既存のVBSファイルの先頭に以下のコードを組み込むだけで、
もし、自分がWScript.exeで起動されると、
自身を非表示のCScript.exeで起動し直します。

Option Explicit

Sub HideExec '[ここから]'
Dim Args
Dim Arg
If LCase(Right(WScript.FullName,11))="wscript.exe" Then
  Args=Array("CScript.exe","""" & WScript.ScriptFullName & """")
  For Each Arg In WScript.Arguments
    ReDim Preserve Args(UBound(Args)+1)
    Args(UBound(Args))="""" & Arg & """"
  Next
  WScript.Quit CreateObject("WScript.Shell").Run(Join(Args),7,True)
End If
End Sub
HideExec '[ここまで]'

'以下は既存コードのサンプル

Dim wShell
Dim oExec
Dim Args
Dim Arg
Args=Array("fc.exe")
For Each Arg In WScript.Arguments
  If InStr(Arg," ") Then Arg="""" & Arg & """"
  ReDim Preserve Args(UBound(Args)+1)
  Args(UBound(Args))=Arg
Next
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec(Join(Args))
MsgBox oExec.StdErr.ReadAll() & vbLf & oExec.StdOut.ReadAll(),,Join(Args)

fc.exeの代わりにfc.vbsで試してみてください。

2007年5月16日 (水)

「写真の印刷ウィザード」に送る。

SendToに「写真の印刷ウィザード」を登録しておくと、
ファイルやフォルダを送って「写真の印刷ウィザード」を開始できます。
そのための拡張子.photowizを追加するレジストリ定義です。

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.photowiz]
@="CLSID\\{60fd46de-f830-4894-a628-6fa81bc0190d}"

[HKEY_CLASSES_ROOT\CLSID\{60fd46de-f830-4894-a628-6fa81bc0190d}]
"NeverShowExt"=""

[HKEY_CLASSES_ROOT\CLSID\{60fd46de-f830-4894-a628-6fa81bc0190d}\DefaultIcon]
@="C:\\WINDOWS\\system32\\photowiz.dll,0"

[HKEY_CLASSES_ROOT\CLSID\{60fd46de-f830-4894-a628-6fa81bc0190d}\shellex]

[HKEY_CLASSES_ROOT\CLSID\{60fd46de-f830-4894-a628-6fa81bc0190d}\shellex\DropHandler]
@="{60fd46de-f830-4894-a628-6fa81bc0190d}"

写真の印刷ウィザード.photowiz
というファイルを作って、SendToなどに入れておきます。

2007年5月15日 (火)

ショートカットの設定値を調べる。

ショートカットの「実行時の大きさ」を「非表示」に設定しても、
プロパティページなどの情報では見えません。

以下のVBSファイルにショートカットをドロップします。
「実行時の大きさ」の実際の設定値を表示します。

Set wShell=CreateObject("WScript.Shell")
Path=WScript.Arguments(0)
Set Link=wShell.CreateShortCut(Path)
WScript.Echo Join(Array(_
  "FullName"&vbTab&vbTab&Link.FullName,_
  "TargetPath"&vbTab&Link.TargetPath,_
  "Arguments"&vbTab&vbTab&Link.Arguments,_
  "WorkingDirectory"&vbTab&Link.WorkingDirectory,_
  "SetWindowStyle"&vbTab&WindowStyle(),_
  "GetWindowStyle"&vbTab&Link.WindowStyle,_
  "Hotkey"&vbTab&Link.Hotkey,_
  "IconLocation"&vbTab&Link.IconLocation,_
  "Description"&vbTab&Link.Description),vbLf)

Function WindowStyle()
Dim Stream
Set Stream=CreateObject("ADODB.Stream")
Stream.Open
Stream.Type=1
Stream.LoadFromFile Path
Stream.Position=&H3C
WindowStyle=AscB(Stream.Read(1))
End Function

2007年5月14日 (月)

バッチファイルで作るteeコマンド

unixのteeコマンド擬似をバッチファイル機能だけで作ります。

tee.CMD 出力ファイル

@ECHO OFF
SETLOCAL
SET X=%*
IF NOT DEFINED X (
ECHO Usage: %~nx0 出力ファイル
GOTO :EOF
)
IF "%~0"=="%~dp0.\%~nx0" GOTO :SUB
MORE >%1 | "%~dp0.\%~nx0" %1
GOTO :EOF
:SUB
SET SS=0
SET LL=0
:TOP
IF %SS%==%~z1 (
rem SLEEP 1
ping localhost -n 2 >NUL
CMD /C "TYPE NUL>>%1" 2>NUL
IF NOT ERRORLEVEL 1 GOTO :EOF
GOTO :TOP
)
SET SS=%~z1
FOR /F "delims=[] tokens=1*" %%1 IN ('FIND /N /V "" ^<%1 ^|MORE +%%LL%%') DO (
SET LL=%%1
ECHO:%%2
)
GOTO :TOP

2007年5月13日 (日)

バッチファイルで作るtail -fコマンド

unixのtail -fコマンド擬似をバッチファイル機能だけで作ります。

tail-f.CMD 入力ファイル

@ECHO OFF
SETLOCAL
IF NOT EXIST "%~1" (
ECHO Usage: %~nx0 入力ファイル
GOTO :EOF
)
SET SS=0
SET LL=0
:TOP
IF %SS%==%~z1 (
rem SLEEP 1
ping localhost -n 2 >NUL
CMD /C "TYPE NUL>>%1" 2>NUL
IF NOT ERRORLEVEL 1 GOTO :EOF
GOTO :TOP
)
SET SS=%~z1
FOR /F "delims=[] tokens=1*" %%1 IN ('FIND /N /V "" ^<%1 ^|MORE +%%LL%%') DO (
SET LL=%%1
ECHO:%%2
)
GOTO :TOP

入力ファイルが出力オープンされている間は監視が継続します。
入力ファイルへの出力オープンがクローズされると終了します。

2007年5月11日 (金)

WScript.ShellのExec()でコンソールアプリを非表示で実行する。

WScript.ShellのExec()でコンソールアプリを実行すると、
コンソールウィンドウが表示されます。それを非表示にする方法です。

コンソールウィンドウがない環境、つまり、WScript.exeからExec()で
コンソールアプリを起動すると、コンソールウィンドウが生成されます。

コンソールウィンドウがある環境、つまり、CScript.exeからExec()で
コンソールアプリを起動すると、コンソールウィンドウは生成されません。

これを利用すれば、Exec()でコンソールアプリを非表示で実行できます。

つまり、WScript.exeからRun()で、CScript.exeを非表示で起動し、
その中からExec()でコンソールアプリを起動すればよいのです。

基本的にはRun()するスクリプトとExec()するスクリプトの二つが必要ですが、
WSFでひとつのファイルにしたり、再帰呼び出しで一本化することもできます。

以下のWSFは、そういうサンプルです。

<package>
<job>
<script language=vbscript>
Dim Args
Dim Arg
Args=Array("CScript.exe //job:exec","""" & WScript.ScriptFullName & """")
For Each Arg In WScript.Arguments
  ReDim Preserve Args(UBound(Args)+1)
  Args(UBound(Args))="""" & Arg & """"
Next
WScript.Quit CreateObject("WScript.Shell").Run(Join(Args),0,True)
</script>
</job>
<job id=exec>
<script language=vbscript>
Dim wShell
Dim oExec
Dim Args
Dim Arg
Args=Array("fc.exe")
For Each Arg In WScript.Arguments
  If InStr(Arg," ") Then Arg="""" & Arg & """"
  ReDim Preserve Args(UBound(Args)+1)
  Args(UBound(Args))=Arg
Next
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec(Join(Args))
MsgBox oExec.StdErr.ReadAll() & vbLf & oExec.StdOut.ReadAll(),,Join(Args)
</script>
</job>
</package>

fc.exeの代わりにfc.wsfで試してみてください。

2007年5月 8日 (火)

バッチファイルなどをショートカットで非表示実行する。

バッチファイルなどのショートカットのプロパティで、
「実行時の大きさ」を「非表示」にすることは出来ません。
しかし、スクリプトからは可能です。

以下のVBSファイルにショートカットファイルをドロップします。

HideLink.vbs ショートカットファイル

set wshell=createobject("wscript.shell")
set lnk=wshell.createshortcut(wscript.arguments.item(0))
lnk.windowstyle=0
lnk.save

ショートカットのプロパティで設定を変更すると、リセットされるので注意。
そのときはもう一度。

2007年5月 6日 (日)

参照が残って終了しないExcelを優しく終了させる。

.NETとCOMの相性の悪さから、終了しないExcelが残ることがあります。
このExcelを外部からTerminateProcess()で強制終了するのではなく、
もっと穏やかに自らExitProcess()させます。

Set Application=GetObject(,"Excel.Application")
Visible=Application.Visible
Application.Visible=True
StatusBar=Application.StatusBar
Application.StatusBar="このExcelを終了しますか?"
If vbOk=MsgBox("このExcelを終了しますか?"&vbTab,vbExclamation+vbOkCancel,WScript.ScriptName) Then
  Application.ExecuteExcel4Macro "CALL(""Kernel32"",""ExitProcess"",""JJ"",999)"
End If
Application.StatusBar=StatusBar
Application.Visible=Visible

2007年5月 5日 (土)

文字列の繰り返し関数はないの?

文字の繰り返し関数はString(n,c)ですが、文字列の繰り返し関数はないの?
ないようです。なので作ってみました。

Function Strings(n,s)
Dim a:ReDim a(n):Strings=Join(a,s)
End Function

MsgBox Strings(5,"abc")

しかし、これくらいなら関数を作らずとも簡単に書けますね。

MsgBox Join(Split(Space(5)),"abc")

更に、こういう方法もあります。

MsgBox Replace(Space(5),Chr(32),"abc")

2007年5月 4日 (金)

すべてのウィンドウを元のサイズに戻す。

Shell.Applicationを使えば、すべてのウィンドウを最小化したり、表示されてるウィンドウを並べて表示することはできますが、すべてのウィンドウを元のサイズに戻す機能がありません。そこで、以下のHTAを実行します。

RestoreAllWindows.hta

<html>
<head>
<script language=vbscript>
resizeTo 0,0
Set wShell=CreateObject("WScript.Shell")
k=0
</script>
<hta:application/>
<script language=vbscript>
Sub window_onload()
wShell.SendKeys "%+{Tab}"
setTimeout "restore",10,"VBScript"
End Sub
Sub restore()
k=k+1
If document.hasFocus() Then
'  MsgBox k,vbInformation
  close
ElseIf k<100 Then
  wShell.SendKeys "%+{Tab}"
  setTimeout "restore",10,"VBScript"
Else
  MsgBox k,vbCritical
  close
End If
End Sub
</script>
</head><body></body></html>

Alt + Shft + Tabキーで、Zオーダの低い順にアクティブにします。一周を判定するため、HTAのdocument.hasFocus()を利用します。念の為、100回で打ち切るようにしています。

タスクマネジャを開いていると終了判定を邪魔するようです。

2007年5月 3日 (木)

URLを構成要素に分解する。

URLを構成要素(protocol/hostname/port/pathname/hash/search)に
分解するにはどうするか? 正規表現を使う?
いえいえ、<a>オブジェクトにそういう機能がありますよ。

Set Document=CreateObject("htmlfile")
Document.write "<html><body><a id=a1 /></body></html>"
Set Location=Document.body.all.a1

Location.href="http://www.hoge.com:60/folder/file#hash?search"
MsgBox Location.protocol
MsgBox Location.hostname
MsgBox Location.port
MsgBox Location.pathname
MsgBox Location.hash
MsgBox Location.search

2007年5月 2日 (水)

URLが表示済か未表示かを判別する。

URLが表示済か未表示かによって、Webページ上でリンクの色が異なります。
つまり、URLが表示済か未表示かをこれで判別できるはずです。

Function IsVisitedURL(URL)
Set Document=CreateObject("htmlfile")
Document.write "<html><body><a id=a1 /></body></html>"
Document.body.all.a1.href=URL
IsVisitedURL=Document.body.all.a1.currentStyle.Color=Document.vlinkColor
End Function

URL="about:blank"
MsgBox IsVisitedURL(URL),,URL

2007年5月 1日 (火)

Doskeyのコマンド履歴にコマンドを事前設定する。

コマンドプロンプトからDoskeyのコマンド履歴にコマンドを
事前設定するには、以下のようなVBSを作って実行します。

hoge.vbs

set wshell=createobject("wscript.shell")
wshell.sendkeys "if 1==2 {(}^m"
wshell.sendkeys "aaa^m"
wshell.sendkeys "bbb^m"
wshell.sendkeys "ccc^m"
wshell.sendkeys "{)}^m"
wshell.sendkeys "{f7}"

コマンドプロンプト起動時にコマンド履歴を事前設定するには、
以下のようなショートカットを作成して実行します。

cmd.exe /k フルパス\hoge.vbs

コマンドプロンプトで、履歴に1行入れてから、それを編集したいときは、

set /p x=
cccccccccccccccccc

« 2007年4月 | トップページ | 2007年6月 »