ちゃっぴ さん 2006年 02月 11日 17時 51分 44秒

To AKA さん 2006年 02月 11日 06時 38分 52秒

> こんな感じ?
> <<IISCOPY.HTM>>
> <A HREF=IISCOPY.VBS>ここをクリックして「開く(O)」を選択し、ファイルコピープログラムを起動してください</A>
>
> <<IISCOPY.VBS>>
> MsgBox "コピー開始します"
> 'ここでコピー実行
> MsgBox "終わりました"

いえ、そもそも Web を使用することが必要か?
といったところからの疑問があります。

VBS を配布して実行してやったりしてもいいわけですし。

まあ、とはいえおかれている状況がみえないので、なんともいえませんが・・・

> そもそも「互換性」の観点からはこんな重要な関数に対してそんなドラスティックな仕様変更は例えしたくてもできないと思いませんか?
> 仮に変更したのならばマイクロソフトは必ずそのことをAPIリファレンスに書くはずです。そうでないと大混乱が起きますから(^^;)

混乱が起きた結果の修正ではないんですかね?

まあ、当時は今ほど脆弱性とかに無頓着な部分があったので、
特に強い反発を受けたと思いますが、現在だったらどうでしょうかね?

とりあえず、OS が 64bit に移行する Timing で修正するってことは
できないでしょうかね?

64bit Native で動かす Application はどうせ作り直すでしょうし・・・

ちゃっぴ さん 2006年 02月 11日 17時 41分 24秒

To 管理人むたぐち さん 2006年 02月 06日 20時 25分 27秒

> そもそもスクリプトを利用する目的は、人間の手でやるには面倒くさい
> 定型作業を自動化するというところにあると思います。
> なので、自動化に要するコストが実際に手動でやるコストより安くないと
> おいしくないです。

たしかにそういう面はありますが、教えてすらいないことによって、
必要になったときに対応できない(する必要すら感じていない)
ってのが問題なわけなのです。

なので、 この辺のことは、できるだけ早いうちに教える
必要があると思っています。

とはいえ、仕様があまり整理されていない & 明確な Guidline が
非常に少ないこともあり、理解している人が少数となっているのが
現状でしょうね。

なので、そういうのを書いてしまうのはある意味仕方がないです。

ただし、理解しているのであれば、そういう Sample を示すべきではないでしょう。
初めて扱う人は、それこそ Sample をそのままとか、
理解せずにちょっと変更して利用するもんですから・・・

少なくとも、そういう考慮をする必要があるというのは、
あわせて記述する必要があると思います。

ちゃっぴ さん 2006年 02月 11日 17時 27分 11秒

To ばんのしゃーによかばんた さん 2006年 02月 06日 16時 11分 49秒

> ほら、これが「なぜそうするのかが、誰にでも分かるように書」いてない典型例です。

空白を含む Path は引用符で囲め という記述はどこかで見た覚えがあったので
調べていたのですが、Windows 2000 の Help にはちゃんと記述がありました。

ドキュメントまたはプログラムへのパスを指定する
http://www.microsoft.com/windows2000/ja/server/help/win_tray_specify_path.htm

まあ、「cmd」 の Help を読めばわかりますが、これでは非常に不十分ですが、
一応記述はあります。ところが、なぜか Windows XP のほうにはこれがないようです。
なぜ、削除されたのか?非常に疑問ですが・・・

> その構文を使うときは、曖昧さをなくすため、正しくは、
> wshShell.Run """cmd.exe"" /s /k """"cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""""
> なのでは?

これは、おっしゃるとおりです。

AKA さん 2006年 02月 11日 09時 53分 21秒

>>ばんのしゃーによかばんた さん 2006年 02月 06日 16時 11分 16秒

> >ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒
> >|ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒
> >|知ってました? ExecメソッドがLFNを完全にサポートしていたのを。
> >|http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/technic.htm
> >| RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。
> >ここで、むたぐちさんの昔の記事を引用しているのは、
> >マイクロソフトのExecメソッドの開発者も、同じように考えたみたい、という意味です。

>を変更。

これって私へのレスみたいなものですよね???

修正しようとしておられるようですが、却っておかしくなってしまっています(^^;)

>>ばんのしゃーによかばんた さん 2006年 02月 07日 14時 33分 49秒

> >知らなかった。CreateProcessがLFNを完全にサポートしていたのを。

>しかし、元の仕様は違ったようです。元の仕様が正しかったのにどうして?

違います(^^;)

CreateProcess()は最初からこの仕様です。

別に色々調べずとも、Win98時代に管理人さんが

>LFNを完全にサポート

しているものがRunの他にあることを知っているわけですからすでに明白ではないですか。

>サポート技術情報
>[NT] アプリケーション起動時にアクセスが拒否される

この文書ですが、

>システムのパーティションのルート ディレクトリに Programというフォルダが存在する場合

にエラーが起こる、ということになっています。
すなわち、「Program」が存在しない場合にはCreateProcess()は""なしの「Program Files」を一つのフォルダ名として解釈できる、ということです。
ですからこれも以前から同じだったという証拠の文書、ということになります(^^;)

そもそも「互換性」の観点からはこんな重要な関数に対してそんなドラスティックな仕様変更は例えしたくてもできないと思いませんか?

仮に変更したのならばマイクロソフトは必ずそのことをAPIリファレンスに書くはずです。そうでないと大混乱が起きますから(^^;)

>Execメソッド→CreateProcess。時間軸は微妙。

したがってこれは微妙ではなく全く無いのです。




あと、リストビュー調査官は見たのかな?

見たのかどうかさえも教えてもらえないとはのう・・・

AKA さん 2006年 02月 11日 06時 38分 52秒

タスクマネージャなどでプロセス一覧を出すとメインモジュールファイル名は出るけれど、コマンドラインは出ません。複数の同じファイル名のプロセスはコマンドラインが違っていても区別ができません。

そこで作りました。

GETPCL.EXE

http://gamdev.org/up/img/4613.lzh
(なぜかWikiのアップローダにアクセスできないので別の場所に置きました。ここは何週間かすると消えると思います)

プロセスIDを指定すると、そのプロセスのコマンドラインを取得して表示するツールです。

例えば複数のWScript.exeが動作中の場合、どれがどれなのか判別するのを助けることができます。まあさすがに全く同じVBSファイルを実行中とかだとそれは区別できませんが・・・ 区別したい場合はダミーのパラメータをコマンドラインに識別子として入れておくとか。(あとユーザーが明示的に起動したわけではないプロセスがどんなコマンドラインで起動されているのかこっそり調べたりすることもできたりするワケなんだ、コレが)

Win9xでは動作しません。

あとサービスプロセスなどは取得できません。


>>いちご さん 2006年 02月 03日 08時 35分 13秒
>恐れ入りますが、ちゃっぴ さんでしたら、
>どのような処理にされるのでしょうか?

>>ちゃっぴ さん 2006年 02月 04日 00時 30分 39秒
>File Server においてあるものを実行させたり

こんな感じ?

<<IISCOPY.HTM>>
<A HREF=IISCOPY.VBS>ここをクリックして「開く(O)」を選択し、ファイルコピープログラムを起動してください</A>


<<IISCOPY.VBS>>
MsgBox "コピー開始します"
'ここでコピー実行
MsgBox "終わりました"


>>管理人むたぐち さん 2006年 02月 03日 14時 16分 54秒
>セキュリティ警告

>>ちゃっぴ さん 2006年 02月 04日 00時 30分 39秒
>ActiveX に Code 署名

実はあるんですよね穴が・・・書けませんが・・・

管理人むたぐち さん 2006年 02月 08日 17時 56分 53秒

To: とうし さん

こちらの環境(Windows XP Pro + Office 2003)では正常に動作しました。
もし動作しないのがタイミングの問題だとすれば、
SendKeysの前に WScript.Sleep 100 のように
100msecほど待ち合わせを入れてみてはいかがでしょうか?

ただ、SendKeysはタイミングの問題などがあり、あまり精度の高い
結果が得られないことも事実です。

ExcelはオートメーションオブジェクトとしてWSHから制御可能ですので、
そちらのアプローチを採用してみるのはいかがでしょうか。

例1:
'C:\test\test.xlsを開いた状態で
Set excel = GetObject("C:\test\test.xls")
excel.ActiveSheet.Cells(1,1) = "aaa"

例2:
'スクリプトから新しくシートを作る
Set excel = CreateObject("Excel.Application")
excel.Visible = True
excel.Workbooks.Add.ActiveSheet.Cells(1,1) = "aaa"

とうし さん 2006年 02月 08日 15時 53分 31秒

既にエクセルが起動している状態で、次のスクリプトを実行しても
セルにaaaが入力されません。
どうすればいいでしょうか?
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.AppActivate("Microsoft Excel")
WshShell.SendKeys "aaa"

ばんのしゃーによかばんた さん 2006年 02月 08日 15時 26分 52秒

>ばんのしゃーによかばんた さん 2006年 02月 07日 14時 33分 49秒
>CreateProcessのほうは、あちこちの文書で随分警告されていますが

どうも、CreateProcessのほうで、書かれているのは、
空白を含むパス名の、より短いパス名への取り違え、だけで、
パス名が空白を含むときは、引用符で囲め、
空白を含まないときは、囲まなくていいよ、
みたい感じなので、
wShell.Execのほうで、誤解なきよう、再度、念を押しますが、

>wShell.Execのコマンド名は必ず引用符で囲む。

これは、

wShell.Execのコマンド名は、空白を含むときは、必ず引用符で囲む。

ではなく、

wShell.Execのコマンド名は、空白があろうがなかろうが、必ず引用符で囲む。

ですので、ご注意ください。

つまり、

wShell.Exec("wordpad.exe a.txt")

は、"wordpad.exe a.txt"というEXEファイルを実行する罠かも知れません。


ばんのしゃーによかばんた さん 2006年 02月 07日 14時 34分 08秒

しかし、MSのろくでもない自動判定好きはいい加減やめて欲しいですね。
fso.OpenTextFile(,,,-2)
wShell.ExecのLFN
CMD/Cの""
Startの""
など有難迷惑です。
かえって、自動判定の誤判定回避方法を考えなければなりません。

また、一般に、自動判定のような仕様の曖昧さは、セキュリティに
隙を与えることにもなって、危険です。

CMD/Cには、
CMD /C コマンド行

CMD /S /C "コマンド行"
の2つの構文があって、
CMD /C "文字列
をどちらに解釈するか、自動判定するみたいです。

後者の構文は、コマンドプロンプトで、
CMD /C ECHO A | MORE
は、ECHO AがCMD /Cに渡り、
CMD /S /C "ECHO A | MORE"
は、ECHO A | MOREがCMD /Cに渡る、
という違いを出すためにあるようです。
CMD /C ECHO A ^| MORE
でも可能なので、必要ではないのですが、簡便のためでしょうか。

シェルの制御文字をどっちに渡すか、ですね。

wShell.RunやwShell.Execのときも、後者の構文は必要ないのですが、
自動判定のせいで、前者の構文のつもりが後者に誤解釈される危険が
あります。

で、自動判定の回避方法ですが、
後者の構文は、/Sで強制できます。

前者の構文は、例えば、
CMD /C=コマンド行
で強制できるようです。他に;,@などが使えます。
ここで、=;,は、
for %0 in (a=b;c,d) do echo %0
で分かるように、シェル/内部コマンドの区切り文字です。
複文の()も使えるでしょう。
CMD /C (コマンド行)

なお、
CMD /S /C "コマンド行"
の引用符の中で、引用符はエスケープする必要がありません。

結局、wShell.RunやwShell.Execでのお勧めは、
wShell.Run "CMD.EXE /C," & CommandLine
かな。

wShell.Run "CMD.EXE /S /C """ & CommandLine & """"
でもよいけれど。ちょっと面倒だなぁ。

過去のサンプルはいずれかに変更してご利用ください。

ところで、例えば、
Start "fox fox.VBS"
も、困ったものです。

これを回避するためには、
Start "hoge" "fox fox.VBS"
とかするのでしょうか。鬱陶しい。。。

Start /tタイトル みたいにオプション引数にして欲しかった。

そして、
Start "C:\Windows\System32\Notepad.exe" "fox fox.VBS"
に騙されないよう、注意しましょう。

御為倒しに、
|他人から送られて来たVBSファイルは、中身を見ないで実行するのは危険です。
|Start "C:\Windows\System32\Notepad.exe" "fox fox.VBS"
|で、まず中身を確認しましょう。
なんて書いてあったら、それこそ罠です。

同様に、
CMD /C "ECHO A.TXT"
も、曖昧さ故に危険です。
EXEファイルを"ECHO A.TXT"にリネームして、実行させる罠かも知れません。

これは、正しくは、
CMD /C,ECHO A.TXT

CMD /S /C "ECHO A.TXT"
でなければなりません。


ばんのしゃーによかばんた さん 2006年 02月 07日 14時 33分 49秒

>ばんのしゃーによかばんた さん 2006年 02月 06日 16時 11分 16秒
>知らなかった。CreateProcessがLFNを完全にサポートしていたのを。

しかし、元の仕様は違ったようです。元の仕様が正しかったのにどうして?
――――――――――――――――――――――――――――――――――――――
サポート技術情報 
[NT] アプリケーション起動時にアクセスが拒否される
文書番号: 179147
最終更新日: 1999/06/10
現象
システムのパーティションのルート ディレクトリに Program というフォルダが存在する場合 (例: C:\Program)、デスクトップ、[スタート] メニュー、またはファイルの関連付けによってアプリケーションを起動するとき、以下のエラー メッセージが表示されます。
Access to the specified device, path or file is denied
この問題は、実行可能ファイルが Program Files ディレクトリのサブディレクトリに存在するアプリケーションのみに発生します。
原因
このエラーは、ロングファイル名を含む引用符付きパス文字列をレジストリに書き込まないアプリケーションによって発生します。プロセスの実行は、Win32 CreateProcess() API によって処理されます。CreateProcess() は、長いファイル名のスペースと関数への引数を区切るスペースを区別できません。引用符付き文字列が API に渡されれば、CreateProcess() はこれらを区別し、正常にアプリケーションを起動できます。
状況
この問題は Windows NT 4.0 日本語版のサービス パック 4 で修正されております。
――――――――――――――――――――――――――――――――――――――
なので、

>ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒
>或いは、時間軸からして、マイクロソフトの開発者がむたぐちさんの記事を見て
>Execメソッドの仕様に取り込んだのかも知れません。

Execメソッド→CreateProcess。時間軸は微妙。

>なんでそんな余計なことをするんだ!という意味です。

障害でもないのに、なんで修正するんだ!ろう?

事程左様に、障害の半分、あるいはもっとかも、は所謂「修正」で作られます。
なので、障害を逐一報告するのは考えものです。
回避可能な障害は「修正」されないほうが安全かも。

兎にも角にも、wShell.Execには、CreateProcessと同じセキュリティ上の
懸念があるので、要注意です。
CreateProcessのほうは、あちこちの文書で随分警告されていますが、
wShell.Execも同じだという話はまだ載ってないようです。
知らないうちに、侵入者を手助けすることがないよう、気を付けましょう。
wShell.Execのコマンド名は必ず引用符で囲む。


管理人むたぐち さん 2006年 02月 06日 20時 25分 27秒

wshShell.Run "cmd /k cscript.exe d:\inetpub\wwwroot\test\test.vbs"
が駄目(或いは正しくない)という話ですが、私はこれでもいいと思っています。
以下理由。

そもそもスクリプトを利用する目的は、人間の手でやるには面倒くさい
定型作業を自動化するというところにあると思います。
なので、自動化に要するコストが実際に手動でやるコストより安くないと
おいしくないです。

コマンドラインから
cmd /k cscript.exe d:\inetpub\wwwroot\test\test.vbs
を打ち込む作業を自動化するとなるとすぐに思いつくのは、
wshShell.Run "cmd /k cscript.exe d:\inetpub\wwwroot\test\test.vbs"
です。そしてこれは実際に動作します。お手軽で安上がりにできました。

しかしこのコマンドは「正しくは」、
wshShell.Run """cmd.exe"" /k """"cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""""
なので、こう書くべきだという話になっているわけですよね?

ですがこれはちゃっぴさんも認めるように「わかりにくい」です。
わかりにくいどころか、「仕様書」(あるいは仕様の書かれているもの)を読み、
実際に書き表すまで、エラーが出ることなく正しく"をつけるのに要する
「コスト」は、決して安いものではありません。

ならば、たとえ仕様上は誤りであっても、実際にコンソールに打ち込むときと
同様な文字列を与えても動作するなら、それを採用してもいいん
じゃないかと思います。
# 動作しないなら、はなから駄目ですけど。

> Cmd.exe には Parameter として任意の文字列を与えるのが
> 1つしかないため、この場合は問題になりませんが、
> 2つ以上の任意の文字列を与える Parameter があった場合
> どうなるでしょう?

それは、2つ以上の任意の文字列を与えるパラメータがある場合にまた考えましょう。

> ですが、Program を作成するとなると、往々にして標準入力を厚かったり、
> InputBox を表示させて User に入力を求めたり、そんなことは当たり前です。
> なので、Programming を行場合、そこまで考慮して "" で
> 囲わないのは基本的に NG ということになります。

それは、標準入力を扱ったり、InputBoxを表示させてユーザーに入力を
求めるときにまた考えましょう。

…というのが私のスクリプトに対する考え方です。

ばんのしゃーによかばんた さん 2006年 02月 06日 16時 11分 49秒

>ちゃっぴ さん 2006年 02月 03日 02時 07分 55秒
>> ただ、なぜそうするのかが、誰にでも分かるように書くべきだと思います。
>> コマンド名に空白を含む場合、コマンド名と引数を区切る空白と
>> 区別するために、コマンド名を二重引用符で囲む必要があります。みたいに。
>とりあえず、この件に関しては Windows の Help に書いてありますが・・・



「なぜそうするのかが、誰にでも分かるように書」いてあります?

>ちゃっぴ さん 2006年 02月 04日 15時 58分 17秒
>正しくは、こちらですね。多分日本語でもあると思うけど・・・
>Windows の Help Cmd から引用

ほら、これが「なぜそうするのかが、誰にでも分かるように書」いてない典型例です。

|ばんのしゃーによかばんた さん 2006年 02月 02日 18時 01分 37秒
|理由があってand納得した仕様は記憶に残りますが、
|理由のないor理解してない仕様は記憶に残りません。

なので、こういう仕様記述があることを知っている人は10%未満で、
この仕様を理解している人はその中で10%未満で、
この仕様の存在理由を理解している人はその中で10%未満でしょう。

>これは正しくありません。正しくは下記のようになります。
>wshShell.Run """cmd.exe"" /k """"cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""""



その構文を使うときは、曖昧さをなくすため、正しくは、
wshShell.Run """cmd.exe"" /s /k """"cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""""
なのでは?

>ちゃっぴ さん 2006年 02月 03日 02時 07分 55秒
>ただ、これはあくまでも自分で Command を入力する場合です。
>Programming となると話が違ってきます。
>というのは、自分で Command を入力する場合、その Command Line に
>なにが含まれるかは明白であって、それで動くように入力してやるだけで
>十分です。
>ですが、Program を作成するとなると、往々にして標準入力を厚かったり、
>InputBox を表示させて User に入力を求めたり、そんなことは当たり前です。
>なので、Programming を行場合、そこまで考慮して "" で
>囲わないのは基本的に NG ということになります。

過去に作ったサンプルを見ると、全般的に
|ばんのしゃーによかばんた さん 2005年 10月 26日 16時 26分 49秒
|RunAs.VBS [/u:user] [/p:password] command [arguments...]
| If InStr(arg," ") Then arg=""""&arg&""""
のように、空白があると、引用符で囲むようにしてますけど、
こういうのはどうしろと?


ばんのしゃーによかばんた さん 2006年 02月 06日 16時 11分 16秒

>ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒
>|ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒
>|知ってました? ExecメソッドがLFNを完全にサポートしていたのを。
>|http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/technic.htm
>| RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。
>ここで、むたぐちさんの昔の記事を引用しているのは、
>マイクロソフトのExecメソッドの開発者も、同じように考えたみたい、という意味です。

を変更。

知らなかった。CreateProcessがLFNを完全にサポートしていたのを。
http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/technic.htm
RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。
マイクロソフトのCreateProcessの開発者も、同じように考えたみたい。

※ここで、「LFNを完全にサポート」と言う表現は、
「空白を含むLFNを引用符で囲まなくても使える」という意味ですね。



ちゃっぴ さん 2006年 02月 04日 23時 52分 00秒

"" の問題に関連して、ちょっと実験してみたところ、
こんな方法でもとりあえず実行できるようです。

cmd /k (cscript.exe d:\inetpub\wwwroot\test\test.vbs)
cmd /k ("cscript.exe" "d:\inetpub\wwwroot\test\test.vbs")

正しい使い方かどうかわわかりませんが・・
ちなみに下記は NG です。

cmd /k ((cscript.exe) (d:\inetpub\wwwroot\test\test.vbs))
cmd /k "(cscript.exe) (d:\inetpub\wwwroot\test\test.vbs)"

LFN で使用する quotetion は "" と決まっているので当然でしょうね。

> Path=WScript.ScriptFullName&"\..\filename"

これに関する問題も一応あるにはあります。
260 文字を超える path を扱う場合、prefix として、
"\\?\"(UNC の場合には "\\?\UNC\") を付与する必要があります。
ですが、これを付与すると 絶対 path で記述することが求められ、
上記の方法は NG となります。

Making Room for Long Filenames
http://msdn.microsoft.com/library/en-us/dnfiles/html/msdn_longfile.asp?frame=true

まあ、260文字以上でないと問題がないので、
被害は非常に限定的ですがね。

ちゃっぴ さん 2006年 02月 04日 23時 18分 55秒

> となっていることからお分かりのように、

ぜんぜん脈絡がなっていないですね。(__)
空白を含む場合は、"" でくくるのが大原則です。
なんで、本来であれば、

> cmd /k cscript.exe d:\inetpub\wwwroot\test\test.vbs

これは、まったくおかしいことになります。
Cmd.exe には Parameter として任意の文字列を与えるのが
1つしかないため、この場合は問題になりませんが、
2つ以上の任意の文字列を与える Parameter があった場合
どうなるでしょう?

cmd /k "cscript.exe d:\inetpub\wwwroot\test\test.vbs"

最低でも上記のようにすべきだと思います。
空白を含む Parameter を "" でくくらずとも受け付けるのは、
Exec Method とおなじおかしな仕様です。

それから、NET USE にはちょろっとですけど、
"" の必要性について記述があります。

http://www.microsoft.com/resources/documentation/WindowsServ/2003/standard/proddocs/ja-jp/net_use.asp?frame=true

> \\ComputerName\ShareName
> サーバーと共有リソースの名前を指定します。
> ComputerName にスペースが含まれている場合は、2 つの円記号 (\\) から
> コンピュータ名の末尾まで、コンピュータ名全体を
> "\\Computer Name"\Share Name のように二重引用符で囲みます。

Platform SDK では、環境変数の話になりますが、
常に "" でくくるべきと推奨されています。

Best Practices for File Associations
http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/fileassociations/fa_best_practices.asp?frame=true
Always Wrap Expanding Strings in Quotation Marks を参照

ちゃっぴ さん 2006年 02月 04日 15時 58分 17秒

>>> You can use most characters as variable values, including white
>>> space. If you use the special characters <, >, |, &, or ^, you must
>>> precede them with the escape character (^) or quotation marks.
>>> If you use quotation marks
>>というようにちゃんと記述はあります。
>
> ?
>
> これは見たところ、環境変数の値の設定の説明のようで、
> 直接の関係はなさそうですが、

お、間違えてしまった。すみません。
正しくは、こちらですね。多分日本語でもあると思うけど・・・

Windows の Help Cmd から引用

> ・Processing quotation marks
> If you specify /c or /k, cmd processes the remainder of String and
> quotation marks are preserved only if all of the following conditions
> are met:
>
> You do not use /s.
> You use exactly one set of quotation marks.
> You do not use any special characters within the quotation marks
> (for example: &<>( ) @ ^ |).
> You use one or more white-space characters within the quotation
> marks.
> The String within quotation marks is the name of an executable file.
> If the previous conditions are not met, String is processed by
> examining the first character to verify whether or not it is an
> opening quotation mark. If the first character is an opening
> quotation mark, it is stripped along with the closing quotation mark. > Any text following the closing quotation marks is preserved.

となっていることからお分かりのように、

> wshShell.Run "cmd /k ""cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""

これは正しくありません。正しくは下記のようになります。

wshShell.Run """cmd.exe"" /k """"cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""""

わかりにくいので、Run に渡している文字列は下記です。

"cmd.exe" /k ""cscript.exe" "d:\inetpub\wwwroot\test\test.vbs""

> 基本的に、引数のシンタクスは、コマンドごとにばらばらで
> 統一ルールはないのです。

まあ、以前は LFN なんてものはなかったのですから、
ある程度ばらばらになるのは仕方がないでしょう。
それから、Microsoft 以外でも Console Application は作れるわけでして、
そこから提供されるものが仕様に反しているのは、ある意味仕方がないでしょう。
# それでも、Programmer としてやっていくのであれば、その程度の仕様は
# ちゃんと調査して実装する義務があると思います。

ですが、LFN という規格ができてから何年たったと思います?
それなのに現状がばらばらってのは正直どうかと思いますが・・・
こうなってしまった原因として

1. Microsoft の仕様の不備
  個人的には、すべての Command, Parameter は "" でくくるのを
  前提にすべきだと思っています。そこまでは、ある程度統一されて
  いますが、問題は、"" を Nest した場合の処理、および " の
  Escape 処理(Path に関しては問題ないのでそれ以外の部分)です。

2. Microsoft の Document の不備
  ここら辺の仕様は、統一されたところだけではなく、すべての
  Command の Reference に記述するか、Link として表示させるとか
  するべきだと思います。

3. Microsoft の実装における不備
  仕様を策定してから何年もたつのに自社においても仕様を
  徹底させられない。まあ、仕様が明確でないってのもありますが・・・
  ちなみに Script とは大きく外れてしまいますが、関連付けされた
  Application の Path を取得する API には、Registry に "" で
  くくられた状態で格納されていると取得できないという有名な問題が
  あったと思います。(詳細は忘れてしまいましたが・・・)

4. 策定された仕様をろくに調べようともしない Programmer, 設計者の増加
  論外です。Professinal 意識を持っていない者には正直消えて欲しいです。

ばんのしゃーによかばんた さん 2006年 02月 04日 14時 44分 21秒

>ばんのしゃーによかばんた さん 2006年 02月 02日 18時 01分 37秒
>C:\Programを作っておくと、「ファイルを開くプログラムの選択」ダイアログが出ます。

右クリックメニューで「プログラムから開く」を選択しようとしたら、ない!
てこと、ありません?

そういうときに、「プログラムから開く.VBS」があると便利です。

WScript.CreateObject("WScript.Shell").Run "RUNDLL32.EXE shell32.dll,OpenAs_RunDLL " & WScript.Arguments.Item(0)

――――――――――――――――――――――――――――――――――――――
こういうサンプルを書くと、それは、

WScript.CreateObject("WScript.Shell").Run "RUNDLL32.EXE shell32.dll,OpenAs_RunDLL """ & WScript.Arguments.Item(0) & """"

の間違いだろう、と突っ込まれそうですが、そうではありません。

基本的に、引数のシンタクスは、コマンドごとにばらばらで統一ルールはないのです。
Long File Nameを引用符で囲まなければならないものもあれば、
この例のように囲むと駄目なものもあり、はたまた、CDやIExplore.exeや
NotePad.EXEのように囲んでも囲まなくてもどっちでもよいものもあります。


ばんのしゃーによかばんた さん 2006年 02月 04日 14時 44分 04秒

>ちゃっぴ さん 2006年 02月 03日 02時 07分 55秒
>とりあえず、この件に関しては Windows の Help に書いてありますが・・・



>> You can use most characters as variable values, including white
>> space. If you use the special characters <, >, |, &, or ^, you must
>> precede them with the escape character (^) or quotation marks.
>> If you use quotation marks
>というようにちゃんと記述はあります。



これは見たところ、環境変数の値の設定の説明のようで、直接の関係はなさそうですが、

SET FULLNAME=C:\Program Files\Internet Explorer\IEXPLORE.EXE

のように、空白があっても、引用符で囲む必要はない、という例でしょうか?

>そこまで考慮して Sample を掲示するとか、説明する場合には、
>必ずしも必要がなくても "" でくくってやりなさいと
>教える必要があると思います。



ちゃっぴさんは、

|管理人むたぐち さん 2006年 02月 03日 14時 16分 54秒
|wshShell.Run "cmd /k cscript.exe d:\inetpub\wwwroot\test\test.vbs"

このような
>Sample が非常によくない
と、お思いなんですね?

この場合は、
wshShell.Run "cmd /k ""cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""
とか、
wshShell.Run "cmd /k ""c:\windows\system32\cscript.exe"" ""d:\inetpub\wwwroot\test\test.vbs"""
のように書くべきだと。

でも、一度、お試しください。これらはエラーになります。

一方、
wshShell.Run "cmd /k ""C:\Program Files\Internet Explorer\iexplore.exe"" ""d:\inetpub\wwwroot\test\test.htm"""
は、OKです。

むたぐちさんの上のサンプルのままでよいと思います。


AKA さん 2006年 02月 04日 11時 07分 51秒

>>管理人むたぐち さん 2006年 01月 30日 14時 07分 22秒
>たしかその文章は私が書いたものです。
>でもいつだったか指摘があって修正したのだったと思います。

私です(^^;)


>>ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒
>知ってました? ExecメソッドがLFNを完全にサポートしていたのを。

>>ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒
>なんでそんな余計なことをするんだ!

そもそもOSに丸投げするとそうなるわけで、Execが何かをやっているわけではありません。

<<以下MSDNライブラリより>>

>Platform SDK: DLLs, Processes, and Threads
>CreateProcess

>If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the >following order:

>c:\program.exe files\sub dir\program name
>c:\program files\sub.exe dir\program name
>c:\program files\sub dir\program.exe name
>c:\program files\sub dir\program name.exe

この公式文書では仕様がおかしいことを半ば認めており、""を使え、と言っています。

Runを作ったプログラマがOSの挙動を正そうとしたのかどうかはわかりませんが、おそらく彼は伝統的なCやDOS/UNIXのシステムについての正しい知識があったのだと思われます。


>>ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒
>ここで、むたぐちさんの昔の記事を引用しているのは、
>マイクロソフトのExecメソッドの開発者も、同じように考えたみたい、という意味です。
>或いは、時間軸からして、マイクロソフトの開発者がむたぐちさんの記事を見てExecメソッドの仕様に取り込んだのかも知れません。

ですのでそういうことは全くありません(^^;)

今回のみならず、Cプログラマには常識的な話なのに間違えたまま延々と書いていることが多いです(^^;)

AKA さん 2006年 02月 04日 06時 25分 14秒

>>ばんのしゃーによかばんた さん 2005年 08月 11日 15時 04分 13秒
>リストビューをCSV化「ListView to CSV」v1.52.06
>スクリプトからCOMで使えるようにしてほしい。
>誰か作ってー。

一応。

http://winscript.s41.xrea.com/wiki/index.php?plugin=attach&pcmd=open&file=LVI001.LZH&refer=%5B%5B%A5%A2%A5%C3%A5%D7%A5%ED%A1%BC%A5%C0%A1%BC%5D%5D

しかしこのソフトウェアをダウンロードしてないし、ソースも見てないので期待したのと違うかも。

というか、この仕様でいいのかな? レスポンス希望。

Win98/Win2000で動作確認しました。


>第三に使用許諾条件。
>「このソフトウェアは、ユーザーが自称初心者(=初心者であることを威張り、
>他の人より多くの利益を得ようとする者)である場合は利用できません。」

人間的に幼稚なオタクの見本。他人が自分の専門について勉強していない、と勝手に怒り出す。

今の日本はこういうのが医者や警察はじめあらゆる所に大勢いるから無意味に人が死ぬ。

一人の人間が何でも全部自分で勉強できるなら社会なんていらない。

まあ、幼稚は幼稚なのだが、この許諾条件は半分冗談だと思うけど?


>>VBA さん 2006年 01月 16日 23時 24分 54秒
>ie.Document.Applicationとはどういう意味でしょうか?

もし、TLBINF32.DLLをインストールしているならば、IE窓とエクスプローラ窓の両方を開いてから、以下のVBSをCScriptでMOREして実行してみて下さい。

Set Shell = CreateObject("Shell.Application")
Set ShellWindows = Shell.Windows()

WScript.Echo "Count of IE = " & ShellWindows.Count
For I = 0 To ShellWindows.Count - 1
     Set IE = ShellWindows.Item(I)
     WScript.Echo "IE No. " & I
     WScript.Echo "LocationName of IE = """ & IE.LocationName & """"
     DisplayInterface "['Document' of IE]", IE.Document
Next
WScript.Quit

Sub DisplayInterface(Title, Object)
     WScript.Echo Title
     Dim TLIApplication
     Set TLIApplication = CreateObject("TLI.TLIApplication")
     Dim InterfaceInfo
     Set InterfaceInfo = TLIApplication.InterfaceInfoFromObject(Object)
     WScript.Echo " Interface Name = """ & InterfaceInfo.Name & """"
     Dim Members
     Set Members = InterfaceInfo.Members
     WScript.Echo " Member Count = " & Members.Count
     Dim I
     For I = 1 To Members.Count
          WScript.Echo " " & I & " """ & Members.Item(I).Name & """, """ & Members.Item(I).HelpString & """"
     Next
End Sub

ってそういう意味ではないのかな・・・?(^^;)

DocumentプロパティについてはInternet Development SDKドキュメントにはこんな風に書かれているわけだけど、これでいったい何がわかるというのか?

When the active document is an HTML page, this property provides access to the contents of the HTML Document Object Model (DOM)

(中略)

When other document types are active, such as a Microsoft Word document, this property returns the document automation object of that document.

>>管理人さん
レスありがとうございます。
なるほど。それでは私に関係するコメントは全くないわけですね。なら私がどうこう言う権利はないですね。失礼しました。

ちゃっぴ さん 2006年 02月 04日 00時 30分 39秒

To いちご さん 2006年 02月 03日 08時 35分 13秒

>> ですが、私ならそんな(htmlから VBS を Call する)仕様には
>> しませんがね。
> 恐れ入りますが、ちゃっぴ さんでしたら、
> どのような処理にされるのでしょうか?
> よろしければ、アドバイスいただけませんでしょうか?

環境の説明がまったくないので、一概に言えませんが、
おそらく社内利用なんでしょう。
SMB/CIFS でやり取りするようですからね。

ということで、まずこの処理を Web で行う必要があるのか?
というのが第一に疑問です。

単純に VBS を配布したり、File Server においてあるものを
実行させたりとかで済む話ではないですか?

.NET 2.0 が使えるのであれば、ClickOnce を用いた配布形式も
考えられますね。

あとは、ActiveX に Code 署名して使ってやるとか。

いろいろ方法がありますので、調査してみてくださいな。

管理人むたぐち さん 2006年 02月 03日 22時 25分 26秒

To: ばんのしゃーによかばんた さん 2006年 02月 03日 16時 02分 08秒

> Path=WScript.ScriptFullName&"\..\filename"

XPのほか、Win98SE、ME、2000、Server 2003で念のために動作確認してみましたが
ちゃんと実行されますね。これは使えるかも。
言われてみれば結構、あたりまえですが、コード量はうんと減りますね。

ばんのしゃーによかばんた さん 2006年 02月 03日 16時 02分 23秒

>管理人むたぐち さん 2006年 01月 26日 17時 34分 43秒
>Function GetDate(dTime)
>   GetDate=FixNumber(Year(dTime)) & FixNumber(Month(dTime)) & FixNumber(Day(dTime))
>End Function
>Function FixNumber(num)
>   FixNumber=Right("0" & CStr(num),2)
>End Function

の別案を再掲。だってこっちのほうが1行で書けて簡単なんだもの。

>ばんのしゃーによかばんた さん 2005年 01月 25日 19時 27分 19秒
>yymmdd=Mid(CStr(Year(fdate)*10000+Month(fdate)*100+Day(fdate)),3)

999年以前に対応して、
yymmdd=Right(CStr(Year(fdate)*10000+Month(fdate)*100+Day(fdate)),6)

yyyymmdd=Right(CStr(100000000+Year(fdate)*10000+Month(fdate)*100+Day(fdate)),8)
がよいかも。

――――――――――――――――――――――――――――――――――――――
>pai さん 2006年 01月 23日 19時 28分 11秒
>zipfile=targetFolderPath & Year(d) & Month(d) & Day(d) & sourceFile.Name & ".zip"

これだと重複します。1月11日と11月1日。



ばんのしゃーによかばんた さん 2006年 02月 03日 16時 02分 08秒

パス名から同じフォルダのファイルのパス名を生成するのに、

普通は、

Path=fso.BuildPath(fso.GetParentFolderName(WScript.ScriptFullName),"filename")



Path=Left(WScript.ScriptFullName,InStrRev(WScript.ScriptFullName,"\"))&"filename"

とかやってたのですが、もっと簡便に、

Path=WScript.ScriptFullName&"\..\filename"

でよいようです。

バッチファイルなら、
"%~0\..\filename"
ですね。

\..\の前の名前が必ずしもフォルダでなくとも、たとえ存在しなくてもよいようです。

ファイルパス名のコンベンションとしてOSレベルで認められているようです。


管理人むたぐち さん 2006年 02月 03日 14時 16分 54秒

To: いちご さん

> お聞きしたいのは、エラーの画面が残ったままになるような設定?(起動方法?)はありませんか?

それに対する解答としては、
wshShell.Run "cmd /k cscript.exe d:\inetpub\wwwroot\test\test.vbs"
でいいと思います。

が、私もHTMLからWSHを呼ぶような運用はなんか間違ってる気がします。
セキュリティ警告も出るでしょうし、出ないようにあえてしているなら
それはセキュアな運用とは言えませんし。
現在WSHで動いている部分も含めてHTA化するのが良いかと思います。

いちご さん 2006年 02月 03日 08時 35分 13秒

ちゃっぴ さん、ご回答ありがとうございます。

>なら、Error を Trap し、その Message をどこかに保存するように
>Coding するだけで済む話でしょう。
>Text の Log にはかせるとか Event Log に出力させるとか・・・
こちらのほうは、logを出力する方法で考えたいと思います。
ですが、できれば、操作している人に直接メッセージを見せたいと思っています...

>ですが、私ならそんな(htmlから VBS を Call する)仕様には
>しませんがね。
恐れ入りますが、ちゃっぴ さんでしたら、
どのような処理にされるのでしょうか?
よろしければ、アドバイスいただけませんでしょうか?

よろしくお願い致します。

ちゃっぴ さん 2006年 02月 03日 02時 07分 55秒

To ばんのしゃーによかばんた さん 2006年 02月 02日 18時 01分 37秒

> 同じフォルダ名だと駄目です。問題は、誤爆しない「一意性」です。

言い訳に聞こえるかもしれませんが、そういう意味で

>> んまあ、使うことはまずないでしょうが・・・

と発言しました。

> ただ、なぜそうするのかが、誰にでも分かるように書くべきだと思います。
> コマンド名に空白を含む場合、コマンド名と引数を区切る空白と
> 区別するために、コマンド名を二重引用符で囲む必要があります。みたいに。

とりあえず、この件に関しては Windows の Help に書いてありますが・・・
手元の環境が Support Tools とか Resource kit Tools を Install した
環境しかないもので、英語でしかないのですが・・・

> You can use most characters as variable values, including white
> space. If you use the special characters <, >, |, &, or ^, you must
> precede them with the escape character (^) or quotation marks.
> If you use quotation marks

というようにちゃんと記述はあります。

ただ、これはあくまでも自分で Command を入力する場合です。
Programming となると話が違ってきます。

というのは、自分で Command を入力する場合、その Command Line に
なにが含まれるかは明白であって、それで動くように入力してやるだけで
十分です。
# それでも、基本的に Path とか Parameter に関しては、
# "" でくくる癖をつけたほうがいいと思いますがね。

ですが、Program を作成するとなると、往々にして標準入力を厚かったり、
InputBox を表示させて User に入力を求めたり、そんなことは当たり前です。
なので、Programming を行場合、そこまで考慮して "" で
囲わないのは基本的に NG ということになります。

まあ、当たり前といっては当たり前のことなんですが、
そこまで考慮して Sample を掲示するとか、説明する場合には、
必ずしも必要がなくても "" でくくってやりなさいと
教える必要があると思います。
# とりあえず、動けば OK という人の数がかなり存在する以上、
# これは最低限の Level なのでそういう人にも叩き込む必要があると思います。

ところが、私の知る限り、そこら辺をちゃんと解説している書籍とかが
あまりにも少ない。しかも、そういう意味では、Sample が非常によくない
というのが大多数を占めていると思います。
# なんとかならんもんですかね〜。

> 「ファイル名を指定して実行」では、
> C:\Program Files\Internet Explorer\IEXPLORE.EXE
> は、起動できますが、
>C:\Program Files\Internet Explorer\IEXPLORE.EXE -nohome
> は、C:\Programが見つかりません。になります。
> また、
> C:\Programを作っておくと、「ファイルを開くプログラムの選択」ダイアログが出ます。
> なので安全です。
> 一方、Execは、
> C:\Program Files\Internet Explorer\IEXPLORE.EXE -nohome
で起動できます。
> なので、Execは「ファイル名を指定して実行」を見ないで作ったようです。

Exec Method に関する検証が足りなかったようです。
しかし、まあこれはちょっとひどいですね。

Win32 API でもおかしな仕様(Bug)? があることがありますが、
WSH に関してはどうやらより一層そういったものが多いみたいですね。
# ここらへんは改善して欲しいと切に願っていますが・・/

ちゃっぴ さん 2006年 02月 03日 01時 14分 18秒

To いちご さん 2006年 02月 01日 09時 43分 58秒

> ただ、途中でエラーになったとき、プロンプト画面でエラーが一瞬表示され、
> すぐにプロンプト画面が消えてしまい、エラーメッセージがわからず困っています。

なら、Error を Trap し、その Message をどこかに保存するように
Coding するだけで済む話でしょう。
Text の Log にはかせるとか Event Log に出力させるとか・・・

ですが、私ならそんな(htmlから VBS を Call する)仕様には
しませんがね。

ばんのしゃーによかばんた さん 2006年 02月 02日 18時 01分 55秒

>ばんのしゃーによかばんた さん 2006年 01月 31日 15時 10分 21秒
>Explorerのウィンドウタイトルは、取得も変更もできません。
>既存の場合はプロセスIDも使えません。

既存のExplorerの場合は、

wShell.SendKeys "%{Tab}"
ie.Visible=True
If wShell.AppActivate(ie.Document.Folder.Self.Path) Then
ElseIf IsNumeric(ie.Document.Folder.Title) Then
ElseIf wShell.AppActivate(ie.Document.Folder.Title) Then
Else
 MsgBox "AppActivate Failed"
End If

Alt+Tabで、foreground lockを外し、
同じパス/タイトルの場合、ie.Visible=Trueでzオーダ(?)が入れ替わるようです。

タイトルバー表示がパス名なら、これでよさそうです。
タイトルバー表示がタイトルで、それがIsNumericの場合を駄目。
後述の奥の手が必要です。

>IEのウィンドウは、タイトルを一意にして、AppActivateできますが、

IEでタイトルを変更しないで行おうとすると、限界があります。

If Not ie.Document.hasFocus Then
 wShell.SendKeys "%{Tab}"
 WScript.Sleep 100
 If IsNumeric(ie.Document.Title) Then
 ElseIf wShell.AppActivate(ie.Document.Title) Then
 ElseIf wShell.AppActivate(ie.LocationURL) Then
 ElseIf wShell.AppActivate(Mid(ie.Document.URLUnencoded,Len("file://")+1)) Then
 Else
  MsgBox "AppActivate Failed"
 End If
End If

同じタイトルがなければ、ここまででOKですが、あると、駄目。以下が必要です。
数字タイトルの場合も以下を足すとOK。

If Not ie Is Shell.Windows().Item() Then
 For k=1 To 100
  If Shell.Windows().Item() Is ie Then Exit For
  wShell.SendKeys "%+{Tab}"
  WScript.Sleep 100
 Next
End If
If Not ie Is Shell.Windows().Item() Then MsgBox "Failed"

Alt+Shift+Tabで、全ウィンドウを順繰りに調べます。


ばんのしゃーによかばんた さん 2006年 02月 02日 18時 01分 37秒

>ちゃっぴ さん 2006年 02月 01日 04時 09分 52秒
>> Explorerのウィンドウタイトルは、取得も変更もできません。
>そんなことはないでしょう。
>InternetExplorer の LocationName で引っ張ってくれば
>なんとかなりますね。

同じフォルダ名だと駄目です。問題は、誤爆しない「一意性」です。

|ばんのしゃーによかばんた さん 2006年 01月 31日 15時 10分 21秒
|IEのウィンドウは、タイトルを一意にして、AppActivateできますが、

あと、LocationNameだと、フォルダ名がIsNumericの場合も、
プロセスIDと見做されて、駄目です。これはAppActivateの障害です。

――――――――――――――――――――――――――――――――――――――
>ちゃっぴ さん 2006年 02月 01日 04時 09分 52秒
>その仕様は、"ファイル名を指定して実行" と同じなので

「ファイル名を指定して実行」では、

C:\Program Files\Internet Explorer\IEXPLORE.EXE
は、起動できますが、

C:\Program Files\Internet Explorer\IEXPLORE.EXE -nohome
は、C:\Programが見つかりません。になります。

また、
C:\Programを作っておくと、「ファイルを開くプログラムの選択」ダイアログが出ます。
なので安全です。

一方、Execは、
C:\Program Files\Internet Explorer\IEXPLORE.EXE -nohome
で起動できます。

なので、Execは「ファイル名を指定して実行」を見ないで作ったようです。

――――――――――――――――――――――――――――――――――――――
>ちゃっぴ さん 2006年 01月 29日 18時 32分 24秒
>ですが、現状では半角 Space を含む場合には、"" でくくる必要がありますって
>教え方してますね。それが一番の問題です。

それはそれでよいと思います。

ただ、なぜそうするのかが、誰にでも分かるように書くべきだと思います。
理由は自明だと思ってか、仕様に理由は無用だと思ってか、
省略することが多いようですが。

コマンド名に空白を含む場合、コマンド名と引数を区切る空白と区別するために、
コマンド名を二重引用符で囲む必要があります。みたいに。

理由があってand納得した仕様は記憶に残りますが、
理由のないor理解してない仕様は記憶に残りません。

それから、一番の問題は、仕様が書いてない、ことだと思います。

Run
| 実行するコマンド ラインを示す文字列値です。
| この引数には、実行可能ファイルに渡すべきパラメータをすべて含める必要があります。

Exec
| スクリプトの実行に使用するコマンド ラインを示す文字列値です。
| コマンド プロンプトから入力する場合と全く同じコマンド ラインを指定します。

これで、仕様を書いたつもりになっているのではないでしょうか。全く。。。
仕様というのは、出来ることと出来ないことの境界を明確にすることです。
会社は違いますが、こういうことが、東証の誤発注取り消し不可仕様みたいなことに
つながるのだと思います。
仕様をしっかり書き出して、自分の目、他人の目に曝されば、
変な仕様がそのまま世に出ることもなくなると思います。


いちご さん 2006年 02月 01日 09時 43分 58秒

先日はお世話になりました。
前回の続きで恐縮ですが、お聞きしたいことがあります。

IISの環境で、画面からボタンをクリックしたとき、
クライアントのVBScriptでtest.vbsを起動し、
起動した、test.vbsでサーバーのフォルダ(共有)をローカルへコピーするという処理を行なっております。
前回のアドバイスのお陰で通常は問題なく実行できるようになりました。

ただ、途中でエラーになったとき、プロンプト画面でエラーが一瞬表示され、
すぐにプロンプト画面が消えてしまい、エラーメッセージがわからず困っています。

自分の環境で起こった場合だと、DOSプロンプトを起動し、本来実行するVBSを手動で実行すればよいのですが、
ユーザーの環境で起こっており、遠隔のため確認できません。

お聞きしたいのは、エラーの画面が残ったままになるような設定?(起動方法?)はありませんか?


また、エラーの原因を考えているのですが、今回初めてWSHを使用しました。
ユーザーの環境にWSHを使用する環境が入っていないのか?と考えたのですが、
これはWindows2000,XPなら標準で使用可能なものと下記URLに記述がありました。
そういう認識で間違っていないですよね?
http://www2.noritz.co.jp/anchor/ashp/netmon/scripting.html


最後に、このエラーが起きているマシンですが、VPNで実行した場合です。
VPNが当方よく分かっていませんが、社内のLAN環境と同じと聞いております。
ただ、気になったのが、VBSの命令で、共有フォルダをコピーする命令を実行しています。
もしかしたら、VPNでは共有フォルダを参照できないのか?と思ったりもします。
その辺り、もし、経験がございましたら、よろしくお願い致します。


以上、度々で申し訳ありませんが、よろしくお願い致します。

●ソース
main.aspのボタンのクリックで、以下を実行

<SCRIPT LANGUAGE="VBScript">
Sub FuncArchiveLocal()
Set wshShell = CreateObject("WScript.Shell")
wshShell.Run "cscript.exe d:\inetpub\wwwroot\test\test.vbs"
Set wshShell = Nothing
</SCRIPT>

test.vbs
WScript.echo "1.Copy中です。しばらくお待ちください..."
Set fso = CreateObject("Scripting.FileSystemObject")
sLocalFolder = "d:\inetpub\wwwroot\test\"
fso.CopyFolder "\\サーバー名\共有フォルダ名\file", sLocalFolder, True
Set fso = Nothing
WScript.echo "1.Copy終了です。しばらくお待ちください..."
WScript.echo "2.Copy中です。しばらくお待ちください..."
Set fso = CreateObject("Scripting.FileSystemObject")
sLocalFolder = "d:\inetpub\wwwroot\test\"
fso.CopyFolder "\\サーバー名\共有フォルダ名\file", sLocalFolder, True
Set fso = Nothing
WScript.echo "2.Copy終了です。しばらくお待ちください..."

環境
Windows2003サーバー
クライアント;Windows2000 or WindowsXP


ちゃっぴ さん 2006年 02月 01日 04時 09分 52秒

To ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒

> 或いは、時間軸からして、マイクロソフトの開発者がむたぐちさんの記事を見て
> Execメソッドの仕様に取り込んだのかも知れません。

その仕様は、"ファイル名を指定して実行" と同じなので
そういうことでは?

> Explorerのウィンドウタイトルは、取得も変更もできません。

そんなことはないでしょう。
InternetExplorer の LocationName で引っ張ってくれば
なんとかなりますね。

Set objShell = CreateObject("Shell.Application") 
For Each objWindow In objShell.Windows
  With objWindow
    Debug.Print .FullName & vbTab & .LocationName
  End With
Next

ちなみ、LocationName で取得したもので AppActivate はききますし、
Navigate で別の Directory に移動することも可能です。

んまあ、使うことはまずないでしょうが・・・

ばんのしゃーによかばんた さん 2006年 01月 31日 15時 10分 21秒

IEのウィンドウは、タイトルを一意にして、AppActivateできますが、
Explorerの場合は、困りますよね。

Explorerのウィンドウタイトルは、取得も変更もできません。
既存の場合はプロセスIDも使えません。

でも、新規ならプロセスIDが使えます。

Set Shell=CreateObject("Shell.Application")
Set wShell=CreateObject("WScript.Shell")
N=Shell.Windows().Count
Set oExec=wShell.Exec("Explorer.EXE /SEPARATE")
Do While N=Shell.Windows().Count
 WScript.Sleep 100
Loop
Set ie=Shell.Windows().Item(N)
ie.StatusText="ウィンドウを切り替えてください。5秒後にAppActivateします。"
WScript.Sleep 5000
wShell.SendKeys "%{Tab}"     'foreground lock解除
wShell.SendKeys "%{Tab}"     'foreground戻し
wShell.AppActivate oExec.ProcessID
ie.StatusText="5秒後に自動的に終了します。"
WScript.Sleep 5000
If TypeName(ie)="IWebBrowser2" Then ie.Quit
WScript.Quit



ばんのしゃーによかばんた さん 2006年 01月 31日 15時 09分 58秒

|ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒
|知ってました? ExecメソッドがLFNを完全にサポートしていたのを。
|http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/technic.htm
| RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。

ここで、むたぐちさんの昔の記事を引用しているのは、
マイクロソフトのExecメソッドの開発者も、同じように考えたみたい、という意味です。
或いは、時間軸からして、マイクロソフトの開発者がむたぐちさんの記事を見て
Execメソッドの仕様に取り込んだのかも知れません。

>新米MCP さん 2006年 01月 30日 01時 34分 33秒
>ExecではできているのにRunでやらないのはなぜだろう、という意味だと思うのですが。
>別におかしくはないような?

逆です。

|でも、こんな半端なサービス(○Exec/×Run)より、
|Execが\App Paths\をサポート(×Exec/○Run)してくれたほうがうれしいのに。:-<

なんでそんな余計なことをするんだ!という意味です。

|Set oExec=wShell.Exec(FullName&" -nohome")
|は、不思議ですね。知らなかった。

でも、原理的に一般的には不可能と考えられる仕様を、一体どう実装しているものやら。
そこがまた不思議だ!という意味です。

想像ですが、空白が現れる度に、そこまでの名前のファイルが存在するか、
をチェックして、有れば、そこで区切るのではないでしょうか。

試しに、calc.exeをProgramにリネームしてC:\に置くと、電卓が立ち上がりました。

これが直ちにセキュリティホールになったりはしないでしょうが、
C:\Programというファイルがもしあれば、そのシステムは侵入されているのかも
知れません。

と言う訳で、やはり、有難迷惑な仕様と言わざるを得ません。

また、拡張子に関係なく起動を許すExecの仕様も、どうかと思います。

Runの場合は、
エラー:     この操作に対して指定されたファイルには、アプリケーションが関連付けられていません。
となって、こちらは安全です。


いちご さん 2006年 01月 30日 19時 21分 06秒

管理人むたぐち さんへ

ありがとうございます。
参考にさせていただきます。m(__)m

ばんのしゃーによかばんた さん 2006年 01月 30日 16時 10分 39秒

IEのオブジェクト作成は、
Set ie=CreateObject("InternetExplorer.Application")
ですが、これに対応する、Explorerのオブジェクト作成はどうするか。

※なぜ、Explorerのオブジェクトの作成が必要か?
※CopyHere/MoveHereのUndoを有効にするには、デスクトップシェル空間に
※同居するExplorerのオブジェクトが必要なんですね。

Set Shell=CreateObject("Shell.Application")
Set wShell=CreateObject("WScript.Shell")
wShell.Run "Explorer.EXE",,True
Set ie=Shell.Windows().Item()

でよさそうなんですが、これで本当に大丈夫なものか。
と思っていたら、ときどき、誤爆します。

Set Shell=CreateObject("Shell.Application")
Set wShell=CreateObject("WScript.Shell")
N=Shell.Windows().Count
wShell.Run "Explorer.EXE",,True
Set ie=Shell.Windows().Item(N)

こちらは大丈夫なようですが。。。
と思っていたら、ときどき、失敗します。

Set Shell=CreateObject("Shell.Application")
Set wShell=CreateObject("WScript.Shell")
N=Shell.Windows().Count
wShell.Run "Explorer.EXE"
Do While N=Shell.Windows().Count
 WScript.Sleep 100
Loop
Set ie=Shell.Windows().Item(N)

これなら大丈夫なようです。今のところ。

非表示の場合は、フォーカスを奪わないようにします。

Set Shell=CreateObject("Shell.Application")
Set wShell=CreateObject("WScript.Shell")
N=Shell.Windows().Count
wShell.Run "Explorer.EXE",6
Do While N=Shell.Windows().Count
 WScript.Sleep 100
Loop
Set ie=Shell.Windows().Item(N)
ie.Visible=False
WScript.Sleep 5000
ie.Visible=True
If ie.Left=-32000 Then wShell.SendKeys "%( r)"
ie.StatusText="5秒後に終了します"
WScript.Sleep 5000
If TypeName(ie)="IWebBrowser2" Then ie.Quit
WScript.Quit

途中で表示に戻すと最小化のままなのでちょっと困ります。


管理人むたぐち さん 2006年 01月 30日 14時 07分 22秒

To: ちゃっぴ さん 2006年 01月 29日 18時 32分 24秒

> To ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒
>
> > ただし、いずれの場合もスペースが含まれたLFN(ロングファイルネーム)は
> > 使えません(ファイルがない、というエラーになる)。
> > どうしてもLFNを使いたい場合は、次のようにします。
> > RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。

たしかその文章は私が書いたものです。
でもいつだったか指摘があって修正したのだったと思います。

ちゃっぴさんのご指摘はもっともなので、オブジェクトの解説のWshShellの記述を
少し補足しておきました。
# ほんとは5.6のオブジェクトも解説しなきゃ、ですが…。


To: いちご さん

書籍はけっこういろいろ出てたのですが、私がみた範囲で決定打はなかったですね。
WSH5.6のヘルプには勝てない、という意味で。
# 数年前にまとめたのだがもう絶版になっているのが多いだろうな…。

某ソーシャルネットワーキングの某コミュで話題になっていたものの受け売りですが、
現在はこういう本が出ていて入手可能なようです。

Amazon.co.jp:Wshクイックリファレンス: 本
http://www.amazon.co.jp/exec/obidos/ASIN/4873110068/ref%3Dpd%5Fsim%5Fdp%5F2/503-9084462-9519964

Amazon.co.jp:VBScriptポケットリファレンスPocket reference: 本
http://www.amazon.co.jp/exec/obidos/ASIN/477410812X/503-9084462-9519964

Amazon.co.jp:VBScriptハッカーズ・プログラミング: 本
http://www.amazon.co.jp/exec/obidos/ASIN/4896272838/503-9084462-9519964

Amazon.co.jp:Windows Script Hostハンドブック―Windows簡単プログラミング講座Windows Start Books: 本
http://www.amazon.co.jp/exec/obidos/ASIN/4839908516/qid%3D1137852893/503-9084462-9519964

JScriptならこんなのも
Amazon.co.jp:JScriptハンドブック―Java Scriptを越えた最強のツール: 本
http://www.amazon.co.jp/exec/obidos/ASIN/483991902X/503-9084462-9519964

いちご さん 2006年 01月 30日 10時 10分 34秒

管理人むたぐち さんへ

>wshShell.Run "cscript.exe d:\inetpub\wwwroot\test\test.vbs"
>のようにcscript.exeでスクリプトを実行するように
>してみてください。
この方法でうまくいきました。
とても助かりました、ありがとうございました。

ところで当方、言語に関しては、オフコン、VB、ASPなど、いろいろ経験があるのですが、
WSHに関しては初心者です。

週末にWSHを理解するため、本屋さんへ行こうと思っていたのですが、
風邪で臥せっておりました。
また、今週にでも探しにいこうと思っていますが、
もし、何か良い参考書などありましたら、アドバイスいただけたら幸いです。
m(__)m

新米MCP さん 2006年 01月 30日 08時 22分 13秒

>ちゃっぴ さん 2006年 01月 30日 02時 18分 35秒

>> なぜに喧嘩腰なのでしょう?
>そういうつもりはなかったのですが、

こちらこそ謝罪させてください。失礼致しました。
文字だけの会話って難しい。

>教育自体に問題が多い場合が非常に多いということからきています

仰っておられるのはデリミタだけに限ったことではないのでしょうけれど、
今回に限って言うならパスのデリミタとエスケープについてきちんと教えてない事に憤っておられるのですね。
確かにあまり解説を見たことがありません…コマンドの使い方入門とかで見るぐらいかな?

私自身、初心者とたいして違いませんが、初心者に解説するときには心がけたいと思います。

ちゃっぴ さん 2006年 01月 30日 02時 18分 35秒

To 新米MCP さん 2006年 01月 30日 01時 34分 33秒

> なぜに喧嘩腰なのでしょう?

そういうつもりはなかったのですが、
そうとられるなら謝罪いたします。
私の指摘は、設計自体に問題がある場合も多いですが、
教育自体に問題が多い場合が非常に多いということからきています。
http://takagi-hiromitsu.jp/diary/20060114.html
http://blogs.wankuma.com/jitta/archive/2006/01/05/20413.aspx

> ExecではできているのにRunでやらないのはなぜだろう、
> という意味だと思うのですが。別におかしくはないような?
>
> でも半角スペースはデリミタなわけで、Argumentsの内容次第では
> 起動ファイルを取り違える可能性もありますよね。

なので、はじめから基本的に "" をつけなさい。
ただし、空白Space が含まれる場合は、省略できる場合もあります
な感じで教えたほうがいいということです。

問題は、すでに書きましたがそういう教え方をしていないものが
Reference、 書籍を含めて非常に多いことです。

物事を理解する上では、簡略化することは必須ですが、
必要以上に簡略化してしまうと物事の本質を見誤ることが発生します。
# これからは、ここら辺が一層意識しないといけない世の中になるでしょうね。

新米MCP さん 2006年 01月 30日 01時 34分 33秒

>ちゃっぴ さん 2006年 01月 29日 18時 32分 24秒

なぜに喧嘩腰なのでしょう?
ExecではできているのにRunでやらないのはなぜだろう、という意味だと思うのですが。
別におかしくはないような?

でも半角スペースはデリミタなわけで、Argumentsの内容次第では起動ファイルを取り違える可能性もありますよね。
起動ファイル名が"xxx.exe -argu.exe" なんていう謎のファイル名だった場合とか。(普通じゃないけど)
やっぱり""で囲んだ方が安心です。

ちゃっぴ さん 2006年 01月 29日 18時 32分 24秒

To ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒

> ただし、いずれの場合もスペースが含まれたLFN(ロングファイルネーム)は
> 使えません(ファイルがない、というエラーになる)。
> どうしてもLFNを使いたい場合は、次のようにします。
> RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。

なにをいいたいのかわかりませんが?
基本的に LFN を使用する場合、Path を "" でくくることは
ごく当たり前のことです。
それを無視すること自体がどうかと思いますが?

確かに巷にあふれている Sample は、Path を "" でくくっていないものが
非常に多いですが、これはその Sample が悪いわけです。
# そこら辺はその提供者に猛省を求めたいですね。

LFN の Path とか Command Line の Parameter を扱う場合には、
基本的に "" でくくるべきということを第一に教えればまったく問題が
ないことです。
ただし、半角Space を含む場合にはそれを省略できます。
というのが、本来の教え方でしょう。
ですが、現状では半角 Space を含む場合には、"" でくくる必要がありますって
教え方してますね。それが一番の問題です。
# ここら辺のことは、Jitta さんの Blog にも書き込みましたが・・・

半角 Space が含まれる可能性が少しでもあるなら、"" でくくる。
このくらいは Programming を扱う以上、最低限考慮に入れなければ
ならないことです。

そのくらいのことを考慮に入れない、予測できないというなら、
素直に Programming をあきらめるべきです。
# 本件は WSH ですが、Web Application とかを作るとなると
# そんなことでは XSS とか SQL Injection の餌食になるでしょうね。

ちゃっぴ さん 2006年 01月 29日 17時 25分 47秒

Link 先がまちがっていたので・・・

<誤>
Setting Client Application Process Security (英語)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/setting_client_application_process_security.asp

<正>
Securing a Remote WMI Connection
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/securing_a_remote_wmi_connection.asp

ここら辺の設定変更って Command Line とか Script でできないかな?

ちゃっぴ さん 2006年 01月 29日 17時 17分 57秒

WMI Remote について

WMI では、Remote Computer の情報をいろいろ取得できて大変便利です。
ですが、この Remote 機能を使うためには、Default では、
Administrators Users Group に所属している必要があります。

とはいえ、Client での権限は Administrators を与えないで、
Remote から Server の情報を取得して、
処理を分岐させたりしたいということは多いでしょう。

この場合、偽装を行うのが普通ですが、前にも指摘したとおり、
Script に Password を埋め込むのは決してやってはいけません。

そこで解決策となるわけですが、一般の User にも Remote からの
Server の情報への Access を許可してやる方法です。

DCOMCNFG で「マイ コンピュータ」から「プロパティ」- 「COM」セキュリティ
にて「起動とアクティブ化のアクセス許可」の <制限の編集>
で指定の Account に [リモートからの起動], [リモートからのアクティブ化]を許可

ここまでの元ネタはここ
Setting Client Application Process Security (英語)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/setting_client_application_process_security.asp

その後に、「コンピュータの管理」-「サービスとアプリケーション」-
「WMI コントロール」-「プロパティ」-「セキュリティ」- <セキュリティ>にて
対象の Account に対して [リモートの有効化]を
[この名前空間と副名前空間] に対して許可

これで、Administrators 権限がなくても Remote 端末の情報を
手に入れることができるようになります。

まあ、Security Level を多少なりとも引き下げることになるので、
実行するときには、そこら辺を十分に考慮してから
Access Control を制御してくださいな。

ばんのしゃーによかばんた さん 2006年 01月 29日 13時 57分 15秒

IEをプロセスIDでAppActvateするためのオブジェクト生成方法です。

'FullName=CreateObject("InternetExplorer.Application").FullName
Set wShell=CreateObject("WScript.Shell")
FullName=wShell.RegRead("HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\iexplore.exe\")
Set Shell=CreateObject("Shell.Application")
N=Shell.Windows().Count
Set oExec=wShell.Exec(FullName&" -nohome")
Do While N=Shell.Windows().Count
WScript.Sleep 100
Loop
Set ie=Shell.Windows().Item(N)
ie.Navigate "about:blank"
Do While ie.Busy Or ie.ReadyState<>4
 WScript.Sleep 100
Loop
ie.Document.body.innerText="ウィンドウを切り替えてください。5秒後にAppActivateします。"
WScript.Sleep 5000
wShell.AppActivate oExec.ProcessID
ie.Document.body.innerText="5秒後に自動的に終了します。"
WScript.Sleep 5000
If TypeName(ie)="IWebBrowser2" Then ie.Quit
WScript.Quit

これならタイトルを一意にする必要はありません。

ところで、
Set oExec=wShell.Exec(FullName&" -nohome")
は、不思議ですね。知らなかった。

知ってました? ExecメソッドがLFNを完全にサポートしていたのを。

http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/technic.htm
--------------------------------------------------------
アプリケーションの起動

 ただし、いずれの場合もスペースが含まれたLFN(ロングファイルネーム)は使えません(ファイルがない、というエラーになる)。どうしてもLFNを使いたい場合は、次のようにします。RunメソッドがLFNを完全にサポートしなかった理由はいまだ謎。

Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run """C:\Program Files\Internet Explorer\IEXPLORE.EXE"""
'ダブルクォーテーションでくくる。一つ目の「"」は文字列を表し、次の「""」は文字列中では「"」と置き換えられる。
'したがって、DOSプロンプトとかでLFNを実行するとき「"」でくくるのと原理は同じ。
--------------------------------------------------------

でも、こんな半端なサービス(○Exec/×Run)より、
Execが\App Paths\をサポート(×Exec/○Run)してくれたほうがうれしいのに。:-<


ばんのしゃーによかばんた さん 2006年 01月 28日 15時 55分 27秒

フォーカス喪失防止対策の別案です。
――――――――――――――――――――――――――――――――――――――
Set wShell=CreateObject("WScript.Shell")
Set Shell=CreateObject("Shell.Application")
N=Shell.Windows().Count
wShell.Run "IExplore.EXE -nohome",6
Do While N=Shell.Windows().Count
WScript.Sleep 100
Loop
Set ie=Shell.Windows().Item(N)
ie.Visible=False
ie.Navigate "about:blank"
Do While ie.Busy Or ie.ReadyState<>4
 WScript.Sleep 100
Loop
WScript.Sleep 10000
ie.Quit
――――――――――――――――――――――――――――――――――――――
ここで、ie.Visible=Falseをコメントアウトすると、
IEを最小化で起こして、そのオブジェクトを捕捉するパラダイムになります。


ばんのしゃーによかばんた さん 2006年 01月 28日 15時 54分 52秒

スクリプトからIEを起こすと、非表示であっても、フォーカスを奪う問題について
調べてみました。

試してみると、確かにそのようです。
IEのウィンドウが非表示なのにフォーカスを持っているようです。

Set ie=CreateObject("InternetExplorer.Application")
ie.Navigate "about:blank"
Do While ie.Busy Or ie.ReadyState<>4
 WScript.Sleep 100
Loop
MsgBox ie.Document.hasFocus     ' -> True
WScript.Sleep 5000
ie.Quit
WScript.Quit

ALT+Tabしてみると、確かにIEのウィンドウが存在し、フォーカスを持ってるようです。
?よく分からない状態ですね。

これもまた、他にIEがあるか/ないかに依存する現象のようです。
ないときだけ発生します。
ならば、その対策も同様にダミーのIEが使えるのではないでしょうか。

>ばんのしゃーによかばんた さん 2005年 12月 16日 18時 38分 57秒
>ばんのしゃーによかばんた さん 2006年 01月 03日 15時 17分 41秒

ということで試してみました。
ただ、ダミーのIEを追加しただけでは、駄目なようで、
本体のIEがNavigateする度にフォーカスを奪いに行きます。
ダミーのIEを一度表示するとよいようです。
ixの3行(:-)を追加します。

フォーカス喪失防止対策.VBS
――――――――――――――――――――――――――――――――――――――
Set ix=CreateObject("InternetExplorer.Application")
ix.Top=-32000:ix.Left=-32000:ix.Visible=True:ix.Visible=False
Set ie=CreateObject("InternetExplorer.Application")
ix.Quit
ie.Navigate "about:blank"
Do While ie.Busy Or ie.ReadyState<>4
 WScript.Sleep 100
Loop
WScript.Sleep 5000
If ie.Document.hasFocus Then MsgBox ie.Document.hasFocus     'False
ie.Quit
WScript.Quit
――――――――――――――――――――――――――――――――――――――
一瞬、フォーカスが移るのはご愛嬌です。


管理人むたぐち さん 2006年 01月 28日 11時 11分 13秒

To: AKA さん

> >某所
>
> 某所ってどこですか?
> この掲示板の書き込みについて批評がされている場所があるのなら、私に> も知る権利はあると思うのですが?

ソーシャル・ネットワーキングサイト mixiの私の日記のコメント欄です。といっても公開レベルをプライベート設定してあるので、ほとんどメール並のプライベートレベルです。

AKA さん 2006年 01月 28日 07時 33分 00秒

WIN32API.EXEをちょっと変わった動作システムに変えてみました。

WIN32X.EXE

http://winscript.s41.xrea.com/wiki/index.php?plugin=attach&pcmd=open&file=W32X001.LZH&refer=%5B%5B%A5%A2%A5%C3%A5%D7%A5%ED%A1%BC%A5%C0%A1%BC%5D%5D

これはWIN32API.EXEと違い、WIN32X.EXEを呼び出したプロセス空間内で動作する、というものです。

したがって関連した一連のWin32APIコールを行うことができます。WScript.exeやCScript.exe内の固有の情報にアクセスも可能です。
まあDW7を入れられればそれが一番良いんですが。

同梱のPEEKPOKE.DLLは私がDW6を作る前にDWで使っていた非オートメーションDLLの機能を絞った版です。

WIN32XとPEEKPOKE.DLLを使えばDW6とほぼ同じようなことができます。

しかし、このプログラムはクラッシュした場合当然親プロセスがクラッシュすることになるので非常な注意が必要です。

そして、残念ながらWin9xでは動作しません。

サンプルは「TMP.TXT」というファイルの最終書き込み日付を1年後にずらすものです。

「TMP.TXT」という名前のファイルをすでに作って使っている人は十分に注意してください。

作っていない人は「TMP.TXT」というファイルをテスト用に作ってから実行してください。

サンプルは何やら長々と書かれていますが、実際にはこれくらいの処理をするためにクラス定義やエラーチェックをする必要は必ずしもありません。しかし、ある程度以上Win32APIや構造体を多用する場合には絶対こうやった方がいいので、そうした場合のヒナ型と考えてください。
ちなみにDW7とWIN32API.VBSを使用すればいちいちクラス定義する必要は全く無く、DLL関数呼び出しも格段に楽で合理的です。


'<<CHGFT.VBS>>

' FileNameで指定したパス名のファイルの最終書き込み日付を1年後に変えます。

Option Explicit

Const ERROR_WIN32X = -1

Dim g_ws
Set g_ws = CreateObject("WScript.Shell")

Dim FileName
'FileName = "C:\Program Files\TMP.TXT"
FileName = "TMP.TXT" '好きなパスに変えてみてください。

Dim hFile
hFile = g_ws.Run("WIN32X KERNEL32 CreateFileA sllllll """ & FileName & """ " & GENERIC_WRITE & " 0 0 " & OPEN_EXISTING & " 0 " & C_NULL, , True)
If (hFile = INVALID_HANDLE_VALUE) Or (hFile = ERROR_WIN32X) Then
     WScript.Echo "CreateFile error"
     WScript.Quit
End If

Dim ftLastWrite
Set ftLastWrite = New FILETIME

Dim bRes
bRes = g_ws.Run("WIN32X KERNEL32 GetFileTime llll " & hFile & " " & C_NULL & " " & C_NULL & " " & ftLastWrite.Address, , True)
If (bRes = C_FALSE) Or (bRes = ERROR_WIN32X) Then
     WScript.Echo "GetFileTime error"
     WScript.Quit
End If

Dim stLastWrite
Set stLastWrite = New SYSTEMTIME

bRes = g_ws.Run("WIN32X KERNEL32 FileTimeToSystemTime ll " & ftLastWrite.Address & " " & stLastWrite.Address, , True)
If (bRes = C_FALSE) Or (bRes = ERROR_WIN32X) Then
     WScript.Echo "FileTimeToSystemTime error"
     WScript.Quit
End If

stLastWrite.wYear = stLastWrite.wYear + 1

bRes = g_ws.Run("WIN32X KERNEL32 SystemTimeToFileTime ll " & stLastWrite.Address & " " & ftLastWrite.Address, , True)
If (bRes = C_FALSE) Or (bRes = ERROR_WIN32X) Then
     WScript.Echo "SystemTimeToFileTime error"
     WScript.Quit
End If

bRes = g_ws.Run("WIN32X KERNEL32 SetFileTime llll " & hFile & " " & C_NULL & " " & C_NULL & " " & ftLastWrite.Address, , True)
If (bRes = C_FALSE) Or (bRes = ERROR_WIN32X) Then
     WScript.Echo "SetFileTime error"
     WScript.Quit
End If

bRes = g_ws.Run("WIN32X KERNEL32 CloseHandle l " & hFile, , True)
If (bRes = C_FALSE) Or (bRes = ERROR_WIN32X) Then
     WScript.Echo "CloseHandle error"
     WScript.Quit
End If

WScript.Quit


'--- Win32API定数 & 構造体クラス定義

Const GMEM_FIXED = 0
Const C_FALSE = 0
Const C_NULL = 0
Const INVALID_HANDLE_VALUE = -1
Const GENERIC_WRITE = &H40000000
Const OPEN_EXISTING = 3

Const SIZE_OF_FILETIME = 8
Const SIZE_OF_SYSTEMTIME = 16
Const RADDRESS_OF_WYEAR_IN_SYSTEMTIME = 0

Class FILETIME
     Private AddressInternal
     Public Property Get Address
          Address = AddressInternal
     End Property
     Private Sub Class_Initialize
          AddressInternal = g_ws.Run("WIN32X KERNEL32 GlobalAlloc ll " & GMEM_FIXED & " " & SIZE_OF_FILETIME, , True)
          If Address = 0 Then
               WScript.Echo "GlobalAlloc() Error"
               WScript.Quit
          End If
     End Sub
     Private Sub Class_Terminate
          g_ws.Run "WIN32X KERNEL32 GlobalFree l " & Address, , True
     End Sub
End Class

Class SYSTEMTIME
     Private AddressInternal
     Public Property Get Address
          Address = AddressInternal
     End Property
     Private Sub Class_Initialize
          AddressInternal = g_ws.Run("WIN32X KERNEL32 GlobalAlloc ll " & GMEM_FIXED & " " & SIZE_OF_SYSTEMTIME, , True)
          If Address = 0 Then
               WScript.Echo "GlobalAlloc() Error"
               WScript.Quit
          End If
     End Sub
     Private Sub Class_Terminate
          g_ws.Run "WIN32X KERNEL32 GlobalFree l " & Address, , True
     End Sub
     Public Property Get wYear
          wYear = g_ws.Run("WIN32X PEEKPOKE PeekShort l " & Address + RADDRESS_OF_WYEAR_IN_SYSTEMTIME, , True)
     End Property
     Public Property Let wYear(Value)
          g_ws.Run "WIN32X PEEKPOKE PokeShort ll " & Address + RADDRESS_OF_WYEAR_IN_SYSTEMTIME & " " & Value, , True
     End Property
End Class


>>管理人むたぐち さん 2006年 01月 15日 13時 02分 24秒
>変数名をクラス名と一緒にしたり

C/C++では「あいまい」でないものはできるだけ通す、という考え方があります。
例えばC++では関数のオーバーロード、というものがあります。(VB.NETにもありますね?)
これは同じ名前でもその呼び出しコンテキストによって別の関数に変化するものです。
関数の仕様ごとに名前を変えればいい、という考え方もありますが、名前が同じことで便利になることもあります。
要するに使われ方が明確でありさえすればそのものが実際にはどれを指しているのかはわかるわけで、オブジェクト指向の言語にはこうした名前の多重使用がしばしば見られます。(使われ方で判断できない場合「あいまい」になります)
オブジェクト指向言語ということになっているVBScriptがそれを許容する、というのならばあえて否定する必要もないでしょう。
確かに混乱が起こる可能性はありますが、例えばC/C++では構造体、あるいはクラスであるXに対し、そのインスタンスを作成する場合、
     X x;
みたいな宣言は普通ですし、
     X X;
も別に間違いというわけではありません。


>某所

某所ってどこですか?
この掲示板の書き込みについて批評がされている場所があるのなら、私にも知る権利はあると思うのですが?


>>ごおお さん 2006年 01月 13日 14時 18分 44秒

>自動実行されるVBSのなかで
>Set objIE = CreateObject("InternetExplorer.application")
>でIEを立ち上げています。そのときにフォーカスが新しく立ち上がったIE
に移ってしまいます。

回答ではないですが、私が確認した所・・・

エクスプローラからVBSを実行すると、objIE.Quitするまでの間フォーカスは失われますね・・・Quitすると戻って来る。
あと、DOSプロンプトやコマンドプロンプトのフルスクリーンモードから実行するとフォーカスがGUI画面に移りますが、Quitしてもプロンプトに戻ってこない・・・サブウィンドウモードなら戻って来ますが・・・
Win2000+IE6では、VBS実行前にすでにiexplore.exeが起動されていればフォーカスは移らないですね。
Win98+IE5ではiexplore.exeが存在していてもフォーカスは移りますね。

あと、Quit前にタスクマネージャとかでVBSを強制終了するとiexplore.exeが永遠に残りますね・・・

管理人むたぐち さん 2006年 01月 27日 19時 54分 58秒

To: いちご さん

cscript //H:CScript
をコマンドラインから実行し、既定のスクリプトホストを
cscript.exeにしてください。

もしくは、
wshShell.Run "cscript.exe d:\inetpub\wwwroot\test\test.vbs"
のようにcscript.exeでスクリプトを実行するように
してみてください。

Return