TAPTAP さん 2004年 05月 11日 17時 30分 02秒

うう、いまいちKenzoさんがどういったことをやりたいのか
ピント来ないんですが(^_^;)
自分が仕事で使っている毎日変更するシートも
セーブしてあれば便利だったので、練習してみました。
いりやさんの方法試してみたのですが
workbookオブジェクトを取得するのが、
私はうまくいきません。(^_^;)
全部 activeworkbook を使ってます。

えっと、WSHからエクセルを開いて
既存のオリジナル(XLSファイル)を開き
変更して、他のXLSファイルに保存するんですよね..
こっちをbook2 としますと、
実際に変更を加えたオリジナルはどうされるのでしょうか?
それには、変更を反映させたくないということかな。。

ちなみに、SaveCopyAs で保存した時点では
ヘルプのダイアログはでてきませんが。

dim objX,mybook
Set objX=WScript.CreateObject("Excel.Application")
objX.visible=true
objX.SheetsInNewWorkbook=1 
bStr="C:\My Documents\keisan\renbook.xls"
bStr2="C:\My Documents\keisan\renbook2.xls"
objX.workbooks.Open bStr
objX.worksheets("sheet1").Cells(1,1).value=33 '変更..
objX.activeworkbook.savecopyas bStr2

全く役に立たないと思いますが、すみませぬ..

いりや さん 2004年 05月 11日 16時 13分 25秒

Kenzo さん、TAPTAP さん、

Workbook オブジェクトの saved プロパティーに true を
設定する、という手は使えませんか??

以下、Microsoft Excel のヘルプからの引用です。

//
Saved プロパティ


True の場合、ブックは最後の保存した状態から変更が加えられていません。値の取得および設定が可能です。ブール型 (Boolean) の値を使用します。

解説

一度も保存されていないブックのとき、Path プロパティは Null 値になります。

変更を加えたブックを保存しない、および保存するかどうかを確認するダイアログ ボックスを非表示にして閉じる場合は、このプロパティに True を設定してください。
//

Kenzo さん 2004年 05月 11日 14時 12分 41秒

TAPTAPさん、早速のお返事有難うございました。

> ActiveWorkbook.SaveCopyAs "C:\TEMP\XXXX.XLS"
> これを試されてみてはどうでしょうか?

これもやって見たのですが、これだと確かにコピーした方は聞いてこず
ちゃんとコピーしてくれますが、オリジナルをどうするか?、と聞いて
来ます。うーむ、一歩前進、一歩後退で、現状維持か。

やっぱりVBAとVBでは細部は違うんですね。感謝です。

TAPTAP さん 2004年 05月 11日 12時 38分 43秒

>Kenzo さん
>ExcelObj.ActiveWorkbook.SaveAs "c:\aaa\bbb\ccc.xls"
>で 、VBSを実行すると既にファイルがあると上書きするか聞いてきます。

私も初心者ですので、正確ではないかもしれませんが
これはエクセルのVBAの SaveAsメソッドですよね
エクセルのvisual Basic のリファレンスが
エクセルのヘルプから参照できると思いますが
それによると、WorkBook オブジェクトには
SaveCopyAs メソッドがあります
ActiveWorkbook.SaveCopyAs "C:\TEMP\XXXX.XLS"
これを試されてみてはどうでしょうか?
エクセル上でのマクロ操作では、これだと
上書き保存のダイアログはでなかったです。






Kenzo さん 2004年 05月 11日 10時 29分 35秒

最近濃いスレッドが続いてて初歩的な質問をするのが恥ずかしいですが、
敢えて。

VBでエクセルの自動処理を書いてます。別のファイルから読み込んだ値
を特定のレンジに挿入してオリジナルを別名で保存するものです。

肝心の個所は

ExcelObj.ActiveWorkbook.SaveAs "c:\aaa\bbb\ccc.xls"

で 、VBSを実行すると既にファイルがあると上書きするか聞いてきます。
これを回避したいのですが、VBでは、実行を強制するTrue, Falseの指定
は出来なかったのでしょうか?

MSDNでVBのファイル・オブジェクトのメソッドなり調べては見ましたが
詳しい事は書いていませんでした。過去スレも探しましたがそれらしきも
のはありませんでした。

ファイルの存在をチェックしてDeleteメソッドで消す方法は分かりますが、
上のオプションが使えれば馬鹿みたいですから。。。

どなたかお分かりでしたら教えて下さい。

ばんのしゃーによかばんた さん 2004年 05月 10日 19時 28分 09秒

>ぷかちん さん 2004年 05月 08日 23時 03分 29秒
>VBScriptで記述したスクリプトを.vbsという拡張子を持つファイルに
>ソースを格納している際に、ファイル分割した場合の
>参照方法がわかりませんでした。
>具体的にやりたいことは、関連する関数を各ファイルに
>まとめて保存しておきたいのですが、
>WSHでは他の言語のようにソースファイルを複数に分けて
>管理・実行することはできるのでしょうか。

標準的にはありませんが、#include擬のSubを作れば同様に出来ます。

インクルードする側、

Sub include(incfile)
Dim fso,folder,file
Set fso=CreateObject("Scripting.FileSystemObject")
folder=fso.GetParentFolderName(WScript.ScriptFullName)
Set file=fso.OpenTextFile(fso.BuildPath(folder,incfile))
ExecuteGlobal file.ReadAll()
file.Close
End Sub

include "a.inc"

WScript.Echo b
WScript.Echo c
Call sss()


インクルードされる側、a.inc

WScript.Echo "a"
b="b"
Dim c
c="c"
Sub sss()
WScript.Echo "s"
End Sub

定数や関数のほか、クラス定義などもインクルードできるようなので、
なかなかよいのではないでしょうか。

ふみふみ さん 2004年 05月 10日 16時 18分 07秒

管理人むたぐち さん、こんにちは。

> > > これってWSHから実行するときも駄目なんでしたっけ?
> というのは、「NameSpaceメソッドの実行は、sp4からfolder.httでは
> 駄目になったけれど、WSHからも駄目になったのかどうか」という
> 意味でした。
すいません、ようやく理解できました。(笑)

先日の報告させて頂いた件について、訂正の報告をさせて頂きます。

履歴の取得の際に Error となる原因は、先日ご報告したレジストリの
件ではないことが判明しました。
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
"NoRecentDocsHistory"=dword:00000001
には関係なく、履歴に検索エンジンなどの検索結果が含まれる場合に
起こる現象の模様です。
Google や Goo で試してみたところ、Error となりました。
(履歴の Path に問題があるのかも? "Administrator"だし… 笑)
9x系のOS では Error とはならないものの、書き出された HTML には
正しい URL が取得できないことも判りました。
URL のエンコードとデコードの問題の模様にも思えるのですが…。
回避策は今のところ判りません。
正しく書き出せない部分は手作業にて修正して回避しております。

> しかし、今回の件は、sp4のセキュリティ対策とは関係なかった
> みたいですね。
はい、「IEの履歴を書き出す」ということは、ある意味では他人の
個人情報に順ずる情報を入手できる可能性もありますし VBS を悪用
した WORM などの懸念からの Microsoft の対策なのかとばかり思っ
ていたもので、大変な勘違いをしてしまいました。
申し訳ございませんでした。

今回の件で、いろいろと検索をしてみた結果、Ruby でも IEの履歴
を取得できるコードを発見しました。
http://www.persistent.org/hiki/hiki.cgi?Historium-modoki

まだ試してみていないのですが、元はむたぐちさんの hist2txt だ
ということです。


勘違いな報告ばかりしてしまって、重ね重ね申し訳ありません。
訂正のご連絡を申し上げます。

ばんのしゃーによかばんた さん 2004年 05月 09日 22時 38分 13秒

>管理人むたぐち さん 2004年 04月 24日 15時 31分 55秒
>ただし、MS Agentのキャラクターのメソッドは、非同期的に実行されるので、
>リアルタイムで情報を喋らせるという用途にはあまり向いてない感じもします。
>(同期的に実行する方法ってあるんでしょうか?)

IAgentCtlRequest.Statusが、2(pending)->4(progress)->0(completed)と変化するので、
話し終わるのは0になるのを待てばよいようです。
TTSModeIDを指定しないと2->4->1(failed)。

Set AgentControl= WScript.CreateObject("Agent.Control")
AgentControl.Connected = True
AgentControl.Characters.Load "Merlin","c:\windows\msagent\chars\merlin.acs"
Set Merlin = AgentControl.Characters("Merlin")
Merlin.Show
Merlin.TTSModeID="{c5c35d60-da44-11d1-B1F1-0000F803E456}"
Set Req=Merlin.Speak( "#1処理中です。" )
Do While Req.Status>1
WScript.Sleep 1000
Loop
Set Req=Merlin.Speak( "#2処理中です。" )
Do While Req.Status>1
WScript.Sleep 1000
Loop
Merlin.Hide

また、バルーンを出し続けるには、
Set Balloon=Merlin.Balloon
Balloon.Style=Balloon.Style And Not 4
とauto-hide(bit 2=long 4)を消す。

バルーンを消す。
Balloon.Visible=False

黒騎士F91 さん 2004年 05月 09日 16時 02分 09秒

ちわ♪黒騎士です。

管理人むたぐち さん
> WScript.ScriptFullName
あは、案外簡単なものなんですね。
散々探しても見つからなかったのは注意力が無い性だなと反省中です。
まだ98では試してないですが、明日試します。
ありがとうございます。
これからも宜しく御願いします。

管理人むたぐち さん 2004年 05月 09日 13時 59分 18秒

To: 黒騎士F91 さん

> a.vbsを実行し、そのコードの中でa.vbsを取得したいと思っています。

WScript.ScriptFullName
では駄目でしょうか。


To: ぷかちん さん

> WSHでは他の言語のようにソースファイルを複数に分けて
> 管理・実行することはできるのでしょうか。

ぱっと思いつくのはこのようなものでしょうか。

1. WSFファイルを利用する。

XMLを用いて一つのファイルに複数のコード、複数の言語、複数のファイルを
含めることができる、wsfファイルを利用する方法です。
<script src="hoge.vbs">のように、別ファイルをインクルードできます。
詳しくはヘルプをご覧ください。

2. WSC(Windows Script Component)ファイルを利用する。

同じくXMLを用いて一つのファイルに複数のコードを含めることができる、
wscファイルを用いる方法です。
こちらはWSFとは違って、コンポーネント可できるのが特徴です。
つまり、呼び出し元から、CreateObjectして呼び出すことが可能になります。
(呼び出し元は、vbsファイルのままで問題ありません)
一度レジストリに登録(regsvr32)してしまえば、後はwscファイルの場所を
気にせずCreateObjectして呼び出せるようになるので、いろんなスクリプトから
呼び出す関数集などをwscにすると便利です。
これも詳しくはヘルプをご覧ください。

3. FileSystemObjectを使ってTextStreamでvbsファイルを読み込み、
Executeステートメントで読み込んだ文字列を実行する。

Executeステートメントは、引数の文字列をそのままvbsのスクリプト
エンジンに送って実行させる働きを持っていますので、
こういうことも可能なわけです。
どうしてもvbsファイルだけで完結させたいという場合のみ使用すると
良いと思われます。

以上、3つの方法を纏めるとこうなります。

1→呼び出し元ファイルをXMLに書き換える必要がある。
2→呼び出すファイルをXMLに書き換える必要がある。
3→XMLに書き換える必要はないが、あまりスマートではない。


To: ふみふみ さん

解決してよかったです。

混乱させて申し訳なかったのですが、
> > これってWSHから実行するときも駄目なんでしたっけ?
というのは、「NameSpaceメソッドの実行は、sp4からfolder.httでは
駄目になったけれど、WSHからも駄目になったのかどうか」という
意味でした。
しかし、今回の件は、sp4のセキュリティ対策とは関係なかった
みたいですね。

ふみふみ さん 2004年 05月 09日 00時 39分 41秒

管理人むたぐち さん、こんにちは。

できました。
History の「マイ コンピュータ」の中に「最近使ったファイル」の履歴のようなものが
記録されていて、これが原因だったような気がします。
レジストリに
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
"NoRecentDocsHistory"=dword:00000001
を設定して再起動(または Logoff)したところ、上記の履歴は保存されなくなり、IE の
履歴のみ保存されるようになりました。
昨年使用していた PC は現在のものではなくて、新規に w2k を Install した現在の PC
には "NoRecentDocsHistory"=dword:00000001 を追記していない状態であった為に IE の
履歴が読み出せなかった模様です。

Const strPath="C:\Documents and Settings\Administrator\デスクトップ\History.html"
Dim strHtml
Set FSO = WScript.CreateObject("Scripting.FileSystemObject")
Set Folder = WScript.CreateObject("Shell.Application")
Set objFolder=Folder.NameSpace("shell:History")

上記の記述で問題なく IE の履歴が取得できるようになりました。

皆様には大変お手数をお掛けいたしました。
有難うございます。

ぷかちん さん 2004年 05月 08日 23時 03分 29秒

はじめまして、ぷかちんと申します。

簡単なツール類を作成しようとWSHを勉強し始めたのですが、
VBScriptで記述したスクリプトを.vbsという拡張子を持つファイルに
ソースを格納している際に、ファイル分割した場合の
参照方法がわかりませんでした。

具体的にやりたいことは、関連する関数を各ファイルに
まとめて保存しておきたいのですが、
WSHでは他の言語のようにソースファイルを複数に分けて
管理・実行することはできるのでしょうか。

ばんのしゃーによかばんた さん 2004年 05月 08日 20時 11分 49秒

>ばんのしゃーによかばんた さん 2004年 05月 06日 19時 32分 07秒
>さらに、98/MEでは、
>Command.comやbatファイルや16ビットコンソールアプリをExecすると、
>CScriptでは動いても、WScriptではhang upします。:-<
>32ビットコンソールアプリはOK。

hang upはoExec.StdOut/StdErrのEOFが上がらないためのようです。
EOFなのに更に読もうとして永久待ちになるようです。
command.comがstdout/stderrをdupしたまま、ほったらかしているのかも。

回避方法はどうもなさそう。

98/MEでは、
コンソールアプリのexecはCScriptでだけ使う。
execはwinアプリだけにして、コンソールアプリはrunを使う。

ばんのしゃーによかばんた さん 2004年 05月 08日 20時 10分 46秒

>ばんのしゃーによかばんた さん 2004年 05月 06日 19時 32分 07秒
>フィルタはExecで使いたいところですが、一般のフィルタはこの壁のため使えません。
>なんとかならんもんでしょうかねぇ。:-<

甲案
2000/XPでcommand.comを咬ませる。
163バイトの壁が4096まで拡大する。
wShell.Exec("command.com /c filter")

乙案
2000/XPでcommand.comの疑似パイプを咬ませる。
疑似パイプは一時ファイルなので、壁がない。
wShell.Exec("command.com /c filter1|filter2")
フィルタがひとつならmoreを足す。

丙案
in/out或いは中間に一時ファイルを置いてcmd.exeのリダイレクションを使う。
wShell.Exec("cmd.exe /c filter>temp")
wShell.Exec("cmd.exe /c filter<temp")
wShell.Exec("cmd.exe /c filter1>temp&filter2<temp")
Runだとin/out、ふたつの一時ファイルを使うので、それよりは少ない。


ばんのしゃーによかばんた さん 2004年 05月 08日 20時 09分 23秒

>om さん 2004年 03月 24日 10時 22分 50秒
>WSHにおいて
>フォルダC:\AAAAフォルダ下にあるファイルと
>フォルダC:\BBBBフォルダ下にあるファイルを
>ファイル名で比較し、一致するファイル名が存在するか
>しないかを判別できるようなコードがわかれば教えて下さい。

こんな方法も。

Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("cmd.exe /c dir /b C:\AAAA\*.* C:\BBBB\*.* |sort|uniq -d")
'WScript.Echo oExec.StdOut.ReadAll()
a=Split(oExec.StdOut.ReadAll(),vbCRLF)
WScript.Echo UBound(a),Join(a,";")

難点は、uniqが標準ではないこと。
一応、Microsoft Windows Services for UnixのMKS Toolkitにあります。

なければ、簡単なので、VBSriptで作ってしまえばよいでしょう。
あると、この例のようにいろいろ使えて便利です。

ふみふみ さん 2004年 05月 07日 18時 43分 39秒

管理人むたぐち さん、はじめまして、こんにちは。
ご回答頂きまして有り難うございます。

> Win2000sp4で、ShellオブジェクトのNameSpaceメソッドに、
> セキュリティ上の制限がかけられたようです。
昨年の秋頃までは正常に動作していたような記憶がありますので、
それ以降の Microsofftの修正パッチに起因しているような気がする
のですが、どのあたりのものに原因があるのかについては不明で、
回避の方法や Microsoft の KB なども、今のところ見つかりません。

> folder.httカスタマイズ時に経験しました。
もしかして、昨年秋以降の頃なのでしょうか…。

> そのときは、上位フォルダのFolderオブジェクトのParseNameメソッドを使って、
> サブフォルダのFolderオブジェクトを取得することで回避しました。
貴重な情報を有り難うございます。
現在 Vine から書き込みをさせて頂いているので、HDD を w2k に交換
して試してみます。
何となく、History Folder の中身の実体(History\History.IE5\〜) を
書き出してしまうような気もしていますが…。
(それとも "サポートされていない Method" かも…)

> これってWSHから実行するときも駄目なんでしたっけ?
はい? すいません、意味が理解できておりません。(笑)

> というのも、WSHからShellのFolderオブジェクトを取得する方法は、
> 基本的にNameSpaceメソッドとBrowseForFolderメソッドしかないですので。
実はプログラマではないので、どのような Method が用意されているの
かについても把握できておりません。
かたっぱしから試してみておりました。

> C:\Documents and Settings\username\Local Settings\History
> のように、実名を指定しても駄目なんでしょうか?
はい、以前はそのような Path の指定で問題なく動作しておりました。
LFN のせいなのかとも思い、SFN(8.3形式) にして試してみたりもした
のですが、前述同様の Error Alart が表示されておりました。


暫く NT系のOS には触れていなかったので気がつかなかったのですが、
履歴を書き出す Script や App が他には見つからないので、非常に
残念に思っております。
重宝していたのですが…。

黒騎士F91 さん 2004年 05月 07日 18時 27分 00秒

お世話になります。
只今実行ファイル名を取得しようと奮闘中です。
a.vbsを実行し、そのコードの中でa.vbsを取得したいと思っています。
手元にWin98がなく、あまり詳しく試していないのですが、
ExecutablePathで検索したところ、Win32_ProcessでCommandLineを使うとどうにかなるのではないかと思いましたが、Win98では実行できませんでした。
NT系、98系両方で実行でき、実行したファイル名を取得できる方法ってないでしょうか?

管理人むたぐち さん 2004年 05月 07日 17時 38分 49秒

To: ばんのしゃーによかばんた さん

> 教訓。レスポンスが遅いなどシステムがなんか変なときには書き込まない。

最近ちょっとこの掲示板、重いことがあるみたいですね。
ていうかサイト全体が…。

> regsvr32してやると、CreateObject("TextToSpeech.TextToSpeech")で
> しゃべってくれるようになりました。

TextToSpeechって実はWSHから使えたんですねえ。

日本語のスピーチエンジンが、もちっといい声になってくれればいいですね。
今のだと、何を喋らせても間抜けな感じです。
英語は結構いい感じなんだけどなぁ。


To: 魔界の仮面弁士 さん

> VB5CCEでは無理だとしても、.NETでCOMコンポーネントを作る、という手がありますよ。

TextToSpeechコントロールをtlbimpした.NETアセンブリを作って、
それをregasmしてWSHから呼び出すというわけですね。
私もちょっと考えたんですけど、これってなんだか
とっても回りくどい感じです。


To: ふみふみ さん

> この Script を IE の履歴(History) を書き出すようにして利用させて頂いておりますが、
> 9x系のOS では問題なく動作するのですが、NT5.x系のOS では正常に動作しなくて困っております。

Win2000sp4で、ShellオブジェクトのNameSpaceメソッドに、
セキュリティ上の制限がかけられたようです。
folder.httカスタマイズ時に経験しました。
そのときは、上位フォルダのFolderオブジェクトのParseNameメソッドを使って、
サブフォルダのFolderオブジェクトを取得することで回避しました。
(folder.httの場合、FileList.Folderで上位フォルダの
Folderオブジェクトが取得できる)

現在、私はWinXPを使っているのでちょっと忘れたんですが、
これってWSHから実行するときも駄目なんでしたっけ?
だとしたらちょっと難しいかもしれません。
というのも、WSHからShellのFolderオブジェクトを取得する方法は、
基本的にNameSpaceメソッドとBrowseForFolderメソッドしかないですので。

C:\Documents and Settings\username\Local Settings\History
のように、実名を指定しても駄目なんでしょうか?

ふみふみ さん 2004年 05月 07日 16時 43分 42秒

初めてお便りさせていただきます。
Download のコーナーから url2htm を愛用させて頂いております。
この Script を IE の履歴(History) を書き出すようにして利用させて頂いておりますが、
9x系のOS では問題なく動作するのですが、NT5.x系のOS では正常に動作しなくて困っております。
"http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/refer/lesson11.htm"

"http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/technic.htm#特殊フォルダを開く"
を参考に、
Set objFolder=Folder.NameSpace("shell:History")
としてみても "obj がない" 旨の Error Alart が表示されます。
昨年秋頃までは正常に書き出すことができていたので、その後の Microsoft の Security Patch
などに起因する問題のような気がしているのですが…。
お判りの方がいらっしゃるようでしたら、宜しくお願い致します。

魔界の仮面弁士 さん 2004年 05月 06日 22時 00分 14秒

》ばんのしゃーによかばんた さん
> もし、VB5CCEでそういうことが出来れば純正MS製の準標準的環境で、
> WSHがフル活用できるのですが、どうなんでしょう。
VB5CCEでは無理だとしても、.NETでCOMコンポーネントを作る、という手がありますよ。
簡単にできるかどうかは別問題ですが、少なくとも.NET Framework SDK自体は無料ですし。


> 試しにTextToSpeechを貼り付けてOCXを作ってみましたが、
> 貼り付けたTextToSpeechにたどり着けない。:-<
どのようなOCXを作り、どのように利用されているのか分からなかったのですが、
ひょんさんの「RunObject」のように、オブジェクトを登録して、
それを外部から利用可能なOCXを作成された…という事でしょうか?
それとも、UserControlにTextToSpeechを貼り、それをOCXにしているのでしょうか?

前者の形式だとすれば、ActiveXコントロールだと難しいと思います。

Microsoft ScriptControl(のAddObjectメソッド)のように、内部に公開する仕様ならば
良いのですが、外部に公開したいのであれば、ActiveX EXEにする必要があるような気がします。
(とはいえ、VB5CCEではActiveXコントロールしか作成できませんけれどね…)
で、内部に公開する形式なのにうまく渡せない、という事であれば、
PropertyBagオブジェクトの利用法に問題があるのかもしれません。。

で、後者の形式(UserControlにTextToSpeechを貼っている場合)だとすると、
内在コントロール(この場合はTextToSpeech)の機能を利用可能にするために
UserControlに定義された「Publicなプロシージャ」の作りに問題があるのかも。

ばんのしゃーによかばんた さん 2004年 05月 06日 19時 32分 07秒

>>まる さん 2004年 02月 04日 10時 30分 54秒
>>DOSのアプリケーションを、ディレクトリーを指定した上で実行させる方法を教えてください。
>>バッチだと
>>cd c:\testfolder
>>mycommand.exe
>>の様に書くと c:\testfolder で mycommand.exe が実行されますが、
>>これと同じ事をWSHスクリプトで行ないたいのです。

>cmd="command /c for %%0 in (""c:"" ""cd c:\testfolder"" ""mycommand.exe"") do %%0"
>として、
>wShell.Run cmd

少々「インチキ」ぽいですが、標準入力を使わないものなら、

wShell.Run "%comsec% /c c:|cd c:\testfolder|mycommand.exe"

という手もあります。

この手を使うと、

>>om さん 2004年 03月 24日 10時 22分 50秒
>>WSHにおいて
>>フォルダC:\AAAAフォルダ下にあるファイルと
>>フォルダC:\BBBBフォルダ下にあるファイルを
>>ファイル名で比較し、一致するファイル名が存在するか
>>しないかを判別できるようなコードがわかれば教えて下さい。

>98/MEでは、バッチを作って、
>@echo off
>C:
>cd C:\AAAA
>for %%0 in ( *.* ) do if exist C:\BBBB\%%0 echo %%0
>それを
>Set oExec=wShell.Exec("なんとか.bat")

バッチにしなくても、

Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("command.com /c C:|cd C:\AAAA|for %%0 in ( *.* ) do if exist %%0 echo %%0")
WScript.Echo oExec.StdOut.ReadAll()

for文はcommand.com /cでは%%、cmd.exe /cでは%と非互換なので、
共通コードにはなりません。:-<

ところが、コマンドEchoがどうしても抑止できないので却下です。

さらに、98/MEでは、
Command.comやbatファイルや16ビットコンソールアプリをExecすると、
CScriptでは動いても、WScriptではhang upします。:-<
32ビットコンソールアプリはOK。

したがって、

>管理人むたぐち さん 2003年 07月 01日 20時 39分 10秒
>To: 神 さん
>> ワイルドカードを含む任意のファイル名から、実在するファイル名を取得したいのですが
>VBSやFileSystemObjectにはワイルドカードを展開する機能はありません。
>ので、そういうコードを書いてやる必要があります。
>ワイルドカードを含む文字列を与えると、マッチしたFileオブジェクトあるいは
>Folderオブジェクトの格納された1次元配列を返すような関数にすれば
>使い勝手が良さそうです。

2000/XPはCScript/WScript共に可、
98/MEはCScript限定、
ですが、

Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("%comspec% /c dir /b *.*")
'WScript.Echo oExec.StdOut.ReadAll()
a=Split(oExec.StdOut.ReadAll(),vbCRLF)
WScript.Echo UBound(a),Join(a,";")

さらに、これの利点はソートが自由自在に指定出来ることです。/Oオプション

ワイルドカードを正規表現で実現するのは、結構面倒そうです。
「*」と「*.」と「*.*」の微妙な差異など。
そもそもブランクパディングの8+3表現用の歪な仕様を真似るのはしんどい。

さて、ソートが出てきたので、ついでに

2000/XPはCScript/WScript共に可、
98/MEはCScript限定、
ですが、

a=Array("c","b","a")
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("sort.exe")
oExec.StdIn.WriteLine Join(a,vbCRLF)
oExec.StdIn.Close
'WScript.Echo oExec.StdOut.ReadAll()
a=Split(oExec.StdOut.ReadAll(),vbCRLF)
WScript.Echo UBound(a),Join(a,";")

ソートは所謂フィルタですが、全部読んで、ソートして、全部書くので、
例のStdInの163バイトの壁を心配する必要はありません。

フィルタはExecで使いたいところですが、一般のフィルタはこの壁のため使えません。
なんとかならんもんでしょうかねぇ。:-<

壁は、2000/XPは163バイトですが、98/MEでは4096バイトのようです。
つまり、98/MEも一時ファイルの疑似パイプではないようです。単なるメモリ渡し ?

ばんのしゃーによかばんた さん 2004年 05月 06日 19時 12分 01秒

>管理人むたぐち さん 2004年 05月 04日 14時 05分 55秒
>「WSHから」TextToSpeechなどのコントロールを呼び出すのに、
>コンテナとしてIEやExcelを用いているのであって、単にTextToSpeechを
>ちなみに、ひょんさんのところで、そういうことをするためのCOMコンポーネントが
>公開されています。Running Object Server ver1.10のがそれです。

もし、VB5CCEでそういうことが出来れば純正MS製の準標準的環境で、
WSHがフル活用できるのですが、どうなんでしょう。
試しにTextToSpeechを貼り付けてOCXを作ってみましたが、
貼り付けたTextToSpeechにたどり着けない。:-<

mi- さん 2004年 05月 06日 01時 59分 26秒
URL:http://www.yourreallife.bz

おうちでおしごと
こんにちは。突然失礼いたします。
自宅からできるお仕事で五万円から10万円の副収入にご興味のある方はいらっしゃいませんか。今まで日本にはなかったインターネットとメールオーダーを組み合わせた新しいシステムで、既に約10年ヨーロッパとUSで大成功を収めているものです。www.yourreallife.bz


oo さん 2004年 05月 06日 00時 46分 38秒

>このまえ流行に乗ってやって来たウイルスメールを見て知ったのですが、
>exeをpifに変えても動くみたいですね。pifの割には大きいので中を見たらexeだった。

WSHの話からそれますが、
コマンドプロンプトからだとべつに拡張子が何でも動くようですよ。WinXPのコマンドプロンプトで、
copy %WINDIR%\system32\calc.exe abc.txt
abc.txt
で、バイナリがメモ帳で開かれるかと思いきや、電卓が起動します。start abc.txt でも同じ。Explorerからのダブルクリックや、「ファイル名を指定して実行」ダイアログでの起動はさすがにOK(メモ帳起動)ですが。

WSHの話に戻ると、
wShell.run "abc.txt" だとメモ帳が、wShell.exec "abc.txt" だと電卓が起動します。

魔界の仮面弁士 さん 2004年 05月 05日 18時 36分 24秒

》ばんのしゃーによかばんた さん
> ヘルプファイル(TlbInf32.chm)、ないのですが、VB6にはあるということでしょうか。

付属はしていません。下記から別途ダウンロードしてください。

[More Controls and Components]
http://msdn.microsoft.com/vbasic/downloads/addins/components/default.aspx
なお、KBの224331からもダウンロード可能です。

> こういうのって悪用されないかなぁ。なんでC~1にしないんだ。
.HTML → .H~1 より、.HTML → .HTM の方が都合が良い、との判断かも。

ただ、.COM になってしまうというのは、ちょっと気になりますね。
もしも、悪用するための手口が見つかりましたら、
http://www.microsoft.com/japan/technet/security/bulletin/alertus.asp
の方に報告してあげてください。

ばんのしゃーによかばんた さん 2004年 05月 05日 18時 01分 10秒

他人が二重書き込みしてると、なんでそんなミスするのかなぁ、と思っていましたが、
自分がやって分かりました。
教訓。レスポンスが遅いなどシステムがなんか変なときには書き込まない。
書き込めたかどうか不安なときは、別の、より新しい書き込みが反映されるのを確認する。

>魔界の仮面弁士 さん 2004年 05月 05日 02時 09分 21秒
>> > CreateObject("VText.VText")は出来ないのに。
>> CreateObject("SAPI.SpVoice").Speak "TEST"
>> が動作しました。(他の環境でも動くのかどうかはわかりません)
>どうやら、SAPIのバージョンによって、動作に違いがあるようです。
>ただ、具体的な違いについては、私自身、調べきれていません。。。

レジストリのHKCR\CLSID\{2398E32F-5C6E-11D1-8C65-0060081841DE}
のところのProgIDを見るとVText.VText.1になっていたので、つい、そうかと
思ったのですが、よく見ると、HKCR\VText.VText.1がなかったです。そんなぁ。
%Windir%Speech\Vtext.DLLを見ると、TextToSpeech.TextToSpeechなんてある。
regsvr32してやると、CreateObject("TextToSpeech.TextToSpeech")で
しゃべってくれるようになりました。
SPCHAPI.INFを見てもregsvr32してないようなので、標準的には、ProgIDは
使わ(え)ないようですね。バージョンごとにProgIDを変えているようだし。変なの。

>> つい最近、TLBINF32.DLLを探して、VB5CCEをダウンロードしました。

言葉足らず、VB5CCEを持ってればCommonDialogが使える、という趣旨でした。

>VB6版とは異なるので、ヘルプファイル(TlbInf32.chm)に書かれているような

ヘルプファイル(TlbInf32.chm)、ないのですが、VB6にはあるということでしょうか。

>管理人むたぐち さん 2004年 05月 04日 14時 05分 55秒
>exeじゃないwscriptってあったかな?

話が完全に脱線しますが、拡張子exeをcomに変えても動きますよね。
98のcommand.comや2000のmore.comは中身はexeだし。
だったらMSは何でexeを作ったのか、不可思議です。

このまえ流行に乗ってやって来たウイルスメールを見て知ったのですが、
exeをpifに変えても動くみたいですね。pifの割には大きいので中を見たらexeだった。

他にも、ファイルの拡張子に関係なく、中身で動かすMIMEのセキュリティホールを作ったり。
とか。まるで、何か考え(設計思想?)があって一貫しているようにも見えるのですが、
何なんでしょう。全くの偶然の一致とは考えられない。

将来的に拡張子を無くす遠大な構想があって、その一環でやっているのかな。
それとも、EXEを作ってみたものの、バッチファイルの互換を保つため、command.comや
more.comの名前で動くようにした。そのとき、やり過ぎて何でも動くようになった?

そうそう、ひとつ気になることが。
SendToにCommand Line.CommandLineがありますが、SFNはCOMMAN~1.COMです。
例えば、Scriptという拡張子のSFNはSCRだし、CommentはCOMだし。
こういうのって悪用されないかなぁ。なんでC~1にしないんだ。

魔界の仮面弁士 さん 2004年 05月 05日 02時 09分 21秒

> > CreateObject("VText.VText")は出来ないのに。
> CreateObject("SAPI.SpVoice").Speak "TEST"
> が動作しました。(他の環境でも動くのかどうかはわかりません)

どうやら、SAPIのバージョンによって、動作に違いがあるようです。
ただ、具体的な違いについては、私自身、調べきれていません。。。

# 会社のWinXP機では、先のTEST.WSFが正常に動作したのに、
# 自宅のWinXP機では、Speakメソッド実行時にエラーになる…何故?

魔界の仮面弁士 さん 2004年 05月 04日 23時 30分 27秒

> これは、TextToSpeechだから出来るのでしょうか。
OCX動作、ActiveX DLL動作の両方に対応したコンポーネントとしては、
他に、CreateObject("ScriptControl")などがありますね。

> PDF、TDC、helperDialogなどはどちらもだめ。
それらは、IEの機能に依存している部分が大きいので、IE以外の
コンテナだと、動作が保障されないのだと思います。

コンポーネントによっては、同様に Office依存、VB6依存、ASP依存などと
いう物もあれば、その一方で VB/IE/Office/Delphiに対応した、
汎用的に設計された物などもあるようですね。

> CreateObjectで動く。
これも突き詰めていくと、VBScriptのCreateObjectなのか、
ASPのServer.CreateObjectなのかによって、動作が変化するものも
ありますので、注意が必要ですね。

ただ、それらの簡単な見分け方があるのかどうかは、正直分かりません。

> CreateObject("VText.VText")は出来ないのに。
どちらかというと、"SAPI.SpVoice" ですかね。
少なくとも当方のWinXP環境では、
CreateObject("SAPI.SpVoice").Speak "TEST"
が動作しました。(他の環境でも動くのかどうかはわかりません)


> つい最近、TLBINF32.DLLを探して、VB5CCEをダウンロードしました。
最新版は、FoxPro7に含まれているようですね。
バージョンを問わないのであれば、国内で入手可能な物として、
・Visual Studio 97 シリーズ
・Visual Studio 6.0 シリーズ, およびそのService Packs
・Small Business Server 2000, 2003
・SQL Server 2000シリーズ
・Access 2000, Outlook 2000など
・Visual Studio Installer 1.0
あたりでしょうか。…入手しやすいのは、確かにVB5CCEあたりですね。

ただ、VB5版(version 1.1.37.15、かな?)に関しては、ProgIDの設定が
VB6版とは異なるので、ヘルプファイル(TlbInf32.chm)に書かれているような
CreateObjectでの生成ができなかったような気がします。
(手元にVB5環境が無いので、確認はできませんが…)

ばんのしゃーによかばんた さん 2004年 05月 04日 22時 39分 33秒

>ばんのしゃーによかばんた さん 2004年 05月 04日 20時 44分 02秒
>CreateShortcut("hoge.lnk")
>でDOSアプリを指定してsaveすると、なな何とhoge.pifに早変わりします。
>fso.FileExistでどちらがあるのか確かめて、Run。

変化(へんげ)した、hoge.pifはWScript.ShellのCreateShortcutでは扱えないので、
Shell.ApplicationのGetLinkで扱えるようです。
逆に、Shell.Applicationでは作成ができないので、作成するときはWScript.Shellを使う。
なんともまぁ。

>そこで、こんなやり方も試してみました。FSOのTextStreamでUnicode指定。

Unicodeでない場合、ロカールに対応したコードページからUnicodeへ変換テーブル
を使ってコード変換されてるようです。

そこで、こういうことってできないものでしょうか。

新規にロカール("bin")とコードページを定義する。
hhを00hhに単純変換する変換テーブルを何らかの方法で作成する。

VBScriptのSetLocale("bin")で変更してfsoのTextStreamで 読み書きする。
読み書き文字列は、バイナリのアンパック形式(00hh)。

どこかにロカールとコードページの具体的作成方法やサンプルはないですかねぇ。

※一般にはロケールと言うようですが、ロカールで覚えてしまったもので、
ロカールが好きです。

既存の"en-us"、iso-8859-1(1252)などを潰して試してみるのは、「今後の課題」と
させていただきます。

ばんのしゃーによかばんた さん 2004年 05月 04日 20時 46分 36秒

>魔界の仮面弁士 さん 2004年 05月 04日 15時 37分 14秒
>> 「WSHから」TextToSpeechなどのコントロールを呼び出すのに、
>失礼しました。コンテナをWSHにした場合の話題だったのですね。
>であれば、こんな感じで如何でしょう。(また外してるかな…)
>==== TEST.WSF ====

あれ、すごい。jawsが見えないのにしゃべってる。
これは、TextToSpeechだから出来るのでしょうか。
CreateObject("VText.VText")は出来ないのに。
PDF、TDC、helperDialogなどはどちらもだめ。

CreateObjectで動く。
WSF object classidで動く。
IE、Excelに貼り付けて動く。
の簡単な見分け方はあるのでしょうか。

>管理人むたぐち さん 2004年 05月 04日 14時 05分 55秒
>> ファイルのバイナリ比較
>ADO Streamオブジェクトあたりで何とかできないですかね。

ADOを使って、試してみました。

Function cmp(srcFile,dstFile)
Const adTypeBinary=1
Dim Src
Dim Dst

Set Src=CreateObject("ADODB.Stream")
Call Src.Open()
Src.Type=adTypeBinary
Call Src.LoadFromFile(srcFile)

Set Dst=CreateObject("ADODB.Stream")
Dst.Type=adTypeBinary
Call Dst.Open()
Call Dst.LoadFromFile(dstFile)

If Src.Size<>Dst.Size Then
cmp=1
Else
Do Until Src.EOS
If CStr(Src.Read(4096))<>CStr(Dst.Read(4096)) Then
cmp=1
Exit Do
End If
Loop
End If
Src.Close
Dst.Close
Set Src=Nothing
Set Dst=Nothing
End Function

で、どうかな、と思っているのですが、あまり確信が持てません。
一応、DLLファイルの1バイトを書き換えてテストしたらうまくいきました。

また、大きなファイルを一度にメモリに持ち上げるやり方にも、抵抗があります。
Openでファイルを指定して、4096バイトずつ読み込むことは出来ないものでしょうか。

そこで、こんなやり方も試してみました。FSOのTextStreamでUnicode指定。

Function cmp(srcFile,dstFile)
Dim fso
Dim Src
Dim Dst

Set fso=CreateObject("Scripting.FileSystemObject")

Set Src=fso.GetFile(srcFile)
Set Dst=fso.GetFile(dstFile)

If Src.Size<>Dst.Size Then
cmp=1
Else
Set Src=Src.OpenAsTextStream(,True)
Set Dst=Dst.OpenAsTextStream(,True)
Do Until Src.AtEndOfStream
If Src.Read(4096)<>Dst.Read(4096) Then
cmp=1
Exit Do
End If
Loop
Src.Close
Dst.Close
End If
Set Src=Nothing
Set Dst=Nothing
End Function

難点は奇数バイトファイルの末尾1バイトが違っていても無視されること。
まぁ、ほとんど例外的なんでしょうが、やはり厳密な処理には使えない。

>しかし、バイト配列を扱うことができない、
>素のVBSでは辛いものがありますね、やっぱり。

「バイト配列を作ること」の一点を除いて、相当程度可能と思います。

例えば、
n=LenB(bytearray) 'バイト配列のバイト長
WScript.Echo n
For k=1 To n
b=AscB(MidB(bytearray,k,1) ''バイト配列の指定バイト値の取り出し
WScript.Echo b
unpack=unpack & Chr(b) 'アンパック形式(Unicodeで00hh)変換
Next
pattern=ChrB(65) & ChrB(66) & ChrB(67) 'バイト文字列"ABC"作成
WScript.Echo LenB(pattern) '奇数バイト文字列 3バイト
start=InStrB(bytearray,pattern) 'バイト文字列検索
WScript.Echo start

re.Pattern="ABC"
re.Test(unpack) 'アンパック形式で正規表現パターンマッチ

For k=1 To Len(unpack)
b=Asc(Mid(unpack,k,1)
pack=pack & ChrB(b) 'パック形式(バイト文字列)変換≠バイト配列
Next

など、など。

>>>If Fs.GetFileName(LCase(WScript.FullName)) = "wscript.exe" Then
>> は、ついつい、
>> If LCase(Fs.GetBaseName(WScript.FullName)) = "wscript" Then
>> と直したくなります。
>これは何か問題があるのでしたっけ?

ソフトウェアデザインレビューの分類で言う、「実」障害ではありません。
「冗長」障害と言います。
どちらのコードがよいか、理由が付くときもありますが、職人的な感覚もあって、
そういうときは説明に困ります。
上記の場合は、走査する文字列の長さがLCaseを外に出したほうが短いし、
GetBaseNameのほうが短い。性能面。拡張子は判定に関係ないので、
含めないほうが、予期せぬ障害の混入する可能性をより小さくできる。堅牢性。
など、理由を付けられなくはないですが、説明するとかえって大袈裟で気恥ずかしい。

因みに、ソースレビューの主眼は、「実」障害の検出修正ではなく、「冗長」障害の
大量検出修正です。品質のよいソフトを作っている会社では、
こういう限界的なレビューを行っているのですが、
それが分かっていない会社の製品は、実障害何万件を未修正で出荷したりします。

>> >DOSのアプリケーションを、ディレクトリーを指定した上で実行させる方法を教えてください。
>あと、WshShell.CreateShortcutしてショートカットを作って、
>WorkingDirectoryを指定するという方法もありますが面倒です。
>というか、DOSアプリでは関係なかったかもしれない…。

CreateShortcut("hoge.lnk")
でDOSアプリを指定してsaveすると、なな何とhoge.pifに早変わりします。
fso.FileExistでどちらがあるのか確かめて、Run。

>To: ゆぎ さん
>> あるアプリケーションを実行するVBSを作りました。
>> その実行中に、ほかのアプリケーションやらなにやらを、
>> 実行できないようにしたいのですが、実現可能でしょうか?

昔、部下の開発技術者が何かのやり方を聞いて来ることがありましたが、
答える前に、必ず、もともとの問題を説明させました。
でないと、とんでもない修正に加担することになり兼ねません。でした。

というわけで、
何かにお困りのみなさんは、問題の核心を説明なさったほうがよろしいかと
思いますです。(会社でも。)

>魔界の仮面弁士 さん 2004年 05月 04日 16時 18分 30秒
>Excelには、Common Dialog Control(のデザインタイムライセンス)が
>付属していないので、それを使うなら、むたぐちさんが書かれた様に、
> Visual Studio系製品(Visual Basic, Visual C++, Visual InterDev等)
> Office Developer Edition
>などといった、他の製品(デザインタイムライセンスを含む物)が
>実行環境にインストールされている必要がありますね。

つい最近、TLBINF32.DLLを探して、VB5CCEをダウンロードしました。
持ってないひとはダウンロード出来るうちに確保しておいたほうがいいです。

TLBINF32.DLLはその後、Office2000Proでも再発見しましたが。

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

>魔界の仮面弁士 さん 2004年 05月 04日 15時 37分 14秒
>> 「WSHから」TextToSpeechなどのコントロールを呼び出すのに、
>失礼しました。コンテナをWSHにした場合の話題だったのですね。
>であれば、こんな感じで如何でしょう。(また外してるかな…)
>==== TEST.WSF ====

あれ、すごい。jawsが見えないのにしゃべってる。
これは、TextToSpeechだから出来るのでしょうか。
CreateObject("VText.VText")は出来ないのに。
PDF、TDC、helperDialogなどはどちらもだめ。

CreateObjectで動く。
WSF object classidで動く。
IE、Excelに貼り付けて動く。
の簡単な見分け方はあるのでしょうか。

>管理人むたぐち さん 2004年 05月 04日 14時 05分 55秒
>> ファイルのバイナリ比較
>ADO Streamオブジェクトあたりで何とかできないですかね。

ADOを使って、試してみました。

Function cmp(srcFile,dstFile)
Const adTypeBinary=1
Dim Src
Dim Dst

Set Src=CreateObject("ADODB.Stream")
Call Src.Open()
Src.Type=adTypeBinary
Call Src.LoadFromFile(srcFile)

Set Dst=CreateObject("ADODB.Stream")
Dst.Type=adTypeBinary
Call Dst.Open()
Call Dst.LoadFromFile(dstFile)

If Src.Size<>Dst.Size Then
cmp=1
Else
Do Until Src.EOS
If CStr(Src.Read(4096))<>CStr(Dst.Read(4096)) Then
cmp=1
Exit Do
End If
Loop
End If
Src.Close
Dst.Close
Set Src=Nothing
Set Dst=Nothing
End Function

で、どうかな、と思っているのですが、あまり確信が持てません。
一応、DLLファイルの1バイトを書き換えてテストしたらうまくいきました。

また、大きなファイルを一度にメモリに持ち上げるやり方にも、抵抗があります。
Openでファイルを指定して、4096バイトずつ読み込むことは出来ないものでしょうか。

そこで、こんなやり方も試してみました。FSOのTextStreamでUnicode指定。

Function cmp(srcFile,dstFile)
Dim fso
Dim Src
Dim Dst

Set fso=CreateObject("Scripting.FileSystemObject")

Set Src=fso.GetFile(srcFile)
Set Dst=fso.GetFile(dstFile)

If Src.Size<>Dst.Size Then
cmp=1
Else
Set Src=Src.OpenAsTextStream(,True)
Set Dst=Dst.OpenAsTextStream(,True)
Do Until Src.AtEndOfStream
If Src.Read(4096)<>Dst.Read(4096) Then
cmp=1
Exit Do
End If
Loop
Src.Close
Dst.Close
End If
Set Src=Nothing
Set Dst=Nothing
End Function

難点は奇数バイトファイルの末尾1バイトが違っていても無視されること。
まぁ、ほとんど例外的なんでしょうが、やはり厳密な処理には使えない。

>しかし、バイト配列を扱うことができない、
>素のVBSでは辛いものがありますね、やっぱり。

「バイト配列を作ること」の一点を除いて、相当程度可能と思います。

例えば、
n=LenB(bytearray) 'バイト配列のバイト長
WScript.Echo n
For k=1 To n
b=AscB(MidB(bytearray,k,1) ''バイト配列の指定バイト値の取り出し
WScript.Echo b
unpack=unpack & Chr(b) 'アンパック形式(Unicodeで00hh)変換
Next
pattern=ChrB(65) & ChrB(66) & ChrB(67) 'バイト文字列"ABC"作成
WScript.Echo LenB(pattern) '奇数バイト文字列 3バイト
start=InStrB(bytearray,pattern) 'バイト文字列検索
WScript.Echo start

re.Pattern="ABC"
re.Test(unpack) 'アンパック形式で正規表現パターンマッチ

For k=1 To Len(unpack)
b=Asc(Mid(unpack,k,1)
pack=pack & ChrB(b) 'パック形式(バイト文字列)変換≠バイト配列
Next

など、など。

>>>If Fs.GetFileName(LCase(WScript.FullName)) = "wscript.exe" Then
>> は、ついつい、
>> If LCase(Fs.GetBaseName(WScript.FullName)) = "wscript" Then
>> と直したくなります。
>これは何か問題があるのでしたっけ?

ソフトウェアデザインレビューの分類で言う、「実」障害ではありません。
「冗長」障害と言います。
どちらのコードがよいか、理由が付くときもありますが、職人的な感覚もあって、
そういうときは説明に困ります。
上記の場合は、走査する文字列の長さがLCaseを外に出したほうが短いし、
GetBaseNameのほうが短い。性能面。拡張子は判定に関係ないので、
含めないほうが、予期せぬ障害の混入する可能性をより小さくできる。堅牢性。
など、理由を付けられなくはないですが、説明するとかえって大袈裟で気恥ずかしい。

因みに、ソースレビューの主眼は、「実」障害の検出修正ではなく、「冗長」障害の
大量検出修正です。品質のよいソフトを作っている会社では、
こういう限界的なレビューを行っているのですが、
それが分かっていない会社の製品は、実障害何万件を未修正で出荷したりします。

>> >DOSのアプリケーションを、ディレクトリーを指定した上で実行させる方法を教えてください。
>あと、WshShell.CreateShortcutしてショートカットを作って、
>WorkingDirectoryを指定するという方法もありますが面倒です。
>というか、DOSアプリでは関係なかったかもしれない…。

CreateShortcut("hoge.lnk")
でDOSアプリを指定してsaveすると、なな何とhoge.pifに早変わりします。
fso.FileExistでどちらがあるのか確かめて、Run。

>To: ゆぎ さん
>> あるアプリケーションを実行するVBSを作りました。
>> その実行中に、ほかのアプリケーションやらなにやらを、
>> 実行できないようにしたいのですが、実現可能でしょうか?

昔、部下の開発技術者が何かのやり方を聞いて来ることがありましたが、
答える前に、必ず、もともとの問題を説明させました。
でないと、とんでもない修正に加担することになり兼ねません。でした。

というわけで、
何かにお困りのみなさんは、問題の核心を説明なさったほうがよろしいかと
思いますです。(会社でも。)

>魔界の仮面弁士 さん 2004年 05月 04日 16時 18分 30秒
>Excelには、Common Dialog Control(のデザインタイムライセンス)が
>付属していないので、それを使うなら、むたぐちさんが書かれた様に、
> Visual Studio系製品(Visual Basic, Visual C++, Visual InterDev等)
> Office Developer Edition
>などといった、他の製品(デザインタイムライセンスを含む物)が
>実行環境にインストールされている必要がありますね。

つい最近、TLBINF32.DLLを探して、VB5CCEをダウンロードしました。
持ってないひとはダウンロード出来るうちに確保しておいたほうがいいです。

TLBINF32.DLLはその後、Office2000Proでも再発見しましたが。

ばんのしゃーによかばんた さん 2004年 05月 04日 16時 30分 44秒

WSHからExcel経由でWin32APIを使う方法。改訂第3版。

Win32APIクラスを作る。なーんだ、こうすりゃよかったんだ。

Win32API.XLS
ポイントは、
標準モジュールにAPI
DeclareにPublicを付ける。
Function/Sub名〜にプリフィクスx〜を付ける。
必要ならAliasを付ける。
クラスインスタンスを返すSub GetWin32Obj(obj)を作る。

クラスモジュールにメソッド
同名〜でPublic Function/Subを作りx〜を呼び出す。

ポイントは、
Call xl.run("GetWin32Obj", Win32)でExcelマクロを呼び出して、クラスオブジェクトを取り出す。
Win32.Function/Sub名〜でメソッドを呼び出す。

以下はWindowsを列挙するVBScript。
CScriptで実行してください。
Set xl=CreateObject("Excel.Application")
'xl.Visible=True
Set book=xl.WorkBooks.Open("d:\vbs\excel\Win32API.xls")
Call xl.run(book.Name & "!GetWin32Obj", Win32)

Private Const GW_HWNDPREV = 3
Private Const GW_OWNER = 4

hwnd=Win32.GetDesktopWindow()
tid=Win32.GetWindowThreadProcessId(hwnd,pid)
ClassName=Win32.GetClassName(hwnd)
Text=Win32.GetWindowText(hwnd)
WScript.Echo hwnd,pid,ClassName,text
hWnd = Win32.FindWindow("Progman", "Program Manager")
tid=Win32.GetWindowThreadProcessId(hwnd,pid)
ClassName=Win32.GetClassName(hwnd)
Text=Win32.GetWindowText(hwnd)
WScript.Echo hwnd,pid,ClassName,text

Win32.Sleep(500)
Windows = GetTopWindows()

Count=UBound(Windows)+1
WScript.Echo Count
For Count=0 To UBound(Windows)
WScript.Echo Join(Windows(Count),vbTab)
Next

Function GetTopWindows()
Dim Windows()
Dim Count
Dim hwnd
Dim Text
Dim pid,tid
Dim ClassName

hPrgmWnd = Win32.FindWindow("Progman", "Program Manager")
'hwnd = Win32.GetWindow(Me.hwnd , GW_HWNDFIRST)
hwnd = hPrgmWnd

Count=0
Do While hwnd <> 0
If hwnd <> hPrgmWnd And _
Win32.GetWindow(hwnd, GW_OWNER) = 0 And _
Win32.IsWindowVisible(hwnd) = 1 Then
tid=Win32.GetWindowThreadProcessId(hwnd,pid)
ClassName=Win32.GetClassName(hwnd)
Text = Win32.GetWindowText(hwnd)
Count=Count+1
ReDim Preserve Windows(Count-1)
Windows(Count-1) = Array(hwnd,pid,ClassName,Text)
End If
hwnd = Win32.GetWindow(hwnd, GW_HWNDPREV) 'GW_HWNDNEXT)
Loop
GetTopWindows = Windows
End Function

xl.ActiveWorkBook.Saved=True
xl.Quit


Win32API.XLS
標準モジュール
Public Declare Function xFindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function xSetForegroundWindow Lib "user32" Alias "SetForegroundWindow" (ByVal hwnd As Long) As Long
Public Declare Sub xSleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Public Declare Sub xkeybd_event Lib "user32" Alias "keybd_event" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Public Declare Function xGetWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function xGetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public Declare Function xIsWindowVisible Lib "user32" Alias "IsWindowVisible" (ByVal hwnd As Long) As Long
Public Declare Function xGetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Public Declare Function xGetTopWindow Lib "user32" Alias "GetTopWindow" (ByVal hwnd As Long) As Long
Public Declare Function xGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Long
Public Declare Function xGetWindowThreadProcessId Lib "user32" Alias "GetWindowThreadProcessId" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Public Declare Function xShowWindow Lib "user32" Alias "ShowWindow" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Public Declare Function xSetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Public Declare Function xGetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Sub GetWin32Obj(obj)
Set obj = New Class1
End Sub

クラスモジュール
Public Sub Sleep(ByVal dwMilliseconds As Long)
Call xSleep(ByVal dwMilliseconds)
End Sub
Public Sub keybd_event(ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Call xkeybd_event(ByVal bVk, ByVal bScan, ByVal dwFlags, ByVal dwExtraInfo)
End Sub
Public Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
If lpClassName = "" Then lpClassName = vbNullString
If lpWindowName = "" Then lpWindowName = vbNullString
FindWindow = xFindWindow(ByVal lpClassName, ByVal lpWindowName)
End Function
Public Function GetWindow(ByVal hwnd As Long, ByVal wCmd As Long) As Long
GetWindow = xGetWindow(ByVal hwnd, ByVal wCmd)
End Function
Public Function IsWindowVisible(ByVal hwnd As Long) As Long
IsWindowVisible = xIsWindowVisible(ByVal hwnd)
End Function
Public Function GetWindowText(ByVal hwnd As Long) As String
Dim strText As String
Dim lngBytes As Long
strText = String(256, 0)
lngBytes = xGetWindowText(hwnd, strText, Len(strText))
GetWindowText = Left(strText, InStr(strText, vbNullChar) - 1)
End Function
Public Function GetTopWindow(ByVal hwnd As Long) As Long
GetTopWindow = xGetTopWindow(ByVal hwnd)
End Function
Public Function GetDesktopWindow() As Long
GetDesktopWindow = xGetDesktopWindow()
End Function
Public Function GetWindowThreadProcessId(ByVal hwnd As Long, lpdwProcessId) As Long
GetWindowThreadProcessId = xGetWindowThreadProcessId(ByVal hwnd, lpdwProcessId)
End Function
Public Function ShowWindow(ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
ShowWindow = xShowWindow(ByVal hwnd, ByVal nCmdShow)
End Function
Public Function SetWindowPos(ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
SetWindowPos = xSetWindowPos(ByVal hwnd, ByVal hWndInsertAfter, ByVal x, ByVal y, ByVal cx, ByVal cy, ByVal wFlags)
End Function
Public Function GetWindowLong(ByVal hwnd As Long, ByVal nIndex As Long) As Long
GetWindowLong = xGetWindowLong(ByVal hwnd, ByVal nIndex)
End Function
Public Function GetClassName(ByVal hwnd As Long) As String
Dim strClassName As String
Dim lngBytes As Long
strClassName = String(256, 0)
lngBytes = xGetClassName(hwnd, strClassName, Len(strClassName))
GetClassName = Left(strClassName, InStr(strClassName, vbNullChar) - 1)
End Function
Public Function SetForegroundWindow(ByVal hwnd As Long) As Long
SetForegroundWindow = xSetForegroundWindow(ByVal hwnd)
End Function

WSH +Excel + Win32API = ナポレオンの辞書
最早、スイスアーミも敵ではない?

魔界の仮面弁士 さん 2004年 05月 04日 16時 18分 30秒

》 管理人むたぐち さん
> > >If Fs.GetFileName(LCase(WScript.FullName)) = "wscript.exe" Then
> > は、ついつい、
> > If LCase(Fs.GetBaseName(WScript.FullName)) = "wscript" Then
> > と直したくなります。
> これは何か問題があるのでしたっけ?
個人的には、「LCaseした結果をメソッドに渡す」よりも、
「メソッドの戻り値をLCaseする」方が安心できます。(^^;

> exeじゃないwscriptってあったかな?
これはわかりません。


> > VBScriptでコモンダイアログを出力し、その値を取得する方法を
> > 教えてください。
> > オブジェクトはExcelを使用しようと思っています。
> おっしゃる意味がよく分からないのですが、ExcelのVBAに付属する
> Common Dialog Controlを用いるという意味でしょうか?

Excelには、Common Dialog Control(のデザインタイムライセンス)が
付属していないので、それを使うなら、むたぐちさんが書かれた様に、
 Visual Studio系製品(Visual Basic, Visual C++, Visual InterDev等)
 Office Developer Edition
などといった、他の製品(デザインタイムライセンスを含む物)が
実行環境にインストールされている必要がありますね。

あるいは、最近のバージョンのExcelであれば、Applicationオブジェクトの
  GetOpenFilename メソッド
  Dialogs メソッド
  FileDialog メソッド
などで表示されるダイアログを使うことでも、「ファイルを開く」の
コモンダイアログのような物を表示することができます。

魔界の仮面弁士 さん 2004年 05月 04日 15時 37分 14秒

> 「WSHから」TextToSpeechなどのコントロールを呼び出すのに、
失礼しました。コンテナをWSHにした場合の話題だったのですね。

であれば、こんな感じで如何でしょう。(また外してるかな…)

==== TEST.WSF ====
<?xml version="1.0" encoding="Shift_JIS"?>
<package>
<job id="SampleTTS">
<?job error="true" debug="true"?>
<object id="TextToSpeech" classid="CLSID:2398E32F-5C6E-11D1-8C65-0060081841DE"></object>
<script language="VBScript">'<![CDATA[
Option Explicit

Speak "Hello!"
Speak "Please wait some time for something is executing now."
Speak "Good bye."

Sub Speak(Text)
TextToSpeech.Speak Text
Do While TextToSpeech.IsSpeaking
WScript.Sleep 1000
Loop
End Sub
']]></script>
</job>
</package>

管理人むたぐち さん 2004年 05月 04日 14時 05分 55秒

To: 魔界の仮面弁士 さん

ばんのしゃーによかばんたさんが提案されているのは、あくまで
「WSHから」TextToSpeechなどのコントロールを呼び出すのに、
コンテナとしてIEやExcelを用いているのであって、単にTextToSpeechを
使うことが目的なのではないと思います。

魔界の仮面弁士さんが示されたとおり、単にTextToSpeechが使いたいので
あれば、HTAをコンテナにするのが一番良い方法だとは思います。
(HTAは、マイコンピュータゾーンのセキュリティー設定に関わらず、
常にすべてのコントロール/コンポーネントが警告なしで実行可能なはずです)

WSHからIEを操作するように、WSHからHTAを操作することができれば
いいんですけどね。
ちなみに、ひょんさんのところで、そういうことをするためのCOMコンポーネントが
公開されています。Running Object Server ver1.10のがそれです。
http://hyons.hp.infoseek.co.jp/


To: ばんのしゃーによかばんた さん

> ファイルのバイナリ比較

ADO Streamオブジェクトあたりで何とかできないですかね。
しかし、バイト配列を扱うことができない、
素のVBSでは辛いものがありますね、やっぱり。

> >If Fs.GetFileName(LCase(WScript.FullName)) = "wscript.exe" Then
> は、ついつい、
> If LCase(Fs.GetBaseName(WScript.FullName)) = "wscript" Then
> と直したくなります。

これは何か問題があるのでしたっけ?
exeじゃないwscriptってあったかな?

> >DOSのアプリケーションを、ディレクトリーを指定した上で実行させる方法を教えてください。

これなんですけど、WSH5.6のWshShell.CurrentDirectoryを使う他にも、
Shell.ApplicationのShellExecuteメソッドも使えるんじゃないかと思います。

ShellExecute sFile [,vArguments] [,vDirectory] [,vOperation] [,vShow]
なので3つ目の引数ですね。
あと、WshShell.CreateShortcutしてショートカットを作って、
WorkingDirectoryを指定するという方法もありますが面倒です。

というか、DOSアプリでは関係なかったかもしれない…。
TAPTAPさんのおっしゃるappletviewer.exeならば、上記の方法で問題ないと思います。

ここからは前ページの返信です。


To: ゆぎ さん

> あるアプリケーションを実行するVBSを作りました。
> その実行中に、ほかのアプリケーションやらなにやらを、
> 実行できないようにしたいのですが、実現可能でしょうか?

WindowsがマルチタスクなOSである限り、それは無理だと思うんですが
どうでしょうか。

> VBScriptでコモンダイアログを出力し、その値を取得する方法を
> 教えてください。
> オブジェクトはExcelを使用しようと思っています。

おっしゃる意味がよく分からないのですが、ExcelのVBAに付属する
Common Dialog Controlを用いるという意味でしょうか?
それならば、MSComDlg.CommonDialog をキーワードにすれば、
VBSからの使い方は見つかると思います。

ただし、ライセンスの関係上、VBやVC++などの開発環境がシステムに
インストールされていないと、WSHからCommon Dialog Controlは
呼び出せない仕組みになっているので注意が必要です。
(Officeがインストールされているだけでも呼び出せたかもしれないですが、
私はちょっと確認できないです)

魔界の仮面弁士 さん 2004年 05月 04日 10時 19分 39秒

> IEはセキュリティダイアログが出たり、セキュリティレベルに依存するので、もうひとつです。
ローカルで実行する前提なら、*.HTA (HTML Application)にしてみては如何でしょう。

これなら、「マイ コンピュータ ゾーン」のセキュリティレベルを
変更しない限りは、そのまま動作すると思います。

===== TEST.HTA =====

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" />
<title>TTSのサンプル</title>
<HTA:APPLICATION
BORDER="dialog"
BORDERSTYLE="static"
CAPTION="yes"
INNERBORDER="no"
MAXIMIZEBUTTON="no"
MINIMIZEBUTTON="yes"
SHOWINTASKBAR="yes"
SINGLEINSTANCE="normal"
SYSMENU="yes"
WINDOWSTATE="dialog"
SCROLL="no"
SCROLLFLAT="yes"
SELECTION="no"
CONTEXTMENU="no"
NAVIGABLE="no"
/>
<script type="text/JScript">
//<![CDATA[
window.resizeTo(480, 240);
var objTextToSpeech, objText;
function fnOnLoad() {
objTextToSpeech = document.getElementById('TextToSpeech');
objTextArea = document.getElementById('TextArea');
document.getElementById('Button').onclick = function() {
var Message = objTextArea.value;
if(Message != '') objTextToSpeech.Speak(objTextArea.value);
}
}
//]]>
</script>
<object id="TextToSpeech" classid="CLSID:2398E32F-5C6E-11D1-8C65-0060081841DE"></object>
<style type="text/css">
body { border:none ; background-color: ThreeDFace; margin: 0px; }
textarea { margin: 3px; width: 100%; height: 150px; }
input { margin: 3px 10px 0px 8px; padding: 3px 5px; }
div { text-align: center; border-top: thin groove; padding-top: 3px; margin-top: 3px; }
</style>
<body onload="fnOnLoad()">
<textarea id="TextArea"></textarea>
<div>
<input type="button" value="発声" id="Button" />
<input type="button" value="閉じる" onclick="window.close()" />
</div>
</body>
</html>

ばんのしゃーによかばんた さん 2004年 05月 03日 16時 26分 52秒

TextToSpeechを使って処理中メッセージを出す。

TextToSpeechはjawsが不気味でいいですね。

TextToSpeechにはコンテナが必要なので、IEまたはExcelを使います。

(A) IE
VOICE.HTM
<html><body>
<object id="TextToSpeech" classid="CLSID:2398E32F-5C6E-11D1-8C65-0060081841DE">
</object>
<textarea id="textarea" rows="10" cols="60"></textarea>
</body></html>

VOICE.VBS
Set ie=CreateObject("InternetExplorer.Application")
ie.Navigate Left(WScript.ScriptFullName,Len(WScript.ScriptFullName)-Len(WScript.ScriptName)) & "VOICE.HTM"
Do While ie.Busy Or ie.ReadyState<>4
WScript.Sleep 100
Loop
IE.Top = 0
IE.Left = 0
IE.Width = 700
IE.Height = 300
IE.AddressBar = False
IE.MenuBar = False
IE.StatusBar = False
IE.ToolBar = False

ie.Visible=True
Set TextToSpeech=ie.Document.TextToSpeech.object

Speak "Hello!"
Speak "Please wait some time for something is executing now."
Speak "Good bye."

'WScript.Echo TextToSpeech.TTSMode
'WScript.Echo TextToSpeech.speaker(1)

ie.Quit
WScript.Quit

Sub Speak(Text)
ie.Document.all.textarea.innerText=Text
TextToSpeech.Speak Text
Do While TextToSpeech.IsSpeaking
WScript.Sleep 1000
Loop
End Sub

(B) Excel

SPEECH.XLS
UserForm1を挿入する。
参照設定にLibrary HTTSLib
C:\Windows\speech\Vtext.dll Microsoft Voice Textを追加する。
その他のコントロールに TextToSpeech Classを追加する。
TextToSpeech1とTextBox1を貼り付ける。
TextBox1はMultiLine=True
ThisWorkbookのコードに以下。
Public Sub GetForm(Form)
UserForm1.Show vbModeless
Set Form = UserForm1
End Sub

SPEECH.VBS
Set xl=CreateObject("Excel.Application")
'xl.Visible=True
xl.WorkBooks.Open Left(WScript.ScriptFullName,Len(WScript.ScriptFullName)-Len(WScript.ScriptName)) & "speech.xls"
Call xl.Run( "ThisWorkbook.GetForm",Form)
'WScript.Echo TypeName(Form)
Set TextToSpeech=Form.Controls.Item(0)
Set TextBox=Form.Controls.Item(1)

Speak "Hello!"
Speak "Please wait some time for something is executing now."
Speak "Good bye."

'WScript.Echo TextToSpeech.TTSMode
'WScript.Echo TextToSpeech.speaker(1)

xl.Quit
WScript.Quit

Sub Speak(Text)
TextBox.Text=Text
TextToSpeech.Speak Text
Do While TextToSpeech.IsSpeaking
WScript.Sleep 1000
Loop
End Sub

IEはセキュリティダイアログが出たり、セキュリティレベルに依存するので、もうひとつです。
Excelは有償ソフトで、インストールされているとは限らない。
標準的にインストールされているソフトでコンテナになるものは他にないものでしょうか。
VBでwrapして配布するのが普通なのかなぁ。

ばんのしゃーによかばんた さん 2004年 05月 02日 19時 31分 11秒

>HELP me さん 2004年 02月 10日 18時 47分 31秒
>ファイル名(複数あり、1行毎に書かれている)を抽出したテキストファイルがあるのですが、
>それを読み込んで、削除していく方法を教えてください。

こういうときには、

for /f "tokens=*" %0 in ( ファイル名 ) do del "%~0"

が簡単です。

ばんのしゃーによかばんた さん 2004年 05月 02日 19時 30分 19秒

>om さん 2004年 03月 24日 10時 22分 50秒
>WSHにおいて
>フォルダC:\AAAAフォルダ下にあるファイルと
>フォルダC:\BBBBフォルダ下にあるファイルを
>ファイル名で比較し、一致するファイル名が存在するか
>しないかを判別できるようなコードがわかれば教えて下さい。

こういう処理は、DOSプロンプトでMetaWare社のfindを使って、
find C:\AAAA -t -^exists C:\BBBB -cp C:\BBBB
find C:\AAAA -t -comp C:\BBBB -rm
などと、とても重宝していました。
ところが、もともとFM-Towns用Hi C Compilerに付いていた年代物なので、
LFN非対応のため、もう限界です。
これに代わるものが欲しいのですが、VBSでなんとかならないかなぁ。
と思案中です。ネックはファイルのバイナリ比較で、ADOか、外部コマンドで
どうかなぁと調べてました。

話を戻して、名前だけの比較なら、

2000/XPでは、
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("cmd.exe /c for %0 in ( C:\AAAA\*.* ) do if exist C:\BBBB\%~nx0 echo %0")
WScript.Echo oExec.StdOut.ReadAll()

98/MEでは、バッチを作って、
@echo off
C:
cd C:\AAAA
for %%0 in ( *.* ) do if exist C:\BBBB\%%0 echo %%0
それを
Set oExec=wShell.Exec("なんとか.bat")

ファイル内容まで比較すると、
98/ME/2000/XPで、
Set oExec=wShell.Exec("%COMSPEC% /c FC C:\AAAA\*.* C:\BBBB\*.*")

または、
2000/XPで、
Set oExec=wShell.Exec("cmd.exe /c comp C:\AAAA\*.* C:\BBBB\*.*")

または、
98/ME/2000/XPで、
Set wShell=CreateObject("WScript.Shell")
wShell.Run("Windiff C:\AAAA C:\BBBB -ssdx savefile",,True)
WScript.Echo fso.OpenTextFile("savefile").ReadAll()

ここでwindiffは
Windows 98 Resource Kit
Windows 2000 Support Tools
などなどにあります。
後処理を考えると日本語版より英語版のほうが扱いやすいでしょう。

参考
windiff path1 {path2} {-L}{-T}{-D}{-O}{-N name}
{-s{s}{l}{r}{d}{x} savefile}
-L to compare SLM library to specified directory
(-LR to compare specified directory to SLM library)
-T to compare whole subtree
-D to compare one directory only
-O Outline view (no automatic expansion)
-N name. NET SEND notification to name at end of comparison
-S to save list of files including Same/Left/Right/Different
e.g. -Sld saves list of Left or Different files
x to exit program after writing list
-L implies -D (use -T to override)
A file can have a SLM version e.g. windiff foo.c@v-3 foo.c
Do not use -L with SLM versions (SLM is implied anyway)

FC、comp、windiff は、出力を処理しないといけないので、使いにくいですね。
中でも、FCはバイナリ比較で延々と出力するので、困ります。
compはプロンプトが出ることがあるので、wShell.Runのほうがいいかも。
windiffがラインコマンドとして使えるなんて瞠目です。
windiffは出力が扱いやすく、お勧めです。

しかし、ExitCodeで分かる、Unixのcmpみたいなコマンドが欲しいものです。
Unixにはdircmpもありますし。
これらは有償のNT SFUに付いているMKS ToolKitには入っていましたが、
無償のSFUにはたぶん入ってないでしょうね。

ばんのしゃーによかばんた さん 2004年 05月 02日 19時 28分 47秒

>ばんのしゃーによかばんた さん 2004年 05月 01日 18時 13分 10秒
>内部コマンドは、Run/Exec共にcommand.com/cmd.exe経由でないとエラー。
>外部コマンドは拡張子がないと、Runは通るがExecはエラー。

訂正。

外部コマンドのうち、COMとBATは拡張子がないと、Runは通るがExecはエラー。
外部コマンドでも、EXEは拡張子がなくても、RunもExecも通る。

したがって、
Exec("cmd /c〜")は通るが、
Exec("command /c〜")はエラーになるので、
Exec("command.com /c〜")としなければならない。

とまぁ、まったく、どこかの国の年金制度のように複雑怪奇でミス・リーディングですなぁ。

ところで、これまた、どこかの国の年金制度のように、思いっきり誤解があるようです。

そのため、年金が受け取れない、じゃなくて、Exec結果が受け取れないどころか、
ハングすることもあります。

2000/XPでは、ExecのStdOutに疑似パイプ(一時ファイル)ではなく、
OSのpipeが使われているようです。
pipeには有限のメモリバッファがあり、溢れると書き込みがブロックされます。
試してみますと、なな何と僅か163バイトのようです。

子プログラムout.vbs
'For n=1 To 163 'OK
For n=1 To 164 'NG
WScript.StdOut.Write " "
Next

親プログラム
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("CScript out.vbs")
Do While oExec.Status=0
WScript.Sleep 100
Loop
WScript.Echo Len(oExec.StdOut.ReadAll())
WScript.Quit

で、正しいコーディングは? と言うと、

Windowアプリは、
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("WScript なんとか")
Do While oExec.Status=0
WScript.Sleep 100
Loop
WScript.Quit

コンソールアプリは、
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("CScript out.vbs")
Do While Not oExec.StdOut.AtEndOfStream
WScript.Echo oExec.StdOut.ReadLine()
Loop
または、
WScript.Echo oExec.StdOut.ReadAll()
WScript.Quit

のように使い分けます。

ニッジュ さん 2004年 05月 02日 19時 00分 52秒

Set WSHShell=Wscript.CreateObject("Wscript.Shell")
inputdata=InputBox("何秒後に起動しますか?")
If inputdata="" Then
Wscript.Quit
End If
WSHShell.Popup "只今待機状態です...",inputdata,"待機...",vbOkOnly
intdata=MsgBox("ウィルスを検出しました" & vbCR &_
"ウィルスバスター2004を起動しますか",vbYesNo +vbExclamation,"ウィルス検出")
If intdata=vbYes Then
WSHShell.Popup "ウィルスバスター2004を起動中...",5,"しばらくお待ち下さい",7 +vbInformation
MsgBox"ウィルスバスター2004を起動できません。",vbExclamation,"エラー"
End If

ジョークソフトです。

TAPTAP さん 2004年 05月 01日 20時 10分 22秒

>ばんのしゃーによかばんた 様

DOSのヘルプと検索で、
comand/ と、for in はわかりました。
DOSのバッチコマンドだったんですね..

cmd="command /k for %%0 in (""c:"" ""cd c:\java"" ""appletviewer defalt.html"") do %%0"
wShell.Run cmd

これで確かに実行できましたが、
defalt.html の フォルダパス名 foldaPath="c:\java"
ファイル名 htmName="defalt.html" を
変数に格納してから、上に代入できるのでしょうか..

これができれば,ダイアログコントロールから値を取得すれば
任意のHTMLファイルをappletviewer で
実行できると思うのですが..


ばんのしゃーによかばんた さん 2004年 05月 01日 18時 15分 38秒

(サブキーを持つ)レジストリキーを削除する方法。

このような方法もあります。

Key="HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\hogehoge.exe"
Var="@"

Call RegDelete(Key,Var)

Subl RegDelete(Key,Var)
Set fso=CreateObject("Scripting.FileSystemObject")
Set wShell=CreateObject("WScript.Shell")
TempName=fso.BuildPath(fso.GetSpecialFolder(2).Path,fso.GetTempName())
Set File=fso.CreateTextFile(TempName)
File.WriteLine "REGEDIT4"
If Var="" Then
File.WriteLine "[-" & Key & "]"
Else
File.WriteLine "[" & Key & "]"
File.WriteLine """" & Var & """=-"
End If
File.Close
wShell.Run "RegEdit /s """ & TempName & """",,True
End Sub

参考
キーの削除
REGEDIT4
[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\hogehoge.exe]

値の削除
REGEDIT4
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\hogehoge.exe]
"PATH"=-

ばんのしゃーによかばんた さん 2004年 05月 01日 18時 14分 18秒

>魔界の仮面弁士 さん 2004年 04月 27日 23時 49分 26秒
>VBE系のオブジェクトを使えば可能なのですが、最近のバージョンでは

直接的なフラグはないみたい。なので、間接的に。

>> マクロの有無を調べる。

CodeModule.CountOfLines>0

>> マクロを無効にする。
>> マクロを削除する。

call CodeModule.DeleteLines(1,CountOfLines)

マクロが有効か無効か?
マクロを書き込んで、呼び出してみる。呼べたら有効。見つからなければ無効。

CodeModule.AddFromString("Sub IsMacroEnable()" & vbCRLF & "End Sub" & vbCRLF)
On Error Resume Next
Call book.Application.Run( "ThisWorkbook.IsMacroEnable")
ErrNumber=Err.Number
ErrDescription=Err.Description
On Error GoTo 0
WScript.Echo ErrNumber,ErrDescription '1004

サンプルの全体
Set book=GetObject("Book1.xls")
Set VBProject=book.VBProject
For Each VBComponent In VBProject.VBComponents
Set CodeModule=VBComponent.CodeModule
If VBComponent.Name="ThisWorkbook" Then
CodeModule.AddFromString("Sub IsMacroEnable()" & vbCRLF & "End Sub" & vbCRLF)
On Error Resume Next
Call book.Application.Run( "ThisWorkbook.IsMacroEnable")
ErrNumber=Err.Number
ErrDescription=Err.Description
On Error GoTo 0
WScript.Echo ErrNumber,ErrDescription '1004
End If
Set CodeModule=Nothing
Next
Set VBProject=book.VBProject
For Each VBComponent In VBProject.VBComponents
Set CodeModule=VBComponent.CodeModule
CountOfLines=CodeModule.CountOfLines
If CountOfLines>0 Then
call CodeModule.DeleteLines(1,CountOfLines)
End If
Set CodeModule=Nothing
Next
Set VBProject=Nothing
book.Saved=True
book.Close
Set book=Nothing

XLSファイルを作っておかなくても、動的にVBAを作り込めますね。
IEでnavigate "about:blank"してdocument.write "<HTML>"するように。

ばんのしゃーによかばんた さん 2004年 05月 01日 18時 13分 10秒

>ばんのしゃーによかばんた さん 2004年 04月 30日 17時 40分 57秒

>また、エラー(ErrorLevel>0)のときだけ、コンソールが閉じないようにするには、
>2000/XP
>cmd="cmd /c mycommand.exe & if errorlevel 1 pause"

または、
cmd="cmd /c mycommand.exe || pause"

>さて、存在しないコマンドを直に指定すると、
>wShell.Execは、Err.Raiseしないし、Statusを見ても、ExitCodeを見ても分かりません。
>これはProcessID=0で判断できます。

これは98/MEの場合で、
2000/XPは、Err.Raise 80070002が返ります。

また、
内部コマンドは、Run/Exec共にcommand.com/cmd.exe経由でないとエラー。
外部コマンドは拡張子がないと、Runは通るがExecはエラー。

各コマンドの仕様はヘルプを参照。
for /?
command /?
help
など

TAPTAP さん 2004年 05月 01日 13時 53分 56秒

下とほとんど同じなんですが^^;
私は、java applet の動作確認のため
appletviewer.exeでダイアログボックスから
選択したhtmlファイルを選んで実行するスクリプトを
こちらを参考に作りたいと思ってるのですが、
まずは、特定したフォルダの一つのHTMLファイルを
ともかく、appetviewer.exeで wshで開けるところまで
やろうかなと..(あとは、選択したファイルの
フォルダパスを変数に格納すればOKなんですよね)

私は、dos promptで、普通ならHTMLファイルの
ディレクトリに移動するんですが、これを
WSHで実現する過程がよくわからないんです^^;
私は98なので、こちらのようですね↓

cmd="command /c for %%0 in (""c:"" ""cd c:\testfolder"" ""mycommand.exe"") do %%0"

上記でやってることは、
どの構文? を調べるといいんでしょうか^^;
for in ステートメント、それから
command/c ってのは、DOSプロンプトを開ける命令?
なのでしょか。。丸写しでできそうなんですが
意味がわからないのは、悲しいし^^;


ばんのしゃーによかばんた さん 2004年 04月 30日 17時 40分 57秒

>まる さん 2004年 02月 04日 10時 30分 54秒
>DOSのアプリケーションを、ディレクトリーを指定した上で実行させる方法を教えてください。
>バッチだと
>cd c:\testfolder
>mycommand.exe
>の様に書くと c:\testfolder で mycommand.exe が実行されますが、
>これと同じ事をWSHスクリプトで行ないたいのです。

こういう方法もあります。※これならWSH5.6前でも使えます。
2000/XP
cmd="cmd /c start /d c:\testfolder mycommand.exe"
または
cmd="cmd /c cd /d c:\testfolder & mycommand.exe"
98/ME
cmd="command /c for %%0 in (""c:"" ""cd c:\testfolder"" ""mycommand.exe"") do %%0"
として、
wShell.Run cmd
する。


また、エラー(ErrorLevel>0)のときだけ、コンソールが閉じないようにするには、

2000/XP
cmd="cmd /c mycommand.exe & if errorlevel 1 pause"
98/ME
cmd="command /c for %%0 in (""mycommand.exe"" ""if errorlevel 1 pause"") do %%0"


また、
CMDはコマンドのErrorLevelをパーコレートして返しますが、
COMMANDは常に0を返して、コマンドのErrorLevelを返しません。

そこで、ErrorLevelをファイルにリダイレクトします。

2000/XP
cmd="cmd /c (mycommand.exe & echo %errorlevel%) >" & filename
98/ME
cmd="command /z /c for %%0 in (""mycommand.exe"") do %%0 >" & filename

ここで、もし、
cmd="command /z /c mycommand.exe >" & filename
とすると、ErrorLevelが出ません。

ファイルへのリダイレクトへの代わりにwShell.Execも使えます。

さて、存在しないコマンドを直に指定すると、
wShell.RunはErr.Raiseしますが、
wShell.Execは、Err.Raiseしないし、Statusを見ても、ExitCodeを見ても分かりません。
これはProcessID=0で判断できます。

CMDを介した場合はExitCode=9009が返ります。
COMMANDを介した場合は、ErrorLevelも返りません。StdErrを見るしかありません。
wShell.Runならcommand /kか
cmd="command /c for %%0 in (""mycommand.exe"" ""pause"") do %%0"
でコンソールを残します。

ばんのしゃーによかばんた さん 2004年 04月 30日 17時 39分 44秒

>管理人むたぐち さん 2004年 04月 24日 15時 31分 55秒
>最近、私がこの手の時間のかかる処理を書くときは、cscript.exe強制実行にして、
>WScript.Echoして情報をリアルタイム出力してやることがほとんどです。
>何だかんだでこれが一番確実で分かりやすいのですね。
>強烈に前世紀的なインターフェースですが。
>ちなみにcscript.exe強制実行のやり方はWikiに書いておきました。

すみません。職業病のレビュー癖が直らず、
>If Fs.GetFileName(LCase(WScript.FullName)) = "wscript.exe" Then
は、ついつい、
If LCase(Fs.GetBaseName(WScript.FullName)) = "wscript" Then
と直したくなります。

ところで、cscript.exe強制実行なら、
VBSファイルの先頭行に、
REM:&@CScript //E:VBS //NoLogo "%~f0" %*&GOTO :EOF
を加えて、拡張子をCMDに変える。
という方法もあります。
難点は、REMがコマンドECHOされることです。

※ REMの後にコロン、ピリオド、+、/、\を付けると複文(&、&&、||)が有効になります。

魔界の仮面弁士 さん 2004年 04月 27日 23時 49分 26秒

》 ばんのしゃーによかばんた さん
> ところでExcelのOLEオートメーションで
> マクロの有無を調べる。
> マクロを無効にする。
> マクロを削除する。
> といったことはできないのでしょうか。

VBE系のオブジェクトを使えば可能なのですが、最近のバージョンでは
外部からの操作が禁止されるようになっているため、注意が必要です。

例えばExcel 2002では、[ツール]-[マクロ]-[セキュリティ]メニューから
「Visual Basic プロジェクトへのアクセスを信頼する」のチェックが
有効になっていないと、VBEオブジェクトへのアクセスが制限されます。

ばんのしゃーによかばんた さん 2004年 04月 27日 22時 39分 19秒

>ばんのしゃーによかばんた さん 2004年 04月 25日 18時 22分 54秒
>Excelのセキュリティ警告の回避方法。
>Set xl=CreateObject("Excel.Application")
>Set book=xl.WorkBooks.Open("なんとか.XLS")
>'book.RunAutoMacros(1) 'Auto_Open()を実行

は、思いっ切り既出ですね。

>いちにい さん 2001年 04月 26日 16時 43分 15秒
>Excelなら、OLEオートメーションで操作した方が良いかも知れませんね。
>とかなら、マクロ確認ダイアログも出ませんので、こちらでどうでしょう?

など。

しかし、

>Auto_Open()は手動でRunAutoMacroしてやらないと動かないみたいですが、
>Auto_Close()は自動で動くようです。
>この方法は、Excelのセキュリティレベルを「高」にして、
>セキュリティ警告なしにマクロを無効、にしていても使えます。

は、考えてみると、少し危ないような気がします。

例えば、
Auto_Close()にウイルスを仕組まれたOfficeドキュメントがあったとして、
一般には、マクロ警告が出て、すぐ気付くので問題ない。
しかし、セキュリティやスクリプトに少し詳しいひとの場合、
Excelのセキュリティレベルを「高」にしていると、
自動でマクロが無効になるので気が付かない。
印刷しようとしてOLEオートメーションで操作すると、ウイルスが出る。

対策としては、
Excelのセキュリティレベルを「中」にしておく。
一般には、セキュリティ警告が出る、
Set book=GetObject("なんとか.XLS")
を使う。といったところでしょうか。

ところでExcelのOLEオートメーションで
マクロの有無を調べる。
マクロを無効にする。
マクロを削除する。
といったことはできないのでしょうか。

Return