フリーズしてしまう モードレスダイアログ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
s707

フリーズしてしまう モードレスダイアログ

#1

投稿記事 by s707 » 14年前

プログラムの実行と終了を何度か繰り返すと
フリーズしてしまいます。
何が原因となっているのでしょうか?

参考書を確認しましたが "0が返ってきたら終了する" などの
エラーが起こった時にそれを回避する様な
コードはこれ以上なさそうです。
resource.hとsample.rcは関係なさそうですが
念のため載せておきます。

コード:

//resource.h
#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

#define IDD_DIALOG1                             101
#define IDD_DIALOG2                             102
#define IDC_BUTTON1                             1000
#define IDC_RADIO1                              1001
#define IDC_RADIO2                              1002
#define IDC_BUTTON2                             1003
#define IDC_BUTTON3                             1004
#define IDC_RADIO3                              1005
#define IDC_RADIO4                              1006
#define IDC_CHECKBOX1                           1007
#define IDC_CHECKBOX2                           1008
#define IDC_CHECKBOX3                           1009
#define IDC_CHECKBOX4                           1010
#define IDC_CHECKBOX5                           1011
#define IDC_CHECKBOX6                           1012
#define IDC_CHECKBOX7                           1013
#define IDC_CHECKBOX8                           1014
#define IDC_CHECKBOX9                           1015
#define IDC_CHECKBOX10                          1016
#define IDC_CHECKBOX11                          1017
#define IDC_CHECKBOX12                          1018
#define IDC_CHECKBOX13                          1019
#define IDC_CHECKBOX14                          1020
#define IDC_CHECKBOX15                          1021
#define IDC_CHECKBOX16                          1022
#define IDC_CHECKBOX17                          1023
#define IDC_CHECKBOX18                          1024
#define IDC_CHECKBOX19                          1025
#define IDC_CHECKBOX20                          1026
#define IDC_CHECKBOX21                          1027
#define IDC_COMBO1                              1028


//sample.rc
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"

//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG1 DIALOG 0, 0, 192, 96
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "メニュー"
FONT 10, "Ms Shell Dlg"
{
    PUSHBUTTON      "オプション", IDC_BUTTON1, 10, 10, 40, 15 
	PUSHBUTTON      "バージョン", IDC_BUTTON2, 70, 10, 40, 15
    PUSHBUTTON      "終了", IDC_BUTTON3, 130, 10, 40, 15 

	LTEXT           "時報", IDC_STATIC,  20, 35, 20, 10, SS_LEFT
	AUTORADIOBUTTON "ON", IDC_RADIO1, 70, 33, 40, 15
    AUTORADIOBUTTON "OFF", IDC_RADIO2, 130, 33, 40, 15
   
	DEFPUSHBUTTON   "OK", IDOK, 70, 60, 40, 15
    PUSHBUTTON      "Cancel", IDCANCEL, 130, 60, 40, 15
}

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG2 DIALOG 0, 0, 224, 144
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "オプション"
FONT 10, "Ms Shell Dlg"
{ 
	AUTOCHECKBOX    "Check1", IDC_CHECKBOX1,  80, 20, 10, 10
    AUTOCHECKBOX    "Check2", IDC_CHECKBOX2, 100, 20, 10, 10
    AUTOCHECKBOX    "Check3", IDC_CHECKBOX3, 120, 20, 10, 10
    AUTOCHECKBOX    "Check4", IDC_CHECKBOX4, 140, 20, 10, 10
    AUTOCHECKBOX    "Check5", IDC_CHECKBOX5, 160, 20, 10, 10
    AUTOCHECKBOX    "Check6", IDC_CHECKBOX6, 180, 20, 10, 10
    AUTOCHECKBOX    "Check7", IDC_CHECKBOX7, 200, 20, 10, 10
	
    AUTOCHECKBOX    "Check8", IDC_CHECKBOX8,    80, 40, 10, 10
    AUTOCHECKBOX    "Check9", IDC_CHECKBOX9,   100, 40, 10, 10
    AUTOCHECKBOX    "Check10", IDC_CHECKBOX10, 120, 40, 10, 10
    AUTOCHECKBOX    "Check11", IDC_CHECKBOX11, 140, 40, 10, 10
    AUTOCHECKBOX    "Check12", IDC_CHECKBOX12, 160, 40, 10, 10
    AUTOCHECKBOX    "Check13", IDC_CHECKBOX13, 180, 40, 10, 10
    AUTOCHECKBOX    "Check14", IDC_CHECKBOX14, 200, 40, 10, 10
	
    AUTOCHECKBOX    "Check15", IDC_CHECKBOX15,  80, 60, 10, 10
    AUTOCHECKBOX    "Check16", IDC_CHECKBOX16, 100, 60, 10, 10
    AUTOCHECKBOX    "Check17", IDC_CHECKBOX17, 120, 60, 10, 10
    AUTOCHECKBOX    "Check18", IDC_CHECKBOX18, 140, 60, 10, 10
    AUTOCHECKBOX    "Check19", IDC_CHECKBOX19, 160, 60, 10, 10
    AUTOCHECKBOX    "Check20", IDC_CHECKBOX20, 180, 60, 10, 10
    AUTOCHECKBOX    "Check21", IDC_CHECKBOX21, 200, 60, 10, 10
    
	DEFPUSHBUTTON   "OK", IDOK, 80, 120, 50, 15
    PUSHBUTTON      "Cancel", IDCANCEL, 160, 120, 50, 15
    
	LTEXT           "月", IDC_STATIC,  80, 5, 10, 10, SS_LEFT
    LTEXT           "火", IDC_STATIC, 100, 5, 10, 10, SS_LEFT
    LTEXT           "水", IDC_STATIC, 120, 5, 10, 10, SS_LEFT
    LTEXT           "木", IDC_STATIC, 140, 5, 10, 10, SS_LEFT
    LTEXT           "金", IDC_STATIC, 160, 5, 10, 10, SS_LEFT
    LTEXT           "土", IDC_STATIC, 180, 5, 10, 10, SS_LEFT
    LTEXT           "日", IDC_STATIC, 200, 5, 10, 10, SS_LEFT
    
	GROUPBOX        "", IDC_STATIC, 5, 15, 60, 20
	LTEXT           "燃えるゴミの日", IDC_STATIC, 10, 20, 45, 10, SS_LEFT
    
	GROUPBOX        "", IDC_STATIC, 5, 35, 60, 20
	LTEXT           "燃えないゴミの日", IDC_STATIC, 10, 40, 50, 10, SS_LEFT
    
	GROUPBOX        "", IDC_STATIC, 5, 55, 60, 20
	LTEXT           "資源ゴミの日", IDC_STATIC, 10, 60, 50, 10, SS_LEFT
    
	GROUPBOX        "", IDC_STATIC, 5, 75, 60, 20
	LTEXT           "再生日切り替え", IDC_STATIC, 10, 80, 50, 10, SS_LEFT
    
	GROUPBOX        "", IDC_STATIC, 5, 95, 60, 20
	LTEXT           "キャラクター設定", IDC_STATIC, 10, 100, 50, 10, SS_LEFT
    
    AUTORADIOBUTTON "前日", IDC_RADIO3, 80, 80, 30, 10
    AUTORADIOBUTTON "当日", IDC_RADIO4, 160, 80, 30, 10
    COMBOBOX        IDC_COMBO1, 80, 100, 50, 10, CBS_DROPDOWN | CBS_HASSTRINGS
}



//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"

#define APP_NAME TEXT("clock")
#define chara_width 64

void jihou(struct dayData* day);
void plan(struct dayData* day);
void Time(struct dayData* day);
void date(struct dayData* day);
void version(struct dayData* day);
int  title(int,struct dayData* day);

unsigned __stdcall mythread(void *lpx);
unsigned __stdcall mythread2(void *lpx);

HANDLE hThread;
HWND hDlg1,hDlg2;
bool nJihou,nSaisei;


BOOL CALLBACK MyDlgProc(HWND , UINT msg, WPARAM wp, LPARAM lp){
	static HWND hRadio1,hRadio2,hRadio3,hRadio4;

	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
			PostQuitMessage(IDOK);
			//SendMessage(GetMainWindowHandle(), WM_CLOSE, 0, 0);
			return TRUE;
		case IDCANCEL:
			PostQuitMessage(IDCANCEL);
			return TRUE;
		case IDC_RADIO1://時報ON
			nJihou = true;
			return TRUE;
		case IDC_RADIO2://時報OFF
			nJihou = false;
			return TRUE;
		case IDC_BUTTON1://オプション
			CloseHandle(hThread);
			hThread = NULL;         
			if (hThread == NULL) {
				hThread = (HANDLE)_beginthreadex(NULL, 0, mythread2, NULL, 0, NULL);
			}  
			return TRUE;
		case IDC_BUTTON3://終了
			SendMessage(GetMainWindowHandle(), WM_CLOSE, 0, 0);
			return TRUE;
		}
		return FALSE;
	case WM_INITDIALOG:
		hRadio1 = GetDlgItem(hDlg1,IDC_RADIO1);
		hRadio2 = GetDlgItem(hDlg1,IDC_RADIO2);
		hRadio3 = GetDlgItem(hDlg2,IDC_RADIO3);
		hRadio4 = GetDlgItem(hDlg2,IDC_RADIO4);

		if(nJihou)
			Button_SetCheck(hRadio1,BST_CHECKED);
		else
			Button_SetCheck(hRadio2,BST_CHECKED);


		if(nSaisei)
			Button_SetCheck(hRadio3,BST_CHECKED);
		else
			Button_SetCheck(hRadio4,BST_CHECKED);

		return TRUE;
	}
	return FALSE;
}

unsigned __stdcall mythread(void *lpx)
{
	MSG msg;
	hDlg1 = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), GetMainWindowHandle(), MyDlgProc);
	ShowWindow(hDlg1, SW_NORMAL);
	while (GetMessage(&msg, NULL, 0, 0)) {
		if (!hDlg1 || !IsDialogMessage(hDlg1, &msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}

unsigned __stdcall mythread2(void *lpx)
{
	MSG msg;
	hDlg2 = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), GetMainWindowHandle(), MyDlgProc);
	ShowWindow(hDlg2, SW_NORMAL);
	while (GetMessage(&msg, NULL, 0, 0)) {
		if (!hDlg2 || !IsDialogMessage(hDlg2, &msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}


LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	static int top = 0;

	switch(uMsg) {
	case WM_MOVING:
		{		
			LPRECT p = (LPRECT)lParam;
			top = p -> top;
			break;
		}
	case WM_WINDOWPOSCHANGING:		
		{
			WINDOWPOS* p = (WINDOWPOS*)lParam;
			p -> y = top;
			break;
		}
	case WM_NCHITTEST:
		return HTCAPTION;
	case WM_LBUTTONDOWN:
		SendMessage(GetMainWindowHandle(), WM_NCLBUTTONDOWN, HTCAPTION, 0);
		break;
	case WM_RBUTTONDOWN:
		if (hThread == NULL) {
			hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);
		}
		break;
	case WM_CLOSE:
		DestroyWindow(hDlg1);
		DestroyWindow(hDlg2);
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return 0;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
	struct dayData day[450];
	// マウス状態管理用変数
	int nClickNow = 0 , nClickPrev = 0;
	int nClickNow_R = 0 , nClickPrev_R = 0;
	int nClickR_Count = 0;

	int status = 0,temp = 0;
	bool menu_flg = false;

	// 画面モードの変更
	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();
	Setup_load(day);//設定を読み込む
	plan(day);//予定を音声再生する	

	DWORD ExitCode = -1;
	while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
		if (hThread) {
			GetExitCodeThread(hThread, &ExitCode);
			if (ExitCode != STILL_ACTIVE) {
				SendMessage(GetMainWindowHandle(), WM_CLOSE, 0, 0);
			}
		}

		ClearDrawScreen( );
                //その他の処理は省略
		ScreenFlip( );
	}
	DxLib_End( );
	return 0;
}

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: フリーズしてしまう モードレスダイアログ

#2

投稿記事 by ISLe » 14年前

CloseHandleにはスレッドを終了させる効果はありませんので、スレッドが増え続けるのみかと思います。
スレッド関数にはウィンドウメッセージループが含まれてますし、中断させずにきちんとスレッド関数を抜けるようにしないと不具合が出ると思います。

スレッドハンドルをいいかげんに使い回すのではなくきちんとスレッドとの同期を意識して管理してください。
ダイアログのウィンドウハンドルも同様です。ハンドルの中身をきちんとチェックしてください。

メッセージループと同様にウィンドウハンドルもスレッドに属しますから、異なるスレッドからウィンドウハンドルを直接使った操作はできません。
具体的にはWindowProc関数にあるダイアログに対するDestroyWindowが無効です。
SendMessageやPostMessageで適切なメッセージを投げるようにしてください。

WM_CLOSEはPostMessageすべきかと思います。

s707

Re: フリーズしてしまう モードレスダイアログ

#3

投稿記事 by s707 » 14年前

ISLe様、ご返信ありがとうございます。
こちらを参考にしました。今のところフリーズはしなくなりました。
http://www.kumei.ne.jp/c_lang/sdk/sdk_90.htm

2つ目のダイアログボックスにて
キャンセルを押すとクローズ成功のメッセージボックスが出現するのですが
OKを押してもクローズ成功のメッセージボックスが出現しません。

Thread2関数の下記の箇所にブレイクポイントを作成したところ
hDlg[1]が0になっていました。

SendMessage(hDlg[1],WM_ENDOK,0,0L);

OKを押してクローズを成功させるには
どうすればいいでしょうか?

コード:

//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"

#define APP_NAME TEXT("clock")
#define chara_width 64

#define WM_ENDTHREAD (WM_USER)
#define WM_ENDOK (WM_USER + 1)

typedef struct{
	HWND hwnd;
	BOOL thread_end;
} DATA, *PDATA;


void jihou(struct dayData* day);
void plan(struct dayData* day);
void Time(struct dayData* day);
void date(struct dayData* day);
void version(struct dayData* day);
int  title(int,struct dayData* day);

DWORD WINAPI Thread1(LPVOID);
DWORD WINAPI Thread2(LPVOID);
LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK MyDlgProc(HWND hChild, UINT msg, WPARAM wp, LPARAM lp);
BOOL CALLBACK MyDlgProc2(HWND hChild, UINT msg, WPARAM wp, LPARAM lp);

static HANDLE hThread[2];
static HWND hDlg[2];

static DATA data1;
static DATA data2;
HINSTANCE hInst;


BOOL CALLBACK MyDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
	DWORD thId2;

	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
		    data1.thread_end = TRUE;
			PostQuitMessage(IDOK);
			return TRUE;
		case IDCANCEL:
		    data1.thread_end = TRUE;
			PostQuitMessage(IDCANCEL);
			return TRUE;
		case IDC_RADIO1://時報ON
			return TRUE;
		case IDC_RADIO2://時報OFF
			return TRUE;
		case IDC_BUTTON1://オプション
			data2.hwnd = hDlg[1];
			data2.thread_end = FALSE;
			hThread[1] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Thread2, (LPVOID)&data2, 0, &thId2);
			return TRUE;
		case IDC_BUTTON3://終了
			SendMessage(GetMainWindowHandle(), WM_CLOSE, 0, 0);
			return TRUE;
		}
		return FALSE;
	case WM_ENDOK:
		if(hThread[0])CloseHandle(hThread[0]);
		MessageBox(hDlg[0],"ダイアログプロシージャ1のクローズ成功" ,"成功",MB_OK);
		break;
	case WM_ENDTHREAD:
		if(hDlg[0]){
			data1.thread_end = TRUE;
			hDlg[0] = 0;
		}
		break;
	}
	return FALSE;
}

BOOL CALLBACK MyDlgProc2(HWND hChild, UINT msg, WPARAM wp, LPARAM lp){
	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
		    data2.thread_end = TRUE;
			PostQuitMessage(IDOK);
			return TRUE;
		case IDCANCEL:
		    data2.thread_end = TRUE;
			PostQuitMessage(IDCANCEL);
			return TRUE;
		case IDC_RADIO1://時報ON
			return TRUE;
		case IDC_RADIO2://時報OFF
			return TRUE;
		case IDC_BUTTON1://オプション
			return TRUE;
		case IDC_BUTTON3://終了
			SendMessage(GetMainWindowHandle(), WM_CLOSE, 0, 0);
			return TRUE;
		}
		return FALSE;
	case WM_ENDOK:
		if(hThread[1])CloseHandle(hThread[1]);
		MessageBox(hDlg[1],"ダイアログプロシージャ2のクローズ成功" ,"成功",MB_OK);
		break;
	case WM_ENDTHREAD:
		if(hDlg[1]){
			data2.thread_end = TRUE;
			hDlg[1] = 0;
		}
		break;
	}
	return FALSE;
}


DWORD WINAPI Thread1(LPVOID data){
	PDATA pData;
	pData = (PDATA)data;

	MSG msg;
	if(!hDlg[0])hDlg[0] = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), GetMainWindowHandle(), MyDlgProc);
	ShowWindow(hDlg[0], SW_NORMAL);

	while(!pData->thread_end){
		while (GetMessage(&msg, NULL, 0, 0)) {
			if (!hDlg[0] || !IsDialogMessage(hDlg[0], &msg)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}
	SendMessage(hDlg[0],WM_ENDOK,0,0L);
	MessageBox(hDlg[0],"スレッド1を終了します","終了",MB_OK);
	return (DWORD)msg.wParam;
}


DWORD WINAPI Thread2(LPVOID data){
	PDATA pData;
	pData = (PDATA)data;

	MSG msg;
	msg.wParam  = 0;

	if(!hDlg[1])hDlg[1] = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), GetMainWindowHandle(), MyDlgProc2);
	ShowWindow(hDlg[1], SW_NORMAL);

	while(!pData->thread_end){
		while (GetMessage(&msg, NULL, 0, 0)) {
			if (!hDlg[1] || !IsDialogMessage(hDlg[1], &msg)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}
	SendMessage(hDlg[1],WM_ENDOK,0,0L);
	MessageBox(hDlg[1],"スレッド2を終了します","終了",MB_OK);
	return (DWORD)msg.wParam;
}


LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	static int top = 0;

	DWORD thId1;

	switch(uMsg) {
	case WM_MOVING:
		{		
			LPRECT p = (LPRECT)lParam;
			top = p -> top;
			break;
		}
	case WM_WINDOWPOSCHANGING:		
		{
			WINDOWPOS* p = (WINDOWPOS*)lParam;
			p -> y = top;
			break;
		}
	case WM_NCHITTEST:
		return HTCAPTION;
	case WM_LBUTTONDOWN:
		SendMessage(GetMainWindowHandle(), WM_NCLBUTTONDOWN, HTCAPTION, 0);
		break;
	case WM_RBUTTONDOWN:
		data1.hwnd = hDlg[0];
		data1.thread_end = FALSE;
		hThread[0] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Thread1, (LPVOID)&data1, 0, &thId1);
		break;
	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
	struct dayData day[450];
	// マウス状態管理用変数
	int nClickNow = 0 , nClickPrev = 0;
	int nClickNow_R = 0 , nClickPrev_R = 0;
	int nClickR_Count = 0;

	int status = 0,temp = 0;
	bool menu_flg = false;

	// 画面モードの変更
	SetGraphMode( 1680 , 1050 , 32 ) ;//パソコンの解像度に合わせる

	SetMainWindowText("clock");
	ChangeWindowMode( TRUE );
	//	SetWindowText( "DxLib:" DXLIB_VERSION_STR );

	SetUseBackBufferTransColorFlag( TRUE );// ウインドウの透過色モードON
	SetWindowStyleMode(2);
	SetAlwaysRunFlag( TRUE );

	SetHookWinProc( WindowProc );
	if ( DxLib_Init( ) == -1 ) return -1;

	SetDrawScreen(DX_SCREEN_BACK);

	Load_Graph();
	Setup_load(day);//設定を読み込む
	plan(day);//予定を音声再生する	

	while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
		 ClearDrawScreen( );
                //その他の処理は省略
        ScreenFlip( );
	}
	DxLib_End( );
	return 0;
}

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: フリーズしてしまう モードレスダイアログ

#4

投稿記事 by ISLe » 14年前

参考にしたページは、メッセージループとスレッドの関係がまったく反対のものですけど。
前回指摘した内容はほとんどスルーしたという認識でよろしいのでしょうか。
ダイアログのウィンドウハンドル以外の指摘についてはどのように考えて対応されたのでしょう。
対応した形跡は見られますけど、参考にしたページのコードを無理矢理当てはめたことでさらに滅茶苦茶になっています。

フリーズしていないのはたまたまです。
新たに不正なウィンドウハンドルを使用する(場合がある)コードが追加されています。
ウィンドウが破棄されているかもしれないのでメッセージループを抜けたあとにウィンドウハンドルを使ってはいけません。

参考にしたページを真似たのでしょうけど、_beginthreadexからCreateThreadに替えることの影響は認識していますか?

スレッド関数を終了するのは、ダイアログのウィンドウを破棄する方法に統一すればシンプルになります。

スレッドを生成したのと同じスレッドでスレッドハンドルをクローズしましょう。
スレッドが自身のハンドルをクローズするのではなく親ウィンドウにメッセージを投げてそのハンドラで処理するという形にすると良いでしょう。
スレッドの終了をきちんと監視して戻り値を使ってOKかキャンセルか判断するようにしましょう。

前回指摘したことももう一度考えてください。

s707

Re: フリーズしてしまう モードレスダイアログ

#5

投稿記事 by s707 » 14年前

貴重なアドバイスを無駄にするような
真似をしてすみません。


手元にスレッド作成の参考書が
ないので、手順と関連用語が
イマイチ分からないです。


アドバイスを参考に今一度考えて
分かりそうな所から修正を
掛けていきます。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: フリーズしてしまう モードレスダイアログ

#6

投稿記事 by ISLe » 14年前

s707 さんが書きました:手元にスレッド作成の参考書が
ないので、手順と関連用語が
イマイチ分からないです。
DXライブラリが隠蔽しているメッセージループにウィンドウメッセージが流れないように、新たに作成したスレッドでダイアログを作成しメッセージループを回すわけですが、一般的にはかなりトリッキーな方法です。
スレッドごとに独立したメッセージループを回す実用的なサンプルを掲載している参考書やサイトを見付けるのは難しいかもしれません。
#そういう仕組みであるということを解説しているサイトはたくさん見付かりますけど。

プログラムとしてはスレッドひとつひとつがウィンドウアプリケーションというふうな構造なので、ひとつひとつ区別して考えましょう。
できるならグローバル変数を使わないようにしてスレッド(ダイアログ)ごとにソースファイルを分ければ区別せざるを得なくなります。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: フリーズしてしまう モードレスダイアログ

#7

投稿記事 by ISLe » 14年前

スレッドハンドルのクローズの仕方のサンプルを作ってみました。
スレッドの生成とクローズを同じスレッド(ウィンドウプロシージャですが)で行います。

コード:

#include "DxLib.h"
#include <process.h>

// スレッド終了を伝えるメッセージ
#define WM_POSTENDTHREAD (WM_USER)

HANDLE hThread;
HWND hDlg;

BOOL CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
			PostQuitMessage(IDOK);
			return TRUE;
		case IDCANCEL:
			PostQuitMessage(IDCANCEL);
			return TRUE;
		}
		return FALSE;
	}
	return FALSE;
}

unsigned __stdcall mythread(void *lpx)
{
	MSG msg;
	hDlg = CreateDialog(GetModuleHandle(NULL), "DIALOG", GetMainWindowHandle(), MyDlgProc);
	ShowWindow(hDlg, SW_NORMAL);
	while (GetMessage(&msg, NULL, 0, 0)) {
		if (!IsDialogMessage(hDlg, &msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	// スレッド終了を伝えるメッセージを親ウィンドウに投げる
	PostMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);
	return msg.wParam;
}


LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg) {
	case WM_RBUTTONDOWN:
		if (hThread == NULL) {
			hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);
		}
		break;
	case WM_POSTENDTHREAD:
		if (WaitForSingleObject(hThread, 0) == WAIT_TIMEOUT) {
			// まだスレッドが終了してなかったらメッセージを投げ直す
			// ※デッドロック回避のため
			PostMessage(hWnd, WM_POSTENDTHREAD, wParam, lParam);
		}
		else {
			// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
			DWORD ExitCode = -1;
			GetExitCodeThread(hThread, &ExitCode);
			CloseHandle(hThread);
			hThread = NULL;
		}
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	ChangeWindowMode(TRUE);
	SetAlwaysRunFlag(TRUE);
	SetHookWinProc(WindowProc);
	if (DxLib_Init() == -1) return 0;
	SetDrawScreen(DX_SCREEN_BACK);

	while (ProcessMessage( ) == 0) {
		ClearDrawScreen();
		DrawFormatString(0,0,GetColor(255,255,255),"%d",(int)GetNowCount());
		ScreenFlip();
	}
	DxLib_End( );
	return 0;
}

s707

Re: フリーズしてしまう モードレスダイアログ

#8

投稿記事 by s707 » 14年前

以前のコメントと今回のコードを照らし合わせて
学ぶことが出来ました。

ISLe様、今回も助かりました。ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る