WSHでWin32APIを呼び出す-その7
2005年7月4日
(←戻る)
前回までの記事で、ユーザー定義型の構造体を引数に持つWinAPIを呼び出せるようになった。引き続き、VBで出来た『Hello, World!』プログラムを見てみよう。
前回詰まったここの部分は、解決した。続きは…
ここまでは問題なし。Main()関数を見てみる。
一番大きな問題はこの行にある。VBscriptでは、『AddressOf 』は使えない。
『AddressOf 』が使えないというよりも、コールバック関数を使うのが無理ではないかと思われる。もともと『AddressOf 』はVBが完全なコンパイラ(ネイティブコードにコンパイルされる)になったVer5からの機能で、Ver4以前には無かったものである。VBscriptでは、ネイティブコードにコンパイルされて実行されるのではなく、Ver4以前のVBに近い形のインタプリタの形式で実行している様に思われる。
スクリプトの中でなにかしらの関数を定義した場合、その関数がJavaのJITの様にコンパイルされてメモリに格納されている可能性はある。ただ、そういった場合でもVBscriptはデータ型がバリアント型のみであるので、コールバック関数の規定の型にはめられるように定義することは無理であろう。やはり、コールバック関数は自作DLLの中に用意するしかない。今回製作した自作DLLの中のコールバック関数に関連する部分は次の通りである。
プロトタイプでは、WndProcの中では何もせずDefWindowProcを呼び出すだけにした(ここの部分が一番重要なのであるが、その対処は次回以降に考えることにしたい)。また、このWndProcのアドレスを与えるDwAddressOfWndProcを用意した。
この機能に対応させて作成したtest.vbsは以下の通りである。
このソースコードは見ての通り、最初に紹介したVB用の『Hello, World!』プログラムと殆ど同じになった。唯一違うのは、コールバック関数が含まれていない点である。実行結果は次のようになる。

残るは、コールバック関数の処理のみ。
(続く)
前回までの記事で、ユーザー定義型の構造体を引数に持つWinAPIを呼び出せるようになった。引き続き、VBで出来た『Hello, World!』プログラムを見てみよう。
Option Explicit Type POINTAPI x As Long y As Long End Type
前回詰まったここの部分は、解決した。続きは…
Const SW_SHOW = 5 (略) Declare Function LoadIcon Lib "user32" Alias "LoadIconA" _ (ByVal hInstance As Long, ByVal lpIconName As String) As Long (略) Private g_chAppName As String Private g_chClassName As String Private p_hInstance As Long, p_hPreInst As Long Private p_pchCmdLine As String, p_iCmdShow As Integer
ここまでは問題なし。Main()関数を見てみる。
Sub Main() 'WinMainと互換性を持たせるための記述 p_hInstance = App.hInstance p_hPreInst = App.PrevInstance p_pchCmdLine = Command p_iCmdShow = SW_SHOW g_chAppName = "TestApplication" 'アプリケーションの名前 g_chClassName = "TestWndClass" 'ウィンドウクラス名 If InitApplication(p_hInstance, AddressOf WndProc) = True Then
一番大きな問題はこの行にある。VBscriptでは、『AddressOf 』は使えない。
『AddressOf 』が使えないというよりも、コールバック関数を使うのが無理ではないかと思われる。もともと『AddressOf 』はVBが完全なコンパイラ(ネイティブコードにコンパイルされる)になったVer5からの機能で、Ver4以前には無かったものである。VBscriptでは、ネイティブコードにコンパイルされて実行されるのではなく、Ver4以前のVBに近い形のインタプリタの形式で実行している様に思われる。
スクリプトの中でなにかしらの関数を定義した場合、その関数がJavaのJITの様にコンパイルされてメモリに格納されている可能性はある。ただ、そういった場合でもVBscriptはデータ型がバリアント型のみであるので、コールバック関数の規定の型にはめられるように定義することは無理であろう。やはり、コールバック関数は自作DLLの中に用意するしかない。今回製作した自作DLLの中のコールバック関数に関連する部分は次の通りである。
long __stdcall DwWndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
{
return DefWindowProc( hWnd, uiMsg, wParam, lParam );
}
long __stdcall DwAddressOfWndProc()
{
return DwWndProc;
}プロトタイプでは、WndProcの中では何もせずDefWindowProcを呼び出すだけにした(ここの部分が一番重要なのであるが、その対処は次回以降に考えることにしたい)。また、このWndProcのアドレスを与えるDwAddressOfWndProcを用意した。
この機能に対応させて作成したtest.vbsは以下の通りである。
option explicit
Dim UserWrap
Set UserWrap = CreateObject("DynamicWrapper")
UserWrap.Register "debug\dwtools.dll", "Test", "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", "DwAddressOfWndProc", "f=s", "R=l"
UserWrap.Register "user32.dll", "UnregisterClassA", "I=sl", "f=s", "R=l"
UserWrap.Register "user32.dll", "RegisterClassExA", "I=l", "f=s","R=t"
UserWrap.Register "user32.dll", "CreateWindowExA", "I=lsslllllllll", "f=s","R=l"
UserWrap.Register "user32.dll", "ShowWindow", "I=ll", "f=s","R=l"
UserWrap.Register "user32.dll", "UpdateWindow", "I=l", "f=s","R=l"
UserWrap.Register "user32.dll", "GetMessageA", "I=llll", "f=s","R=l"
UserWrap.Register "user32.dll", "TranslateMessage", "I=l", "f=s","R=l"
UserWrap.Register "user32.dll", "DispatchMessage", "I=l", "f=s","R=l"
Const SW_SHOW = 5
Const CS_BYTEALIGNWINDOW = &H2000
Const CS_HREDRAW = &H2
Const CS_VREDRAW = &H1
Const COLOR_BACKGROUND = 1
Const WS_OVERLAPPEDWINDOW = &HCF0000
Const CW_USEDEFAULT = &H80000000
Const WM_PAINT = &HF
Const WM_DESTROY = &H2
Const IMAGE_ICON = 1
Const LR_DEFAULTCOLOR = &H0
Dim g_chAppName, g_chClassName
Dim p_hInstance, p_hPreInst, p_pchCmdLine, p_iCmdShow
Call Main
Wscript.quit
Sub Main()
p_hInstance = 0
p_pchCmdLine = ""
p_iCmdShow = SW_SHOW
g_chAppName = "TestApplication" 'アプリケーションの名前
g_chClassName = "TestWndClass" 'ウィンドウクラス名
If InitApplication(p_hInstance, UserWrap.DwAddressOfWndProc) = True Then
If InitInstance(p_hInstance, p_iCmdShow) = True Then
Call Run
End If
Call UserWrap.UnregisterClassA(g_chClassName, p_hInstance)
End If
End Sub
'ウィンドウクラス
Class WNDCLASSEX
public cbSize ' As Long
public style ' As Long
public lpfnWndProc ' As Long
public cbClsExtra ' As Long
public cbWndExtra ' As Long
public hInstance ' As Long
public hIcon ' As Long
public hCursor ' As Long
public hbrBackground ' As Long
public lpszMenuName ' As String
public lpszClassName ' As String
public hIconSm ' As Long
Public Function Structure()
UserWrap.DwClearBuffer
Structure=UserWrap.DwGetAddressOfString("",48) 'Length of structure is 48
UserWrap.DwCopyLong cbSize, Structure ' As Long
UserWrap.DwCopyLong style, Structure+4 ' As Long
UserWrap.DwCopyLong lpfnWndProc, Structure+8 ' As Long
UserWrap.DwCopyLong cbClsExtra, Structure+12 ' As Long
UserWrap.DwCopyLong cbWndExtra, Structure+16 ' As Long
UserWrap.DwCopyLong hInstance, Structure+20 ' As Long
UserWrap.DwCopyLong hIcon, Structure+24 ' As Long
UserWrap.DwCopyLong hCursor, Structure+28 ' As Long
UserWrap.DwCopyLong hbrBackground, Structure+32 ' As Long
UserWrap.DwCopyLong StrAddress(lpszMenuName), Structure+36 ' As String
UserWrap.DwCopyLong StrAddress(lpszClassName), Structure+40 ' As String
UserWrap.DwCopyLong hIconSm, Structure+44 ' As Long
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
'ウィンドウクラスを登録
Function InitApplication(p_hInstance, AddressOfWndProc )
Dim stWndClass
Set stWndClass=New WNDCLASSEX 'ウィンドウクラス
Call UserWrap.UnregisterClassA(g_chClassName+"", p_hInstance)
stWndClass.cbSize = 48
stWndClass.style = CS_BYTEALIGNWINDOW Or CS_HREDRAW Or CS_VREDRAW
stWndClass.lpfnWndProc = AddressOfWndProc
stWndClass.cbClsExtra = 0
stWndClass.cbWndExtra = 0
stWndClass.hInstance = p_hInstance
stWndClass.hIcon = 0
stWndClass.hCursor = 0
stWndClass.hbrBackground = COLOR_BACKGROUND
stWndClass.lpszMenuName = ""
stWndClass.lpszClassName = g_chClassName
stWndClass.hIconSm = 0
If UserWrap.RegisterClassExA(stWndClass.Structure) Then
InitApplication=True
Else
InitApplication=False
End If
End Function
'ウィンドウの表示
Function InitInstance(p_hInstance, p_nCmdShow)
Dim hWnd 'ウィンドウハンドル
'ウィンドウを作製
hWnd = UserWrap.CreateWindowExA(0, g_chClassName+"", g_chAppName+"", _
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 200, 100, 0, 0, _
p_hInstance, 0)
'ウィンドウを表示
Call UserWrap.ShowWindow(hWnd, p_nCmdShow)
Call UserWrap.UpdateWindow(hWnd)
If hWnd = 0 Then
InitInstance = False
Else
InitInstance = True
End If
End Function
'メッセージループ
Function Run()
'MSG構造体
Dim stMsg
UserWrap.DwClearBuffer
stMsg=UserWrap.DwGetAddressOfString("",28) 'Length of MSG is 28
'メッセージを送る
Do While (UserWrap.GetMessageA(stMsg, 0, 0, 0))
Call UserWrap.TranslateMessage(stMsg)
Call UserWrap.DispatchMessage(stMsg)
Loop
'Run = stMsg.wParam
End Functionこのソースコードは見ての通り、最初に紹介したVB用の『Hello, World!』プログラムと殆ど同じになった。唯一違うのは、コールバック関数が含まれていない点である。実行結果は次のようになる。

残るは、コールバック関数の処理のみ。
(続く)