by 淡幻星 » 2005年12月11日(日) 00:27
「おぉ!!できるんだ、こういうことも☆」ってノリが全てです(笑)。
【やってること】
DLLを呼び出し、呼び出した先のDLLの内部でウィンドウを作成し、
呼び出し元のウィンドウはロック。
処理が終わった後に、DLL側のウィンドウを破棄し、
ロックを解除し制御を、呼び出し元に返します。
動作確認AB3.13+AB2.59
【以下、コードなど】
『プロジェクト→
DLL-プロシージャライブラリ』で作成。
※DLL内部でグローバル変数を使っていることに注意。
[
'DLLのインスタンス記録用]の部分
※DLLエントリポイント云々[
DllMain()の中]にも一行書き込んでいることに注意。
[
'窓作成に使うのでDLLのインスタンスを保持。]の部分
DLLコードはこちら。 [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
'#include "DLLonWnd.idx"'ここは任意ですね^^;
'-------------------------------------------------------------------
' メモ - このファイルには、DLLの構成要素を記述します。
' (例:関数定義、グローバル変数、定数定義など)
'
' エクスポートが必要な関数には、"Export" 修飾子を指定します。
' (例:Function Export FuncName() As Long)
'-------------------------------------------------------------------
'DLLのインスタンス記録用
Dim g_hInstance As Long
Function Export DllMain(hinstDLL As DWord, fdwReason As DWord, lpvReserved As VoidPtr) As Long
'DLLエントリポイント
Select Case fdwReason
Case DLL_PROCESS_ATTACH
'DLLがプロセス空間にロードされた時に実行されます。
g_hInstance = hinstDLL '窓作成に使うのでDLLのインスタンスを保持。
_System_StartupProgram()
DllMain=1
End Select
End Function
'DLLの外から呼ばれる関数。
'窓を作って任意の処理をする。
'実際の処理の内容は下のメッセージループMainProc()に記述する。
Function Export DllWnd( hBaseWnd As Long ) As Long
Dim hInstance As DWord
Dim WinClass As WNDCLASSEX
Dim hWnd As DWord
Dim msgMain As MSG
'初期値設定処理
FillMemory( VarPtr(WinClass), Len(WinClass), NULL )
hInstance = g_hInstance'GetModuleHandle( NULL )
'ウインドウクラス生成
With WinClass
.cbSize = Len( WinClass )
.hInstance = hInstance
.style = CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
.lpszClassName = "WsSelfWnd"
.lpszMenuName = "WsSelfMenu"
.lpfnWndProc = AddressOf( MainProc )
.hbrBackground = GetStockObject( WHITE_BRUSH )
.cbClsExtra = NULL
.cbWndExtra = NULL
.hIcon = LoadIcon( hInstance, NULL )
.hCursor = LoadCursor( NULL, IDC_ARROW )
EndWith
If( NULL=RegisterClassEx( WinClass ) )Then
DllWnd = FALSE
EndIf
'ウインドウ生成
hWnd = CreateWindowEx( NULL, "WsSelfWnd", "テストAB3", (WS_OVERLAPPEDWINDOW or WS_VISIBLE), _
CW_USEDEFAULT , CW_USEDEFAULT, _
CW_USEDEFAULT , CW_USEDEFAULT, _
hBaseWnd, NULL, hInstance, NULL )
EnableWindow( hBaseWnd, FALSE )'親窓をロック
'メッセージループ
While( GetMessage( msgMain, NULL, 0, 0 ) )
TranslateMessage( msgMain )
DispatchMessage( msgMain )
Wend
DllWnd = msgMain.wParam
EnableWindow( hBaseWnd, TRUE )'親窓のロックを解除
EndFunction
'メッセージループ
Function MainProc( hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord ) As DWord
SelectCase dwMsg
Case WM_DESTROY
'窓の破棄処理
PostQuitMessage(0)
MainProc = 0
ExitFunction
'Case
'以下、ここに処理を書いていく。
EndSelect
' デフォルトプロシージャを呼び出す。
MainProc = DefWindowProc( hWnd, dwMsg, wParam, lParam )
End Function
それの呼び出し元のAB2のコードの例は以下です。
DLLファイル名をDLLonWnd.dllとしています。
スペースを押すと、DLLの中のDllWnd()を呼び出して窓を表示します。
それを閉じればAB2側の窓に制御が戻ります。
AB2からの利用例。 [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Declare Function DllWnd Lib "DLLonWnd.dll" ( ByVal hBaseWnd As Long ) As Long
Ver2Wnd( Ownerwnd() )
End
Sub Ver2Wnd( ByVal hBaseWnd As Long )
dim hThisWnd As Long
dim Message As Long
dim wParam As Long
dim lParam As Long
dim hWnd As Long
Dim retAns As Long
Window hWnd, hBaseWnd, -1, -1, _
320, 240, _
"AB2テスト", _
WS_OVERLAPPED or WS_CAPTION or WS_DLGFRAME or WS_SYSMENU or WS_VISIBLE, _
"NORMAL"
While 1
GetWndMsg hThisWnd, Message, wParam, lParam
If ( hThisWnd<>hBaseWnd ) Then
SelectCase Message
'終了操作
Case WM_CLOSE
Msgbox hWnd, "終了処理"
ExitWhile
EndSelect
'スペースでDLLの関数呼び出し
If KeyState(Asc(" ")) And &H8000 Then
retAns = DllWnd( hWnd )
Msgbox hWnd, "ほげ"
EndIf
EndIf
Wend
DelWnd hWnd
EndSub
AB2でプログラムを組んでいて、
負荷の高い処理はAB3/AB4で作ったDLLを呼び出して処理する、
などという変なことをしている人(=私の仲間w)にしか
参考にならないかもしれません(苦笑)。
ついでに。
DLL作成のときは、デバックモードが無いので、
大抵別途に組んで動作を確かめてから関数だけをコピペしてますよね、きっと。
そのときの『動作の確かめ用』のコードも以下に載せておきます。
『プロジェクト→
EXE-N88プロンプトベース』で作成。
でも当然ながらN88BASICのプロンプト画面は使いません^^;
使ったらDLLに移したときにエラーします。
あ、Print文とかでデバッグするのは楽になるかも?
(『
EXE-ベース無し』を選べばよかったのかな?)
なにはともあれ、そのときのコードです。
窓作成 [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
#N88BASIC
' ↓ ここからプログラムが実行されます
Dim retAns As Long
retAns = WinMain( _PromptSys_hWnd )
End 'ExitProcess(0)を呼んでいます。
Function WinMain( hBaseWnd As Long ) As Long
Dim hInstance As DWord
Dim WinClass As WNDCLASSEX
Dim hWnd As DWord
Dim msgMain As MSG
'初期化
FillMemory( VarPtr(WinClass), Len(WinClass), NULL )
hInstance = GetModuleHandle( NULL )
'ウインドウクラス生成
With WinClass
.cbSize = Len( WinClass )
.hInstance = hInstance
.style = CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
.lpszClassName = "WsSelfWnd"
.lpszMenuName = "WsSelfMenu"
.lpfnWndProc = AddressOf( MainProc )
.hbrBackground = GetStockObject( WHITE_BRUSH )
.cbClsExtra = NULL
.cbWndExtra = NULL
.hIcon = LoadIcon( hInstance, NULL )
.hCursor = LoadCursor( NULL, IDC_ARROW )
EndWith
If( NULL=RegisterClassEx( WinClass ) )Then
WinMain = FALSE
EndIf
'ウインドウ生成
hWnd = CreateWindowEx( NULL, "WsSelfWnd", "テストAB3", (WS_OVERLAPPEDWINDOW or WS_VISIBLE), _
CW_USEDEFAULT , CW_USEDEFAULT, _
CW_USEDEFAULT , CW_USEDEFAULT, _
hBaseWnd, NULL, hInstance, NULL )
While( GetMessage( msgMain, NULL, 0, 0 ) )
TranslateMessage( msgMain )
DispatchMessage( msgMain )
Wend
WinMain = msgMain.wParam
EndFunction
メッセージループ [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
'メッセージループ
Function MainProc( hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord ) As DWord
' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。
SelectCase dwMsg
Case WM_DESTROY
PostQuitMessage(0)
MainProc = 0
ExitFunction
'Case
'以下、ここに処理を書いていく。
EndSelect
' デフォルトプロシージャを呼び出す。
MainProc = DefWindowProc( hWnd, dwMsg, wParam, lParam )
End Function
以上二つをプロジェクトに参加させて下さい。
なお、こちらは親ウィンドウ(=DLLでの呼び出し元の窓)であるプロンプトウインドウはロックしていません。
ふむ。
『Win32プログラミング講座 ~ Step14. DLLを作る ~』で思いっきり
DLLに窓ハンドル渡して内部で保存ダイアログなどを呼んでいるわけだから、
出来て当然なのか^^;
12/11 2:30修正しました。
「おぉ!!できるんだ、こういうことも☆」ってノリが全てです(笑)。
【やってること】
DLLを呼び出し、呼び出した先のDLLの内部でウィンドウを作成し、
呼び出し元のウィンドウはロック。
処理が終わった後に、DLL側のウィンドウを破棄し、
ロックを解除し制御を、呼び出し元に返します。
動作確認AB3.13+AB2.59
【以下、コードなど】
『プロジェクト→[i]DLL-プロシージャライブラリ[/i]』で作成。
※DLL内部でグローバル変数を使っていることに注意。
[[b]'DLLのインスタンス記録用[/b]]の部分
※DLLエントリポイント云々[[b]DllMain()[/b]の中]にも一行書き込んでいることに注意。
[[b]'窓作成に使うのでDLLのインスタンスを保持。[/b]]の部分
[hide=DLLコードはこちら。][code]'#include "DLLonWnd.idx"'ここは任意ですね^^;
'-------------------------------------------------------------------
' メモ - このファイルには、DLLの構成要素を記述します。
' (例:関数定義、グローバル変数、定数定義など)
'
' エクスポートが必要な関数には、"Export" 修飾子を指定します。
' (例:Function Export FuncName() As Long)
'-------------------------------------------------------------------
'DLLのインスタンス記録用
Dim g_hInstance As Long
Function Export DllMain(hinstDLL As DWord, fdwReason As DWord, lpvReserved As VoidPtr) As Long
'DLLエントリポイント
Select Case fdwReason
Case DLL_PROCESS_ATTACH
'DLLがプロセス空間にロードされた時に実行されます。
g_hInstance = hinstDLL '窓作成に使うのでDLLのインスタンスを保持。
_System_StartupProgram()
DllMain=1
End Select
End Function
'DLLの外から呼ばれる関数。
'窓を作って任意の処理をする。
'実際の処理の内容は下のメッセージループMainProc()に記述する。
Function Export DllWnd( hBaseWnd As Long ) As Long
Dim hInstance As DWord
Dim WinClass As WNDCLASSEX
Dim hWnd As DWord
Dim msgMain As MSG
'初期値設定処理
FillMemory( VarPtr(WinClass), Len(WinClass), NULL )
hInstance = g_hInstance'GetModuleHandle( NULL )
'ウインドウクラス生成
With WinClass
.cbSize = Len( WinClass )
.hInstance = hInstance
.style = CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
.lpszClassName = "WsSelfWnd"
.lpszMenuName = "WsSelfMenu"
.lpfnWndProc = AddressOf( MainProc )
.hbrBackground = GetStockObject( WHITE_BRUSH )
.cbClsExtra = NULL
.cbWndExtra = NULL
.hIcon = LoadIcon( hInstance, NULL )
.hCursor = LoadCursor( NULL, IDC_ARROW )
EndWith
If( NULL=RegisterClassEx( WinClass ) )Then
DllWnd = FALSE
EndIf
'ウインドウ生成
hWnd = CreateWindowEx( NULL, "WsSelfWnd", "テストAB3", (WS_OVERLAPPEDWINDOW or WS_VISIBLE), _
CW_USEDEFAULT , CW_USEDEFAULT, _
CW_USEDEFAULT , CW_USEDEFAULT, _
hBaseWnd, NULL, hInstance, NULL )
EnableWindow( hBaseWnd, FALSE )'親窓をロック
'メッセージループ
While( GetMessage( msgMain, NULL, 0, 0 ) )
TranslateMessage( msgMain )
DispatchMessage( msgMain )
Wend
DllWnd = msgMain.wParam
EnableWindow( hBaseWnd, TRUE )'親窓のロックを解除
EndFunction
'メッセージループ
Function MainProc( hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord ) As DWord
SelectCase dwMsg
Case WM_DESTROY
'窓の破棄処理
PostQuitMessage(0)
MainProc = 0
ExitFunction
'Case
'以下、ここに処理を書いていく。
EndSelect
' デフォルトプロシージャを呼び出す。
MainProc = DefWindowProc( hWnd, dwMsg, wParam, lParam )
End Function[/code][/hide]それの呼び出し元のAB2のコードの例は以下です。
DLLファイル名をDLLonWnd.dllとしています。
スペースを押すと、DLLの中のDllWnd()を呼び出して窓を表示します。
それを閉じればAB2側の窓に制御が戻ります。
[hide=AB2からの利用例。][code]Declare Function DllWnd Lib "DLLonWnd.dll" ( ByVal hBaseWnd As Long ) As Long
Ver2Wnd( Ownerwnd() )
End
Sub Ver2Wnd( ByVal hBaseWnd As Long )
dim hThisWnd As Long
dim Message As Long
dim wParam As Long
dim lParam As Long
dim hWnd As Long
Dim retAns As Long
Window hWnd, hBaseWnd, -1, -1, _
320, 240, _
"AB2テスト", _
WS_OVERLAPPED or WS_CAPTION or WS_DLGFRAME or WS_SYSMENU or WS_VISIBLE, _
"NORMAL"
While 1
GetWndMsg hThisWnd, Message, wParam, lParam
If ( hThisWnd<>hBaseWnd ) Then
SelectCase Message
'終了操作
Case WM_CLOSE
Msgbox hWnd, "終了処理"
ExitWhile
EndSelect
'スペースでDLLの関数呼び出し
If KeyState(Asc(" ")) And &H8000 Then
retAns = DllWnd( hWnd )
Msgbox hWnd, "ほげ"
EndIf
EndIf
Wend
DelWnd hWnd
EndSub[/code][/hide]
AB2でプログラムを組んでいて、
負荷の高い処理はAB3/AB4で作ったDLLを呼び出して処理する、
などという変なことをしている人(=私の仲間w)にしか
参考にならないかもしれません(苦笑)。
ついでに。
DLL作成のときは、デバックモードが無いので、
大抵別途に組んで動作を確かめてから関数だけをコピペしてますよね、きっと。
そのときの『動作の確かめ用』のコードも以下に載せておきます。
『プロジェクト→[i]EXE-N88プロンプトベース[/i]』で作成。
でも当然ながらN88BASICのプロンプト画面は使いません^^;
使ったらDLLに移したときにエラーします。
あ、Print文とかでデバッグするのは楽になるかも?
(『[i]EXE-ベース無し[/i]』を選べばよかったのかな?)
なにはともあれ、そのときのコードです。
[hide=窓作成][code]#N88BASIC
' ↓ ここからプログラムが実行されます
Dim retAns As Long
retAns = WinMain( _PromptSys_hWnd )
End 'ExitProcess(0)を呼んでいます。
Function WinMain( hBaseWnd As Long ) As Long
Dim hInstance As DWord
Dim WinClass As WNDCLASSEX
Dim hWnd As DWord
Dim msgMain As MSG
'初期化
FillMemory( VarPtr(WinClass), Len(WinClass), NULL )
hInstance = GetModuleHandle( NULL )
'ウインドウクラス生成
With WinClass
.cbSize = Len( WinClass )
.hInstance = hInstance
.style = CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
.lpszClassName = "WsSelfWnd"
.lpszMenuName = "WsSelfMenu"
.lpfnWndProc = AddressOf( MainProc )
.hbrBackground = GetStockObject( WHITE_BRUSH )
.cbClsExtra = NULL
.cbWndExtra = NULL
.hIcon = LoadIcon( hInstance, NULL )
.hCursor = LoadCursor( NULL, IDC_ARROW )
EndWith
If( NULL=RegisterClassEx( WinClass ) )Then
WinMain = FALSE
EndIf
'ウインドウ生成
hWnd = CreateWindowEx( NULL, "WsSelfWnd", "テストAB3", (WS_OVERLAPPEDWINDOW or WS_VISIBLE), _
CW_USEDEFAULT , CW_USEDEFAULT, _
CW_USEDEFAULT , CW_USEDEFAULT, _
hBaseWnd, NULL, hInstance, NULL )
While( GetMessage( msgMain, NULL, 0, 0 ) )
TranslateMessage( msgMain )
DispatchMessage( msgMain )
Wend
WinMain = msgMain.wParam
EndFunction[/code][/hide][hide=メッセージループ][code]'メッセージループ
Function MainProc( hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord ) As DWord
' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。
SelectCase dwMsg
Case WM_DESTROY
PostQuitMessage(0)
MainProc = 0
ExitFunction
'Case
'以下、ここに処理を書いていく。
EndSelect
' デフォルトプロシージャを呼び出す。
MainProc = DefWindowProc( hWnd, dwMsg, wParam, lParam )
End Function[/code][/hide]以上二つをプロジェクトに参加させて下さい。
なお、こちらは親ウィンドウ(=DLLでの呼び出し元の窓)であるプロンプトウインドウはロックしていません。
ふむ。
『Win32プログラミング講座 ~ Step14. DLLを作る ~』で思いっきり
DLLに窓ハンドル渡して内部で保存ダイアログなどを呼んでいるわけだから、
出来て当然なのか^^;
[size=84][color=#ff0000]12/11 2:30修正しました。[/color][/size]