WSHでWin32APIを呼び出す-その6
2005年7月1日
(←戻る)
前回までの記事で、ANSI文字列を自作DLL内で確保したメモリ領域に構築し、そのANSI文字列に対するポインタをVBscriptに渡すことに成功した。今回はいよいよ、ユーザ定義型の構造体を引数に持つWin32APIの呼び出しである。テストとして、comdlg32.dllにある、GetOpenFileNameを呼び出してみた。このAPIはOPENFILENAME構造体を使用している。
今回使用した自作DLLは次の通りである。
『DwGetAddressOfString』でメモリ領域を確保し、『DwCopyLong』と『DwCopyInt』でその領域に書き込みを行う。『DwClearBuffer』は、使用したメモリ領域を開放する時に呼び出す。これらの関数群と連携させるようにVBscript上で構築した、OPENFILENAME様のスクリプトが、次である。Visual Basicでの構造体の取り扱いと互換性を持たせるため、クラスを用いた。
このクラスには、『Structure()』という、パブリック関数を持たせてある。この関数を『xxxxx.Structure』という形で呼び出すことによって、DLL内のメモリに構築されたOPENFILENAMEへのポインタ値を得ようということである。
さて、ここまで来ればあとはメインルーチンを書き上げるだけである。作成したスクリプト、『OpenFile.vbs』のメインの部分を下に示す。(実際にはこの記述のあとに、上記のOPENFILENAMEクラスが記述されている。)
このスクリプトの実行結果は、次の通り。成功である。これで、ユーザ定義型の構造体を引数に持つAPIも呼び出せるようになった。一つ山を越した感がある。引き続き、『Hello world!』プログラムの検討に戻ってみよう。さらなる難関が待ち受けている…。

pop up
(ここで使用したOpenFile.vbs及びdwtools.dllはここからダウンロードできます。)
(続く)
前回までの記事で、ANSI文字列を自作DLL内で確保したメモリ領域に構築し、そのANSI文字列に対するポインタをVBscriptに渡すことに成功した。今回はいよいよ、ユーザ定義型の構造体を引数に持つWin32APIの呼び出しである。テストとして、comdlg32.dllにある、GetOpenFileNameを呼び出してみた。このAPIはOPENFILENAME構造体を使用している。
今回使用した自作DLLは次の通りである。
char TempStr[4096]="";
int TempStrPoint=0;
char* __stdcall DwGetAddressOfString(char* T, int Size)
{
int i;
//Copy T to TempStr
for (i=0;(TempStr[TempStrPoint+i]=T[i])!=0;i++)
if (4095<=TempStrPoint+i) return 0;//if buffer is full
if (0<Size)
{
if (Size<i) return 0;//if size exceeds
i=Size;
}//else if (0==Size) do nothing
//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
}
}
void __stdcall DwCopyLong(unsigned long org,long* dest)
{
if (TempStr<=dest && dest<=TempStr+4092) *dest=org;
}
void __stdcall DwCopyInt(unsigned short org,short* dest)
{
if (TempStr<=dest && dest<=TempStr+4094) *dest=org;
}
void __stdcall DwClearBuffer()
{
TempStrPoint=0;
}『DwGetAddressOfString』でメモリ領域を確保し、『DwCopyLong』と『DwCopyInt』でその領域に書き込みを行う。『DwClearBuffer』は、使用したメモリ領域を開放する時に呼び出す。これらの関数群と連携させるようにVBscript上で構築した、OPENFILENAME様のスクリプトが、次である。Visual Basicでの構造体の取り扱いと互換性を持たせるため、クラスを用いた。
Class OPENFILENAME
Public lStructSize ' As Long
Public hwndOwner ' As Long
Public hInstance ' As Long
Public lpstrFilter ' As String
Public lpstrCustomFilter ' As String
Public nMaxCustFilter ' As Long
Public nFilterIndex ' As Long
Public lpstrFile ' As String
Public nMaxFile ' As Long
Public lpstrFileTitle ' As String
Public nMaxFileTitle ' As Long
Public lpstrInitialDir ' As String
Public lpstrTitle ' As String
Public flags ' As Long
Public nFileOffset ' As Integer
Public nFileExtension ' As Integer
Public lpstrDefExt ' As String
Public lCustData ' As Long
Public lpfnHook ' As Long
Public lpTemplateName ' As String
Public Function Structure()
UserWrap.DwClearBuffer
Structure=UserWrap.DwGetAddressOfString("",76) 'Length of structure is 76
UserWrap.DwCopyLong lStructSize, Structure ' As Long
UserWrap.DwCopyLong hwndOwner, Structure+4 ' As Long
UserWrap.DwCopyLong hInstance, Structure+8 ' As Long
UserWrap.DwCopyLong StrAddress(lpstrFilter), Structure+12 ' As String
UserWrap.DwCopyLong StrAddress(lpstrCustomFilter), Structure+16 ' As String
UserWrap.DwCopyLong nMaxCustFilter, Structure+20 ' As Long
UserWrap.DwCopyLong nFilterIndex, Structure+24 ' As Long
UserWrap.DwCopyLong StrAddress(lpstrFile), Structure+28 ' As String
UserWrap.DwCopyLong nMaxFile, Structure+32 ' As Long
UserWrap.DwCopyLong StrAddress(lpstrFileTitle), Structure+36 ' As String
UserWrap.DwCopyLong nMaxFileTitle, Structure+40 ' As Long
UserWrap.DwCopyLong StrAddress(lpstrInitialDir), Structure+44 ' As String
UserWrap.DwCopyLong StrAddress(lpstrTitle), Structure+48 ' As String
UserWrap.DwCopyLong flags, Structure+52 ' As Long
UserWrap.DwCopyInt nFileOffset, Structure+56 ' As Integer
UserWrap.DwCopyInt nFileExtension, Structure+58 ' As Integer
UserWrap.DwCopyLong StrAddress(lpstrDefExt), Structure+60 ' As String
UserWrap.DwCopyLong lCustData, Structure+64 ' As Long
UserWrap.DwCopyLong lpfnHook, Structure+68 ' As Long
UserWrap.DwCopyLong StrAddress(lpTemplateName), Structure+72 ' As String
End Function
Private Function StrAddress(str)
Select Case VarType(str)
Case vbString
StrAddress=UserWrap.DwGetAddressOfString(str+"",0)
Case Else
StrAddress=0 'return Null string
End Select
End Function
End Classこのクラスには、『Structure()』という、パブリック関数を持たせてある。この関数を『xxxxx.Structure』という形で呼び出すことによって、DLL内のメモリに構築されたOPENFILENAMEへのポインタ値を得ようということである。
さて、ここまで来ればあとはメインルーチンを書き上げるだけである。作成したスクリプト、『OpenFile.vbs』のメインの部分を下に示す。(実際にはこの記述のあとに、上記のOPENFILENAMEクラスが記述されている。)
option explicit
Dim UserWrap
Set UserWrap = CreateObject("DynamicWrapper")
UserWrap.Register "comdlg32.dll", "GetOpenFileNameA", "I=l", "f=s", "R=l"
UserWrap.Register "debug\dwtools.dll", "DwGetAddressOfString", "I=su", "f=s", "R=l"
UserWrap.Register "debug\dwtools.dll", "DwClearBuffer", "f=s"
UserWrap.Register "debug\dwtools.dll", "DwCopyLong", "I=ll", "f=s", "R=l"
UserWrap.Register "debug\dwtools.dll", "DwCopyInt", "I=ul", "f=s", "R=l"
Dim OpenFile
Set OpenFile=New OPENFILENAME
OpenFile.lpstrInitialDir = "C:\temp"
OpenFile.lStructSize = 76
OpenFile.hwndOwner = 0
OpenFile.lpstrFilter = "*.*"
OpenFile.nFilterIndex = 1
OpenFile.lpstrFile = "Test.txt" + String(256, 0)
OpenFile.nMaxFile = 256
OpenFile.lpstrDefExt = ""
OpenFile.lpstrTitle = "Open File"
OpenFile.flags = 4 '読み込み専用チェックボックスを隠す
call UserWrap.GetOpenFileNameA(OpenFile.Structure)このスクリプトの実行結果は、次の通り。成功である。これで、ユーザ定義型の構造体を引数に持つAPIも呼び出せるようになった。一つ山を越した感がある。引き続き、『Hello world!』プログラムの検討に戻ってみよう。さらなる難関が待ち受けている…。

pop up
(ここで使用したOpenFile.vbs及びdwtools.dllはここからダウンロードできます。)
(続く)