スレッドの生成を制御したい
Posted: 2012年5月25日(金) 23:57
現在デスクトップクロックを作成中です。
開発環境はvc++ express 2010 , DXライブラリです。
実行画面にはキャラ画像と時計画像を描画し
キャラ画像を左クリックするとセリフを喋ります。
画像の上で右クリックするとトラックポップアップメニューを生成します
キャラが喋っている最中に連続で右クリックするとメニューが必要以上に生成されてしまうことと
セリフとセリフの間を区切る為にSleep関数を使うと時計の描画が止まってしまうことを解決したいです。
スレッドを使用して時計を描画しようとしたのですが、うまくいきませんでした。
WindowProc3関数の1行目にブレークポイントを設定してもそこで止まる様子が無いです。
質問が多くて申し訳ないのですが、ご助力の程よろしくお願いします。
開発環境はvc++ express 2010 , DXライブラリです。
実行画面にはキャラ画像と時計画像を描画し
キャラ画像を左クリックするとセリフを喋ります。
画像の上で右クリックするとトラックポップアップメニューを生成します
キャラが喋っている最中に連続で右クリックするとメニューが必要以上に生成されてしまうことと
セリフとセリフの間を区切る為にSleep関数を使うと時計の描画が止まってしまうことを解決したいです。
スレッドを使用して時計を描画しようとしたのですが、うまくいきませんでした。
WindowProc3関数の1行目にブレークポイントを設定してもそこで止まる様子が無いです。
質問が多くて申し訳ないのですが、ご助力の程よろしくお願いします。
//main.cpp
#include <windows.h>
#include <process.h>
#include <WindowsX.h>
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#include "Setup.h"
#include "resource.h"
#include <windowsx.h>
#define APP_NAME TEXT("clock")
#define chara_width 64
#define WM_POSTENDTHREAD (WM_USER)// スレッド終了を伝えるメッセージ
#define WM_POSTENDTHREAD2 (WM_USER + 1)// スレッド終了を伝えるメッセージ
#define WM_CLOCK (WM_USER + 2)
void jihou(struct dayData* day);
void plan(struct dayData* day);
void Time(struct dayData* day);
void date(struct dayData* day);
LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WindowProc2 (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WindowProc3 (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK MyDlgProc(HWND hChild, UINT msg, WPARAM wp, LPARAM lp);
unsigned __stdcall mythread(void *lpx);
unsigned __stdcall mythread_clock(void *lpx);
static HANDLE hThread,hThread2 = 0;
static HWND hDlg[3];
static int chara_id;
HINSTANCE hInst;
POINT pt;
struct dayData day[471];
unsigned __stdcall mythread(void *lpx){
WNDCLASSEX wc;
HWND hWnd;
MSG msg;
// ウィンドウクラスの情報を設定
wc.cbSize = sizeof(wc); // 構造体サイズ
wc.style = CS_HREDRAW | CS_VREDRAW; // スタイル
wc.lpfnWndProc = WindowProc2; // ウィンドウプロシージャ
wc.cbClsExtra = 0; // 拡張情報1
wc.cbWndExtra = 0; // 拡張情報2
wc.hInstance = hInst; // インスタンスハンドル
wc.hIcon = (HICON)LoadImage( // アイコン
NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED
);
wc.hIconSm = wc.hIcon; // 子アイコン
wc.hCursor = (HCURSOR)LoadImage( // マウスカーソル
NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR,
0, 0, LR_DEFAULTSIZE | LR_SHARED
);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // ウィンドウ背景
wc.lpszMenuName = NULL; // メニュー名
wc.lpszClassName = _T("Default Class Name");// ウィンドウクラス名
// ウィンドウクラスを登録する
RegisterClassEx( &wc );
// ウィンドウを作成する
hWnd = CreateWindow(
wc.lpszClassName, // ウィンドウクラス名
_T("Sample Program"), // タイトルバーに表示する文字列
WS_OVERLAPPEDWINDOW, // ウィンドウの種類
CW_USEDEFAULT, // ウィンドウを表示する位置(X座標)
CW_USEDEFAULT, // ウィンドウを表示する位置(Y座標)
CW_USEDEFAULT, // ウィンドウの幅
CW_USEDEFAULT, // ウィンドウの高さ
NULL, // 親ウィンドウのウィンドウハンドル
NULL, // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
if( hWnd == NULL ){ return 1; }
ShowWindow( hWnd, SW_HIDE );
UpdateWindow( hWnd );
while( 1 )
{
BOOL ret = GetMessage( &msg, NULL, 0, 0 ); // メッセージを取得する
if( ret == 0 || ret == -1 )
{
// アプリケーションを終了させるメッセージが来ていたら、
// あるいは GetMessage() が失敗したら( -1 が返されたら )、ループを抜ける
break;
}
else
{
// メッセージを処理する
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return 0;
}
unsigned __stdcall mythread_clock(void *lpx){
WNDCLASSEX wc;
HWND hWnd;
MSG msg;
// ウィンドウクラスの情報を設定
wc.cbSize = sizeof(wc); // 構造体サイズ
wc.style = CS_HREDRAW | CS_VREDRAW; // スタイル
wc.lpfnWndProc = WindowProc3; // ウィンドウプロシージャ
wc.cbClsExtra = 0; // 拡張情報1
wc.cbWndExtra = 0; // 拡張情報2
wc.hInstance = hInst; // インスタンスハンドル
wc.hIcon = (HICON)LoadImage( // アイコン
NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED
);
wc.hIconSm = wc.hIcon; // 子アイコン
wc.hCursor = (HCURSOR)LoadImage( // マウスカーソル
NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR,
0, 0, LR_DEFAULTSIZE | LR_SHARED
);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // ウィンドウ背景
wc.lpszMenuName = NULL; // メニュー名
wc.lpszClassName = _T("clock");// ウィンドウクラス名
// ウィンドウクラスを登録する
RegisterClassEx( &wc );
// ウィンドウを作成する
hWnd = CreateWindow(
wc.lpszClassName, // ウィンドウクラス名
_T("clock Program"), // タイトルバーに表示する文字列
WS_OVERLAPPEDWINDOW, // ウィンドウの種類
CW_USEDEFAULT, // ウィンドウを表示する位置(X座標)
CW_USEDEFAULT, // ウィンドウを表示する位置(Y座標)
CW_USEDEFAULT, // ウィンドウの幅
CW_USEDEFAULT, // ウィンドウの高さ
NULL, // 親ウィンドウのウィンドウハンドル
NULL, // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
if( hWnd == NULL ){ return 1; }
ShowWindow( hWnd, SW_HIDE );
UpdateWindow( hWnd );
while( 1 )
{
BOOL ret = GetMessage( &msg, NULL, 0, 0 ); // メッセージを取得する
if( ret == 0 || ret == -1 )
{
// アプリケーションを終了させるメッセージが来ていたら、
// あるいは GetMessage() が失敗したら( -1 が返されたら )、ループを抜ける
break;
}
else
{
// メッセージを処理する
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return 0;
}
LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static int top,left;
switch(uMsg) {
case WM_CREATE:
Setup_load(day);//設定を読み込む
left= (day + 0) -> number[0] * 1000 +
(day + 0) -> number[1] * 100 +
(day + 0) -> number[2] * 10 +
(day + 0) -> number[3];
top = (day + 1) -> number[0] * 1000 +
(day + 1) -> number[1] * 100 +
(day + 1) -> number[2] * 10 +
(day + 1) -> number[3];
if (hThread2 == NULL) {
hThread2 = (HANDLE)_beginthreadex(NULL, 0, mythread_clock, NULL, 0, NULL);
}
break;
case WM_MOVING:
{
LPRECT p = (LPRECT)lParam;
top = p -> top;
left = p -> left;
break;
}
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* p = (WINDOWPOS*)lParam;
p -> y = top;
p -> x = left;
break;
}
case WM_NCHITTEST:
return HTCAPTION;
case WM_CLOCK:
draw_clock(day);
ScreenFlip( );
break;
case WM_LBUTTONDOWN:
{
// マウス状態管理用変数
int nClickNow = 0 , nClickPrev = 0;
// マウス状態の更新
nClickNow = (GetMouseInput() & MOUSE_INPUT_LEFT);
if( nClickNow != nClickPrev){
int MouseX = 0,MouseY = 0;
GetMousePoint( &MouseX , &MouseY ) ;// マウスの位置を取得
if(MouseX > chara_x && MouseX < chara_x + chara_width && MouseY > chara_y && MouseY < chara_y + chara_width ){
date(day);//日付を再生
Time(day);//時刻を再生
plan(day);
}
}
SendMessage(GetMainWindowHandle(), WM_NCLBUTTONDOWN, HTCAPTION, 0);//キャラクター画像の座標以外の時
// 今回のクリック状態を保持する
nClickPrev = nClickNow;
break;
}
case WM_RBUTTONDOWN:
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
// if (hThread == NULL) {
hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);
// }
break;
case WM_POSTENDTHREAD:
if (WaitForSingleObject(hThread, 0) != WAIT_TIMEOUT || hDlg[0] == 0 || hDlg[1] == 0) {
// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
DWORD ExitCode;
ExitCode = -1;
GetExitCodeThread(hThread, &ExitCode);
CloseHandle(hThread);
hThread = NULL;
}
else {
// まだスレッドが終了してなかったらメッセージを投げ直す
// ※デッドロック回避のため
PostMessage(hWnd, WM_POSTENDTHREAD, wParam, lParam);
}
break;
case WM_POSTENDTHREAD2:
if (WaitForSingleObject(hThread2, 0) != WAIT_TIMEOUT ) {
// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
DWORD ExitCode;
ExitCode = -1;
GetExitCodeThread(hThread2, &ExitCode);
CloseHandle(hThread2);
hThread2 = NULL;
}
else {
// まだスレッドが終了してなかったらメッセージを投げ直す
// ※デッドロック回避のため
PostMessage(hWnd, WM_POSTENDTHREAD2, wParam, lParam);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return 0;
}
LRESULT CALLBACK WindowProc2 (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_CREATE:
if( !hDlg[0] && !hDlg[1]){
HMENU hMenu,hSubMenu;
hMenu = LoadMenu(hInst,"MYMENU");
hSubMenu = GetSubMenu(hMenu ,0);
ClientToScreen(GetMainWindowHandle() , &pt);
SetForegroundWindow(hWnd);
TrackPopupMenu(hSubMenu,TPM_LEFTALIGN,pt.x,pt.y,0,hWnd,NULL);
DestroyMenu(hMenu);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)){
case IDM_OPTION:
if(!hDlg[0] && !hDlg[1])hDlg[0] = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG), GetMainWindowHandle(), MyDlgProc);
break;
case IDM_EXIT:
Setup_save(day);//設定を書き込む
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;
case IDM_VERSION:
if(!hDlg[0] && !hDlg[1])hDlg[1] = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), GetMainWindowHandle(), MyDlgProc2);
break;
}
break;
case WM_CLOSE:
PostMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
SendMessage(GetMainWindowHandle(), WM_CLOSE,0,0);
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);//Getmessageの返り値が0になる
break;
default:
return ( DefWindowProc(hWnd , uMsg , wParam , lParam) );
}
return 0;
}
LRESULT CALLBACK WindowProc3 (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_CREATE:
PostMessage(GetMainWindowHandle(), WM_CLOCK, 0, 0);
break;
case WM_NCHITTEST:
return HTCAPTION;
case WM_CLOSE:
PostMessage(GetMainWindowHandle(), WM_POSTENDTHREAD2, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
if(FindWindow(APP_NAME , NULL) != NULL ){
MessageBox(NULL , TEXT("多重起動を確認しました") , NULL , MB_OK);
return 0;
}
// 画面モードの変更
SetGraphMode( 1680 , 1050 , 32 ) ;//パソコンの解像度に合わせる
SetMainWindowText("clock");
ChangeWindowMode( TRUE );
SetUseBackBufferTransColorFlag( TRUE );// ウインドウの透過色モードON
SetWindowStyleMode(2);
SetAlwaysRunFlag( TRUE );
SetHookWinProc( WindowProc );
if ( DxLib_Init( ) == -1 ) return -1;
SetDrawScreen(DX_SCREEN_BACK);
Load_Graph();
plan(day);//予定を音声再生する
while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
ClearDrawScreen( );
draw_face(day);
//draw_clock(day); スレッドを使って描画する為、コメントアウト
jihou(day);//全ての描画関数が終わってから呼ぶ
ScreenFlip( );
}
DxLib_End();
return 0;
}