WSHでWin32APIを呼び出す-その5
2005年6月30日
(←戻る)
VBscriptとDynaWrapで、ユーザ定義型の構造体を因数に持つWin32APIを呼び出す方法を考えている。前回までで、文字列に対するポインタを呼び出すことを解決しなければいけないという結論になった。ここで新たな問題が発生した。
下にdnyawrapNt.zipに含まれているMsgBox.vbsから実行部分だけを抜粋した。
このスクリプトの実行結果は、次の様になる。
このスクリプトに少し改変を加えたのが次である。
Set UserWrap = CreateObject("DynamicWrapper")
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", _
"f=s", "R=l"
T="MessageBox (ANSI)"
UserWrap.MessageBoxA Null, T, _
"From DynaWrap Object", 3
このスクリプトの実行結果は次のようになった。
なんと、この場合文字列のAPIへの受け渡しがうまく行っていない。
スクリプトをさらに改変し、『T+""』を引数として与えてみた。
このスクリプトの実行結果は次のようになった。
つまり、文字列を引数として与える場合、変数をそのまま参照しては駄目で、『"MessageBox (ANSI)"』もしくは『T+""』の様に、テンポラリな文字列の計算結果を引数として与えなければならない。色々調べた結果、このように文字列を与えるとANSI文字列として受け渡されることが分かった。一方、文字列型のデータが変数に入っている場合、Unicodeでメモリに格納されている。だから、dynawrapNt.zipに含まれていたMsgBox.vbsは、『MessageBox (ANSI)』と表示するサンプルだったと納得。
ということは、自作DLLの中でANSI文字列をメモリ上に構築し、そのANSI文字列へのポインタを用いればよいということになる。例えば、次のようなDLLを使えばよいということが分かった。
(続く)
VBscriptとDynaWrapで、ユーザ定義型の構造体を因数に持つWin32APIを呼び出す方法を考えている。前回までで、文字列に対するポインタを呼び出すことを解決しなければいけないという結論になった。ここで新たな問題が発生した。
下にdnyawrapNt.zipに含まれているMsgBox.vbsから実行部分だけを抜粋した。
Set UserWrap = CreateObject("DynamicWrapper")
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", _
"f=s", "R=l"
UserWrap.MessageBoxA Null, "MessageBox (ANSI)", _
"From DynaWrap Object", 3
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", _
"f=s", "R=l"
UserWrap.MessageBoxA Null, "MessageBox (ANSI)", _
"From DynaWrap Object", 3
このスクリプトの実行結果は、次の様になる。
このスクリプトに少し改変を加えたのが次である。
Set UserWrap = CreateObject("DynamicWrapper")
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", _
"f=s", "R=l"
T="MessageBox (ANSI)"
UserWrap.MessageBoxA Null, T, _
"From DynaWrap Object", 3
このスクリプトの実行結果は次のようになった。
なんと、この場合文字列のAPIへの受け渡しがうまく行っていない。
スクリプトをさらに改変し、『T+""』を引数として与えてみた。
Set UserWrap = CreateObject("DynamicWrapper")
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", _
"f=s", "R=l"
T="MessageBox (ANSI)"
UserWrap.MessageBoxA Null, T+"", _
"From DynaWrap Object", 3
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", _
"f=s", "R=l"
T="MessageBox (ANSI)"
UserWrap.MessageBoxA Null, T+"", _
"From DynaWrap Object", 3
このスクリプトの実行結果は次のようになった。
つまり、文字列を引数として与える場合、変数をそのまま参照しては駄目で、『"MessageBox (ANSI)"』もしくは『T+""』の様に、テンポラリな文字列の計算結果を引数として与えなければならない。色々調べた結果、このように文字列を与えるとANSI文字列として受け渡されることが分かった。一方、文字列型のデータが変数に入っている場合、Unicodeでメモリに格納されている。だから、dynawrapNt.zipに含まれていたMsgBox.vbsは、『MessageBox (ANSI)』と表示するサンプルだったと納得。
ということは、自作DLLの中でANSI文字列をメモリ上に構築し、そのANSI文字列へのポインタを用いればよいということになる。例えば、次のようなDLLを使えばよいということが分かった。
#include <windows.h>
char TempStr[4096]="";
int TempStrPoint=0;
char* __stdcall DwGetAddressOfString(char* T)
{
int i;
//Copy T to TempStr
for (i=0;TempStrPoint+i<4096;i++)
if ((TempStr[TempStrPoint+i]=T[i])==0) break;
//Check if buffer is full
if (TempStrPoint+i<4095)
{
TempStrPoint+=i+1;
return TempStr+TempStrPoint-i-1;
} else {
TempStrPoint=4096;
return 0;//Return zero if buffer is full
}
}
char TempStr[4096]="";
int TempStrPoint=0;
char* __stdcall DwGetAddressOfString(char* T)
{
int i;
//Copy T to TempStr
for (i=0;TempStrPoint+i<4096;i++)
if ((TempStr[TempStrPoint+i]=T[i])==0) break;
//Check if buffer is full
if (TempStrPoint+i<4095)
{
TempStrPoint+=i+1;
return TempStr+TempStrPoint-i-1;
} else {
TempStrPoint=4096;
return 0;//Return zero if buffer is full
}
}
(続く)