ばんのしゃーによかばんた さん 2004年 11月 19日 15時 59分 40秒

VBScriptでCollection

>管理人むたぐち さん 2003年 07月 01日 17時 59分 07秒
>もっとも、Classステートメントでは無理そうだが、もしかするとWSCなら可能なのかも
>しれない。というのも、WSCでは<method name="methodName" dispid=dispID>のように、
>dispIDを指定することができるからだ。もっとも、DictionaryオブジェクトでFor Each...Next
>した際に返って来るのはKeyのセットなので、clsCollectionのようにValueの方に
>オブジェクトを入れるのではなく、Keyにオブジェクトを入れなきゃならないが(できるのか?)。
>うん、何か大きな勘違いをしてなければ、できそうだぞ。これ、後で試してみよう)

これは、その後、どうなりましたでしょうか。

で、試してみました。

Collect.WSC
――――――――――――――――――――――――――――――――――――――
<?xml version="1.0" encoding="UTF-8"?><package>
<component>
<public>
<method name="Item" dispid="0" />
<method name="_NewEnum" dispid="-4" />
<method name="Add" />
<property name="Count" />
</public>
<script language="VBScript"><![CDATA[

Option Explicit
Private dic,dic2
Public Count
Set dic=CreateObject("Scripting.Dictionary")
Set dic2=CreateObject("Scripting.Dictionary")
Count=0

Public Sub Add(value)
dic.Add Count,Value
dic2.Add Value,Count
Count=Count+1
End Sub

Public Function Item(ind)
Item=dic.Item(ind)
End Function

Public Function [_NewEnum]()
[_NewEnum]=dic2.[_NewEnum]
End Function

']]></script>
</component>
</package>
――――――――――――――――――――――――――――――――――――――

Collect.VBS
――――――――――――――――――――――――――――――――――――――
Set fso=CreateObject("Scripting.FileSystemObject")
Set col=GetObject("script:" & fso.GetAbsolutePathName("collect.wsc"))
WScript.Echo TypeName(col)
col.Add("A")
col.Add("B")
WScript.Echo col.Count
For Each m In col
WScript.Echo m
Next
For k=0 To col.Count-1
WScript.Echo col(k)
Next

ばんのしゃーによかばんた さん 2004年 11月 19日 15時 58分 49秒

VBScriptのMsgBoxなどの関数をTLBINF32などを使って、
dispid(?)指定で呼び出すことはできないでしょうか。

魔界の仮面弁士 さん 2004年 11月 19日 15時 42分 18秒

》 say さん
> 一つ質問ですが
> >Function Proc()
> >::Dim A(0)
> >::A(0) = "あ"
> >::Proc = A
> >End Function
> のスコープ解決子(::)ってVBSで出来るんですか?文の区切り?

スコープ解決子ではなく、ステートメントの区切りの「:」です。

この掲示板では、空白やタブが潰れてしまうため、インデントの
替わりに利用しています。JScriptなら ; ですかね。

(この方法を使いだした載って、ばんのしゃーによかばんたさんでしたっけ?)

say さん 2004年 11月 18日 22時 51分 15秒

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

多分私へのコメントだと思ったので、感謝。
Constの扱いって変ですよね。Constなのに
配列サイズ指定とかに使えないなんて(インタープリタの
気持ちはわからんでもない)。

ただいま &h8000と&h8001~&hffff の扱いに激怒中。

COM調べてる間に「時代に取り残されてるなぁ」と痛感し、
私も MS様の戦略に乗ってあげようと .NET Framework SDK を
いざインストール!、しようと思ったら Win98 非対応の
つれないお言葉が…ロートルには冷たいWindow(s)

ばんのしゃーによかばんた さん 2004年 11月 18日 19時 49分 56秒

>管理人むたぐち さん 2004年 11月 17日 20時 50分 55秒
>AYAさんがJScript.NETの講座を始められたのは、.NET Framework SDKに含まれる
>JScript.NETに含まれるコンパイラがタダで利用できるからかと思ってたくらいですよ、私。

それは知っていたのですが、
JScriptの仕様はOpenなので、無償提供。
VBはプロプライアタリなので、有償提供。
と当然の如く思い込んでいました。思い込みは損ですね。

>管理人むたぐち さん 2004年 11月 17日 22時 30分 06秒
>今回は11取れなかったんですけどね。

11 って0011 ナポレオンソロの11? ※そればっかり。

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

>ばんのしゃーによかばんた さん 2004年 11月 14日 15時 13分 52秒
>>管理人むたぐち さん 2004年 11月 04日 16時 53分 35秒
>>UTF-8を扱っていて一番困るのが、チルダ" ~ "と"〜"です。
>>これらの文字は、同一文字として扱われるようで、他の文字コードに変換したり
>>すると、"?"などに化けてしまうのです。
>>URLなどで頻出の文字なので、とても困ります。
>これは、確認できませんでした。
>ASCIIの7Eは,
>charset=shift_jisで見ると、チルダが上に張り付いて見えますが、
>charset=ISO-8859-1で見ると、真ん中に見えます。
>これが、半角/全角共通の〜(&#65374;%uFF5E)に似てはいますが、
>別のコードで区別されています。
>?に化けるのは、〜(&#65374;%uFF5E)でしょうか。

似た現象に遭遇しました。これです。

> ?.CGI自身か、それのあるフォルダは、実行はできるけれど、read openは出来ない、
> というようなアクセス権になっているのでは、ありませんか。

シフトJIS全角の〜は、ネスケでも同じ〜に見えますが、これをクリップボードに
コピーすると、波型(&#12316;%u301C)に化けます。
これをメモ帳に貼り付けてシフトJISで保存すると、?に化けます。
シフトJIS→Unicode変換処理の障害ですが、誰の処理でしょうね?

ASCIIの7Eについては、まだ。

ばんのしゃーによかばんた さん 2004年 11月 18日 19時 48分 52秒

For ...
...
Const adTypeText=2
...
Next

も二重定義エラーになりました。

※こういうのって、ちゃんと書いといて欲しいですね。

たくや さん 2004年 11月 18日 19時 44分 21秒

To: 管理人むたぐちさん&みなさん

助言いただき、ありがとうございました。

たんぼ さん 2004年 11月 18日 14時 29分 11秒

むたぐちさん助言ありがとうございます。
MSDNを参考にやってみたのですが、駄目でした。
すみませんが、どこか間違いがあったら教えていただけないでしょうか?

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

const HKEY_CURRENT_USER = &H80000001
strComputer = "."
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
strKeyPath = "Software\Microsoft\Windows\ShellNoRoam\MUICache\C:\Windows\a.exe"
oReg.DeleteKey HKEY_CURRENT_USER, strKeyPath

MsgBox("finish")
Wscript.quit

mmm さん 2004年 11月 18日 10時 55分 05秒

早速ありがとうございます。
試してみました。
wscript.exe delfol.vbs フォルダ1 [フォルダ2...]
上記の部分を特定のフォルダでdeleteを実行するので、スクリプト内に組み込めれば完璧になりそうです。
色々取り組んでみたいと思います。
何か良い方法がありましたら、また教えてください。
よろしくお願いいたします。

-----------------------------
このスクリプトでは、再帰呼び出しを上手く使うのがポイントです。

'中身のないフォルダの削除
'使い方 wscript.exe delfol.vbs フォルダ1 [フォルダ2...]
'フォルダを指定すると、そのサブフォルダのうち、空のサブフォルダを削除します。
'もしさらにその下の階層も空なら削除します。

Set WshShell = WScript.CreateObject("WScript.Shell")
Set Fs = WScript.CreateObject("Scripting.FileSystemObject")
iDel=0 : iLeft=0

For Each sArg In WScript.Arguments
If Fs.FolderExists(sArg) Then
DeleteFolder Fs.GetFolder(sArg)
End If
Next

Sub DeleteFolder(oFolder)
For Each oSubFolder In oFolder.SubFolders
DeleteFolder oSubFolder
Next
If oFolder.Files.Count=0 And oFolder.SubFolders.Count=0 Then
oFolder.Delete
iDel = iDel + 1
Else
iLeft = iLeft+1
End If
End Sub

sMsg = iDel & "個の空フォルダを削除しました。"

If iLeft<>0 Then
sMsg = sMsg & vbCrLf & iLeft & "個のフォルダは空ではないです。"
End If
MsgBox sMsg

say さん 2004年 11月 18日 01時 40分 16秒

魔界の仮面弁士 さん へ


いつもどうもです。

>本的には、IDispatchEx が使われるのではないでしょうか。
>それが利用できない時に IDispatch になるという事で。

教えていただいた参考資料を元にSDKを見たらそのようでした。念の
ためオブジェクト変数にはいってるアドレスからVTbl見ると自前の
オブジェクトおよび関数はInvokeのアドレスが全部同じでした(あたりまえ)。

>あれ? 宣言場所によって宣言されていない事になる…?
>具体例を教えていただけないでしょうか。ちょっとイメージが浮かびません

これはグローバル配列変数のDimをいろんなところに書くという意味です。
C++でコードブロック({…})の先頭にだけ宣言が許されてブロックだけ
有効な変数がありますがあれと同じようなことをするのです。VBSでは
入れ子のスコープがないので何をしようがスコープは変わらないのですが
見やすくなります。それでたとえばこうするとエラーです。

Option Explicit
Dim i
For i=0 to 10
Dim a(10) ' <- 二重定義エラー
For j=0 to 10
a(j)=...

ところが これは配列だからであって、次のようだとエラーは出ませんし
単純変数jの初期化だって当然しません。

Option Explicit
Dim i
For i=0 to 10
dim j
For j=0 to 10
...


「宣言場所で宣言されていない事になる」というのは次のようなやつです。

'***vvv Start Of Prog.
Option Explicit

For i=0 to 10 ' <− No Error
a(i)=0 ' <− 未宣言エラー
Next

Dim i
Dim a(10)
'***^^^ End Of Prog.

ソースも挙動も見るからに変ですが、グローバルスコープに宣言した
単純変数はOKです、でも配列はダメ、って宣言になってないじゃん、
ということです。こんなソース書かないと思われるかもしれませんが
ソースを分割してインクルードする時にこうなる可能性が高いです。
なにより困るのはこれを明示的に実行するプログラムはC++に変換する
とき配列をSafeArray以外に変換できそうにないことです。

VBSの記事がSDKに書かれていることを今日初めて知りました。読んでみたら
Dimはなるべくソースの最初に書くように とありました。副作用は書いて
なさそうでした

>配列の括弧と、関数呼び出しの括弧は混同しやすいですね…。

多分QuickBasicの名残が受け継がれたのでしょうが、せめて配列を[]に
してくれれば 実行中の変数型を見る必要がなくなるので字面だけでの
変換つまりはVARIANTやSafeArray使わなくて済むのですがねぇ。
あ、これでもコレクションと配列の違い(For…Each)は解決しないか、はぁ…

型チェックのソースは似たようなやつを私も書きました。VBSって日々
発見だぁ。Integer(VT_I2?)が基本で、&hがUnsignとは今まで気が
つかなかった。&H定数とLongのビット演算挙動が変だったわけが
なんとなくつかめた。

一つ質問ですが

>Function Proc()
>::Dim A(0)
>::A(0) = "あ"
>::Proc = A
>End Function

のスコープ解決子(::)ってVBSで出来るんですか?文の区切り?


(管理人により削除) さん 2004年 11月 18日 01時 25分 28秒
URL:http://

(管理人により削除)

管理人むたぐち さん 2004年 11月 17日 22時 30分 06秒

そういえば、2ch Windows板のWSHスレがPart4に突入していました。

お前ら、wsh使ってますか? Part4
http://pc5.2ch.net/test/read.cgi/win/1100489339/

今回は11取れなかったんですけどね。
Part3(現在DAT落ち状態で不可視)のミラー、うちでしといた方がいいかな?

管理人むたぐち さん 2004年 11月 17日 20時 50分 55秒

To: ばんのしゃーによかばんた さん 2004年 11月 17日 20時 11分 25秒

> いえいえ、Unixのexec()は、
> exec(Xpath,Xargs...)
> で呼ばれると、実行ファイルXpathの先頭を見て、
> #! Ypath Yargs...
> なら、
> exec(Ypath,Yargs...,Xpath,Xargs...)
> として実行します。

そうなんですけど、それはUNIXのシェルスクリプトやPerlやRuby等のスクリプト言語の
コメント行がすべて # であるからそういう実装になっているのであって、
言語(vbs, js, bat…も一応)によってコメント行の形式が違うWindows Scriptでは
一行目のYpath Yargsを取得した後は、そこを読み捨てして実行するような
仕様にしてあるんじゃないかなーと勝手に思っているんですが、どうでしょうか。
(そうじゃないと、AnHTTPDが内部的に持っている #!という値を、スクリプト系によって
いちいち変更しなきゃならなくなりますよね、ご指摘のとおりですけど)

まあ実際のところは、作者さんに聞いてみないと分からないかもです。

> 〜.CGI自身か、それのあるフォルダは、実行はできるけれど、read openは出来ない、
> というようなアクセス権になっているのでは、ありませんか。

あ、なるほど、その可能性はありますね。
CGIが動くアカウントでは、フォルダかファイルに実行属性がないのかも。
後ほど検討してみます。


To: ばんのしゃーによかばんた さん 2004年 11月 17日 20時 12分 21秒

> えー、そうだったのですか。VB.NETは、買わないと使えないのかと思って、
> VB.NET Standardを買って、1年近くなりますが、インストールしたまんまです。

えー、むしろご存知でなかったのが驚きです。
AYAさんがJScript.NETの講座を始められたのは、.NET Framework SDKに含まれる
JScript.NETに含まれるコンパイラがタダで利用できるからかと思ってたくらいですよ、私。

http://homepage3.nifty.com/aya_js/JScript.NET/index.htm

さっき上げたEmEditor4のマクロも、SDKさえあればちゃんと使えるはずです。

管理人むたぐち さん 2004年 11月 17日 20時 37分 17秒

To: たんぼ さん

> を含まない項目だと成功するのですが、:を含む項目だとどうしても成功しません。
> ""や"でくくったりしたのですが、駄目です。
> この様な場合にレジストリを削除するにはどうしたらよいのでしょうか?

: を含むというより、むしろ \ を含む項目が削除できないんじゃないでしょうか?
つい最近、同様の報告例があったと思います。
WMIのStdRegProvクラスを使う方法を検討してみてください。


To: たくや さん

> JavaScriptで値を保存するのに
> WSHでレジストリを読み書きするのではなく、
> WINAPIの
> GetPrivateProfileString
> WritePrivateProfileString
> などを利用して
> 初期ファイルの読み書きができればと考えているのですが、

WSH Page 1
http://www.borncity.de/WSHBazaar/WSHDynaCall.htm

ここにあるDynaCallを使えばできると思います。
ちょうどGetPrivateProfileStringがサンプルとして挙がっていますね。

iniを読み書きするクラスを実装したWSCやCOMコンポーネントを使うのもいいかもしれません。
ちょっとすぐURLを出せないですが、探せばきっとあります。


To: mmm さん

> 作成したいスクリプトは、ファイルやフォルダを削除するのですが、以下の条件があります。
> 例えば、d:\testというフォルダ内のサブフォルダの中に、サブフォルダやファイルがないかを判断して、ファイルもサブフォルダもない場合は、そのサブフォルダを削除するというようなスクリプトを作成しています。

まったく同じものを自作して使ってますので、ここに載せておきますねw
こういうのをSendToにいくつか登録していると、エクスプローラがすごーく便利になります。
この手の未公開スクリプト、結構溜まってるんですよね実は。

このスクリプトでは、再帰呼び出しを上手く使うのがポイントです。

'中身のないフォルダの削除
'使い方 wscript.exe delfol.vbs フォルダ1 [フォルダ2...]
'フォルダを指定すると、そのサブフォルダのうち、空のサブフォルダを削除します。
'もしさらにその下の階層も空なら削除します。

Set WshShell = WScript.CreateObject("WScript.Shell")
Set Fs = WScript.CreateObject("Scripting.FileSystemObject")
iDel=0 : iLeft=0

For Each sArg In WScript.Arguments
If Fs.FolderExists(sArg) Then
DeleteFolder Fs.GetFolder(sArg)
End If
Next

Sub DeleteFolder(oFolder)
For Each oSubFolder In oFolder.SubFolders
DeleteFolder oSubFolder
Next
If oFolder.Files.Count=0 And oFolder.SubFolders.Count=0 Then
oFolder.Delete
iDel = iDel + 1
Else
iLeft = iLeft+1
End If
End Sub

sMsg = iDel & "個の空フォルダを削除しました。"

If iLeft<>0 Then
sMsg = sMsg & vbCrLf & iLeft & "個のフォルダは空ではないです。"
End If
MsgBox sMsg

ばんのしゃーによかばんた さん 2004年 11月 17日 20時 12分 21秒

>あんのうん さん 2004年 11月 15日 01時 23分 45秒
>のアプリをVB.NETで書いて、.NET FRAMEWORK付属(無料)のコマン
>ドラインVBコンパイラでコンパイル後、*.SCRとリネームして使っ
>た覚えがあります。

えー、そうだったのですか。VB.NETは、買わないと使えないのかと思って、
VB.NET Standardを買って、1年近くなりますが、インストールしたまんまです。
買うことなかったのかな。MSDNライブラリは十分使ってますが。。。

>管理人むたぐち さん 2004年 11月 15日 20時 52分 20秒
>To: あんのうん さん
>> 単純に「Wscript.exe *.vbs 渡されたパラメータ」をShellキック
>> するexeを作り、*.cgiにリネームというのはどうでしょう?
>ええ、標準入出力や環境変数を子プロセスにちゃんと渡せないので
>駄目っぽいですね。

やっぱり、CreateProcessですかね。
そこで。※なぜか、JScript.NET。

import System
import System.IO
import System.Diagnostics

var Args : String[]=Environment.GetCommandLineArgs();
var sName=Args[0];
if(sName.charAt(sName.length-4)!='.'){throw 'Erroneous file name';}
sName=sName.substr(0,sName.length-4) + '.VBS';
var args = new Array();
args.push(sName);
for(var k=1;k<Args.length;k++){
args.push(Args[k]);
}
var proc : Process = new Process();
var startInfo : ProcessStartInfo = new ProcessStartInfo('CScript.EXE');
startInfo.UseShellExecute = false;
startInfo.Arguments=args.join(' ');
proc.StartInfo = startInfo;
proc.Start();

proc.WaitForExit();
proc.Close();

※話変わって、子プロセスの標準出力と標準エラーを安全にパイプで取り出すには
スレッドを使うしかないのかなぁ。Unixだと、unblocked read(?)とかで、
バッファにデータがないとread()が長さ0で帰って来るのだけれど。。。
Peekが使えるかと思ったけれど、blockされるし。
unblocked read(?)とか、ないのかなぁ。
或いは、listen()のような、データの有無を調べるような機能はないのかなぁ。

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

>管理人むたぐち さん 2004年 11月 16日 14時 34分 23秒
>いえ、さすがにそこまで融通の利かない実装はされてないでしょう。
>つまり、まず#!の行を読み取って、その次の行からをcscriptに渡している、はずです…。

いえいえ、Unixのexec()は、
exec(Xpath,Xargs...)
で呼ばれると、実行ファイルXpathの先頭を見て、
#! Ypath Yargs...
なら、
exec(Ypath,Yargs...,Xpath,Xargs...)
として実行します。

OSにこういう機能がない、Windowsの場合、アプリ側、AnHTTPDで代行します。
そのとき、本家と異なる実装をするとは、考えにくいです。

メッセージの違いですが、
[A]Microsoft VBScript コンパイル エラー: ステートメントがありません。
[B]Windows Script Host の実行に失敗しました。 (この操作を完了するのに十分な記憶域がありません。 )

アクセス権の問題でファイルを読み込めないるときは、[B]。
ファイルを読み込めるときは、[A]。
ではないか、と思います。したがって、問題は二つあって、両方直さないと駄目。

〜.CGI自身か、それのあるフォルダは、実行はできるけれど、read openは出来ない、
というようなアクセス権になっているのでは、ありませんか。

Unixにおいても、#!のスクリプトファイルはxとrの両方の権限を付けないと
いけなかったです。

ばんのしゃーによかばんた さん 2004年 11月 17日 20時 10分 35秒

>kuroneko さん 2004年 11月 17日 13時 37分 25秒
>10件データ処理を行なったら10件目、15件行なったら15件目に

処理が1件ずつ逐次化されていないのではありませんか。
処理の起動方法を見直してみては。

もし、Notesの仕様か何かで、処理の逐次化ができないようなら、
この方式は諦めて、むたぐちさん推奨の方法に乗り換えるしかないかと。

mmm さん 2004年 11月 17日 17時 41分 52秒

いつも質問に回答いただきまして、ありがとうございます。
wsh初心者のため色々つまづいております。

作成したいスクリプトは、ファイルやフォルダを削除するのですが、以下の条件があります。
例えば、d:\testというフォルダ内のサブフォルダの中に、サブフォルダやファイルがないかを判断して、ファイルもサブフォルダもない場合は、そのサブフォルダを削除するというようなスクリプトを作成しています。

ファイルをカウントしたり、if exsitsを利用してフォルダの有無を確認し、それぞれ、trueだった場合はflgを立てるなどしてみたのですが、どうもうまくいきません。

何か良い方法がありましたら、伝授いただけますか?
よろしくお願いいたします。

たくや さん 2004年 11月 17日 16時 15分 19秒

JavaScriptで値を保存するのに
WSHでレジストリを読み書きするのではなく、
WINAPIの
GetPrivateProfileString
WritePrivateProfileString
などを利用して
初期ファイルの読み書きができればと考えているのですが、
方法があれば教えていただけませんか?

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

たんぼ さん 2004年 11月 17日 15時 49分 13秒

レジストリの項目の削除の方法について教えてください。

レジストリを削除しようとしているのですが、
Dim WSHShell
Set WSHShell = WScript.CreateObject("WScript.Shell")
WSHShell.Regdelete "HKCU\Software\Microsoft\Windows\ShellNoRoam\MUICache\C:\WINDOWS\notepad.exe"
Wscript.Quit

では失敗してしまいます。メモ帳は開いていませんし管理者権限です。
:を含まない項目だと成功するのですが、:を含む項目だとどうしても成功しません。
""や"でくくったりしたのですが、駄目です。
この様な場合にレジストリを削除するにはどうしたらよいのでしょうか?

管理人むたぐち さん 2004年 11月 17日 15時 05分 32秒

*.cs, *.vb, *.jsをコンパイルして実行するEmEditor4のマクロ。
コマンドラインオプションを選択すると、そのオプションをつけて
コンパイルして、生成したexeを実行してくれます。

たとえば*.vbなら、'/r:System.Windows.Forms.Dll /t:winexe
のように記述しておき、その行を選択した状態でマクロを実行すると、
vbc.exe /r:System.Windows.Forms.Dll /t:winexe /out:...
が実行されます。

文字列を選択しない場合はsDefaultArgumentsをオプションとしてつけます。
文字列を選択してても、/*:*のような文字列が含まれていなければ
オプションなしでコンパイラを実行します。

cmd.exe /k をつけているのは、コンパイラが出すエラーを表示した直後に
コマンドプロンプトが閉じるのを防ぐためです。
実際にコンパイルしたファイルが実行されるのは、コンパイラの出力結果
が表示されるコマンドプロンプトの窓を閉じてからです。
これが手間だと思われる方は、cmd.exe /kを省略してください。

'*.cs, *.vb, *.jsをコンパイルして実行
Set regEX = New RegExp
regEx.Global = True
regEX.IgnoreCase = True
Set Fs = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")

sCompilerDir = "C:\windows\Microsoft.NET\Framework\v1.1.4322\"
sDefaultArguments = "/t:winexe"
sSourcePath = Document.FullName
sEXEPath = Fs.BuildPath(Fs.GetParentFolderName(sSourcePath),Fs.GetBaseName(sSourcePath) & ".exe")
sExt = LCase(Fs.GetExtensionName(sSourcePath))

Document.Save sSourcePath 'ソース保存

Select Case sExt
Case "vb" : sCompilerPath = sCompilerDir & "vbc.exe"
Case "cs" : sCompilerPath = sCompilerDir & "csc.exe"
Case "js" : sCompilerPath = sCompilerDir & "jsc.exe"
Case Else : sCompilerPath = ""
End Select

Set sel = Document.Selection

If sel.IsEmpty Then
sArguments = sDefaultArguments
Else
regEx.Pattern = "\s?(\/[^\:]+\:\S+)\s?"
If regEx.Test(sel.Text) Then
For Each oMatch In regEx.Execute(sel.Text)
sArguments = sArguments & oMatch.SubMatches(0) & " "
Next
Else
sArguments = ""
End If
End If

If sCompilerPath="" Then
Alert sExt & "ファイルに対応するコンパイラがありません。"
Else
sCommandLine = "cmd.exe /k " & sCompilerPath & " " & _
"/out:" & """" & sEXEPath & """" & " " & sArguments & " " & _
"""" & sSourcePath & """"
WshShell.Run sCommandLine ,,True 'コンパイル実行
If Fs.FileExists(sEXEPath) Then
WshShell.Run sEXEPath,,True 'コンパイルしたファイルを実行
Else
Alert "コンパイルに失敗したようです。"
End If
End If

kuroneko さん 2004年 11月 17日 13時 37分 25秒

助けてください。切羽詰ってます!!

ばんのしゃーによかばんた さん。
いつもお世話になっております。kuronekoです。
以前投稿いたしましたIEを閉じる件は何とかできましたが
ばんのしゃーによかばんた さんに教えていただきました
IEのソースをテキストに保存するスクリプトで
10件データ処理を行なったら10件目、15件行なったら15件目に
WSHのエラーが表示されます。
これはいったいどういう意味なのでしょうか?

どうかご教授お願いいたします。

エラー内容
行19
文字1
エラー エラー内容を特定できません。
コード 80004005
ソース (null)
です。

スクリプトは
Option Explicit
Dim fso
Dim wShell
Dim Shell
Dim ie
Dim File
Dim TempName
Dim IEApp

Set fso=CreateObject("Scripting.FileSystemObject")
Set wShell=CreateObject("WScript.Shell")
Set Shell=CreateObject("Shell.Application")

Set ie=Shell.Windows.Item
If ie Is Nothing Then
WScript.Echo "No IE Found."
WScript.Quit
End If
If TypeName(ie.Document)<>"HTMLDocument" Then
WScript.Echo "IE is not active."
WScript.Quit
End If

TempName=fso.BuildPath(fso.GetSpecialFolder(2).Path,fso.GetTempName())
'Set File=fso.CreateTextFile("AAA.txt")
Set File=fso.CreateTextFile("C:\Docume~1\Administrator\デスクトップ\AAA.txt")

File.Write ie.Document.documentElement.outerHTML
File.Close
'Call wShell.Run("NotePad.Exe " & "AAA.txt",,True)
'fso.DeleteFile "AAA.txt"

WScript.Sleep 1000
ie.Quit

以上 宜しくお願いいたします。

魔界の仮面弁士 さん 2004年 11月 17日 11時 51分 52秒

》 魔界の仮面弁士 さん 2004年 11月 17日 11時 44分 54秒
しまった。修正前のバグソースを貼ってしまった…。

すみません、貼りなおします。


Option Explicit
Dim Var1
Dim Var2(0)

Set Var1 = GetRef("Proc")
Set Var2(0) = GetRef("Proc")

MsgBox "メソッドの呼び出し(括弧を省略)", vbInformation
MsgBox TypeName( Proc ) '"Variant()"を返す
MsgBox TypeName( Var1 ) '"Object"を返す
MsgBox TypeName( Var2(0) ) '"Object"を返す

MsgBox "メソッドの呼び出し(括弧あり)", vbInformation
MsgBox TypeName( Proc() ) '"Variant()"を返す
MsgBox TypeName( Var1() ) '"Variant()"を返す
MsgBox TypeName( Var2(0)() ) '"Variant()"を返す

MsgBox "戻り値の配列から、0番目の値を取得", vbInformation
MsgBox Proc()(0) '"あ"を返す
MsgBox Var1()(0) '"あ"を返す
MsgBox Var2(0)()(0) '"あ"を返す

'これらは、0x800A01C2のエラーになる
'『引数の数が一致していません。または不正なプロパティを指定しています。』
'MsgBox Proc(0) 'エラー:0x800A01C2『引数の数が〜』
'MsgBox Var1(0) 'エラー:0x800A01C2『引数の数が〜』
'MsgBox Var2(0)(0) 'エラー:0x800A01C2『引数の数が〜』


MsgBox "標準的な関数呼び出し"
Proc() '正常
Proc '正常
Call Proc() '正常
Call Proc '正常

MsgBox "GetRefを変数に格納してからの呼び出し"
Var1() '正常
Var1 '正常
Call Var1() '正常
Call Var1 '正常

MsgBox "GetRefを配列に格納してからの呼び出し"
Var2(0)() '正常
'Var2(0) 'エラー:0x800A000D『型が一致しません。』
Call Var2(0)() '正常
'Call Var2(0) 'エラー:0x800A000D『型が一致しません。』


Function Proc()
::Dim A(0)
::A(0) = "あ"
::Proc = A
End Function

魔界の仮面弁士 さん 2004年 11月 17日 11時 44分 54秒

》 say さん
> 以前こちらで書いたようにVBSをC++に機械的に変換するため
すみません、それはいつの投稿でしょうか?

# 最近ここに来ておらず、過去ログは流し読みしかしていなかったので、
# あまり質問の内容を把握できていません。反省。


> VBSは関数呼び出しをすべてIDispatchで行ってると勘ぐって、
基本的には、IDispatchEx が使われるのではないでしょうか。
それが利用できない時に IDispatch になるという事で。


> まさかグローバルの配列宣言が宣言場所によって宣言されてないことになるとわ
あれ? 宣言場所によって宣言されていない事になる…?
具体例を教えていただけないでしょうか。ちょっとイメージが浮かびません。


> 変数の現在の型をみないと配列と区別出来ないんでちょっと困った
配列の括弧と、関数呼び出しの括弧は混同しやすいですね…。
「配列を返す関数」をGetRefで配列変数に入れたりすると、大混乱。(^_^;)


'========================
Option Explicit
Dim Var1
Dim Var2(0)

Set Var1 = GetRef("Proc")
Set Var2(0) = GetRef("Proc")

MsgBox "メソッドの呼び出し(括弧を省略)", vbInformation
MsgBox TypeName( Proc ) '"Variant()"を返す
MsgBox TypeName( Var1 ) '"Object"を返す
MsgBox TypeName( Var2(0) ) '"Object"を返す

MsgBox "メソッドの呼び出し(括弧あり)", vbInformation
MsgBox TypeName( Proc() ) '"Variant()"を返す
MsgBox TypeName( Var1() ) '"Variant()"を返す
MsgBox TypeName( Var2(0)() ) '"Variant()"を返す

MsgBox "戻り値の配列から、0番目の値を取得", vbInformation
MsgBox Proc()(0) '"あ"を返す
MsgBox Var1()(0) '"あ"を返す
MsgBox Var2(0)()(0) '"あ"を返す


'これらは、0x800A01C2のエラーになる
'『引数の数が一致していません。または不正なプロパティを指定しています。』
'MsgBox Proc(0)
'MsgBox Var1(0)
'MsgBox Var2(0)(0)

'これらは、正常に処理される。
Proc()
Proc
Call Proc()
Call Proc

'0x800A01C2『引数の数が一致していません。または不正なプロパティを指定しています。』
'Var1(0)()
'Var1(0)
'Call Var1(0)()
'Call Var1(0)

'0x800A000D『型が一致しません。』
'Var2()
'Var2
'Call Var2()
'Call Var2

Function Proc()
::Dim A(0)
::A(0) = "あ"
::Proc = A
End Function

管理人むたぐち さん 2004年 11月 17日 09時 56分 09秒

そもそもなんで*.cgiというファイル名にこだわったかという理由を
言ってなかった気がしますね。

実はこれ、2chブラウザで書き込みができるようにするためには、
ファイル名がbbs.cgiでないと駄目だからという、
とても小さな理由だったりします。
それがまさかこんな大掛かりなネタに発展するとは。

管理人むたぐち さん 2004年 11月 17日 09時 48分 54秒

と、もっともらしく言ってる割には、結局は普通の2ch互換スクリプトじゃん、
車輪の再発明じゃん、と言われそうですが、
これはWindows標準機能だけですべてを構築しているところがエライのです。
HTTPDだけは標準機能じゃないですが、IISでも動作するはずですし。

それと、無駄に色んな技術を惜しげもなく投入しているところが
痺れませんか?

管理人むたぐち さん 2004年 11月 17日 09時 14分 46秒

紆余曲折を経て、WSHBBS、ついに完成しました。
http://librage.mine.nu:2424/wshbbs/wsh/index.html

いろいろレスしたりスレッドとか立てて遊んでくださって結構です。

内部的には、「ダウンロード」のページで公開しているWSHBBSに
若干の修正を加えたものに、ばんのしゃーによかばんたさんの
vbs2js.vbsでJScript.NETのコード(内部的にはScriptControlで
VBScriptを実行している)に変換したものを、
jsc.exeでコンパイルしたものを、*.cgiにリネームしたものです。

なんだか訳が分からなくなりそうですが、ともかく動作します。

say さん 2004年 11月 17日 01時 13分 18秒

魔界の仮面弁士 さん

どうもたびたびのご回答ありがとうございます。

>正直なところ、何をお聞きになりたいのか、よくわかっていません。(汗)

以前こちらで書いたようにVBSをC++に機械的に変換するためVBSの挙動を
知りたかったのです。通常の言語なら関数呼び出しは字面を見ただけで
理解できるようにしてあるので、VBSは関数呼び出しをすべてIDispatchで
行ってると勘ぐって、それならメンバ名をどう取得してるか知りたかったのです。
返答を書いた後になってようやくこれがVBSの言語仕様なんだと気が
つきました。要するにメンバアクセス子(というのかな?"・"です)
のないオブジェクト変数による関数呼び出しは DispId=0 なんですね。
これで関数の直接呼出しとオブジェクト変数による関数呼出しの機構が
大体見当つきました。でもこれ、変数の現在の型をみないと配列と区別
出来ないんでちょっと困った(For…Eachのコレクションと配列変数も
そうだが)…

今のところCOMがぜんぜん理解できてないので頓珍漢なことをいって
混乱させてしまったようで申し訳ありませんでした。vtblの件はC++変換に
あたって Idispatch I/Fを擬似的に作ることになるので「規定のDispId」が
こちらの勝手に設定したIdとかぶるとまずいと思ったのです。
参考資料ありがとうございました。熟読します。


しかしVBSの挙動って面白い。まさかグローバルの配列宣言が
宣言場所によって宣言されてないことになるとわ(SafeArrayだから
当然といえば当然、かな?)ループ内で宣言してもエラーだ。宣言じゃ
ねーなぁこりゃ。

ゆうゆう さん 2004年 11月 16日 15時 10分 55秒

mapiで悩んでます。
ちょっと、教えてください。
自PCのoutlook expressの受信トレイ.dbxを"MSMapi.MAPISession"で読めるよになったのですが、「開封済み」にする方法がわかりません。
何方か、開封済みの方法をご存知の方、教えてください。

ゆうゆう さん (know1know10@sdn.co.jp) 2004年 11月 16日 15時 00分 47秒

mapiで悩んでます。
ちょっと、教えてください。
自PCのoutlook expressの受信トレイ.dbxを"MSMapi.MAPISession"で読めるよになったのですが、「開封済み」にする方法がわかりません。
何方か、開封済みの方法をご存知の方、教えてください。

管理人むたぐち さん 2004年 11月 16日 14時 34分 23秒

To: ばんのしゃーによかばんた さん 2004年 11月 16日 13時 06分 22秒

> 忘れてました。このままでは、この行がエラーになります。
>
> そこで、
> AnHTTPDが何処かに持っている#!の文字列を'!に書き換える。先頭行も
> '! C:\Windows\System32\CScript.EXE //E:VBS
> に変えます。

いえ、さすがにそこまで融通の利かない実装はされてないでしょう。
つまり、まず#!の行を読み取って、その次の行からをcscriptに渡している、はずです…。

それの傍証となるかどうかは微妙ですが、
「#!の行を調べる」をチェックしないで、単に拡張子との関連付けで
AnHTTPDからcscriptを呼び出したときに、一行目に#!の行があると
出るエラーは次の通りです。

C:\www\admin\wshbbs\test\test.vbs(1, 1) Microsoft VBScript コンパイル エラー: ス
テートメントがありません。

つまり、#!行の読み込みはうまくいってるものの、次行からの内容をcscriptに渡す際、
何らかの不具合が生じており、その結果、
「Windows Script Host の実行に失敗しました。 (この操作を完了するのに十分な記憶域がありません。 ) 」
というエラーが出るのだと思われます。


> ばんのしゃーによかばんた さん 2004年 11月 16日 14時 06分 10秒
> ばんのしゃーによかばんた さん 2004年 11月 16日 14時 06分 40秒

これらは後ほど検討させていただきます。

StdInが駄目だったのは、Set oStdIn = WScript.StdInして
変数に入れてるせいかもしれません

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

>管理人むたぐち さん 2004年 11月 15日 20時 52分 20秒
>でも手持ちのvbsを変換し、それをコンパイルしたものを動作させた際、
>StdInの引数が違うとか言われて動きませんでした。

Stdin、stdinとかではありませんか。

さらに、さらにパワーアップしたvbs2js.vbsです。

Option Explicit
Dim fso
Dim fo
Dim iFile
Dim oFile
Dim oPath
Dim header
header="import System" & vbCRLF & _
"var fso=new ActiveXObject('Scripting.FileSystemObject');" & vbCRLF & _
"var WScript=new Object();" & vbCRLF & _
"WScript.StdIn=fso.GetStandardStream(0);" & vbCRLF & _
"WScript.StdOut=fso.GetStandardStream(1);" & vbCRLF & _
"WScript.StdErr=fso.GetStandardStream(2);" & vbCRLF & _
"WScript.Echo=function(p){var pArray=new Array();" & vbCRLF & _
"for(var k=0;k<WScript.Echo.arguments.length;k++){pArray.push(WScript.Echo.arguments[k]);}" & vbCRLF & _
"WScript.StdOut.WriteLine(pArray.join(' '));}" & vbCRLF & _
"WScript.Arguments=function(n){return(Environment.GetCommandLineArgs()[n+1]);}" & vbCRLF & _
"WScript.Arguments.Item=function(n){return(Environment.GetCommandLineArgs()[n+1]);}" & vbCRLF & _
"WScript.Arguments.Count=Number(Environment.GetCommandLineArgs().length-1);" & vbCRLF & _
"WScript.Quit=function(n){Environment.Exit(n);}" & vbCRLF & _
"WScript.Sleep=function(msec:int){System.Threading.Thread.Sleep(msec);}" & vbCRLF & _
"var SC=new ActiveXObject('ScriptControl');" & vbCRLF & _
"SC.Language='VBScript';" & vbCRLF & _
"SC.AllowUI=true;" & vbCRLF & _
"SC.TimeOut=-1;" & vbCRLF & _
"SC.AddObject('WScript',WScript,true);" & vbCRLF & _
"try{" & vbCRLF & _
"SC.ExecuteStatement("
Dim trailer
trailer="'');" & vbCRLF & _
"}catch(e){" & vbCRLF & _
"WScript.StdOut.WriteLine('Number:' + SC.Error.Number);" & vbCRLF & _
"WScript.StdOut.WriteLine('Description:' + SC.Error.Description);" & vbCRLF & _
"WScript.StdOut.WriteLine('Source:' + SC.Error.Source);" & vbCRLF & _
"WScript.StdOut.WriteLine('Text:' + SC.Error.Text);" & vbCRLF & _
"WScript.StdOut.WriteLine('Line:' + SC.Error.Line);" & vbCRLF & _
"WScript.StdOut.WriteLine('Column:' + SC.Error.Column);" & vbCRLF & _
"}"
Dim line
Dim re
Set re=new RegExp
re.IgnoreCase=True
re.Global=True

Set fso=CreateObject("Scripting.FileSystemObject")

If Wscript.Arguments.Count<>1 Then
WScript.Echo "Usage: vbs2js vbsfile"
WScript.Quit
End If
Set fo=fso.GetFile(WScript.Arguments(0))
oPath=fso.BuildPath(fso.GetParentFolderName(fo.Path),fso.GetBaseName(fo.Name) & ".JS")
Set iFile=fso.OpenTextFile(fo.Path)
Set oFile=fso.CreateTextFile(oPath)
oFile.Write header
Do While Not iFile.AtEndOfStream
line=iFile.ReadLine
re.Pattern="$bWScript\.":line=re.Replace(line,"WScript.")
re.Pattern="\.StdIn$b":line=re.Replace(line,".StdIn")
re.Pattern="\.StdOut$b":line=re.Replace(line,".StdOut")
re.Pattern="\.StdErr$b":line=re.Replace(line,".StdErr")
re.Pattern="\.Echo$b":line=re.Replace(line,".Echo")
re.Pattern="\.Sleep$b":line=re.Replace(line,".Sleep")
re.Pattern="\.Arguments$b":line=re.Replace(line,".Arguments")
re.Pattern="\.Count$b":line=re.Replace(line,".Count")
re.Pattern="\.Item$b":line=re.Replace(line,".Item")
re.Pattern="\.Quit$b":line=re.Replace(line,".Quit")
line=Replace(line,"\","\\")
line=Replace(line,"'","\'")
oFile.WriteLine "'" & line & "'+'\r\n' +"
Loop
oFile.Write trailer
iFile.Close
oFile.Close
WScript.Quit

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

知らないのですが、CGIって引数を見ます?
もし、引数が +1 ずれてよければ、

先頭行をSC.VBSを呼び出すように変える。
#! C:\Windows\System32\CScript.EXE SC.VBS

SC.VBSは以下。
Set fso=CreateObject("Scripting.FileSystemObject")
Set file=fso.OpenTextFile(WScript.Arguments(0))
file.SkipLine
Set SC=CreateObject("ScriptControl")
SC.Language="VBScript"
SC.AllowUI=False
SC.TimeOut=-1
Call SC.AddObject("WScript",WScript,True)
On Error Resume Next
Call SC.AddCode(file.ReadAll())
On Error GoTo 0
If SC.Error.Number<>0 Then
WScript.StdOut.WriteLine "Number:" & SC.Error.Number
WScript.StdOut.WriteLine "Description:" & SC.Error.Description
WScript.StdOut.WriteLine "Source:" & SC.Error.Source
WScript.StdOut.WriteLine "Text:" & SC.Error.Text
WScript.StdOut.WriteLine "Line:" & SC.Error.Line
WScript.StdOut.WriteLine "Column:" & SC.Error.Column
End If

魔界の仮面弁士 さん 2004年 11月 16日 13時 54分 55秒

》 say さん
> んだったらこりゃやっかいだわ…
そもそもの、GetRefが「VBSでどう解釈されているか」という質問ですが、
正直なところ、何をお聞きになりたいのか、よくわかっていません。(汗)
質問の意図が見えていない状態の回答なので、的外れな事を答えるかも。

# VB以外の言語をほとんど知らない事もあって、COMはあまり詳しく無いです…。
## 突っ込んだ話になると付いていけないので、間違っていたら誰かフォローよろしく。

> SDK でみると COM のイベントはIUnknownのようだったので
> 違うのかなと思っていました。

イベントを保持しているかどうかに関係なく、すべてのCOMオブジェクトは、
必ず IUnknownインターフェイスを持っていますよね。これによって、
型変換(IUnknown.QueryInterface)や、オブジェクトの参照(IUnknown.AddRef)と
解放(IUnknown.Release)が実装されているわけですし。

そういう意味では、GetRefを使ったイベントの割り当て…たとえば、DHTMLで
 Set window.onclick = GetRef("MyMethod")
のようにした時のonclickイベントの呼び出しについても、IUnknownは
当然使われているでしょう。


なお GetRef関数で得た関数オブジェクトをVBScriptで利用する場合は、このように書けます。

'===================
Option Explicit

Dim P1, P2
MsgBox "GetRef関数の戻り値を取得します。"
Set P1 = GetRef("Test1")
Set P2 = GetRef("Test2")
MsgBox "取得した関数オブジェクトを呼び出します。"
P1
P2 "あいうえお"
Call P1()
Call P2("ABCDE")
MsgBox "終了します。"

WScript.Quit 0

Sub Test1()
::MsgBox "Test1が呼ばれました。"
End Sub

Sub Test2(X)
::MsgBox "Test2が呼ばれました。引数は" & X & "です。"
End Sub


C++等からの呼び出しなら、下記が参考になるかも。
http://www.interq.or.jp/student/exeal/dss/res/alpha/diary0404.html#d0619



> ということはVテーブルって使用固定領域があるのかな。
質問の意図がつかめませんが、呼び出されるべきメソッドは、DISPID_VALUE なメソッドに
固定されているので、vtable が無くとも、DispIDだけでメソッドを呼べますよね。

[Visual Basic 6.0] - [How Binding Affects ActiveX Component Performance]
http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconhowbindingaffectsolecomponentperformance.asp
http://www.microsoft.com/japan/developer/library/VBCon98/vbconhowbindingaffectsolecomponentperformance.htm

[Automation] - [IDispatch Data Types and Structures] - [DISPID]
http://msdn.microsoft.com/library/en-us/automat/htm/chap6_7x2c.asp


『Makoto さん 2000年 09月 06日 02時 43分 40秒』なども参考に。

kuroneko さん 2004年 11月 16日 13時 54分 54秒

いつもお世話になっております。kuronekoです。
以前投稿いたしましたIEを閉じる件は何とかできましたが
10件データ処理を行なったら10件目、15件行なったら15件目に
WSHのエラーが表示されます。
これはいったいどういう意味なのでしょうか?

どうかご教授お願いいたします。

エラー内容
行19
文字1
エラー エラー内容を特定できません。
コード 80004005
ソース (null)
です。

スクリプトは
Option Explicit
Dim fso
Dim wShell
Dim Shell
Dim ie
Dim File
Dim TempName
Dim IEApp

Set fso=CreateObject("Scripting.FileSystemObject")
Set wShell=CreateObject("WScript.Shell")
Set Shell=CreateObject("Shell.Application")

Set ie=Shell.Windows.Item
If ie Is Nothing Then
WScript.Echo "No IE Found."
WScript.Quit
End If
If TypeName(ie.Document)<>"HTMLDocument" Then
WScript.Echo "IE is not active."
WScript.Quit
End If

TempName=fso.BuildPath(fso.GetSpecialFolder(2).Path,fso.GetTempName())
'Set File=fso.CreateTextFile("AAA.txt")
Set File=fso.CreateTextFile("C:\Docume~1\Administrator\デスクトップ\AAA.txt")

File.Write ie.Document.documentElement.outerHTML
File.Close
'Call wShell.Run("NotePad.Exe " & "AAA.txt",,True)
'fso.DeleteFile "AAA.txt"

WScript.Sleep 1000
For Each IEApp In CreateObject("Shell.Application").Windows()
If InStr(1, IEApp.fullname, "iexplore.exe", vbTextCompare) > 0 Then
IEApp.Quit
End If
Next

以上 宜しくお願いいたします。


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

>ばんのしゃーによかばんた さん 2004年 11月 15日 17時 58分 44秒
>なら、VBSファイルの先頭行に、
>#! C:\Windows\System32\CScript.EXE //E:VBS
>を加えて、*.cgiにリネームしておくと、実行してくれませんかねぇ。

忘れてました。このままでは、この行がエラーになります。

そこで、
AnHTTPDが何処かに持っている#!の文字列を'!に書き換える。先頭行も
'! C:\Windows\System32\CScript.EXE //E:VBS
に変えます。

say さん 2004年 11月 16日 01時 13分 33秒

魔界の仮面弁士 さん へ

ご返答ありがとうございます。

>GetRef関数の戻り値は、ディスパッチID = 0 なメソッド
>(つまり、規定のメソッド)を持ったオブジェクトへの参照です。

簡単に検索したかんじでは「規定のメソッド」とはイベント呼び出しにおいて
「規定」してあるようですが SDK でみると COM のイベントはIUnknownのよう
だったので違うのかなと思っていました。ということはVテーブルって使用固定
領域があるのかな。Dispid=0 である情報はどこから出てくるんだ?VBSが独自
管理してるってことかなぁ…。んだったらこりゃやっかいだわ…

管理人むたぐち さん 2004年 11月 15日 21時 08分 06秒

一応検証用のコードです。test.cgi

拡張子.cgiには「#!の行を調べる」をチェックしています。
また、一行目を省略して、test.vbsとした場合は
正常に動作することを確認しています。

#!C:\Windows\System32\CScript.EXE //E:VBS //nologo

EchoHTML "test"

Sub EchoHTML(HTML)
Wscript.Echo "Content-Type: text/html"
Wscript.Echo
Wscript.Echo HTML
End Sub

「Windows Script Host の実行に失敗しました。 (この操作を完了するのに十分な記憶域がありません。 ) 」
これ、どういうエラーか分かるかた、いますか?

管理人むたぐち さん 2004年 11月 15日 20時 52分 20秒

To: say さん 2004年 11月 14日 23時 09分 48秒

> 実はVBSを機械的にC++に変換する方法を探るべくいろいろ調べてたのですが、
> まぁオートメーションの手間のかかること…。単純にShell.Environment.Countを
> 呼ぶだけのループをまわすと500000回程度じゃコンパイルしてもまったく差が
> 出ませんでした。このまま進めるか思案中です。

それは効率等を度外視してでも、進めてみる価値があるんじゃないでしょうか?
純粋に知的好奇心を覚えるテーマです。


To: あんのうん さん

> 単純に「Wscript.exe *.vbs 渡されたパラメータ」をShellキック
> するexeを作り、*.cgiにリネームというのはどうでしょう?
>
> #CGIの仕組に疎いので、外していたらごめんなさい。(ブラウザ
>  への出力に難あり?)

ええ、標準入出力や環境変数を子プロセスにちゃんと渡せないので
駄目っぽいですね。


To: ばんのしゃーによかばんた さん 2004年 11月 15日 13時 56分 29秒

> さらにパワーアップしたvbs2js.vbsです。

おお、随所に工夫が見られますね。
でも手持ちのvbsを変換し、それをコンパイルしたものを動作させた際、
StdInの引数が違うとか言われて動きませんでした。
機械的な変換はやっぱり難しいですね。


To: ばんのしゃーによかばんた さん 2004年 11月 15日 17時 58分 44秒

> なら、VBSファイルの先頭行に、
> #! C:\Windows\System32\CScript.EXE //E:VBS
> を加えて、*.cgiにリネームしておくと、実行してくれませんかねぇ。

そうでした、実はAnHTTPD自体には、一行目の#!を読み込んで、適切なインタプリタに
渡す機能はあるんでした。
あーなるほど、そこで//E:VBSが意味を持ってくるわけですねー。
//Eオプションの意味が初めて分かりました…。

試してみると、
CScript エラー: Windows Script Host の実行に失敗しました。 (この操作を完了するのに十分な記憶域がありません。 )

こんなのが標準出力に出てきました。
一応、cscriptにスクリプトは渡されているような感じです。
何が悪いのかなぁ?

試しにCScriptをWScriptにすると、同じエラーがダイアログで表示されます。
もう一息という感じはしますね。

魔界の仮面弁士 さん 2004年 11月 15日 20時 31分 59秒

》 sayさん
> GetRefが返す関数ポインタがVBSでどう解釈されているかどなたかご教授
> ください。VBS上でポインタは全てIDispatchらしいのはわかるのですが、

GetRef関数の戻り値は、ディスパッチID = 0 なメソッド
(つまり、規定のメソッド)を持ったオブジェクトへの参照です。

スクリプトコンポーネントで言えば、
<public><method name="MyMethod" dispid="0" /></public>
を公開しているクラスのような状態ですね。

ちなみに、GetRef関数の戻り値が VB/VBA に渡された場合は、
CallByName objGetRef, "", VbMethod, 引数…
のようにして呼び出せるようです。


# …って、そういう事を聞いているのでは無いのかな。(汗

ばんのしゃーによかばんた さん 2004年 11月 15日 17時 58分 44秒

>say さん 2004年 11月 14日 23時 09分 48秒
>> AnHTTPDの機能で、ファイルを*.cgiにリネームしておくと、
>> 実行時に中身を判断し、実行形式(exe)ならばファイルを
>> 実行してくれる機能があるんですね。その機能を使いたいんです。
>この話題をよく理解できていませんが VectorにVBSソースにヘッダを
>つけることで拡張子を.COMに変換してインタプリタを見かけ上実行せずに
>直接実行するというのがあります。.COMなので多分ファイルサイズに
>制限があると思いますがコンパイルとか考えるならこの方法が良いかも
>しれません(ウィルス的方法ですが)。

EXEファイルは先頭に,"MZ"のようなIDが入っているので、それと分かります。
COMファイルには、EXEファイルのような、ヘッダがありません。
なので、COMファイルは使えません。

――――――――――――――――――――――――――――――――――――――
>あんのうん さん 2004年 11月 15日 01時 23分 45秒
>単純に「Wscript.exe *.vbs 渡されたパラメータ」をShellキック
>するexeを作り、*.cgiにリネームというのはどうでしょう?
>#CGIの仕組に疎いので、外していたらごめんなさい。(ブラウザ
> への出力に難あり?)

CGIに関しては、これが一番ですね。確実な方法です。
ただ、Shellキックは標準入出力を子プロセスに渡してくれます?
そこがポイントですね。

――――――――――――――――――――――――――――――――――――――
>To: 管理人むたぐち さん
>> AnHTTPDの機能で、ファイルを*.cgiにリネームしておくと、
>> 実行時に中身を判断し、実行形式(exe)ならばファイルを
>> 実行してくれる機能があるんですね。その機能を使いたいんです。

なら、VBSファイルの先頭行に、
#! C:\Windows\System32\CScript.EXE //E:VBS
を加えて、*.cgiにリネームしておくと、実行してくれませんかねぇ。

※これまた、AnHTTPDを知らずに書いてますので、外れていたらご容赦。

null さん (null) 2004年 11月 15日 16時 23分 15秒
URL:null

To: 管理人むたぐち さん

> To: 楽々園の秀 さん
>
> > 表示は改善されましたが、掲示板への書込ボタンを押すと特定の記事のみしか
> > 右フレームに表示されません。
>
> これらの不具合は再現しませんでした。
> 一度ログを再取得してみてもらえませんか?

再取得してみましたが変化ありません。

別フォルダを作成し、新規に取得して比較しましたら、
$res.txt と $comment.txt が不足。

中をチェックしましたら、これが特定の記事でした。

結果は
$res.txtが表示された時に上書き保存すると$comment.txtに同一
内容が格納され掲示板への書込ボタンを押すと最新内容が表示される。

送信しない限り$res.txtと$comment.txtは削除されないので、再起動
しても残っている。(削除は本返信で確認します。)

と言うことで私が正しい使い方を知らなかっただけです。
どうもお騒がせしました。m(__)m

では!

以下実験結果です。

ボタン=掲示板への書込ボタン

1.記事選択後ボタンを押す
空の投稿用フォームが表示される。

2.もう一回ボタンを押す。
空の投稿用フォームが表示される。
(何度押しても同じ)

3.同記事を再表示し、右フレームの投稿者をクリック
登録エディタで引用符付テキストが表示される($res.txt)
WshLab.hta があるフォルダに 上記と $res.txt.bak が出来る。

4.$res.txtを閉じ ボタンを押す
1回目:空の投稿用フォーム
2回目:引用符付記事が入った投稿用フォームが表示される。
$comment.txt 生成

5.何もせず次の記事を表示してボタンを押す
前の記事がそのまま表示。(4.2回目と同じ)

6.同記事を再表示し、右フレームの投稿者をクリック
前の記事に続いて現在の記事が追加されそ表示。($res.txt と同一内容)
$comment.txtは前回の内容。

7.$res.txtを閉じ ボタンを押す
前の記事がそのまま表示。(4.2回目と同じ)
この時、$res.txtの内容が$comment.txtの内容で上書きされている。
(古い内容に戻っている)

注:4.と7.の時点で $res.txt を 上書き保存すると $comment.txt も同じになる。

say さん 2004年 11月 15日 14時 44分 36秒

GetRef返却値のVBS実装予想

GetRefが返す関数ポインタがVBSでどう解釈されているかどなたかご教授
ください。VBS上でポインタは全てIDispatchらしいのはわかるのですが、
これをオブジェクト変数に入れて関数を呼び出せる機構がぜんぜん想像
できません。オブジェクトのメンバ関数として呼ぶならメンバ関数名を
どう処理しているのかどうにも見当がつきません。

ばんのしゃーによかばんた さん 2004年 11月 15日 13時 58分 14秒

>管理人むたぐち さん 2004年 11月 12日 22時 24分 48秒
>おっと、失礼しました。番号は控えていませんでしたが、エラー内容は、
>「書き込みできません」
>というものです。

オープンしているファイルを削除しようとしたときに出る、
&H46 70 ですね。

>: Case t1,t2,t3 'Continue if timing error
>: Case p1,p2 p3
>: : WScript.StdOut.WriteLine Join(path,"not deleted. Permanent Error:",Err.Number,Err.Description)
>: : Exit Sub
>: Case Else
>: End Select

のところを、

: Case 70 'Continue if timing error
: Case Else
: : WScript.StdOut.WriteLine Join(path,"not deleted. Permanent Error:",Err.Number,Err.Description)
: : Exit Sub
: End Select

と変えてください。

>To: オズ さん
>> (もしかしてMoveFileで移動中にエラーがあってもそんなこと起きないですか?)
>何となく、ですが、NTFSだから大丈夫じゃないかな、とか思っています。
>移動と言っても、実質はコピーしてから削除なわけでしょうから。
>少なくともファイル移動のミスでファイルを消失させた経験は、
>Win2000,XPを使い始めてからは、ないです。

NTFSはログを採ってトランザクション制御しているので堅牢。と言っても、
堅牢なのは管理情報だけで、データ部分は、ミラーリングでもしないと。
ですね。

>> つまり、CopyFile終了後DeleteFile発行時にはまだCopyFileが対象ファイルを
>> 保持しており、DeleteFileには手が出せない状態なのではないか、と。
>可能性はありますね。
>CopyFile後にちょっとだけウェイトを入れてみたりするとどうでしょう?

昔々、Fault Tolerant OSを作ってたとき、似たような話があったような
気がします。ファイルをクローズして、すぐオープンするとエラー。
このOSの特徴は当時流行のメッセージベースOSでした。
そのコンポは、資源獲得要求は復帰値があるのでsend and receive、つまり同期、
資源解放要求は復帰値がないのでsendのみ、つまり非同期,突き放し、
で作ったのです。そことはだいぶ喧嘩したような。誤りを認めなかったような。
結局、FT化のためには、メッセージは脱送(抜け)しては駄目で、冗送(重複)
側に倒す必要がある。そのためには、発信者は、send and receiveを使って
メッセージを再送。受信者は、冗送に耐えるよう、処理を冪等化(idempotent)する。
ということで、結果的に直ったような。

というわけで、オープン中のロックをクローズ時に解放するとき、ロック解放を
非同期にやっているのかも。これはちょっと厄介です。何故かと言うと、
ロック解放を非同期にやることが、根本原因だと、開発者が気付く/認めるのが
なかなか難しいのです。ありがちなのは、開発者がロック解放要求後に
ちょっとだけウェイトを入れて問題回避を図ることです。
そうすると、開発元のテストでは再現せず、ユーザの環境でときどき発生する。
ということが、延々続きます。

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

>管理人むたぐち さん 2004年 11月 14日 19時 30分 41秒
>To: cian さん
>> WSHで非アクティブ状態の特定ウィンドウにキーボード操作を送りたいと思っております。(具体的にはショートカットキー)
>これはWshShell.SendKeysではできなかったような気がします。
>APIのkeybd_event関数を使えばできるみたいです。
>DynaCallから呼び出して使ってみては。

別のアプリにキーイベントを発生させるには、以下の方法もあります。

>ばんのしゃーによかばんた さん 2004年 04月 23日 18時 48分 56秒
>WSHからExcel経由でWin32APIを使う方法。

しかし、キーイベントはアクティブなウィンドウに渡ると思うので、
要件と合わないかも。

SendMessageを使えばいいのかも。この辺(Win32API)はよく知りません。

ところで、

>>そこで、SendKeysメソッドがあったのですが、この場合ですとウィンドウをアクティブ化してからしかキーボード操作を送れません。

ウィンドウをアクティブ化すれば、簡単なのに、そうしたくない理由は何でしょう?

ばんのしゃーによかばんた さん 2004年 11月 15日 13時 56分 29秒

>管理人むたぐち さん 2004年 11月 14日 19時 30分 41秒
>StdInとか、Echoとか、環境変数とか、結構いろいろ使ってるんですよね。
>CGIスクリプトだけに。

さらにパワーアップしたvbs2js.vbsです。

WScript.〜は、以下を除き、使用できません。
大文字/小文字は厳密に。引数も、制限あり。
WScript.StdIn
WScript.StdOut
WScript.StdErr
WScript.Echo text
WScript.Arguments.Count
WScript.Arguments(n)
WScript.Arguments.Item(n)
WScript.Quit [n]

vbs2js.vbs
――――――――――――――――――――――――――――――――――――――
Option Explicit
Dim fso
Dim fo
Dim iFile
Dim oFile
Dim oPath
Dim header
header="import System" & vbCRLF & _
"var fso=new ActiveXObject('Scripting.FileSystemObject');" & vbCRLF & _
"var WScript=new Object();" & vbCRLF & _
"WScript.StdIn=fso.GetStandardStream(0);" & vbCRLF & _
"WScript.StdOut=fso.GetStandardStream(1);" & vbCRLF & _
"WScript.StdErr=fso.GetStandardStream(2);" & vbCRLF & _
"WScript.Echo=function(text){WScript.StdOut.WriteLine(text);}" & vbCRLF & _
"WScript.Arguments=function(n){return(Environment.GetCommandLineArgs()[n+1]);}" & vbCRLF & _
"WScript.Arguments.Item=function(n){return(Environment.GetCommandLineArgs()[n+1]);}" & vbCRLF & _
"WScript.Arguments.Count=Number(Environment.GetCommandLineArgs().length-1);" & vbCRLF & _
"WScript.Quit=function(n){Environment.Exit(n);}" & vbCRLF & _
"var SC=new ActiveXObject('ScriptControl');" & vbCRLF & _
"SC.Language='VBScript';" & vbCRLF & _
"SC.AllowUI=true;" & vbCRLF & _
"SC.TimeOut=-1;" & vbCRLF & _
"SC.AddObject('WScript',WScript,true);" & vbCRLF & _
"try{" & vbCRLF & _
"SC.ExecuteStatement("
Dim trailer
trailer="'');" & vbCRLF & _
"}catch(e){" & vbCRLF & _
"WScript.StdOut.WriteLine('Number:' + SC.Error.Number);" & vbCRLF & _
"WScript.StdOut.WriteLine('Description:' + SC.Error.Description);" & vbCRLF & _
"WScript.StdOut.WriteLine('Source:' + SC.Error.Source);" & vbCRLF & _
"WScript.StdOut.WriteLine('Text:' + SC.Error.Text);" & vbCRLF & _
"WScript.StdOut.WriteLine('Line:' + SC.Error.Line);" & vbCRLF & _
"WScript.StdOut.WriteLine('Column:' + SC.Error.Column);" & vbCRLF & _
"}"
Dim line

Set fso=CreateObject("Scripting.FileSystemObject")

If Wscript.Arguments.Count<>1 Then
WScript.Echo "Usage: vbs2js vbsfile"
WScript.Quit
End If
Set fo=fso.GetFile(WScript.Arguments(0))
oPath=fso.BuildPath(fso.GetParentFolderName(fo.Path),fso.GetBaseName(fo.Name) & ".JS")
Set iFile=fso.OpenTextFile(fo.Path)
Set oFile=fso.CreateTextFile(oPath)
oFile.Write header
Do While Not iFile.AtEndOfStream
line=iFile.ReadLine
line=Replace(line,"\","\\")
line=Replace(line,"'","\'")
oFile.WriteLine "'" & line & "'+'\r\n' +"
Loop
oFile.Write trailer
iFile.Close
oFile.Close
WScript.Quit
――――――――――――――――――――――――――――――――――――――
因みに、vbs2js.vbs自身をvbs2js.vbsでJSにして、EXEにして、
そのEXEでvbs2js.vbsをJSにしてみました。
※なんか、言語系はこういうことをよくやるようで。。。
この程度のVBScriptは完動しました。

まだ、足りないもの、あります?

一応、
Echoの複数引数(完*)
大文字/小文字の緩和(RegExp)
ScriptFullName(?)
はback logにあります。

※完*は業界用語で、カンアスタと読む。完了と見做してよい状態を言う。

あんのうん さん 2004年 11月 15日 01時 23分 45秒

To: 管理人むたぐち さん

> AnHTTPDの機能で、ファイルを*.cgiにリネームしておくと、
> 実行時に中身を判断し、実行形式(exe)ならばファイルを
> 実行してくれる機能があるんですね。その機能を使いたいんです。

なるほど、、

単純に「Wscript.exe *.vbs 渡されたパラメータ」をShellキック
するexeを作り、*.cgiにリネームというのはどうでしょう?

#CGIの仕組に疎いので、外していたらごめんなさい。(ブラウザ
 への出力に難あり?)

WikiにソースごとまだUploadされていると思いますが、HTAでスク
リーンセーバを作った時、HTAを直接起動できなかったので、同様
のアプリをVB.NETで書いて、.NET FRAMEWORK付属(無料)のコマン
ドラインVBコンパイラでコンパイル後、*.SCRとリネームして使っ
た覚えがあります。

say さん 2004年 11月 14日 23時 09分 48秒

はじめまして。

>AnHTTPDの機能で、ファイルを*.cgiにリネームしておくと、
>実行時に中身を判断し、実行形式(exe)ならばファイルを
>実行してくれる機能があるんですね。

この話題をよく理解できていませんが VectorにVBSソースにヘッダを
つけることで拡張子を.COMに変換してインタプリタを見かけ上実行せずに
直接実行するというのがあります。.COMなので多分ファイルサイズに
制限があると思いますがコンパイルとか考えるならこの方法が良いかも
しれません(ウィルス的方法ですが)。

実はVBSを機械的にC++に変換する方法を探るべくいろいろ調べてたのですが、
まぁオートメーションの手間のかかること…。単純にShell.Environment.Countを
呼ぶだけのループをまわすと500000回程度じゃコンパイルしてもまったく差が
出ませんでした。このまま進めるか思案中です。

管理人むたぐち さん 2004年 11月 14日 22時 54分 26秒

やはり*.vbs→*.vbの無謀な変換を試みるよりも、
ScriptControlを通じてVBSを呼び出す方が現実的っぽいですねぇ。

そうなると、WScriptオブジェクトを書くだけで済みます。
って一言で言ってますが、そんなに単純なものでもないことは分かってます。
DMonkeyのソースを移植とかできないかな…。

Return