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はここからダウンロードできます。)
(続く)