汎用にhta.commandlineを配列にばらすサンプルです。
<html><head>
<script language="vbscript">
window.MoveTo window.screen.availWidth,0
</script>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<title>ClipName</title>
<HTA:APPLICATION applicationName="ClipName" version=1.00 id=hta>
<script language="vbscript">
argv=splitcommandline(hta.commandline)
For k=1 To UBound(argv)
argv(k-1)=argv(k)
Next
argv(k-1)=""
rc=window.clipboarddata.setdata("text",join(argv,vbcrlf))
window.alert window.clipboarddata.getdata("text")
window.close
Function splitcommandline(commandline)
dim argv(),argc
dim s,p
s=1
Do While s<=Len(commandline)
If Mid(commandline,s,1)=" " Then
s=s+1
ElseIf Mid(commandline,s,1)="""" Then
s=s+1
p=InStr(s,commandline,"""")
Do While p
If p+2>Len(commandline) Then Exit Do
If Mid(commandline,p+1,1)<>"""" Then Exit Do
p=InStr(p+2,commandline,"""")
Loop
If p=0 Then Alert("Unpaired Quote"):close:Exit Do
If p<Len(commandline) Then If Mid(commandline,p+1,1)<>" " Then Alert("Not Space"):close:Exit Do
ReDim Preserve argv(argc)
argv(argc)=Replace(Mid(commandline,s,p-s),"""""","""")
argc=argc+1
s=p+1
Else
p=InStr(s,commandline," ")
If p=0 Then p=Len(commandline)+1
ReDim Preserve argv(argc)
argv(argc)=Mid(commandline,s,p-s)
argc=argc+1
s=p
End If
Loop
splitcommandline=argv
End Function
</script></head><body></body></html>
汎用にコマンド引数のワイルドカードを展開するサンプルです。
Option Explicit
Dim arg
Dim argc
Dim argv()
For Each arg In Wscript.Arguments
If InStr(arg,"*") Then
call glob(arg)
ElseIf InStr(arg,"?") Then
call glob(arg)
Else
argc=argc+1
ReDim Preserve argv(argc-1)
argv(argc-1)=arg
End If
Next
WScript.Echo Join(argv,vbcrlf)
WScript.Quit
Function Glob(arg)
Dim fso
Dim Folder
Dim bre
Dim pre
Dim xre
Dim file
Dim dir
Dim found
Set fso=CreateObject("Scripting.FileSystemObject")
dir=fso.GetParentFolderName(fso.GetAbsolutePathName(arg))
Set Folder=fso.GetFolder(dir)
Set pre=New RegExp
Set bre=New RegExp
Set xre=New RegExp
pre.Global=True
bre.IgnoreCase=True
xre.IgnoreCase=True
pre.Pattern="([\]\^\[\\\$\+\.\(\)\|\{\}])"
bre.Pattern="^" & pre.Replace(fso.GetBaseName(arg),"\$1") & "$"
bre.Pattern=Replace(bre.Pattern,"?",".")
bre.Pattern=Replace(bre.Pattern,"*",".*")
xre.Pattern="^" & pre.Replace(fso.GetExtensionName(arg),"\$1") & "$"
xre.Pattern=Replace(xre.Pattern,"?",".")
xre.Pattern=Replace(xre.Pattern,"*",".*")
For Each file In Folder.Files
If bre.Test(fso.GetBaseName(file.Name)) And xre.Test(fso.GetExtensionName(file.Name)) Then
argc=argc+1
ReDim Preserve argv(argc-1)
argv(argc-1)=file.Path
found=True
End If
Next
If Not found Then
argc=argc+1
ReDim Preserve argv(argc-1)
argv(argc-1)=arg
End If
End Function
いりやさん。ありがとうございました。
解決しました。
一箇所訂正。
》魔界の仮面弁士 2004年 09月 03日 22時 39分 44秒
> (「CreateObject関数」のように、ホストではなく、VBScript自身が持っている機能なので、ASPでもWSHでも呼び出せますけれどね)
誤) VBScript自身が持っている機能なので
正) VBScript自身が持っている機能ならば
魔界の仮面弁士さん、ありがとうございますーー
いきなり出てきた要件で、今日中に解決せねばならず、困り果てていました。
調査不足でほんとうに情けない限りです。精進します。
ほんとうにありがとうございました。
》 まきもと さん
> VBScript内でWScriptを使って、アプリの起動パスを取得するだけなので、
> サーバ側のVBScript内で完結できると思っています。
提供されているグローバルオブジェクトは、実行ホストによって異なります。
ASP上では WScript.ScriptName プロパティは使えないかと。
クライアント側(DHTMLやWSHなど)のVBScriptでは、Response/Server/Requestオブジェクトなどを使えないのと同様、サーバ側では WScriptオブジェクトを直接呼び出せません。
例えば今回、『Server.CreateObject』を使っておられましたが、これは、「ASPでは使えるけれど、WSH上では使えない」構文になります。
その一方で、『WScript.CreateObject』に関しては、その逆であり、「WSHでは使えるけれど、ASP上では使えない」という結果になります。
(「CreateObject関数」のように、ホストではなく、VBScript自身が持っている機能なので、ASPでもWSHでも呼び出せますけれどね)
で、本題。
ASPのパス自身を知りたいのであれば、ServerVariablesを使ってみてください。
たとえば、『 http://localhost/folder/default.asp?test=data 』という URL なら、
<%=Request.ServerVariables("PATH_TRANSLATED")%>
→ "c:\inetpub\wwwroot\folder\default.asp"
<%=Request.ServerVariables("SCRIPT_NAME")%>
→ "/folder/default.asp"
<%=Request.ServerVariables("URL")%>
→ "/folder/default.asp"
<%=Server.MapPath(Request.ServerVariables("URL"))%>
→ "c:\inetpub\wwwroot\folder\default.asp"
などと変換できます。
いりやさん、ありがとうございます。
いりやさんの教えて頂いたアーカイブを読んで、
勉強させて頂きましたが、やはりわかりません。未熟者ですみません。
VBScript内でWScriptを使って、アプリの起動パスを取得するだけなので、サーバ側のVBScript内で完結できると思っています。
http://www.atmarkit.co.jp/fwin2k/operation/wsh03/wsh03_01.html
↑にある文章なのですが、
WScriptオブジェクトは、暗黙にインスタンス化されるので(暗黙のうちにオブジェクトが生成されるので)、ほかのオブジェクトとは違い、明示的にオブジェクトを生成しなくても、スクリプト中のどこからでも呼び出すことができる。
大きな考え間違いをしているのかもしれません。
もう一度よく考えてみます。
>念仏くん さん 2004年 08月 31日 21時 53分 36秒
>@システム時間(HH:MM)を取得する。
>A取得したシステム時間(HH:MM)に+5分して、変数Aに格納する。
>Bvbsから次のDOSコマンドを実行する
> AT 変数A "c:\batch.bat"
>実現方法はVBSでもバッチ(DOSコマンド)でもかまわないのですが、
バッチならこうですね。
setlocal
set hhmm=%time%
set hh=%hhmm:~0,2%
set mm=%hhmm:~3,2%
set /a mm=mm+5
set /a hh=hh+mm/60
set /a mm=mm%%60
set /a hh=hh%%24
set mm=0%mm%
set hh=0%hh%
set hhmm=%hh:~-2%:%mm:~-2%
echo %hhmm%
AT %hhmm% "c:\batch.bat"
まきもとさん、
| 実行環境ですか。。なんで"WScript.Shell"の方はオブジェクトが
| 作成できるのかが謎です。
このあたりの話は、USERS GROUP が主催する WSH メーリングリス
トでの議論が役にたつとおもいます。
http://www.users.gr.jp/ml/archive/list.aspx?name=wsh&no=332
[WSH:00332] IE から WScript オブジェクトが使用できない
[WSH:00333] Re: IE から WScript オブジェクトが使用できない
[WSH:00334] Re: IE から WScript オブジェクトが使用できない
[WSH:00335] Re: IE から WScript オブジェクトが使用できない
[WSH:00336] Re: IE から WScript オブジェクトが使用できない
[WSH:00337] Re: IE から WScript オブジェクトが使用できない
[WSH:00338] Re: IE から WScript オブジェクトが使用できない
[WSH:00339] Re: IE から WScript オブジェクトが使用できない
[WSH:00340] Re: IE から WScript オブジェクトが使用できない
『WScript グローバル変数には WScript オブジェクトがバインド
されている』、この前提は Windows Script Host (wscript.exe,
cscript.exe) からスクリプトが実行された時のはなしです。
それゆえ、それ以外の実行環境からアクセスするためには、たとえ
ば、
http://www.users.gr.jp/ml/archive/list.aspx?name=wsh&no=1001
[WSH:01097] WSC 内で WScript オブジェクトの使い方について教えて下さい
[WSH:01098] Re: WSC 内で WScript オブジェクトの使い方について教えて下さい
で青柳臣一さんが Windows Script Component を対象に紹介されて
いるとおり、WScript 変数を使って WScript オブジェクトのリファ
レンスを利用したい環境に渡す必要があります。
いりやさん、ありがとうございます!
実行環境ですか。。なんで"WScript.Shell"の方はオブジェクトが
作成できるのかが謎です。
こんなに早くご回答頂ききまして感激です。
問題がわかりましたら、また書き込みます。
ありがとうございました。
まきもとさん、
その2行をデスクトップで test.vbs ファイルを作成し書き込み、
ダブルクリックして実行しましたが再現しませんでした。
とすれば、実行環境 (あるいはファイルにどう格納されているか)
に違いがありそうですね。
どうしてもわからないことがあり、書き込みさせて頂きます。
現在、VBScriptでコーディングしているのですが、
Dim objWSHShell
Set objWSHShell = Server.CreateObject("WScript.Shell")
intRet = objWSHShell.Run(strExePath & " 1," & mstrYearMonth, 0, False)
というコードは実行されるのに、
Dim Wk_ScriptName
Wk_ScriptName = WScript.ScriptName
というコードは、「この変数は宣言されていません。: 'WScript'」
というエラーが発生します。
どなたか、解決のヒントを頂けませんでしょうか?
よろしくお願いいたします。
\ をエスケープする必要があります。
例
var WshShell = new ActiveXObject('WScript.Shell');
var objExec = WshShell.Exec("C:\\Program Files\\K2Editor\\K2Editor.exe");
はじめまして。
IEの右クリックからアプリケーションを起動したいと思っているのですが、
<script language="JScript">
var WshShell = new ActiveXObject("WScript.Shell");
var objExec = WshShell.Exec("C:\Program Files\Hidemaru\Hidemaru.exe");
</script>
でやってみたんですけど、”指定したファイルが見つかりません。”というエラーが出てダメでした。
初歩的なことで申し訳ないのですが、どなたかご指導お願いします。
初めまして!いつもコッソリ拝見させて頂いております。
最近WSHを使い始めたばかりなのですが、Webの動作確認用スクリプトの作成を行っております。
実際人が確認するような動きをスクリプトで実現したいと思い(ボタンをクリック、文字を入力して検索等)、Sendkeysで作成に取り掛かりました。
その中でリンクをクリックした際、別ウィンドウが開く時があります。
IEオブジェクトを取得して確認して、そのオブジェクト上で確認作用の実現を考えておりますが(テキストを取得したり、Busyで同期を取る等)、別ウィンドウが開いた時、そのウィンドウはWSHの制御下でなくなってしまいます。
制御をそのウィンドウに移す事、若しくはその他の良い方法等がありましたら、ご指導頂けないでしょうか?
この出力を .bat ファイルにリダイレクトしてそれを実行することもできますね。
念仏くん、
| ATにセットする時間がシステム時間ならばBATファイルのみで実現できるので
| すが、システム時間+5分にしなければならないので、困り果ててます。
Subtype Date に関するマニュアルを参考にしてみてください。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/script56/html/vtoriVBScript.asp
Now() 関数, DateAdd() 関数, FormatDateTime() 関数を使ったサンプルをお
送りします。
[ 実行例 (cscript.exe で実行のこと) ]
C:\Documents and Settings\iriyak\デスクトップ>cscript //nologo test.vbs
AT 23:28 "c:\batch.bat"
C:\Documents and Settings\iriyak\デスクトップ>
[ サンプル (全角スペースは半角スペースに置き換えること) ]
batchCommand = "c:\batch.bat"
GenerateCommandLineWith(batchCommand)
Sub GenerateCommandLineWith(batchCommand)
Dim writeStream
Set writeStream = WScript.Stdout
fiveMinutesLater = DateAdd("n", 5, Now())
writeStream.Write("AT")
writeStream.Write(" ")
writeStream.Write(FormatDateTime(fiveMinutesLater, vbShortTime))
writeStream.Write(" ")
writeStream.WriteLine(DoubleQuote(batchCommand))
writeStream.Close()
End Sub
Function DoubleQuote(s)
DoubleQuote = Chr(34) & s & Chr(34)
end Function
はじめまして。
vbsで以下のような処理をしたいのですが実現可能でしょうか?
@システム時間(HH:MM)を取得する。
A取得したシステム時間(HH:MM)に+5分して、変数Aに格納する。
Bvbsから次のDOSコマンドを実行する
AT 変数A "c:\batch.bat"
困っているのはBのところです。
ATにセットする時間がシステム時間ならばBATファイルのみで実現できるのですが、システム時間+5分にしなければならないので、困り果ててます。
実現方法はVBSでもバッチ(DOSコマンド)でもかまわないのですが、実現方法を教えていただけないでしょうか?
どうぞ宜しくお願い致します。
はじめまして。わからないことがあって書き込みさせて頂きました。私のパソコンは起動するとスクリプトファイル”ファイル名”が見つかりません。というエラーメッセージが出てきます。このメッセージをでないようにしたいのですがどうしたらよいでしょうか。すみませんが返答よろしくお願いします。
Set ie_self=Shell.Windows.Item
はExplorerに限らず、IEも同じなので、
CloseIE.VBS
Set Shell=CreateObject("Shell.Application")
Dim ies(),k,ie_self
Set ie_self=Shell.Windows.Item
For Each ie In Shell.Windows
: If TypeName(ie.document)="HTMLDocument" Then
: : If ie Is ie_self Then
: : Else
: : : k=k+1
: : : ReDim Preserve ies(k-1)
: : : Set ies(k-1)=ie
: : End If
: End If
Next
For Each ie In ies
: ie.Quit
Next
ここで、降順でなく、配列転写を選んでいるのは、
ビルの解体で、最上階から順に壊すのはまだしも、跳び跳びに壊したら、どうなるものやら。
という不安からです。
降順も、ちょっと試したところでは問題ないようです。
>いりや さん 2004年 08月 24日 03時 43分 58秒
>こうした要素をきちんと理解してプログラムに反映させて初めて正しいプログラ
>ムが得られるのでしょうが、そのためのハードルがなんと高いことか。
いろいろ知っていると、つい使いたくなるものですが、そういう誘惑を抑えて、
筋のよい、堅実堅牢なプログラム作りを心掛けることが最重要だと思います。
でも、筋の良し悪しの評価は、むずかしいです。
私のおすすめは、アナロジーを考えることです。たとえば、
>For Each ie In shell.Windows
> ie.Quit
>Next
や
>For k=0 To shell.Windows.Count-1
> shell.Windows(k).Quit
>Next
昇順は、ビルの解体を1階からやるようなもの。 危険。
>For k=shell.Windows.Count-1 To 0 Step -1
>: shell.Windows(k).Quit
>Next
降順は、ビルの解体を最上階からやるようなもの。低コスト。
でもやっぱりちょっと不安です。
>For Each ie In shell.Windows
>: k=k+1
>: ReDim Preserve ies(k-1)
>: Set ies(k-1)=ie
>Next
>For Each ie In ies
>: ie.Quit
>Next
転写は、足場を組んでやるやるようなもの。高コスト。安全確実。
堅実堅牢なプログラム作りのほうで、私のお勧めのひとつは、
自己証明的プログラミングと呼んでるものです。
「〜のはず」をプログラム上でチェックします。
例えば、双方向リンクを考えてください。
[next]->[next]->[next]
[prev]<-[prev]<-[prev]
そこからひとつ抜く関数は、普通、
function remove(pTable){
pTable->next->prev=pTable->prev;
pTable->prev->next=pTable->next;
}
と書きますが、
function remove(pTable){
if(pTable->next->prev!=pTable||pTable->prev->next!=pTable) abort();
pTable->next->prev=pTable->prev;
pTable->prev->next=pTable->next;
}
のように、抜く前に、リンクが正しいことをチェックします。
WScript強制実行の判定でも、普通、
If UCase(fso.GetBaseName(WScript.FullName))="CSCRIPT" Then
' NG Run WScript.Exe
WScript.Quit
Else
' OK Continue
End If
のように書くところを、
Host=UCase(fso.GetBaseName(WScript.FullName))
If Host="CSCRIPT" Then
' NG Run WScript.Exe
WScript.Quit
ElseIf Host="WSCRIPT" Then
' OK Continue
Else
Err.Raise xxx
End If
のように、CScriptでなかったらWScriptのはずだ、をチェックします。
このように、もし「はず」どおりでなかったら、プログラムがそれ以上走らないようにします。
つまり、動いてるということは、「はず」どおりであることを意味します。
このようなチェックのオーバヘッドは数%で、実用上は誤差範囲です。
実用上は、その程度の性能より品質のほうが、よほど重要です。
>いりや さん 2004年 08月 24日 03時 43分 58秒
>これを書いていて、並行プログラミングの難しさを実感しました。
>ShellWindows コレクションに対して副作用を与える主体がこのプロセス内に閉
>じていて、ie.Quit() が非同期ではなく同期で実行されるような、そんなシンプ
>ルな実行モデルであれば、このようなタイミングイシューも発生しない。
うーん、そうでしょうか。以下はそんなシンプルな実行モデルです。
よくある制御表チェインを想像してください。
[anchor]->[next]->[next]->>->[0]
これを解放してください。
×案
for(pTable=anchor;pTable;pTable=pTable->next){
free(pTable);
}
>For Each ie In shell.Windows
> ie.Quit
>Next
や
>For k=0 To shell.Windows.Count-1
> shell.Windows(k).Quit
>Next
は、この×案に通じるものがあります。
忍法水渡りの術。左足が沈む前に右足を出す。結局、沈むだけ。。。
×案は、論理的には明らかな障害、バグなのですが、始末の悪いことに、
現実にはなかなか露顕しません。
ユーザが再現スクリプトを提示しないと、障害と認めないような会社では、
この種の障害は、再現スクリプトを作ることが困難なため、なかなか直りません。:-(
さて、以下はどれが正しいでしょうか。
この障害はマルチスレッドでのみ発生する。
この障害は(シングルスレッドでも)発生する。
(勿論、この制御表チェインを操作するのは私だけという前提です。)
で、私の推奨する○案は、
while(anchor){
pTable=anchor;
anchor=anchor->next;
free(pTable);
}
参考までに、あまり好きではないが、間違っているとは言えず、一応は正しい、
△案
for(pTable=anchor;pTable;pTable=next){
next=pTable->next;
free(pTable);
}
anchor=NULL;
要するに、
水渡りの術で沈まないためには、右足を出す前に左足をしっかりした足場に置け。
ということです。
性能に敏感な人は、
△案はコンパイラの最適化でメモリアクセスがレジスタアクセスになり性能的に有利、
○案はanchorのところがレジスタに載らないので性能的に不利。などと言うのですが、
性能クリティカルな箇所を除いて、この程度の性能差の優先順位は低いと思います。
私は、△案より○案のほうが堅牢(ロバスト)でよいと思います。
>いりや さん 2004年 08月 24日 03時 10分 38秒
>上は ies 配列に windows メソッドの返す ShellWindows コレクションの要素を
>コピーした後は最後に count プロパティーを参照するときに一回呼んでいます。
>一方、下は、shell.Windows(k).quit で、都度呼んでいます。
>この違いから、最後の count プロパティーがゼロになったりならなかったりす
>る理由を「count プロパティーの変化の引き金の一つは windows() メソッドに
>よって引かれる」と推理してみました。
>とすれば、「すべて消えて、かつ、Countも0」の説明ができます。
昇順と降順の違いかと思っていたら、そういう違いがあったのですね。
ただ、理由はもっと単純に、オブジェクト呼出しのオーバヘッドが、
Sleepを入れているのと同じ効果を出しているのではありますまいか。
試しに、10個のExplorerをQuitするループの時間をTimerで計ると、それぞれ、
配列 0.47sec
降順 1.29sec
でした。
そこで、配列転写にSleep 40を入れると0.50secできれいに消えました。
やはりSleep効果のようですね。
おひさしぶりです。黒騎士F91です。
過去ログを調べたのですが、解決できなかったので質問させていただきます。
Win98,Win2000User権限ではファイルのダウンロードダイアログ警告が出ずに実行できるVBScriptファイルのショートカットを実行できるのですが、
XPproSP1コンピュータ管理者権限ではファイルダウンロードの警告が出てきます。元々XPはテストしてなかったのですが、新規PC購入によりテストすることになりました。
「ファイルによっては、コンピュータに問題を起こす可能性があります。」のダイアログ内容から、レジストリ関連の命令が原因だと思ったのですが、レジストリの読み込みはしていても、書き込みはしていません。
Win2000とXPで、IE6のオプションのセキュリティレベルは全て同じなっています。
XPでファイルダウンロードの警告がでる原因は何か、解らないでしょうか?
思い当たることは調べたのですが、後何を調べれば良いのかわからなくなってしまい質問させていただきました。
> # たとえば、拡張子(*.pifや*.lnkや*.urlなど)の指定を忘れているとか…。
次のスクリプトファイルに対象ファイルをドラッグ&ドロップして、
このあたりを目視することが可能です。
Set Arguments = WScript.Arguments
If Arguments.Length = 1 Then
WScript.Echo(Arguments.Item(0))
End If
※ 全角スペースは半角スペースに変更してください。
》 ja さん
> ショートカットはさらっとムシされてしまいます^^
私の環境では、(FileSystemObjectの)FileExistsメソッドで、
ショートカットの有無をチェック出来ていますよ。
ショートカットのファイル名が間違っていないか確認してみてください。
# たとえば、拡張子(*.pifや*.lnkや*.urlなど)の指定を忘れているとか…。
こんばんは
初めて投稿します。
いま、ショートカットが存在するかどうか?というvbsプログラムをつくりたいのですがファイルやフォルダーはexistsで存在確認できるのですが
ショートカットはさらっとムシされてしまいます^^
どなたかご存知の方がいましたらよろしくお願いします。
Smalltalk with Style という Smalltalk 言語のプログラミング・スタイルを説
く本があるのですが、今回の配列を操作するときの指針が紹介されていました。
指針の後者を適用したものが、ばんのしゃーによかばんたさんのおっしゃる「業
務用には確実な配列」でしょうか。
// ここから
Guideline 100
Avoid modifying a collection while iterating over it. Use the proper
protocols or make a copy of the collection first.
Example (よくない例)
aCollection do: [:element |
element = someFilterCriteria
ifTrue: [ aCollection remove: element ]].
(中略)
Example (よい例)
aCollection := aCollection reject: [: element |
element = someFilterCriteria ].
もしくは
aCollection copy do: [:element |
element = someFilterCriteria
ifTrue: [ aCollection remove: element ]].
// ここまで (Page 80)
ここで紹介されている reject: は ie.Quit のようにまわりにまわって
ShellWindows コレクションに副作用を与えるものではなく、ある条件 (element
= someFilterCriteria) を満足する要素を除いたものを集めるので、直接的です
が、ご参考までにどうぞ。
!!!(びっくり仰天暫し呆然)
オブジェクトブラウザでShellWindowsを見ていたら、
Item([index])となっているではありませんか。
試しに、いくつかのexplorerを立ち上げて、違うフォルダを表示させて、
MsgBox shell.Windows.Item.LocationURL
してみると、直前にアクティブにしたフォルダを表示します。
あのCloseWinでの、SendKeys等々の苦労は一体何だったのでしょう。。。
なんて、嘆いていても仕方がないので、早速使ってみましょう。
Set Shell=CreateObject("Shell.Application")
Dim ies(),k,ie_self
Set ie_self=Shell.Windows.Item
For Each ie In Shell.Windows
: If InStr(typename(ie.document),"IShellFolderViewDual") Then
: : If ie Is ie_self Then
: : Else
: : : k=k+1
: : : ReDim Preserve ies(k-1)
: : : Set ies(k-1)=ie
: : End If
: End If
Next
For Each ie In ies
: ie.Quit
Next
これにて、駄作シリーズにピリオド。
//E:VBS - & wShell.Execの続報です。
98/MEでも可能です。
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("Command.com /C MORE | WScript.EXE -E:VBS -")
oExec.StdIn.WriteLine "MsgBox ""aaaa"" "
oExec.StdIn.WriteLine "MsgBox ""bbbb"" "
oExec.StdIn.Close
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("Command.com /C ECHO MsgBox ""aaaa"" | WScript.EXE -E:VBS -")
コンソールが鬱陶しいときは、
98/MEでは、
Command.comのPIFファイルを作ってそれを指定。PIFのプロパティで最小化を指定。
2000/XPでは、???
CMD.EXEのLNKファイルを作っても、wShell.Exec出来ない。
それでは、と wShell.SendKeys "%( n)" を投げても、効かない。
コンソールにはSendKeysが効かないんですね。
せいぜい、コンソールのプロパティ設定でWindowSizeをなるべく小さくするくらい。
同じタイトルのコンソールに適用をチェック。
なんか、よい方法ないですかね。
SHELL32.DLLのUnicode Stringsをチェックすると、WindowSizeの他にWisdowPosition
というのがあるようなので、これをデスクトップ画面外に持って行けばすっきりするかも。
こんにちは(*'-')
PCのホストネームを取得して条件分岐させたいと考えているのですが、アドバイスを頂けないでしょうか。
適用PCのOSがWin2K/98と2種類ある為、共通コマンドのpingを使って以下のように実行してみました。
WshShell.Run "ping -n 1 localhost > c:\temp\hostname.txt"
ところがW2Kでは、実行するとDOS窓が開き、"Bad Parameter >."とだけ表示され、"c:\temp\hostname.txt"が生成されません。
W98はDOS窓が閉じるのが早く、同じエラーなのかは不明ですが、やはり同様に"c:\temp\hostname.txt"が生成されません。
もちろん、コマンドラインから"ping -n 1 localhost > c:\temp\hostname.txt"
だけ実行してみると、正常動作します。
どうしてWshShell.Runからコマンド実行すると、動きが変わってしまうのでしょうか?
[追記]
本当は変数等に一発で代入出来ればよいのですが、諸事情によりPCがWsh5.1なので、WshExecが使えないのです。
仕方ないので、ファイルに落としてから再読込する方法で考えました。
もしもっとスマートな方法があれば、是非教えて下さい。
ちょっと話が横道にそれますが、
| For Each ie In shell.Windows
| : ie.Quit
| Next
|
| こちらは、以前からばんのしゃーによかばんたさんが指摘していた「ShellWindows
| コレクションの要素に対する繰り返しの中で、ShellWindows コレクションに副
| 作用を与える操作」をしたコーディング誤りの例でしょう。
|
| ちょっと内部の振る舞いを想像してみました。
|
| 1. VBScript スクリプトエンジンで shell.Windows の呼び出しによって得た
| ShellWindows コレクションへのリファレンスを得る。
| 2. ie 変数に、item(インデックス) の戻り値をバインドする。
| 3. ie.Quit を実行する。
| 4. (上限に達するまで) インデックスを 1 増やして Go to 2.
これを書いていて、並行プログラミングの難しさを実感しました。
ShellWindows コレクションに対して副作用を与える主体がこのプロセス内に閉
じていて、ie.Quit() が非同期ではなく同期で実行されるような、そんなシンプ
ルな実行モデルであれば、このようなタイミングイシューも発生しない。
だけれども、実際は、ShellWindows コレクションは、ユーザによる画面操作に
よってどんどん変化するし ie.Quit() は非同期で実行される。
以前 WScript.Network オブジェクトの EnumNetworkDrives() を通じてネットワー
クドライブの動的な map/remove が話題にのぼりましたが、そのときにでてきた
問題と同じ構造をしています。
こうした要素をきちんと理解してプログラムに反映させて初めて正しいプログラ
ムが得られるのでしょうが、そのためのハードルがなんと高いことか。
ばんのしゃーによかばんたさん、
ばんのしゃーによかばんたさん 2004年 08月 22日 19時 58分 44秒
| Set shell=CreateObject("Shell.Application")
| Dim ies(),k
| WScript.Echo shell.Windows.Count
| For Each ie In shell.Windows
| : k=k+1
| : ReDim Preserve ies(k-1)
| : Set ies(k-1)=ie
| Next
| For Each ie In ies
| : ie.Quit
| Next
| WScript.Echo shell.Windows.Count
|
| では、この時点ではまだCount>0なのですが、
| (※ つまり、ie.Quitは非同期に実行されて、shell.Windowsへの反映は遅延する、)
| 確実にすべて消えます。
これと、
| Set shell=CreateObject("Shell.Application")
| WScript.Echo shell.Windows.Count
| For k=shell.Windows.Count-1 To 0 Step -1
| : shell.Windows(k).quit
| Next
| WScript.Echo shell.Windows.Count
この違いをながめて気づいたことがあります。Shell.Application オブジェクト
の windows() メソッドの呼び出しポイントです。
上は ies 配列に windows メソッドの返す ShellWindows コレクションの要素を
コピーした後は最後に count プロパティーを参照するときに一回呼んでいます。
一方、下は、shell.Windows(k).quit で、都度呼んでいます。
この違いから、最後の count プロパティーがゼロになったりならなかったりす
る理由を「count プロパティーの変化の引き金の一つは windows() メソッドに
よって引かれる」と推理してみました。
とすれば、「すべて消えて、かつ、Countも0」の説明ができます。
ただ windows() メソッドと quit() は両方とも並行して動作するので、count
が 0 にならないタイミングイシューが発生するシナリオはありえます。
そのため ShellWindows コレクションの count プロパティーに依存したロジッ
クを考えるときは、ShellWindows コレクションに対する副作用を与えるポイン
トをプログラマがすべて把握できていない状況はプログラマにとっては厳しいで
すね。
今回の話は、ウインドウをすべて閉じることが目標なので、上記のタイミングイ
シューはウインドウを閉じることには影響を与えないのでその状況そのものがた
またまではありますがイシューにはならなさそうです。
ところで、
For Each ie In shell.Windows
: ie.Quit
Next
こちらは、以前からばんのしゃーによかばんたさんが指摘していた「ShellWindows
コレクションの要素に対する繰り返しの中で、ShellWindows コレクションに副
作用を与える操作」をしたコーディング誤りの例でしょう。
ちょっと内部の振る舞いを想像してみました。
1. VBScript スクリプトエンジンで shell.Windows の呼び出しによって得た
ShellWindows コレクションへのリファレンスを得る。
2. ie 変数に、item(インデックス) の戻り値をバインドする。
3. ie.Quit を実行する。
4. (上限に達するまで) インデックスを 1 増やして Go to 2.
4. → 2. にいたる途中に ShellWindows コレクションを、このプロセス以外の
誰かが変更しているのでしょう。変更するにあたり、新しく数え上げるロジック
に変更がなければ、要素が一個減って詰まることになる。
このプロセスは知る由もなくインデックスを増やして item() で得ようとするの
で、当初のコレクションから比べて一個飛ばしでアクセスしている。
「いくつか消えずに」のいくつかというのはこの飛び越した要素だと推測します。
いりや
みなたんです!メル友募集なりぃv(^^)v
いい感じになったら実際会ってもいいなりょ!
写メつけて送ってチョ写メなぃ人ゎシカトするなりぃ('〜`;)
みなゎR歳ダョ!写メつけてくれた方が返事ゎ確実だにゃんヘ(^エ^=)
//E:VBS - については、
>ばんのしゃーによかばんた さん 2004年 03月 14日 20時 26分 55秒
>単純な応用としては、スクリプト内で子スクリプトを生成して、ExecでCScriptに
>StdIn経由で喰わせる。パラに走る子スクリプトを別ファイルを作らずに実行できます。
を一番最初に考えたのですが、
wShell.Execのほうで、随分苦労いたしまして、(過去ログ参照)
>ばんのしゃーによかばんた さん 2004年 03月 15日 19時 27分 29秒
>最初の応用については同じ手が使えるか研究中です。
のまま、研究が停まっていました。
今回、研究を再開して、いくつか実験しましたところ、やっとのことで成功しましたので、
報告します。
2000/XPのみ。98/MEは不可。
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("CMD.EXE /C Command.com /c WScript.EXE -E:VBS -")
oExec.StdIn.WriteLine "MsgBox ""aaaa"" "
oExec.StdIn.WriteLine "MsgBox ""bbbb"" "
oExec.StdIn.Close
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("CMD.EXE /C ECHO MsgBox ""aaaa"" | command /c WScript.EXE -E:VBS -")
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("CMD.EXE /C (ECHO MsgBox ""aaaa"" & ECHO MsgBox ""bbbb"") | command /c WScript.EXE -E:VBS -")
まさに組合せのパズルですね。
CScript.EXEでも同じ。
コンソールが開くのは、愛嬌で我慢。(LNKで最小化できるかも。)
メリットは何と言っても一時ファイルを作る必要がないことですね。
WScript //E:VBS - の続報です。
? CScriptの間違いでは ? と思ったひと。ピンポーンです。
スクリプトを標準入力から読み込むのが「-」指定なんだから、CScriptだろう、
と思うのが常識です。しかし、そんな常識的な発想を裏切るのがMSの常です。
以下をお試しください。
single-line.bat for 98/ME
echo MsgBox "aaa" | WScript //E:VBS -
single-line.cmd for 2000/XP
Command.com /c echo MsgBox "aaa" ^| WScript //E:VBS -
multi-line.bat for 98/ME
@FIND /V "@" <%0 | WScript //E:VBS -
@GOTO :@EOF
WScript.Echo "AAA"
WScript.Echo "BBB"
WScript.Echo "CCC"
:@EOF
multi-line.cmd for 2000/XP
@COMMAND /C MORE +1 %0 ^| WScript //E:VBS - & GOTO :EOF
WScript.Echo "AAA"
WScript.Echo "BBB"
WScript.Echo "CCC"
WScriptのメリットは特にないです。
>isp1014 さん 2004年 08月 18日 15時 43分 37秒
>ASPに記述したVBSについての質問です。
>あるWEBページでボタンを押下した時に
>ファイル選択ではなくて、フォルダを選択したいのです。
>(フォルダ選択ダイアログボックスの表示)
>そのときに使用する命令として
>BrowseForFolderオブジェクトを使用しています。
>しかし、実行してみると「書き込みできません」と
>VBSのエラーが発生してしまいます。
>WEBではない、ただのVBSではうまく動作します。
>(クライアント上のVBSファイルを実行)
>ひょっとしてWEBでは使用できないのでしょうか?
>使用できないのであれば、別の方法があるのでしょうか?
>大変困っています。
もし、どうしても、と言うなら、
フォルダ選択処理を、"Scripting.FileSystemObject"でVBSファイルに書き出し、
ボタンを押下したとき、"WScript.Shell"でRunする。
VBSファイル側は、結果をIEの画面に書き込んで、後の処理をキックする。
と言うのはどうでしょう。
駄作の屋上屋を架すようですが、
むたぐちさんを真似て「他のフォルダを閉じる」VBSを作ってみました。
※結局、VBSファイル方式に戻ってきました。
「お気に入り」に格納して、実行します。
CloseWin.VBS
Set wShell=CreateObject("WScript.Shell")
Set Shell=CreateObject("Shell.Application")
Dim ies(),k,ie_self
wShell.SendKeys "%( )"
For Each ie In Shell.Windows
: If InStr(typename(ie.document),"IShellFolderViewDual") Then
: : If ie.StatusText="このウィンドウを通常の大きさに戻します。" Then
: : : Set ie_self=ie
: : Else
: : : k=k+1
: : : ReDim Preserve ies(k-1)
: : : Set ies(k-1)=ie
: : End If
: End If
Next
wShell.SendKeys "{ESC}"
If Not IsEmpty(ie_self) Then
: For Each ie In ies
: : ie.Quit
: Next
End If
※これだと、比較的、違和感なく、使えるのではないでしょうか。
※また、応用も効きそうです。
※SendKeysは確実性の低い方法ですが、StatusTextのチェックと組み合わせると、
精度が向上したり、結構応用が効くのではないかと予予使い道を考えておりました。
例えば、InvokeVerbで起動できない動詞も、{F10}と{DOWN}を繰り返しSendKeysして、
StatusTextで確認して{Enter}を送ることで、実行できるとか。
あ、あと、wshでntfsアクセス権は設定可能なのでしょうか?これもよろしくお願いします
過去にファイル属性について質問したものです。
c:\testというフォルダーの中にある全ファイルとフォルダーの
属性を解除したいのですが
例えば
dim objff,objfolder
set objff = WScript.CreateObject("Scripting.FileSystemObject")
set objfolder = objff.getfolder("c:\test\")
for each obj in objfolder.subfolders
obj.attributes = 0
next
と作ると中の全フォルダーだけ解除だし
dim objff,objfolder
set objff = WScript.CreateObject("Scripting.FileSystemObject")
set objfolder = objff.getfolder("c:\test\")
for each obj in objfolder.files
obj.attributes = 0
next
と書くとtestの直下のファイルのみ解除になります。
testの中の全てのフォルダー内のファイルの属性を解除するにはどうすればいいのでしょうか?知恵をお貸しください^^よろしくお願いします。
>isp1014 さん 2004年 08月 18日 15時 43分 37秒
>ASPに記述したVBSについての質問です。
>あるWEBページでボタンを押下した時に
>ファイル選択ではなくて、フォルダを選択したいのです。
>(フォルダ選択ダイアログボックスの表示)
>そのときに使用する命令として
>BrowseForFolderオブジェクトを使用しています。
>しかし、実行してみると「書き込みできません」と
>VBSのエラーが発生してしまいます。
>WEBではない、ただのVBSではうまく動作します。
>(クライアント上のVBSファイルを実行)
>ひょっとしてWEBでは使用できないのでしょうか?
>使用できないのであれば、別の方法があるのでしょうか?
ASPは知りませんが、
クライアント上のHTMファイルなら使えます。
>大変困っています。
<input type=file>を使って、フォルダの任意のファイルを選択させる、
という運用が、現実的で、かつ、安全 & 確実ではないでしょうか。
だって、スクリプトやActiveXコンポーネントやらを動かすために、
クライアントのセキュリティレベルを下げさせるのでしょう。
私は下げたくない。:-<
>管理人むたぐち さん 2004年 08月 02日 16時 52分 50秒
>To: ちゃきちゃっき〜 さん
>> なのですが、vbs起動時にIEが起動していないと
>> 行:16
>> エラー:起動されたオブジェクトはクライアントから切断されました
>> コード:80010108
>> ソース:(null)
>> のエラーで落ちる場合があります。
>For Each objWindow In objShell.Windows
>の中で、IEのオブジェクトを終了させる処理を入れているからという気がします。
>一度別の配列にobjShell.Windowsの各要素を格納してから、
>その後ポップアップかどうかを判定し、ポップアップなら終了させる処理を
>入れてみてはいかがでしょうか。
その後の結果の成否、指摘の正誤が不明なので、追試してみました。
Set shell=CreateObject("Shell.Application")
For Each ie In shell.Windows
: ie.Quit
Next
では、いくつか消えずに残ります。
Set shell=CreateObject("Shell.Application")
Dim ies(),k
WScript.Echo shell.Windows.Count
For Each ie In shell.Windows
: k=k+1
: ReDim Preserve ies(k-1)
: Set ies(k-1)=ie
Next
For Each ie In ies
: ie.Quit
Next
WScript.Echo shell.Windows.Count
では、この時点ではまだCount>0なのですが、
(※ つまり、ie.Quitは非同期に実行されて、shell.Windowsへの反映は遅延する、)
確実にすべて消えます。
やはり、確実にやるには、配列に転写しないといけないようですね。
ところで、降順方式はというと、
Set shell=CreateObject("Shell.Application")
WScript.Echo shell.Windows.Count
For k=shell.Windows.Count-1 To 0 Step -1
: shell.Windows(k).quit
Next
WScript.Echo shell.Windows.Count
の場合も、何回かやってみたところでは、すべて消えて、かつ、Countも0でした。
これがどの程度確実なものなのかは不明です。インプリメントに依存しそうです。
お勧めは、個人用には簡単な降順。業務用には確実な配列でしょうか。
大ボケの上塗りみたいですが、
>ばんのしゃーによかばんた さん 2004年 08月 18日 16時 42分 46秒
>メモリ処理とIO処理を単純に比べれば、当然のことながら、メモリのほうが速い。
>以前のは、y=c*x**2とy=b*xの比較で、今回はy=b*x同士のbの比較ですね。
>概算で、10msec*IO回数で見積もります。
>ただし、IO Cacheがwrite backの場合は、効果は小さい。
テストプロの測定結果を見ると、メモリ処理は、40nsec、IOは400nsecくらいで、
確かに、メモリ処理のほうが1桁くらい速いのですが、実IOの10msecに比べれば
1〜2桁くらい小さい。sequential writeなので、OSのIO bufferingが効くのでしょう。
というわけで性能改善の余地はあまりなさそうです。
OS論理IOと実IOの1〜2桁オーダ差は、4096byteバッファ/行(80byte)=50
のような数に由来するのかも知れません。
駄作の上塗りのようですが、「他のフォルダを閉じる」URLを作ってみました。
「お気に入り」に格納して、実行します。
[InternetShortcut]
URL=javascript:execScript('Set shell=CreateObject("Shell.Application")'+'\n'+'For k=shell.Windows.Count-1 To 0 Step -1'+'\n'+'If InStr(TypeName(shell.Windows(k).Document),"IShellFolderViewDual")>0 Then shell.Windows(k).Quit'+'\n'+'Next',"VBScript")
または、
[InternetShortcut]
URL=vbscript:execute("Set shell=CreateObject(""Shell.Application"")" & vbLF & "For k=shell.Windows.Count-1 To 0 Step -1" & vbLF & "If InStr(TypeName(shell.Windows(k).Document),""IShellFolderViewDual"")>0 Then shell.Windows(k).Quit" & vbLF & "Next")
※JScriptだと、TypeName相当がない(?)ので、VBScriptで作ってみました。
※ただ、エクスプローラから実行すると、インターネットゾーンになってしまって、
セキュリティレベルが高いと動きません。下げると、動き出しますが、
「書き込みできません」や「文字が正しくありません」などのエラーになります。
つまり、結局、役立たずです。:-p
駄作の連作のようですが、「他のフォルダを閉じる」HTMを作ってみました。
「お気に入り」に格納して、実行します。
チラっどころではない変化をします。が、誤動作は少ないかも。
CloseWin.HTM
<html>
<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=shift_jis">
<title>
ただいま、他のフォルダを閉じております。しばらく、そのままでお待ちください。・・・
</title>
<script language=VBScript>
Sub CloseWin()
Set shell=CreateObject("Shell.Application")
'MsgBox shell.Windows.Count
For k=shell.Windows.Count-1 To 0 Step -1
' MsgBox TypeName(shell.Windows(k).Document)
If InStr(TypeName(shell.Windows(k).Document),"IShellFolderViewDual")>0 Then
shell.Windows(k).Quit
ElseIf shell.Windows(k).LocationURL=window.location Then
Set ie=shell.Windows(k)
End If
Next
ie.GoBack
End Sub
</script>
<head>
<body onload=CloseWin>
ただいま、他のフォルダを閉じております。<br>
しばらく、そのままでお待ちください。・・・
</body>
<html>
大ボケでした。
>ばんのしゃーによかばんた さん 2004年 08月 18日 16時 42分 46秒
>そこで、件のスクリプトですが、
>のように変えれば、相当速くなります。
一般論としては、正しいのですが、
件のスクリプトでは、IOを文字化け検出に利用してましたので、
変えると、元の木阿彌になります。
いまのところ、文字化け対策と性能改善は二者択一です。
両立は今後の研究課題、、、、
ばんのしゃーによかばんたさん
実用スクリプト内にある読取専用属性解除プログラムのro.lzhを活用したいのですが、このプログラムを起動するだけで特定フォルダ内(たとえば"c:\test")の全フォルダやファイルの読取専用属性を解除するプログラム(すでにプログラムの中に"c:\test"が指定してある)がほしいのですがどのようにしたらよろしいのでしょう?なにとぞ知恵をお貸しください^^
の件で回答ありがとうございます。
できることならばwsh(vbs)上で動くプログラムに組み込みたいんですよ。
なのでvbsのプログラムでどうにかなれば・・・とおもうのですが。。。
まだプログラムの超初心者なので本当にすいませんがお願いします。
》 たけゆき さん
> 記述法がわからないため、"Service Of A"と認識させることができません。
"NET STOP ""Service Of A"" "
のように、ダブルクォーテーションを連記してください。
http://blogs.sqlpassj.org/yamaken/archive/2004/08/16/3760.aspx
もしくは、
》 魔界の仮面弁士 2004年 07月 18日 18時 13分 09秒
のログにあるように、ServiceStopメソッドを使う方法もあるかと思います
CreateObject("Shell.Application").ServiceStop "Service Of A", False
サービスを停止・開始するVBスクリプトを作成中です。
あるサービス「Service Of A」を停止させる処理として、
Sendkeysを使って実現しようとしているのですが、
サービス名に半角スペースがあり、ダブルコーテーションの
記述法がわからないため、"Service Of A"と認識させることができません。
いろいろ調べましていくつかトライしましたがNGでした。
どなたかおわかりになる方がいらっしゃればご教授お願いします。
【NG例】
・WshShell.SendKeys "NET STOP Service Of A"
・WshShell.SendKeys "NET STOP "Service Of A""
・WshShell.SendKeys "NET STOP '"'Service Of A'"' "
サービスを停止・開始するVBスクリプトを作成中です。
あるサービス「Service Of A」を停止させる処理として、
Sendkeysを使って実現しようとしているのですが、
サービス名に半角スペースがあり、ダブルコーテーションの
記述法がわからないため、"Service Of A"と認識させることができません。
いろいろ調べましていくつかトライしましたがNGでした。
どなたかおわかりになる方がいらっしゃればご教授お願いします。
【NG例】
・WshShell.SendKeys "NET STOP Service Of A"
・WshShell.SendKeys "NET STOP "Service Of A""
・WshShell.SendKeys "NET STOP '"'Service Of A'"' "