ばんのしゃーによかばんた さん 2004年 06月 09日 14時 19分 56秒

>いりや さん 2004年 06月 08日 11時 39分 26秒
>| InvokeVerbは「仕様」としても、これを「仕様」と言うのは難しいのでは。
>あれ? 仕様という表現をしましたっけ。

???

>いりや さん 2004年 02月 11日 19時 18分 18秒
>// [1] ファイル削除が完了するまで待つ処理
>// FileSystemObject>>deleteFile() メソッドは非同期に実行されることがわ
>// かっている。つまりメソッドから返った時点ではファイルの削除が保証され

この記事を見たときの印象は、「すわ、第二のInvokeVerb現る」です。
ボーグに「抵抗しても無駄だ。同化する。」と言われているような感じです。:-p
InvokeVerbが非同期なのはたぶん「仕様」でしょうから、InvokeVerbを使うひとは
みんな考慮しないといけないのでしょう。これはもう仕方がない。

しかし、DeleteFileのほうは、
>いりや さん 2004年 06月 06日 20時 39分 19秒
>観測したのは Scripting.FileSystemObject>>deleteFile() メソッドを実行した
>後にスクリプトホスト (wscript.exe) が実行を終えようとした時にスクリプト
>ホストがエラーを報告し実行を中断する、という事象でした。
ということなので、これをまさか「仕様」と言わないでしょうから、
DeleteFileを使うひとがみんな考慮しないといけない、ということにはならないだろう、
ということです。

修正されるまでじっと我慢、発生条件に該当するひとだけが回避方法を取ればよい。
ただし、発生条件が限定的に特定されればの話です。

もし、発生条件が限定的でない、特定できないとなると、みんなが予防的に回避方法を
取るか、怪現象をじっと我慢しなくてはならない。これは勘弁してほしいです。:-<

>いりや さん 2004年 06月 06日 20時 39分 19秒
>推測を重ねていますが、エラーを報告する裏側には (4) の事前条件として「非
>同期に実行されるメソッドがすべて完了している」ことが予想されます。にもか
>かわらず、Scripting.FileSystemObject>>deleteFile() の場合はスクリプトホ
>ストで知るための手段が提供されていない。これが問題だとおもっています。
>通常、完了通知イベントを受ける口をスクリプトホストに用意して非同期メソッ
>ドの本体でイベントをスクリプトホストに発行します。(WScript.connectObject()
>メソッド) ですが、Scripting.FileSystemObject>>deleteFile() メソッドには、
>そのようなイベントを発行してなさそうです。

私の想像では、(好きなことが言える:-p)、
以下のような、よくありがちな障害ではないかと。
見た目のレスポンスを稼ぐために、子スレッドを起こして、処理をやらせる。
そんなことを忘れて、親スレッドが先に終了する。
親スレッドが終了時にメモリを解放する。そこを子スレッドが見てこける。

もし、こういうことだと、スクリプト終了時に発生しやすく、
いりや さんのwaitUntilRemoved() メソッドのように、FileExistsなどで間接的に
スレッドの終了を待ち合わせて、スクリプト終了を遅らせるしか方法はないでしょう。

>[*3] 彩香さん 他、WSH Lab. 掲示板より

この中で、DDE問題についてのいりや さんの解説がすばらしい。
MSはこのDDE問題を理解しているのでしょうか。
MS製OSを自社製サーバに組み込むソフト部門長をやってたひとが、
MSはマルチタスクが分かってない、とぼやいていましたが、
大袈裟に言っているだけだと思っていました。
しかし、このDDE問題の解説を読んで、それが誇張でないと分かりました。
これは、明らかに障害ですから、さっさと認めて直してほしいものです。

例えば、
>nemo さん 2003年 11月 25日 17時 23分 02秒
>下記のVBSをタスクスケジューラで起動していますが動作が不安定です。
>「エクセルが起動しない」場合や
>「エクセルの処理まではうまく走るけどWindowsが終了しない」場合があります。
>動作確認は起動直後で、ネットワークドライブの割り当ては他にありません。
>OSはWindows2000です。なにかアドバイスはありませんでしょうか?
>'-------------------------------------------------------
>'ネットワークドライブの割り当て
>On Error Resume Next
>set WshNet = CreateObject("Wscript.Network")
>WshNet.MapNetworkDrive "X:","\\server\dir",,"user","pass"
>Set WshNet = Nothing
>'エクセルの起動
>Set objXL = WScript.CreateObject("Excel.Application")
>Set WShell = WScript.CreateObject("WScript.Shell")
>WShell.Run("X:\○○○.xls")
>Set WShell = Nothing
>Set objXL = Nothing

で、エクセルが起動しないのは、このDDE問題のせいですね。(たぶん)
そんなこと、いりや さんの解説を読んでないひとには絶対分かりません。:-<

ばんのしゃーによかばんた さん 2004年 06月 09日 14時 19分 03秒

>rika さん 2004年 01月 15日 11時 52分 43秒
>クライアントPCに設定されている、プリントサーバ上のプリンタとの接続を
>解除したいのに、削除できません。
>----------------------------------------------------------------------
>Set WshNetwork = WScript.CreateObject("WScript.Network")
>Set oPrinters = WshNetwork.EnumPrinterConnections
>For i = 0 to oPrinters.Count - 1 Step 2
>on error resume next
>WshNetwork.RemovePrinterConnection oPrinters.Item(i+1), true, true
>Next
>----------------------------------------------------------------------

このケースも、「コレクション参照中の要素削除の祟り」ではありますまいか。

しかも、on error resume nextでエラーを無視していますから、
あとは野となれ山となれ状態です。:-<


どうも、「コレクション参照中の要素削除」は
ヘルプの使用例が助長(ヘルプ)しているようです。

EnumNetworkDrivesの使用例
Set WshNetwork = WScript.CreateObject("WScript.Network")
Set oDrives = WshNetwork.EnumNetworkDrives
Set oPrinters = WshNetwork.EnumPrinterConnections
WScript.Echo "Network drive mappings:"
For i = 0 to oDrives.Count - 1 Step 2
WScript.Echo "Drive " & oDrives.Item(i) & " = " & oDrives.Item(i+1)
Next
WScript.Echo
WScript.Echo "ネットワーク ドライブ割り当て :"
For i = 0 to oPrinters.Count - 1 Step 2
WScript.Echo "Port " & oPrinters.Item(i) & " = " & oPrinters.Item(i+1)
Next

RemoveNetworkDriveの使用例
Dim WshNetwork
Set WshNetwork = WScript.CreateObject("WScript.Network")
WshNetwork.RemoveNetworkDrive "E:"

RemovePrinterConnectionの使用例
Set WshNetwork = WScript.CreateObject("WScript.Network")
PrinterPath = "\\printserv\DefaultPrinter"
WshNetwork.RemovePrinterConnection PrinterPath, true, true

単純に組み合わせると「コレクション参照中の要素削除」になります。
しかも、Count - 2とすべきところをCount - 1と書いてたりして、あんまりです。
ヘルプがこれでは、まず、ヘルプを見よう、と言えないではありませんか。:-<

ばんのしゃーによかばんた さん 2004年 06月 09日 14時 17分 55秒

>kenji さん 2004年 06月 08日 15時 20分 58秒
>なおこの前解説頂きましたエラー・トラッキングのスクリプトですが問題
>が生じました。ソースの冒頭に書き込み走らせるとマップをかけてアプリ
>を起動する頃にエラーを吐いて中断します。
>The script you are executing is taking longer than expected to
>run. End or Continue
>Continue を選ぶと正常に動作し終わります。
>これはスクリプト・コントロールのTimeout値がデフォルトの5秒を過ぎた
>為に発生したと思われます。これを回避すべくその値を変えられないか調
>べて見たのですが、この値はscript.dllにハード・コードされているので
>変えられない、との指摘をネット上のQAで見つけました。

以下、繰り返しになりますが、

調べ方について、

>ばんのしゃーによかばんた さん 2004年 05月 16日 21時 41分 07秒
>まず、これらヘルプを参照されることを強くお勧めします。
(略)
>と、しっかり書かれています。
>インターネットで探すよりローカルのヘルプファイルで探すほうが簡単です。

ヘルプについて、

>ばんのしゃーによかばんた さん 2004年 05月 20日 21時 02分 37秒
>ただし、2000などの標準環境ではヘルプが付いてないので、
>作る側はダウンロードしたほうがよいでしょう。

英語のメッセージが出るところをみると、標準環境をお使いですね。
Script ControlはWSH5.6と同じところにありました。

あと、オブジェクトブラウザも併用したほうがよいでしょう。
ヘルプがなければ、尚更です。

>管理人むたぐち さん 2004年 04月 24日 15時 31分 55秒
>これだけはVBAの「オブジェクトブラウザ」を併用してやる必要があると思います。
>Word、Excelに限らず、COMのオブジェクトにどんなメンバ(プロパティ、
>メソッド、定数、イベントなど)があるかを調べるのには有効です。
>ちなみに、オブジェクトブラウザのダイアログを出すには、VBAでF2キーを押すと
>すぐ出ます。

参照設定は、
Library MSScriptContro
C:\PROGRAM FILES\MICROSOFT SCRIPT CONTROL\MSSCRIPT.OCX
Microsoft Script Control 1.0
Microsoft スクリプト コントロール Version 1.0
です。

この手順を踏めば、SC.TimeOut=-1とすればよいと分かるはずです。

Hiro さん 2004年 06月 09日 12時 33分 59秒

こんにちは、初投稿させて頂きます、初心者のHiroと申します。

さっそく初歩的質問で恐縮ですが、下記用途のスクリプトを何方かご教授いただけないでしょうか。参考例を調べたのですが、良い例が見つからず困っています。

-------------------------------------
URLを送信して、IEアプリでそのリンク先を開き(非表示でも良い)、そのViewSource HTMLソースを、指定するディレクトリに、指定する名前で、HTMLテキスト書類として作成する。最後に使用アプリを閉じて、終了。
-------------------------------------

以上なのですが、よろしくお願いいたします。

ただし さん 2004年 06月 09日 11時 58分 37秒

kimiok さん

そのものずばりはどうだか分かりませんが、Active Directoryに関する
VBScriptとPerlのサンプルコードは次のURLを当って見て下さい。
邦訳はまだ出ていないようです。

http://www.rallenhome.com/books/adcookbook/code.html

麻巳子S さん (jpc0859@jpcom.jp) 2004年 06月 09日 11時 06分 50秒

初投稿です。女の子が募集するとメールたくさん来るってホント??マミには来なかったりして;^_^A
メールから初めて夏にはステディな関係になれたらいいなo(^o^)o写メ交換OKデス。


kimiok さん 2004年 06月 08日 17時 50分 58秒

いつも拝見させていただいております。kimiok と申します。

Active Directory 上に既存する数100のユーザーのパスワードの変更を考えております。SetPassword を使用し実行できそうなことを調べましたが
テストユーザーで試したところ以下のエラーが出力され失敗してしまいます。

<エラー内容>
=====================================
C:\pass2.vbs(6, 1) (null):
サーバーにそのようなオブジェクトはありません。
=====================================

<記述>
=====================================
Option Explicit

DIM strPWD

strPWD = "*****"
Set objUser = GetObject("LDAP://cn=***,ou=Users,dc=***,dc=***,dc=***")
objUser.SetPassword strPWD
=====================================

<環境>
=====================================
Windows XP Pro SP1 → 実行マシン
Windows Server 2003 Active Directory
=====================================

当然ではございますが、admin権限のユーザーアカウントで実行し、
ユーザーも存在しています。
かなり初歩的なことだと思っているのですが、それすら解決できず
ご相談をさせていただきました。
恐れ入りますが、もしアドバイスをいただけることがございましたらご教示お願い致します。


kenji さん 2004年 06月 08日 15時 20分 58秒

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

> 訂正。こうでしょうね、たぶん。
> For i = objDrives.Count -2 to 0 Step -2

ありがとうございます。下記にて全てのマップを外す処理、完動確認致
しました。

Dim WshNet
Set WshNet = WScript.CreateObject("WScript.Network")
Set Drives = WshNet.EnumNetworkDrives

For i = Drives.Count -2 to 0 Step -2
WshNet.RemoveNetworkDrive Drives.Item(i)
Next

Set WshNet = Nothing


復習を兼ねて三通りの方法でEからZまで22ドライブを一度にマップさせる
動きを追って見ました。これはただローカルドライブの増減状態を見える
ようにしたまででツールで正確に計測したものではありません。動作環境
は大きなLANに繋がっているSambaサーバーとW2000クライアントです。


1. 単純繰り返し

Set WshNet=CreateObject("Wscript.Network")

WshNet.MapNetworkDrive "E:","\サーバー名\フォルダー1"
|
WshNet.MapNetworkDrive "Z:","\サーバー名\フォルダー22"

Set WshNet = nothing


2. 単純配列を二つ利用

Set WshNet=CreateObject("Wscript.Network")

local = array("E:",   - "Z:")
network = array("フォルダー1", - "フォルダー22")

For i = 0 to 21 ' 配列数
WshNet.MapNetworkDrive local(i), "\\サーバー名\" & network(i)
Next

Set WshNet = Nothing


3. 連想配列、Dictionary Objectを利用(いりやさん案)

Set WshNet = CreateObject("Wscript.Network")
Set mapTable = CreateObject("Scripting.Dictionary")

initialize(mapTable)
Sub initialize(mapTable)

mapTable.Add "E:", "\\libux\index-1"
|
mapTable.Add "Z:", "\\libux\index-22"

End Sub

add(mapTable)
Sub add(mapTable)
For Each localname In mapTable
remotename = mapTable.item(localname)
WshNet.MapNetworkDrive localname, remotename
Next
End Sub

Set NetWsh = Nothing


結論から言いますとマップの速度は大体この通りです。1の方法は
18ドライブ位で一度止まりしばらくしてから残りをマップします。

2の方法は配列が別個になっているので両方の変数を読み込むのに最初
時間がかかっていると思われますが走り出すと一気にマップします。

3は2より心持早い感じですね。新環境、W2000サーバーにW2000クライア
ントの組み合わせはほぼpeer-to-peerですのでいずれも素早く終わり明
らかな差は感じられませんでした。


なおこの前解説頂きましたエラー・トラッキングのスクリプトですが問題
が生じました。ソースの冒頭に書き込み走らせるとマップをかけてアプリ
を起動する頃にエラーを吐いて中断します。

The script you are executing is taking longer than expected to
run. End or Continue

Continue を選ぶと正常に動作し終わります。

これはスクリプト・コントロールのTimeout値がデフォルトの5秒を過ぎた
為に発生したと思われます。これを回避すべくその値を変えられないか調
べて見たのですが、この値はscript.dllにハード・コードされているので
変えられない、との指摘をネット上のQAで見つけました。

そして全体のTimeout値を変えるには、 WaitForSingleObjectないしWaitForMultipleObjects
を使う、との指摘も見つけたのですが何だか本道を外れて行くような気が
します。実際そのような方法を取るのでしょうか? 何度もお尋ねして済
みません。

いりや さん 2004年 06月 08日 11時 39分 26秒

ばんのしゃーによかばんたさん、

| >いりや さん 2004年 06月 06日 20時 39分 19秒
| >| ファイル"a"を削除して直後にスクリプトを抜けると"a"が削除されない?
| >後にスクリプトホスト (wscript.exe) が実行を終えようとした時にスクリプト
| >ホストがエラーを報告し実行を中断する、という事象でした。
|
| InvokeVerbは「仕様」としても、これを「仕様」と言うのは難しいのでは。
| データインテグリティの問題ではなさそうなので、まだしもですが、
| ユーザは原因不明の怪現象に悩まされることになります。

あれ? 仕様という表現をしましたっけ。

ただこのスクリプトホストの振る舞いがその通りなのであれば (作っ
た通りに動きますという意味で) 実装仕様と言えますね。

とはいうものの、

| 98/2000/XPで試してみましたが、再現しません。
| 発生しやすいOS/WSHのVersionとかあるのでしょうか。
| それとも大量に削除するとか、負荷をかけないと駄目なのでしょうか。

こちらについては、記事を投函した当時の事象をきちんと記録して
おかなかったのが災いして、6/6 に再現試験を試みたのですが事象
が再現しませんでした。ですので、ちょっとこちらは別環境で再現
試験を継続してみます。Nothing 定数のバインドの件も合わせて。

ところで、今回の事象に出会って Component Object Model の
Win32 API に直接アクセスしなきゃなと感じるようになりました。

スクリプトホストを通して得られるエラー情報が丸められることが
避けられないこと、メソッドの実行モデルがよくわからないことが、
事象の解析の手かせ足かせになっています。簡単なプログラムがこ
さえられればシナリオの裏とりなんて一発なのにともどかしい!

魔界の仮面弁士 さん 2004年 06月 08日 11時 26分 50秒

》 ばんのしゃーによかばんた さん
> ローカルなHTMLファイルをインターネットゾーンか、またはスクリプトを無効にして、
> HTMLDocumentに取り出す方法はありませんか。

こちらはわかりませんでした。。。


> また、変更したHTMLDocumentをファイルに格納する方法は、
> document.body.parentElement.outerHTMLをFSOで書き出すしか、
> ないのでしょうか。

「DHTMLEditコントロール」を使って見たところ、
  strHTML = DHTMLEdit1.DOM.documentElement.outerHTML
のように、HTMLDocument経由で取得する替わりに、
  strHTML = DHTMLEdit1.DocumentHTML
のようにして受け取ることが出来ました。実行ホストはHTAです。


また、HTAではなく、Visual Basicを利用した場合には、
  DHTMLEdit1.SaveDocument "C:\foo.html", False
のように、SaveDocumentメソッドを使って保存したり、あるいは、
  Dim F As IPersistFile
  Set F = DHTMLEdit1.DOM
  F.Save "C:\foo.html", True
のように、IPersistFile(もしくはIPersistStreamInit)を使って、
ファイルに保存させる事も出来ました。

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

>管理人むたぐち さん 2004年 06月 03日 19時 33分 47秒
>:は内部的には改行と同等に扱われているんでしょうか。

なので、継続行には使えません。
単純に行頭空白を置換すると、誤置換してしまいます。
なので、今のところ手作業。なので、ついつい忘れてしまいます。
正規表現は要研究。

ところで、
ローカルなHTMLファイルをインターネットゾーンか、またはスクリプトを無効にして、
HTMLDocumentに取り出す方法はありませんか。
ie.navigate file

GetObject(file,"htmlfile")
だとマイコンピュータゾーンになって、スクリプトが有効になってしまいます。
マイコンピュータゾーンの設定はあまり変えたくありません。

また、変更したHTMLDocumentをファイルに格納する方法は、
document.body.parentElement.outerHTMLをFSOで書き出すしか、
ないのでしょうか。
今のところ、それで特に困るということはないのですが、
あまりスマートじゃないなぁという感じがするもので。

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

>kenji さん 2004年 06月 06日 18時 36分 21秒
>> For i = objDrives.Count -1 to 0 Step -2<BR>
>これは音なしの構えでまったく人畜無害でした。元の

訂正。こうでしょうね、たぶん。

For i = objDrives.Count -2 to 0 Step -2


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

>いりや さん 2004年 06月 06日 20時 39分 19秒
>| ファイル"a"を削除して直後にスクリプトを抜けると"a"が削除されない?
>後にスクリプトホスト (wscript.exe) が実行を終えようとした時にスクリプト
>ホストがエラーを報告し実行を中断する、という事象でした。

InvokeVerbは「仕様」としても、これを「仕様」と言うのは難しいのでは。
データインテグリティの問題ではなさそうなので、まだしもですが、
ユーザは原因不明の怪現象に悩まされることになります。

>(1) Scripting.FileSystemObject>>deleteFile() を実行する。
>(2) 非同期に実行されるメソッドなので、処理依頼が完了した時点で、制御がス
>  クリプトホストに戻る。
>(3) これ以上スクリプトがないことを確認する。
>(4) ActiveX オブジェクトの解放処理をはじめる。
>(4-1) Scripting.FileSystemObject オブジェクトのリファレンスを解放する。
>(4-2) (4-1) のタイミングで deleteFile() メソッドの処理が完了していない。

と、すると、
fso.DeteFile
Set fso=Nothing
でも、発生する筈ですね。
もし、これで、発生しないのなら、回避方法となりますが、どうでしょう。

98/2000/XPで試してみましたが、再現しません。
発生しやすいOS/WSHのVersionとかあるのでしょうか。
それとも大量に削除するとか、負荷をかけないと駄目なのでしょうか。

いりや さん 2004年 06月 06日 20時 39分 19秒

ばんのしゃーによかばんたさん、

こんばんわ。いりやです。

| これって、どういう現象なのでしょうか。問題が発生するシーケンスは、
| ファイル"a"を削除して直後に"a"を作るとエラーになる?
| ファイル"a"を削除して直後にスクリプトを抜けると"a"が削除されない?
| というようなことでしょうか。

後者に近いシナリオです。

観測したのは Scripting.FileSystemObject>>deleteFile() メソッドを実行した
後にスクリプトホスト (wscript.exe) が実行を終えようとした時にスクリプト
ホストがエラーを報告し実行を中断する、という事象でした。

それで、なぜエラーを報告するのか。

scrrun.dll とスクリプトホストのソースコードが分からないので確証はありま
せんが、こういうシナリオでスクリプトホストが動き (4-2) のタイミングでエ
ラーが起きたのかと推測しています。

(1) Scripting.FileSystemObject>>deleteFile() を実行する。
(2) 非同期に実行されるメソッドなので、処理依頼が完了した時点で、制御がス
  クリプトホストに戻る。
(3) これ以上スクリプトがないことを確認する。
(4) ActiveX オブジェクトの解放処理をはじめる。
(4-1) Scripting.FileSystemObject オブジェクトのリファレンスを解放する。
(4-2) (4-1) のタイミングで deleteFile() メソッドの処理が完了していない。

この (4-2) にヒットするようなタイミング・イシューは Windows Script Host
の他に UWSC でも同様のシナリオで確認することができました。[*1][*2] また
他のメソッドでは、

  Shell.Application>>shellExecute() メソッド
  FolderItem>>invokeVerb() メソッド

で確認できました。[*1][*3]

では、そもそも、何が問題なのか。

推測を重ねていますが、エラーを報告する裏側には (4) の事前条件として「非
同期に実行されるメソッドがすべて完了している」ことが予想されます。にもか
かわらず、Scripting.FileSystemObject>>deleteFile() の場合はスクリプトホ
ストで知るための手段が提供されていない。これが問題だとおもっています。

通常、完了通知イベントを受ける口をスクリプトホストに用意して非同期メソッ
ドの本体でイベントをスクリプトホストに発行します。(WScript.connectObject()
メソッド) ですが、Scripting.FileSystemObject>>deleteFile() メソッドには、
そのようなイベントを発行してなさそうです。

ですので、スクリプトホスト側で完了したと判断するための手段を検討しなけれ
ばなりません。

Scripting.FileSystemObject>>deleteFile() メソッドの場合は、メソッドの事
後条件が「対象ファイルの削除が完了している」ことと言えるので「削除が完了
していれば、Scripting.FileSystemObject>>fileExists() メソッドで false が
返ってくる」という点に着目して、Scripting.FileSystemObject>>fileExists()
が true の間ループするという方式が思い浮かびます。

Array>>waitUntilRemoved() メソッドは、その方式を採用した待ち合わせ処理で
す。

function Array.prototype.waitUntilRemoved() {
    var discriminator = function (each) { return FileSystemObject.fileExists(each) };
    var testArray = this;
    while (true) {
        var testArray = testArray.select(discriminator);
        if (testArray.length == 0)
            break;
        WScript.sleep(270);
    }
}

こういうような話が成り立たない場合は、[*1], [*3] の一時対処案のように十
分な時間待つ (WScript>>sleep() メソッド) より他に手はありません。

[ おわりに ]

「非同期に実行するメソッド」という表現が文中でてきたかと思います。こちら
は、制御がメソッドの実行を待たないで返ってくる、という意味で書いています。
フォーマルな表現ではありません。

msdn の Component Object Model の頁は斜め読みしかしていないので、適切な
定義があればご指摘いただければありがたいです > 有識者の皆さん。


[ リファレンス ]

[*1] いりや 他, うみうみ屋さんの掲示板より
   「Shell.Application で .doc ファイルが開かない」
   http://hidebbs.net/bbs/umiumi?s=7&n=15169181

[*2] いりや, UWSC WiLiKi 「UWSC:待ち合わせ処理:Mutexを使用」
   http://iriyak.adam.ne.jp/wiliki/uwsc.cgi?UWSC%3a%c2%d4%a4%c1%b9%e7%a4%ef%a4%bb%bd%e8%cd%fd%3aMutex%a4%f2%bb%c8%cd%d1&l=jp
   こちらで紹介している Monitor.uws の destroySharedBuffer() プロシー
   ジャ。UWSC WiLiKi トップページは
   http://iriyak.adam.ne.jp/wiliki/uwsc.cgi
   こちらから。

[*3] 彩香さん 他、WSH Lab. 掲示板より
   「WSHを使ってフォルダの中にあるファイル(拡張子を選ばず) を一切
   合切通常使うプリンタで印刷を行うことってできますか。」
   http://www.roy.hi-ho.ne.jp/mutaguchi/bbs/list86.shtml
   http://www.roy.hi-ho.ne.jp/mutaguchi/bbs/list85.shtml
   スレッドは 85.shtml から入っていますが、関連する記事は、
   いりや さん 2003年 06月 27日 02時 37分 49秒
   管理人むたぐち さん 2003年 06月 27日 08時 45分 46秒

kenji さん 2004年 06月 06日 18時 36分 21秒

WSH修行中さん

私は教えて頂くばっかりで肩身が狭いのですがこんな私でもお役に立てて幸い
です。

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

> 実際のVBScriptが以下ですね。

ソースまでご配慮頂いてたんですね。失礼致しました。

> 実際に試してないので、確かなことは言えませんが、
> こういう場合、

> For i = objDrives.Count -1 to 0 Step -2<BR>

> としないといけない、或いは、少なくとも、としたほうがよい、
> のではないでしょうか。
> ひょっとするとこれでもだめかも。

これは音なしの構えでまったく人畜無害でした。元の

For i = 0 to objDrives.Count -1 Step 2

はネットで何件か応用例を見つけたのですが結局スカでした。

> もっと、堅実には、最初に別の配列に転写するなどして、静止画(snapshot)
> を取っておきそれを見ながら動的な変更を加える(削除する)。
> というのがよいのではないでしょうか。

仰る通りです。地道にやるしか方法はなさそうです。

このシステムは元々先輩が開発されたものでサーバーのOSにはLinuxを使い
ウインドウズ・クライアントへのサービスはマイクロソフト・ネットワーク
を話すSambaを使っています。

SambaにはクライアントからHTTPを介してブラウザーでリソースやユーザーや
ログの管理が出来るSwatという便利なサービスがありますしログ取りは解析は
Linuxの得意とする分野ですから安心です。

クライアントからの接続にはAddMapとRemoveを必要なだけ書き連ねるシンプル
なものですがこれといったトラブルもなく一年以上の連続運転に耐える頑丈さ
が目玉です。

しかし先輩も離れられサーバーもW2000に代えることになり全体の見直しを進め
て来ました。Linuxからマイクロソフト純正に代えたら使い物にならなくなった
では洒落にもなりませんので先輩の資産をダウングレードさせないように見守っ
て行きたいと願ってます。

ご指導・ご鞭撻これからもよろしくお願い申し上げます。

ばんのしゃーによかばんた さん 2004年 06月 06日 18時 25分 53秒

>管理人むたぐち さん 2004年 06月 03日 19時 33分 47秒
>> window.Document.HasFocus()
>げげ、そんなもんがあるんですか。

げげ、そう言えば、以下は、、、

>hoge さん 2004年 01月 11日 14時 51分 02秒
> 現在開いている IE のウィンドウから、ページのタイトルと URL を得て、
> クリップボードにコピーしようと試みてます。
> で、IE のウィンドウが一つのときは、とりあえずできたんですが、
> 複数の IE ウィンドウがあるときに、一番上にあるものを選び出す方法が
> 分からず困ってます。
> // 現在開いている IE のウィンドウ(?)を得る。
> var Shell = WScript.CreateObject("Shell.Application");
> var WindowsShell = Shell.Windows();
> for (var i = 0; i < WindowsShell.Count; i++) {
> if (WindowsShell.item(i).FullName.match(/iexplore.exe$/i)) {
> var ie = WindowsShell.item(i);
> break;
> }
> }
> こうすると、一番最初に開いたウィンドウが得られてしまい、目的がかないません。

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();
for (var i = 0; i < WindowsShell.Count; i++) {
; ; if (WindowsShell.item(i).FullName.match(/iexplore.exe$/i)) {
; ; ; ; var ie = WindowsShell.item(i);
; ; ; ; if(ie.Document.hasFocus()) break;
; ; }
}

とすればよかったわけですね。

ただし、上のコードはIEからフォルダを開いているとこけます。

VBScriptなら、
Set Shell = CreateObject("Shell.Application")
For Each ie In Shell.Windows()
: : If TypeName(ie.Document)="HTMLDocument" Then
: : : : If ie.Document.hasFocus() Then Exit For
: : End If
Next
とすればよいのですが、JScriptは分かりません。悪しからず。:-p

ばんのしゃーによかばんた さん 2004年 06月 05日 23時 15分 00秒

マイコンピュータゾーンにするため、
about:blankを使わず、HTMLファイルも使わないで、dialogHelperを使う方法。
res://はOS? IE? versionによってフルパスでないといけないようです。

Set fso=CreateObject("Scripting.FileSystemObject")
Set ie=CreateObject("InternetExplorer.Application")
'ie.Navigate "res://mshtml.dll/blank.htm"
ie.Navigate "res://" & fso.GetSpecialFolder(1).Path & "\mshtml.dll/blank.htm"
Do While ie.Busy Or ie.ReadyState<>4
WScript.Sleep 100
Loop
'ie.Visible=True

Set dialogHelper=ie.Document.CreateElement("object")
dialogHelper.id="dialogHelper"
dialogHelper.classid="CLSID:3050f4e1-98b5-11cf-bb82-00aa00bdce0b"
call ie.document.body.insertadjacentelement("AfterBegin",dialogHelper)

WScript.Echo dialogHelper.object.openfiledlg("", "", "すべてのファイル (*.*)|*.*|", "Open File Dialog")

WScript.Echo dialogHelper.object.savefiledlg("a", "", "すべてのファイル (*.*)|*.*|", "Save File Dialog")

WScript.Echo ie.document.body.parentelement.outerhtml
ie.Quit
WScript.Quit

管理人むたぐち さん 2004年 06月 05日 20時 17分 29秒

To: 魔界の仮面弁士 さん

> HTMLの<pre>要素に相当する表示を、スタイルシートで対応させるとなると、
> 「white-space: pre」を指定する必要があるのですが、調べてみたところ、
> これは、IE5.5以下では使えないそうです。

はい、これは私も調査済みでして、実際に試してみたんですけど、
>厳密モードのHTMLが必要
だったんですね。何でうまくいかなかったのかが分かりました。

スクリプトで<pre>タグ挿入…となってくると、処理速度とかが心配ですし、
どうしたもんでしょうね。うーむ。


To: 放置機 さん

> WSH1.0ではFiles.Countでコレクションの数を取得できないのでしょうか。

はるか昔、私も同じところでつまずいた記憶がかすかにあります。
もしかしたら、そうだったかもしれません。
ただ単に私の勘違いで、魔界の仮面弁士さんの説が正しいかもしれませんので、
まずはそちらをお試しください。


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

> それって、
> 最近Windowsが使用している文字コード種が増えて、
> ほとんど無力化してい文字列指定のファイル検索の代替になるのでしょうか?

namazuはShift_JIS、JIS、EUCあたりは対応してるんですが、
なんとUTF-8に対応してないらしいです。
言われるまで気づきませんでした。
しかし、nkfを通せばいいらしいので今度やってみます。

Windowsのファイル検索とは違って、ファイルからインデックスを作成して、
それを検索するわけですから、インデックス作成時に参照する辞書が
取りこぼしをすると、探したい単語が見つからないことはあります。
が、実用上はほとんど問題ないと思いますし、とにかく検索スピードが
桁違いなので重宝します。

> Windowsのフリーソフト(≠フリーソフトウェア)はバイナリだけのものが多く、
> 余程のものでない限り、どうも使う気になりません。

私も単純なファイル操作などは、スクリプトをさくっと書いて
済ませるのが好きですね。
Windowsの場合、オープンソースでも、コンパイラが有料だったりしますしね。

放置機 さん 2004年 06月 05日 20時 14分 54秒

>もしかして、「C:」ではなく、「C:\」では無いでしょうか。

やはりNGでした。WSHのバージョンによる差異なのか。
だとしたら旧版ではどうやってFilesコレクションの数を
取得していたのでしょう。

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

>いりや さん 2004年 02月 11日 19時 18分 18秒
>// [1] ファイル削除が完了するまで待つ処理
>// FileSystemObject>>deleteFile() メソッドは非同期に実行されることがわ
>// かっている。つまりメソッドから返った時点ではファイルの削除が保証され
>// ない。さらにこのスクリプトはそのまま終了してしまう。このような時に具
>// 合の悪いタイミング・イシューが発生する。それはスクリプト終了時に、
>// ActiveX オブジェクトの解放処理をスクリプトホスト (wscript.exe) がおこ
>// なうのだが、その時にまだ FileSystemObject>>deleteFile() メソッドの処
>// 理が完了していない場合のエラーである。
>// 以上を踏まえ、非同期処理の待ち合わせ処理を呼び出し元でつくりこんでや
>// る必要がある。具体的には FileSystemObject.fileExists() メソッドで存在
>// 有無を検査する。FileSystemObject.fileExists() メソッドの内部実装は未
>// 確認だが、FileSystemObject>>deleteFile() メソッドの実行が完了した後は
>// false を返す、という前提をおいている。

これって、どういう現象なのでしょうか。問題が発生するシーケンスは、
ファイル"a"を削除して直後に"a"を作るとエラーになる?
ファイル"a"を削除して直後にスクリプトを抜けると"a"が削除されない?
というようなことでしょうか。

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

>管理人むたぐち さん 2004年 06月 03日 19時 33分 47秒
>検索といえば私は最近、namazuを使ってローカル検索できるようにしてるんですが、

それって、
最近Windowsが使用している文字コード種が増えて、
ほとんど無力化してい文字列指定のファイル検索の代替になるのでしょうか?
このファイル検索はどうにかならんものでしょうか。

>http://www31.ocn.ne.jp/~h_ishida/xdoc2txt.html
>で公開されている、xdoc2txtをnamazuのフィルタに使うと、
>さらに一太郎ドキュメントなどマニアックなファイルも検索対象に
>できてしまいます

テキスト抽出ツールとして強力ですね。レイアウトは、、、しつこい。:-p

>スクリプトってほんと、すばらしいもんですね〜
賛成です。
特に、フリーソフトウェアの趣旨に合致している点がよいです。
Unixのフリーソフトウェアは原則的にソース提供でしたが、
Windowsのフリーソフト(≠フリーソフトウェア)はバイナリだけのものが多く、
余程のものでない限り、どうも使う気になりません。
その点、スクリプトはなんたってソース提供で安心だし、自由に改造できて、
フリーソフトウェアの開発言語として最適です。

xo さん 2004年 06月 05日 13時 19分 37秒

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

> もし、ActiveXコンポーネントがなんちゃらというメッージが出てもよければ、
> たぶん、没ですね。失礼しやした。ちゃんちゃん。

いえいえ、大変勉強になりました。私、Unixの心得が少々あるんです。シェル・
レベルではなんでもありなんですが、ウインドウズでもVBAであれ、VBSであれ、
ASPであれ「スクリプトはなんでもどこでも試してみるべし」ですね。

いやー、スクリプトは本当に面白い、これむたぐちさんの台詞だったかな?




WSH修行中 さん 2004年 06月 05日 07時 04分 21秒

kenjiさん

ネットワークドライブ接続のサンプルありがとうございました。
私が期待した動作をしております。感激いたしました。
また、時折質問させていただくかもわかりませんが、
これからもよろしくお願いいたします。

ばんのしゃーによかばんた さん 2004年 06月 04日 21時 08分 04秒

>SUNY さん (uno@qq.emis.or.jp) 2004年 06月 01日 13時 30分 32秒
>FileExistsメソッドってワイルドカード使用できないんですね。
>ファイルの存在チェックでそれに代わる関数ってあるのでしょうか?

これは、むたぐちさんの記事を参照。

しかし、ちょっと待った! ですね。

以前にも、お話しした通り、
>ばんのしゃーによかばんた さん 2004年 05月 04日 20時 44分 02秒
>昔、部下の開発技術者が何かのやり方を聞いて来ることがありましたが、
>答える前に、必ず、もともとの問題を説明させました。
>でないと、とんでもない修正に加担することになり兼ねません。でした。
の通りで、解決したい問題は以下ですよね。

>要はDeleteFileメソッドでファイルを削除したいのです。
>(↑このメソッドはワイルドカード使用可ですよね)
>削除する前に存在チェックを行わないと、ファイルが存在しない場合エラーとなってしまいま>す。私が行いたい処理はファイルが存在したら削除、存在しなければスルーってな感じです。

これは、以下のようなところでしょうか。
Set fso=CreateObject("Scripting.FileSystemObject")
On Error Resume Next
fso.DeleteFile "aaaa*.txt"
ErrNumber=Err.Number
ErrSource=Err.Source
ErrDescription=Err.Description
On Error GoTo 0
If ErrNumber<>53 Then Err.Raise ErrNumber,ErrSource,ErrDescription

On Errorについては以下も参照願います。
>ばんのしゃーによかばんた さん 2004年 04月 10日 16時 13分 29秒
>On Error Resume Nextの正しい使い方について、

アブナイ、アブナイ。こういうことがあるから、
>ばんのしゃーによかばんた さん 2004年 05月 04日 20時 44分 02秒
>というわけで、
>何かにお困りのみなさんは、問題の核心を説明なさったほうがよろしいかと
>思いますです。(会社でも。)
なんですね。

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

>xo さん 2004年 06月 03日 17時 52分 43秒
>HTMLに書いて呼び出す場合、タイトルの所に”VBScript:”が入りますが
>これは消せませんか?

もし、ActiveXコンポーネントがなんちゃらというメッセージが出てもよければ、

<html>
<head>
<script language = "VBScript"></script>
</head>
<body>

<form>
<input name = "Button1" Type = "Button" Value = "押してね" OnClick = 'CreateObject("WScript.Shell").PopUp "こんにちわ", , "テスト", 0'>
</form>

</body>
</html>

たぶん、没ですね。失礼しやした。ちゃんちゃん。

ばんのしゃーによかばんた さん 2004年 06月 04日 21時 05分 29秒

>kenji さん 2004年 06月 04日 08時 42分 06秒
>装出来ません。後半部分の絡みremotename をご説明願えませんか?

> Option Explicit
> Dim remotename
> Set wShell=CreateObject("WScript.Shell")
> remotename="XXX"
> y 'Error Raise
> WScript.Quit

上の部分は動作確認用のサンプルですので、実際のVBScriptに置き換えてください。

> Set wShell=CreateObject("WScript.Shell")
はゴミです。これが混乱の元かな? :-p

実際のVBScriptが以下ですね。その一部。
>add(mapTable) 'マップテーブルの実行
>Sub add(mapTable)
>For Each localname In mapTable
>remotename = mapTable.item(localname)
>Wsh.Net.MapNetworkDrive localname, remotename
>Next
>End Sub

>Wsh.Net.MapNetworkDrive localname, remotename
で、エラーが予想される。

とすると、エラー発生時のremotenameの中身を知りたくなる。

そこで、ヘッダの、
WScript.ScriptFullName & vbTab & _
[_SC].Error.Line & vbTab & _
[_SC].Error.Column & vbTab & _
[_SC].Error.Description & vbTab & _
[_SC].Error.Text & vbTab & _
Hex([_SC].Error.Number) & vbTab & _
[_SC].Error.Source & vbTab & _
[_CO].remotename ' <- ここ
で出力する。

という仕組みです。

それとも、なんで、[_CO].remotenameで見えるの? ということでしょうか?
そのへんはよく分かりません。そうやったら見えた、ということで。。。
ScriptControlのヘルプを見れば書いてあるのかも知れません。
ScriptControlについては最近の過去ログを参照願います。

放置機 さん 2004年 06月 04日 19時 18分 59秒

>もしかして、「C:」ではなく、「C:\」では無いでしょうか。

もう一度確かめてみます。
ありがとうございます。

放置機 さん 2004年 06月 04日 19時 18分 48秒

>もしかして、「C:」ではなく、「C:\」では無いでしょうか。

もう一度確かめてみます。
ありがとうございます。

WSH初心者 さん 2004年 06月 04日 16時 49分 19秒

どうもはじめまして

”常時起動中にしてある(ロックがかかっている)サーバーのPCが何らかの理由でログオフされたとき、もしくはログオフしようとしているとき、それをメールで知らせる” といったものをVBSで・・・と考えているのですが
助言お願いします。 ヒントでもありましたら助かります。

kenji さん 2004年 06月 04日 13時 23分 29秒

WSH修行中さん、

私の場合は与えられたドライブをきれいに使うのが目的なので
ご希望にそえるかは存じませんが、こんな方法も試してました。

まず特定のドライブを指定するなら、ファイルシステム・オブジェクト
でフォルダー名が使われているか調べて無ければマップ、使われて
いれば削除してマップします。

Set fso = CreateObject("Scripting.FileSystemObject")
Set WshNetwork = WScript.CreateObject("WScript.Network")

If fso.folderexists("X:\")=False Then
WshNetwork.MapNetworkDrive "x:", "\\サーバー名\フォルダー名"
Else
WshNetwork.RemoveNetworkDrive "x:"
WshNetwork.MapNetworkDrive "x:", "\\サーバー名\フォルダー名"
End If


もう少し工夫してドライブの中から空きを探して最初に見つかった
ドライブにマップするようにしています。

Function FreeDrive()
Dim I, objFso

Set objFso = CreateObject("Scripting.FileSystemObject")

For I = Asc("F") to Asc("Z")
If Not objFso.DriveExists(Chr(I)) Then
FreeDrive = Chr(I) & ":"
Exit Function
End If

Next
End Function

strDriveLetter=FreeDrive()
WScript.Echo strDriveLetter

If strDriveLetter>"" then

strShareName="\\サーバー名\フォルダー名"

Set WshNetwork = WScript.CreateObject("WScript.Network")
WshNetwork.MapNetworkDrive strDriveLetter, strShareName
'+++++++++++++++++++++++++++++++++++++++++++++++++
' 何か処理があればここに書く
'+++++++++++++++++++++++++++++++++++++++++++++++++
WshNetwork.RemoveNetworkDrive strDriveLetter
End If

Set WshNetwork= Nothing

但し、これはシングルの場合だけですので複数ドライブへ応用にはご改良
お願い致します。

もっと厳密にするにはEnumNetworkDriveメソッドのWshCollection
オブジェクトを使ってネットワークドライブを調べて、マップ・テー
ブルと対比し分岐させるような高級な方法があるとは思いますが、私も
修行中(正しくは苦行中)の身ですのでこの程度でご容赦下さい。

kenji さん 2004年 06月 04日 08時 42分 06秒

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

>VBSriptを自動で実行した場合、エラーの情報をどうするか。

ご指導・ご鞭撻まことにありがとうございます。教えて頂きました
スクリプトですが恥ずかしながら理解力が不足しておりますので実
装出来ません。後半部分の絡みremotename をご説明願えませんか?

> 既存のVBScriptの前に以下のヘッダを付加します。'<!--から'-->まで。

省略

> "x: " & [_CO].remotename , _
> vbCritical+vbSystemModal,WScript.Name
> End If
> WScript.Quit
> '-->

> Option Explicit
> Dim remotename
> Set wShell=CreateObject("WScript.Shell")
> remotename="XXX"
> y 'Error Raise
> WScript.Quit

xo さん 2004年 06月 04日 08時 27分 14秒

むたぐちさん、

# MsgBoxの使い方

# > HTMLに書いて呼び出す場合、タイトルの所に”VBScript:”が入りますが
# > これは消せませんか?

# おそらくですが、消せないのではないかと思います。

VBSの画面出力はこれしかないので色々工夫してますが、むたぐちさんが
そう仰るのなら駄目っぽいですね。

ありがとうございました。

WSH修行中 さん (k-okuda@mctv.ne.jp) 2004年 06月 04日 08時 22分 54秒

MapNetworkDriveで、ネットワークドライブの接続を行いたいのですが、コマンドプロンプトの 「NET USE *」のように、空いているドライブに自動的に割り付けるといったオプションはないのでしょうか?どなたかお教えください。 

魔界の仮面弁士 さん 2004年 06月 04日 06時 38分 42秒

> Set folder = fso.GetFolder("C:")
> cnt = folder.Files.Count

もしかして、「C:」ではなく、「C:\」では無いでしょうか。

C:\の場合、「Cドライブの直下のファイル数」を示しますが、
C:では「Cドライブのカレントフォルダのファイル数」となります。

放置機 さん 2004年 06月 04日 00時 52分 08秒

VBSでファイルを扱いたいのですが
WSH1.0ではFiles.Countでコレクションの数を取得できないのでしょうか。
WSH5.6で以下の様に書きますと、
Dim fso, folder, cnt
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder("C:")
cnt = folder.Files.Count
Msgbox cnt
これでcntにファイル数を得られますが、これをWindows95などで実行すると
cntは0にしかなりません。

魔界の仮面弁士 さん 2004年 06月 03日 22時 17分 35秒

[Microsoft Developer Deep Dive]に参加してきました。
残念ながら、Scriptネタはありませんでしたけど、
なかなか面白い(でも、難しすぎて眠い)話が聞けました。(^-^

》 管理人むたぐち さん
> この、:を使ったVBSのインデントは盲点というか、いいアイデアですね。
結構使えますね。とても面白いアイディアだと思います。

> :は内部的には改行と同等に扱われているんでしょうか。
全く同じというわけでは無さそうです。改行扱いだと、
 「If 式 Then ステートメント1: ステートメント2」
なコードの意味が変わってしまいますから。


ところで。
インデントの件ですが、cgi側の対応が無いとちょっと難しそうです。

HTMLの<pre>要素に相当する表示を、スタイルシートで対応させるとなると、
「white-space: pre」を指定する必要があるのですが、調べてみたところ、
これは、IE5.5以下では使えないそうです。

とりあえずIE6だけでも対応できれば…とも思ったのですが、
IE6の場合も、互換モードではなく、厳密モードのHTMLが必要に
なるそうなので、<head>〜</head>内しか手を出せないとなると、
これもNGという事になりそうです。

残るは、スクリプトでpreタグを挿入するという方法ぐらいでしょうか。

管理人むたぐち さん 2004年 06月 03日 19時 33分 47秒

返信は前ページのものから。


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

> ※こんなインデントはどうでしょう。スペースに置換する必要はありません。

この、:を使ったVBSのインデントは盲点というか、いいアイデアですね。
:は内部的には改行と同等に扱われているんでしょうか。
だとしたら実行速度などに悪影響もなさそうですし、
インデントが効かない掲示板にコードを貼る場合は有効に使えそうです。

# ただ、説明なしにやると、「なんじゃそりゃ?」って言われそうですが。


To: SUNY さん

> FileExistsメソッドってワイルドカード使用できないんですね。
> ファイルの存在チェックでそれに代わる関数ってあるのでしょうか?

そういった関数/メソッドはないので、自分で用意してやる必要があります。

まずFolderオブジェクトを取得して、そのFilesメソッドから
Filesコレクションを取得。
次にFor...Each...Nextで各Fileオブジェクトを取り出し、
各々のPathに対してFs.FileExistsメソッドを実行、その結果で
Fs.DeleteFileするようにするのが良いと思います。

ただし、ばんのしゃーによかばんた さん 2004年 06月 03日 14時 17分 53秒 も
おっしゃられてるように、この手の、対象のコレクション(この場合は
Filesコレクション)に要素を追加/削除を伴う作業をする際は、
>最初に別の配列に転写するなどして、静止画(snapshot)を取っておき、
>それを見ながら動的な変更を加える(削除する)。
のがいいです。
理由は、
>つまり、参照中のオブジェクトは、他者の操作によって、動的に変化するわけです。
>況んや、自分の操作をや。でんがな。
ですね。

私は、DictionaryオブジェクトのkeyにFile.Pathを格納して、
最後にDictionaryオブジェクトの全keyに対してFs.DeleteFileメソッドを
実行するようにしています。これだと安全です。
というか、Filesコレクションのループの中で、Deleteやリネームはご法度です(よね?)


ここからはこのページの返信。


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

> 私のお勧めの学習法は、この掲示板の過去ログを検索/読むことです。
>
> 検索は、過去ログを専用のディレクトリに格納しておき、分からないことはgrepする。

掲示板の特性上、情報がまとまってないのでまともに読むと大変ですが、
情報量はおかげさまで、かなりのものがありますので、
学習の役にも立つと思います。
(Wikiにまとめたい〜と思ってるんですが、中々あれですね…)

↑にリンクがありますが、HTAの検索スクリプトもGoogleもありますし、
使ってみてください。


検索といえば私は最近、namazuを使ってローカル検索できるようにしてるんですが、
最近のnamazuは、WordドキュメントやらPowerPointスライドやらPDFやら
mp3のID3タグやら、そんなものも検索対象にできてしまうんですねぇ。

http://www31.ocn.ne.jp/~h_ishida/xdoc2txt.html
で公開されている、xdoc2txtをnamazuのフィルタに使うと、
さらに一太郎ドキュメントなどマニアックなファイルも検索対象に
できてしまいます。

Windows付属のインデックスサービスよりよっぽど使えます。
導入するのは面倒ですけど、一度環境構築するとすごく便利です。

フロントエンドは、CGIで動くのがWin32版namazuに同梱されてますけど、
ここの掲示板の趣旨に沿ってこれを紹介しておきましょう。
Namazu Search
http://www.hi-ho.ne.jp/akios/namazu/
AKiOSさん作のIENamazuです。HTAで作られてます。

CGIで動く奴は、検索結果のWordなどのファイルをリンクから直接開くことができないので
(IEのセキュリティ上の問題だと思いますが、file:///c:/hoge.docなどが開けないんですね)、
私はIEの右クリックメニューに、「リンク先をローカルで開く」なるスクリプトを
登録して使っています。

これの中身は、ただ、リンク先を
external.menuArguments.event.srcElement.hrefで取得して、適当にパスを変換して、
WshShell.Runするだけのものですが、これでWordでもなんでも直接開けるように
なりました。

スクリプトってほんと、すばらしいもんですね〜

> window.Document.HasFocus()

げげ、そんなもんがあるんですか。


To: xo さん

> HTMLに書いて呼び出す場合、タイトルの所に”VBScript:”が入りますが
> これは消せませんか?

おそらくですが、消せないのではないかと思います。

これはクライアントスクリプトが、ユーザーにパスワードなどを入力させる
偽装ダイアログを出して、情報漏えいすることを防ぐための、
セキュリティ上の措置だと勝手に思ってますが、実際はどうなんでしょうね。

ActiveXやJavaが出すダイアログも、「スクリプトダイアログ」だの
「アプレットなんとか(忘れた)」のキャプションが付加されますしね。
そういうものなんではないでしょうか。

管理人むたぐち さん 2004年 06月 03日 18時 45分 23秒

Exact Audio Copy (EAC)というCDリッピング&ライティングソフトが
あるんですけど、それにWindows Media Encoder 9付属のWMCmd.vbsが
同梱されててびっくりしました(改良版とのことですが)。
ああいうのはいいんでしょうかねえ。

まあそれはともかく、WMCmd.vbsがまともに動作しない原因が判明しました。
結論を先に言うと、ヘルプが腐っていました。スクリプトは色々と変ですけど、
バグはなかったです。

ヘルプの使用例に、
cscript.exe wmcmd.vbs -adevice 1 -vdevice 4 -broadcast 8080 -duration 620
などと書いてあるんですが、よーーーく目を凝らしてみると、broadcastの前の
-(ハイフン)が微妙に変です。それだけUnicode文字になってるんですね。
(ここでは文字化けを防ぐため置換してるので、現物を参照してください。
ソースはShift_JISなのに、わざわざそこだけ&#0150;と指定してあります)

それをそのままコマンドプロンプトにコピーして実行したので、
うまくいかなかったわけですが、まあこんなところに落とし穴があるとは
思ってもみませんでした。

というわけで、みなさんも一見ANSIっぽいけど実はUnicodeな文字には
十分お気をつけください…。

             =-=-=-=-=

ここ最近、MS AgentやText-to-Speechの話がいくつか出てたので、
それ関係で注目の記事を一つ。

ITmediaニュース:“アニメ声”で自然にしゃべる音声合成技術、富士通が新開発
http://www.itmedia.co.jp/news/articles/0405/27/news022.html

自然で多様な喋り方をする音声合成技術を開発- FUJITSU Japan
http://pr.fujitsu.com/jp/news/2004/05/27.html

下の方のURLをたどると、サンプル音声があるんですが、結構いい線を
行ってると思いました。
日本語の音声合成でも、自然なイントネーションを実現しつつあるようで
今後が楽しみです。

おそらく、まずは業務用の端末の類に使われると思うんですが、
いつかデスクトップPCにも搭載される日が来ると思います。

xo さん 2004年 06月 03日 17時 52分 43秒

どなたかがMsgBox関数の事で質問されていましたね。細かい事ですが
お尋ね致します。

MsgBoxの使い方は

MsgBox "表示する文字列"、ボタン(番号ないし定数)、"タイトル文字列"、オプション等

が基本と思います。

HTMLに書いて呼び出す場合、タイトルの所に”VBScript:”が入りますが
これは消せませんか?



<html>
<head>
<script language = "VBScript"></script>
</head>
<body>

<form>
<input name = "Button1" Type = "Button" Value = "押してね" OnClick = 'MsgBox "こんにちわ", 0, "テスト"'>
</form>

</body>
</html>

実行するとタイトルは "VBScript: テスト" となります。

ばんのしゃーによかばんた さん 2004年 06月 03日 17時 35分 40秒

>管理人むたぐち さん 2004年 05月 18日 08時 09分 12秒
>http://www.roy.hi-ho.ne.jp/mutaguchi/bbs/list103.shtml
>ばんのしゃーによかばんた さん 2004年 04月 25日 16時 24分 29秒
>の記事を参考に、「他のフォルダを閉じる」スクリプトを作ってみました。
>WinXP用です。2000でも動くかも。
>If typename(window.document)="IShellFolderViewDual2" Then

汎用に書くと、

If InStr(typename(window.document),"IShellFolderViewDual") Then

ですね。Win98SEで確認しました。

>"IShellFolderViewDual2"のところを"HTMLDocument"にすれば、IE用も
>作れるかもしれません。

IEの場合は、window.Document.HasFocus() が使えるので、
こんな苦労をしなくても済みます。:-p

ばんのしゃーによかばんた さん 2004年 06月 03日 17時 34分 42秒

>MAKOTO さん 2004年 05月 26日 09時 48分 56秒
>早いこと、VBSの書籍を購入しに行ってきます。

ちょっと、待った!

私のお勧めの学習法は、この掲示板の過去ログを検索/読むことです。

検索は、過去ログを専用のディレクトリに格納しておき、分からないことはgrepする。

読むときは、ブラウザではなく、コンポーザ/HTMLエディタで読みながら、
自分の習熟レベルにとって既知で不要な記事/行を削除していきます。

何回か繰り返すと、有用な情報と未知の情報に凝縮されていきます。

これで、本数冊買ったのと同じか、それ以上になります。
というか、そんなにいい本がないのでは。。。

ばんのしゃーによかばんた さん 2004年 06月 03日 17時 33分 58秒

>魔界の仮面弁士 さん 2004年 05月 11日 22時 07分 55秒
>》 ばんのしゃーによかばんた さん
>> wscの場合に、
>> Private Sub Class_Initialize()
>> は、そのまま書けばよさそうですが、
>> Private Sub Class_Terminate()
>> に相当するものはないのでしょうか。
>うちでは、WSC内でクラスを定義しておき、それを利用しています。

それしかなさそうですね。

こういう書き方もできますね。

<?xml version="1.0" encoding="UTF-8"?><package>
<component>
<public>
<method name="MyMethod" />
</public>
<script language="VBScript"><![CDATA[Option Explicit
Dim C
Set C = New MainComponent
MsgBox CStr(Timer), vbInformation, "WSC_Initialize"

Public Sub MyMethod()
MsgBox CStr(Timer), vbOKOnly, "MyMethod"
End Sub

Class MainComponent
Private Sub Class_Terminate()
MsgBox CStr(Timer), vbExclamation, "Class_Terminate"
End Sub
End Class
']]></script>
</component>
</package>

ばんのしゃーによかばんた さん 2004年 06月 03日 17時 33分 12秒

>ばんのしゃーによかばんた さん 2004年 06月 03日 14時 19分 59秒
>Call [_SC].AddCode(String([_k],vbCRLF) & [_line] & vbCRLF & [_file].ReadAll())

解説の追加
- 改行を追加しているのは、Err行番号を実際のファイルの行番号に合わせるためです。

ばんのしゃーによかばんた さん 2004年 06月 03日 14時 19分 59秒

>kenji さん 2004年 05月 29日 12時 43分 01秒
>なおこのシステムを使用しているのはある専門図書館で来訪した方
>の資料検索に自由に使ってもらってます。
>色々考えたのですが、最初に教えて頂いた方式にエラー・トラップを
>組み合わせるようにしました。入力は各スクリプトのショート・カッ
>トをダブルクリックするのでエラーは起こりませんが、ネットワーク
>絡みのエラーが起きた場合に切り分けし易いようにエラーの概要をポ
>ップ・アップするようにしています。
>以下拙作ご覧下さい。
>On Error Resume Next

永年、腐海でバグハンターをやってた経験からしますと、
業務用としてはエラー処理の設計が甘いように思います。

個人用としても? 詳しくは以下の記事を参照願います。

>ばんのしゃーによかばんた さん 2004年 04月 10日 16時 13分 29秒
>On Error Resume Nextの正しい使い方について、

業務用の場合、切り分けに必要な情報を取って、ログなどに記録します。
※どんなエラーメッセージが出たか、正確な情報をユーザに求めるほうが間違い。
Err.Number
Err.Description
Err.Source
行番号
獲得しようとしたリソース名など、切り分けに必要な変数値

リソース名などが文字列で各行に書かれていれば、行番号だけで特定できますが、
配列や変数に入っていると、行番号だけでは、情報不足。

とは言ったものの、実装は自明ではありません。
つい最近の以下の記事を発展させてみました。

>ばんのしゃーによかばんた さん 2004年 05月 17日 17時 30分 34秒
>VBSriptを自動で実行した場合、エラーの情報をどうするか。

既存のVBScriptの前に以下のヘッダを付加します。'<!--から'-->まで。

'<!--
Option Explicit
Dim [_wShell],[_fso],[_SC],[_file],[_k],[_line],[_CO]
Set [_wShell]=CreateObject("WScript.Shell")
Set [_fso]=CreateObject("Scripting.FileSystemObject")
Set [_SC] = CreateObject("ScriptControl")
[_SC].Language = "VBScript"
Call [_SC].AddObject("WScript",WScript,True)
Set [_file]=[_fso].OpenTextFile(WScript.ScriptFullName)
Do While Not [_file].AtEndOfStream
[_line]=[_file].ReadLine()
If Left([_line],4)="'-->" Then
[_line]=Mid([_line],5)
Exit Do
End If
[_k]=[_k]+1
Loop
On Error Resume Next
Call [_SC].AddCode(String([_k],vbCRLF) & [_line] & vbCRLF & [_file].ReadAll())
On Error GoTo 0
[_file].Close
Set [_CO]=[_SC].CodeObject
If [_SC].Error.Number Then
[_wShell].LogEvent 1, _
WScript.ScriptFullName & vbTab & _
[_SC].Error.Line & vbTab & _
[_SC].Error.Column & vbTab & _
[_SC].Error.Description & vbTab & _
[_SC].Error.Text & vbTab & _
Hex([_SC].Error.Number) & vbTab & _
[_SC].Error.Source & vbTab & _
[_CO].remotename
MsgBox "スクリプト: " & WScript.ScriptFullName & vbCRLF & _
"行: " & [_SC].Error.Line & vbCRLF & _
"文字: " & [_SC].Error.Column & vbCRLF & _
"エラー: " & [_SC].Error.Description & vbCRLF & _
" " & [_SC].Error.Text & vbCRLF & _
"コード: " & Hex([_SC].Error.Number) & vbCRLF & _
"ソース: " & [_SC].Error.Source & vbCRLF & _
"x: " & [_CO].remotename , _
vbCritical+vbSystemModal,WScript.Name
End If
WScript.Quit
'-->Option Explicit
Dim remotename
Set wShell=CreateObject("WScript.Shell")
remotename="XXX"
y 'Error Raise
WScript.Quit

解説
- 既存のVBScriptにOption Explicitがある場合は、'-->の行に移します。
- 「'<!--」と「'-->」にシンタクス上の意味はありません。単に、ヘッダという感じを
出したかったのと、区切りとして適当な文字列が欲しかっただけです。
- [_〜]は既存のVBScriptとヘッダの変数名の衝突を避けるためです。
- CodeObjectは既存のVBScript側の変数をヘッダ側から参照するために使用しています。
- MsgBoxはWSHが出すものを真似ています。適当にカストマイズしてください。
- 既存のVBScript側では全般的なOn Error Resume Nextをしない。


ばんのしゃーによかばんた さん 2004年 06月 03日 14時 19分 00秒

似たようなシチュエーションを思い出しました。

昔、オブジェクトデータベース管理システム(ODBMS)を担当していたとき、
集合をスキャンするループの中では、インスタンスの削除が出来ない、
という仕様を聞いて、随分面倒臭いものだなぁ、と思ったものです。

では、どうするかと言うとスキャンループの中で、オブジェクトIDを覚えておいて、
ループを抜けてから、あらためて削除します。

更に、この処理論理も、
たくさんのshareロックを取ってから、更に一部のexclusiveロックを取るので、
多重処理環境では、デッドロックを頻発させやすい、という構造的問題を持っています。

したがって、この場合、スキャンと削除でトランザクションを分けます。
しかし、トランザクションを分けると、リソースロックが一旦外れるので、
他者が更新している可能性があり、削除トランザクション側で、
再度条件チェックが必要になります。

これで、完璧。

ばんのしゃーによかばんた さん 2004年 06月 03日 14時 17分 53秒

>kenji さん 2004年 05月 24日 09時 22分 49秒
>ようにしておけばまず問題は起こらないと思いますが、まず何らかの理由で
>マップが残った場合の処理を頭に付けようと考えました。
>Dim WshNet
>Set WshNet = WshNet("WScript.Network")
>Set objDrives = WshNet.EnumNetworkDrives
>For i = 0 to objDrives.Count -1 Step 2
>WshNet.RemoveNetworkDrive objDrives.item(i)
>Next
>何故かある時点で「パラメーターが違います。」というエラーを吐いてそれ
>以上マップを外せなくなり止まってしまいました。エラーコード 277801を

実際に試してないので、確かなことは言えませんが、

こういう場合、

For i = objDrives.Count -1 to 0 Step -2

としないといけない、或いは、少なくとも、としたほうがよい、のではないでしょうか。
ひょっとするとこれでもだめかも。

もっと、堅実には、
最初に別の配列に転写するなどして、静止画(snapshot)を取っておき、
それを見ながら動的な変更を加える(削除する)。
というのがよいのではないでしょうか。

例えば、FSOで、

Set fs=CreateObject("Scripting.FileSystemObject")
Set Folder=fs.GetFolder(".")
Count=Folder.Files.Count
Do
: : If Count<>Folder.Files.Count Then
: : : : WScript.Echo Count,Folder.Files.Count
: : : : Count=Folder.Files.Count
: : End If
: : WScript.Sleep 1000
Loop

或いは、Shellで、

Set fso=CreateObject("Scripting.FileSystemObject")
Set Shell=CreateObject("Shell.Application")
arg=fso.GetAbsolutePathName(".")
Set Folder=Shell.NameSpace(arg)
Count=Folder.Items.Count
Do
: : If Count<>Folder.Items.Count Then
: : : : WScript.Echo Count,Folder.Items.Count
: : : : Count=Folder.Items.Count
: : End If
: : WScript.Sleep 1000
Loop

とすると、精度はともかく、ファイル作成、削除が大抵、検出できます。
つまり、参照中のオブジェクトは、他者の操作によって、動的に変化するわけです。
況んや、自分の操作をや。でんがな。

FSOでFiles.Item()が数値インデクスを持たない背景には、
こういった理由があるのかも知れません。
えー? そこまで考えてる訳がないって? :-p

いりや さん 2004年 06月 03日 12時 34分 48秒

WonderWall さん、魔界の仮面弁士 さん、

UWSC という自動化ソフトウェアを使えば、例えばこんなスクリプトで、メモ帳の
テキストデータを取得できます。(Windows2000 で確認しています)

ご参考までにどうぞ。

// すでにメモ帳がたちあがっていてウインドウ内のテキストを取得する

windowID = GETID("無題 - メモ帳");
ifb windowID <> -1 then
    wholeText = ALL_ITEM_LIST[GETITEM(windowID, ITM_EDIT) - 1];
    MSGBOX(wholeText);
endif

// あらたにメモ帳をたちあげて、スクリプトで自動記入した内容を UWSC で取得し
// 表示する。表示後には、メモ帳を自動終了させる。

windowID = EXEC("notepad", false);
ifb windowID <> -1 then
    SENDSTR(windowID, "こんにちは<#CR>"); // スクリプトでテキスト入力
    SENDSTR(windowID, "ただいま試験中");
    wholeText = ALL_ITEM_LIST[GETITEM(windowID, ITM_EDIT) - 1];
    MSGBOX(wholeText); // ウインドウ内のテキストをダイアログで表示する
    CTRLWIN(windowID, CLOSE); // ダイアログを閉じると自動的にメモ帳も終了
    CLKITEM(windowID, "No");
endif

[ リンク ]

UWSC, うみうみ屋さん
http://www.h7.dion.ne.jp/~umiumi/

魔界の仮面弁士 さん 2004年 06月 03日 02時 39分 44秒

》 WonderWall さん
> WSHのGetObjectコマンドでメモ帳を読み込みたいのですが
> プログラムIDは何になるのでしょうか?

残念ながら、メモ帳自体は COMコンポーネントでは無いので、
GetObjectで直接制御する事はできません。

# DynamicWrapper や Excel を経由させて、APIで制御するとか、
# BASP21を使って、メモ帳に文字列を表示するぐらいはできますけれど…。

しかし、「メモ帳を読み込みたい」という質問の意図が、
「テキストファイルを読み込みたい」という意味であれば、
TextStreamオブジェクトを使って読み込む事ができます。
(この場合、GetObjectではなく、CreateObjectになりますけれどね)
http://www.microsoft.com/japan/msdn/library/ja/script56/html/jsmthreadall.asp

ばんのしゃーによかばんた さん 2004年 06月 02日 20時 27分 56秒

AndAlso/OrElseの新作です。Select Caseを使います。

※前作より、こっちがお勧めです。
※前作と新作の他にFor Nextを使った駄作もあります。:-p

' If x AndAlso y Then tt Else ff
Select Case False
Case x,y ff
Case Else tt
End Select

' If x OrElse y Then tt Else ff
Select Case True
Case x,y tt
Case Else ff
End Select

※OrElseの場合、x,yはBooleanであること。念の為、CBoolを被せておくとよいでしょう。
※AndAlsoの場合は、そんなに厳密でなくてよい。
※これは以下と同じ話です。要するに「Trueと比べるな」です。
○使用可 ×使用禁止
True
○If x Then
○If x<>0 Then
○If x<>False Then
○If Not x=0 Then
○If Not x=False Then
×If x=True Then
×If x=-1 Then
False
○If x=0 Then
○If x=False Then
○If Not x Then
×If Not x=True Then
×If Not x=-1 Then
×If x<>True Then
×If x<>-1 Then

WonderWall さん 2004年 06月 02日 17時 36分 22秒

WSHのGetObjectコマンドでメモ帳を読み込みたいのですがプログラムIDは何になるのでしょうか?御存知でしたら教えて頂けないでしょうか。

Return