ab.com コミュニティ https://www.activebasic.com/forum/ |
|
汎用メッセージスレッド&サンプル https://www.activebasic.com/forum/viewtopic.php?t=449 |
ページ 1 / 1 |
作成者: | NoWest [ 2005年11月13日(日) 18:29 ] |
記事の件名: | 汎用メッセージスレッド&サンプル |
メッセージスレッドとは簡単に言いますと、スレッドとメッセージループを組み合わせたものです。 通常メッセージループはウィンドウを制御するために使いますが、実は各スレッドが1つのメッセージキューを持つことができ、そのメッセージキューの内容をスレッドメッセージを使って制御することができます。 スレッドメッセージキューにメッセージを送る際には 専用のPostThreadMessage関数が使われますが、メッセージを取得する側は通常のメッセージループがスレッド内にあるだけでほとんど違いはありません。 違うとすれば、PeekMessage関数とSleep関数を使って メッセージキューを作成するところだけです。 コード: Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" (lpEventAttributes As *SECURITY_ATTRIBUTES, bManualReset As Long, bInitialState As Long, lpName As *Char) As HANDLE Declare Function SetEvent Lib "kernel32" (hEvent As HANDLE) As Long Declare Function ResetEvent Lib "kernel32" (hEvent As HANDLE) As Long Sub MessageThreadProc(hEvent As HANDLE) /* スレッドメッセージキューの作成 */ Dim msg As MSG Do PostThreadMessage(GetCurrentThreadId(),WM_USER,0,0) If PeekMessage(msg,NULL,WM_USER,WM_USER,PM_REMOVE)=TRUE Then Exit Do Sleep(0) Loop /* メインスレッドに準備の完了を通知 */ If hEvent<>NULL Then SetEvent(hEvent) /* スレッドメッセージループ */ While GetMessage(msg,0,0,0)>0 Select Case msg.message Case WM_USER+1 /*ここに処理を記述 1*/ Case WM_USER+2 /*ここに処理を記述 2*/ Case WM_USER+・・・ /*ここに処理を記述 ・・・*/ End Select Wend /* メインスレッドに終了の完了を通知 */ If hEvent<>NULL Then SetEvent(hEvent) /* メインスレッドの終了 */ ExitThread(&HE0F) End Sub Class CMessageThread Private m_hThread As HANDLE m_idThread As DWord m_hEvent As HANDLE Public Sub CMessageThread() /* イベントを作成 */ m_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL) /* スレッドを作成 */ m_hThread=CreateThread(ByVal NULL,0,AddressOf(MessageThreadProc),m_hEvent,0,VarPtr(m_idThread)) /* スレッドメッセージキュー作成まで待機 */ If m_hEvent<>NULL and m_hThread<>NULL Then WaitForSingleObject(m_hEvent,INFINITE) End Sub Sub ~CMessageThread() If m_hEvent<>NULL Then ResetEvent(m_hEvent) /* スレッドへ終了を通知 */ SendMsg(WM_QUIT,0,0) /* スレッド終了まで待機 */ If m_hEvent<>NULL and m_hThread<>NULL Then WaitForSingleObject(m_hEvent,INFINITE) /* ハンドルを破棄 */ If m_hEvent<>NULL Then CloseHandle(m_hEvent) If m_hThread<>NULL Then CloseHandle(m_hThread) End Sub Function SendMsg(dwMsg As DWord, wParam As DWord, lParam As DWord) As Long /* スレッドにメッセージを送信 */ SendMsg=PostThreadMessage(m_idThread,dwMsg,wParam,lParam) End Function End Class コードを見ていただくと、MessageThreadProc内に コード: Case WM_USER+1 /*ここに処理を記述 1*/となっている所があると思います。 これを見て分かるように、WM_USER+1というようにメッセージによって処理を振り分けています。 このプログラムを動かしたい場合 コード: ***.SendMsg(WM_USER+1,0,0)いう感じでメッセージを送信します。 WPARAMやLPARAMといった追加情報も同時に送信できたり、同時に複数のメッセージが送信されてもメッセージキューに貯められて逐次実行されるのでメモリ関連のエラーもあまり気にすることはありません。 ただ、メッセージを送信しても戻り値を取得できないという問題はあります。。。 何か良いアイデアをお持ちの方は改良に挑戦してください。 サンプル(MCIを使った別スレッドでの再生) [ここをクリックすると内容が表示されます]
私はゲーム開発でこれをよく使います。
コード: Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" (lpEventAttributes As *SECURITY_ATTRIBUTES, bManualReset As Long, bInitialState As Long, lpName As *Char) As HANDLE Declare Function SetEvent Lib "kernel32" (hEvent As HANDLE) As Long Declare Function ResetEvent Lib "kernel32" (hEvent As HANDLE) As Long Const MEM_SOUND1 = WM_USER+1 Const MEM_SOUND2 = WM_USER+2 Sub PMciEngine(hEvent As HANDLE) Dim Msg As MSG Do PostThreadMessage(GetCurrentThreadId(),WM_USER,0,0) If PeekMessage(Msg,NULL,WM_USER,WM_USER,PM_REMOVE)=TRUE Then Exit Do Sleep(0) Loop If hEvent=NULL Then ExitThread(&HE0F) Exit Sub End If SetEvent(hEvent) /* MCIデバイスを開く */ Dim mop[ELM(2)] As MCI_OPEN_PARMS mop[0].lpstrElementName="sound1.wav" mop[1].lpstrElementName="sound2.wav" mciSendCommand(0,MCI_OPEN,MCI_OPEN_ELEMENT,mop[0]) mciSendCommand(0,MCI_OPEN,MCI_OPEN_ELEMENT,mop[1]) /* スレッドメッセージを使ってMCIデバイスを再生 */ Dim mpp As MCI_OPEN_PARMS While GetMessage(Msg,0,0,0)>0 Select Case Msg.message Case MEM_SOUND1 mciSendCommand(mop[0].wDeviceID,MCI_PLAY,MCI_FROM,mpp) Case MEM_SOUND1 mciSendCommand(mop[1].wDeviceID,MCI_PLAY,MCI_FROM,mpp) End Select Wend /* MCIデバイスを閉じる */ Dim mgp As DWord mciSendCommand(mop[0].wDeviceID,MCI_CLOSE,0,mgp) mciSendCommand(mop[1].wDeviceID,MCI_CLOSE,0,mgp) If hEvent<>NULL Then SetEvent(hEvent) ExitThread(&HE0F) End Sub Class CMciEngine Private m_hThread As HANDLE m_idThread As DWord m_hEvent As HANDLE Public Sub CMciEngine() m_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL) m_hThread=CreateThread(ByVal NULL,0,AddressOf(PMciEngine),m_hEvent,0,VarPtr(m_idThread)) If m_hEvent<>NULL and m_hThread<>NULL Then WaitForSingleObject(m_hEvent,INFINITE) End Sub Sub ~CMciEngine() If m_hEvent<>NULL Then ResetEvent(m_hEvent) SendMsg(WM_QUIT,0,0) If m_hEvent<>NULL and m_hThread<>NULL Then WaitForSingleObject(m_hEvent,INFINITE) If m_hEvent<>NULL Then CloseHandle(m_hEvent) If m_hThread<>NULL Then CloseHandle(m_hThread) End Sub Function SendMsg(dwMsg As DWord, wParam As DWord, lParam As DWord) As Long SendMsg=PostThreadMessage(m_idThread,dwMsg,wParam,lParam) End Function End Class Dim me As *CMciEngine '----------------------------------------------------------------------------- ' ウィンドウメッセージを処理するためのコールバック関数 Function MainWndProc(hWnd As HWND, dwMsg As DWord, wParam As WPARAM, lParam As LPARAM) As DWord ' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。 ' イベントプロシージャの呼び出しを行います。 MainWndProc=EventCall_MainWnd(hWnd,dwMsg,wParam,lParam) End Function '----------------------------------------------------------------------------- ' ここから下は、イベントプロシージャを記述するための領域になります。 Sub MainWnd_Destroy() Delete me MciEngine_DestroyObjects() PostQuitMessage(0) End Sub Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT) me=New CMciEngine End Sub Sub MainWnd_CommandButton1_Click() me->SendMsg(MEM_SOUND1,0,0) End Sub Sub MainWnd_CommandButton2_Click() me->SendMsg(MEM_SOUND2,0,0) End Sub |
ページ 1 / 1 | 全ての表示時間は UTC+09:00 です |
Powered by phpBB® Forum Software © phpBB Limited https://www.phpbb.com/ |