ページ 11

スレッドの生成を制御したい

Posted: 2012年5月25日(金) 23:57
by s707
現在デスクトップクロックを作成中です。
開発環境は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;
}

Re: スレッドの生成を制御したい

Posted: 2012年5月26日(土) 00:07
by softya(ソフト屋)
えーと、動作しているスレッドの関係がわからないのですが(まだコード解析していないため)分かりやすく解説してもらえますか?
基本的にはメニューの連続処理はフラグなどで抑止できますし、セリフなどの表示はSleepを使わずTimerを使うことでスレッドの出番はないと思うんですが何処にしスレッドを使っているんでしょうか?
※ ちなみにDXライブラリはスレッドでの動作を保証されていません。 DxLib_Initから DxLib_EndまではもちろんDXライブラリ関数は全てDxLib_Initと同じスレッドの動作のみ保証されています。

[補足]
少し解読・・・。
ソースが全部無いですしコメントがないので短時間で完全解析は困難ですね。
スレッドでDXライブラリは呼んでいないかな? だとすれば後はメッセージ処理の流れで変になっているところだけ直せば良いと思いますがSendMessage()が気になります。
PostMessage()とSendMessage()をちゃんと意識して使わけていないとしたらデッドロックする可能性があるでしょう。

Re: スレッドの生成を制御したい

Posted: 2012年5月26日(土) 09:01
by s707
softya(ソフト屋)様、ご返信ありがとうございます。
ソースコードを追加します。

キャラ画像をクリックすると現在の日付と時間等を喋ります。
日付と時間を喋る時に間を空ける為、sleep関数を使用しています。

Sleepを使わず、Timerも試してみますね。

使い分けは意識していたのですが
postmessageやsendmessageも再々確認してみます。

コード:

//dayData.h
struct dayData{
    char name[41];
    char number[6];
} ;


//draw_clock.h
void draw_clock(struct dayData* day);
void draw_face(struct dayData* day);
void draw_mouse(struct dayData* day);
void Load_Graph();
extern int GHandle[18];



//Setup.h
void Setup_load(struct dayData* day);
void Setup_save(struct dayData* day);
extern int character;
extern int ch;
extern int clock_x;
extern int clock_y;
extern int chara_x;
extern int chara_y;
extern int wait_time;


//date.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dayData.h"
#include "draw_clock.h"
#include "DxLib.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

void date(struct dayData* day){
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255

	int SHandle;
	
	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(local->tm_mon + 1){
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+63+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:			
			hiduke = strcmp((day+i+ch)->name, (day+64+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:			
			hiduke = strcmp((day+i+ch)->name, (day+65+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+66+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+67+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+68+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+69+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+70+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 10:
			hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 11:
			hiduke = strcmp((day+i+ch)->name, (day+72+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 12:
			hiduke = strcmp((day+i+ch)->name, (day+73+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day + 109 + ch) -> name ) ;//がつ
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;


	while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
	int date[2];
	date[0] = (local->tm_mday / 10)%10;//十の位
	date[1] = local->tm_mday % 10;//一の位

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(date[0]){
		case 1:
			if(date[1]){
				hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+121+ch)->name);//十日  今の音声は"じゅう"
				if( !hiduke )sound = true;
			}
			break;
		case 2:
			if(date[1]){
				hiduke = strcmp((day+i+ch)->name, (day+74+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+122+ch)->name);//二十日  今の音声は"にじゅう"
				if( !hiduke )sound = true;
			}
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+75+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(date[0])PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}


	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(date[1]){
		case 0:
			if(date[0] == 3){
				hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
				if( !hiduke )sound = true;
			}
			break;
		case 1:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+112+ch)->name);//一日 今の音声は"いち"
				if( !hiduke )sound = true;
			}
			break;
		case 2:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+63+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+113+ch)->name);//二日
				if( !hiduke )sound = true;
			}
			break;
		case 3:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+64+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+114+ch)->name);//3日
				if( !hiduke )sound = true;
			}
			break;
		case 4:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+65+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+115+ch)->name);//4日
				if( !hiduke )sound = true;
			}
			break;
		case 5:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+66+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+116+ch)->name);//5日
				if( !hiduke )sound = true;
			}
			break;
		case 6:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+67+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+117+ch)->name);//6日
				if( !hiduke )sound = true;
			}
			break;
		case 7:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+68+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+118+ch)->name);//7日
				if( !hiduke )sound = true;
			}
			break;
		case 8:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+69+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+119+ch)->name);//8日
				if( !hiduke )sound = true;
			}
			break;
		case 9:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+70+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+120+ch)->name);//9日
				if( !hiduke )sound = true;
			}
			break;
		}	

		if(sound){//音声再生フラグがon
			if( !(date[0] && !date[1]) ){
				SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			}
			if(date[0] && date[1] || date[0] == 3){
				while( CheckSoundMem( SHandle) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
				SHandle = LoadSoundMem( (day + 110 + ch) -> name ) ;//にち
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle, DX_PLAYTYPE_BACK ) ;
			}
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(local->tm_wday){
		case 0:
			hiduke = strcmp((day+i+ch)->name, (day+78+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+79+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+80+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+81+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+82+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+83+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+84+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day + 111 + ch) -> name ) ;//です
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
	while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ	
	Sleep(wait_time);
	InitSoundMem() ;//サウンドデータの削除
}


//draw_clock.cpp
#include <time.h>
#include "DxLib.h"
#include "dayData.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

#define chara_width 64
#define needle_x clock_x + 96
#define needle_y clock_y + 96

#define FontSize 16
#define PI	3.1415926535897932384626433832795f

int GHandle[18];
int GHandle_F[5][16];

void draw_clock(struct dayData* day){
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換
	
	DrawGraph( clock_x , clock_y , GHandle[0] , TRUE ) ;//文字盤
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_hour%12)*30 + (local->tm_min/2) + 180)*PI/180, GHandle[1], TRUE ) ;//短針  時間*30度%12時間 + 分/2   1分毎に0.5度づつ進む為/2
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_min*6) + 180)*PI/180, GHandle[2], TRUE ) ;//長針
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_sec*6) + 180)*PI/180, GHandle[3], TRUE ) ;//秒針
}

void draw_face(struct dayData* day){
	static int frmcnt = 0;//フレームカウント
	frmcnt++;

	//現状の数値は1199フレーム(約20秒)  数列は11990
	int blink = (day + 8) -> number[0] * 1000 + (day + 8) -> number[1] * 100 + (day + 8) -> number[2] * 10 + (day + 8) -> number[3];

	if(frmcnt % blink >= 0 && frmcnt % blink <= (day + 9) -> number[0] ){
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ 1 ] , TRUE ) ;//2枚目(目パチ) アニメーションスピードは3フレーム
	}
	else{
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ 0 ] , TRUE ) ;//通常時の顔
	}
}

void draw_mouse(struct dayData* day){
	static int frmcnt = 0;//フレームカウント
	frmcnt++;
	static int arr = 2;

	if( frmcnt % (day + 10) -> number[0] == 0){
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ arr++ ] , TRUE ) ;//3枚目からアニメーション10枚 アニメーションスピードは3フレーム
	}

	if(arr == 12)arr -= 10;
}

void Load_Graph(){
	GHandle[0] = LoadGraph( "Resourse./PNG/mojiban.png" );
	GHandle[1] = LoadGraph( "Resourse./PNG/tanshin.png");
	GHandle[2] = LoadGraph( "Resourse./PNG/cyoushin.png" );
	GHandle[3] = LoadGraph( "Resourse./PNG/byoushin.png");
//	LoadDivGraph( "Resourse./PNG/menu.png" , 14 , 2 , 7 , 128 , 16 , GHandle + 4 ) ;

	LoadDivGraph( "Resourse./PNG/face_00.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[0] ) ;
	LoadDivGraph( "Resourse./PNG/face_01.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[1] ) ;
	LoadDivGraph( "Resourse./PNG/face_02.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[2] ) ;
	LoadDivGraph( "Resourse./PNG/face_03.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[3] ) ;
	LoadDivGraph( "Resourse./PNG/face_04.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[4] ) ;
}


//jihou.cpp
#include <time.h>
#include "dayData.h"
#pragma warning ( disable : 4996 )

void Time(struct dayData* day);

void jihou(struct dayData* day){
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int min[2],sec[2];
	min[0] = (local->tm_min / 10)%10;
	min[1] = local->tm_min % 10;

	sec[0] = (local->tm_sec / 10)%10;
	sec[1] = local->tm_sec % 10;

	if( !min[0] && !min[1] && !sec[0] && !sec[1] && ( day + 5 ) -> number[0] )Time(day);//時報がONの時 一時間毎に時刻を読む
}


//plan.cpp
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#include "Setup.h"
#include <time.h>
#pragma warning ( disable : 4996 )

void plan(struct dayData* day){
	int SHandle[35];
	int arr;
	int frmcnt = 0;
	frmcnt++;
	bool alarm = false;

	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換
	
	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255

	if(!alarm && frmcnt == 1){
		for(int i = 0; i < 7; i++){//先にデータロードを完了させる
			SHandle[i] = LoadSoundMem( (day + i + 36 + ch) -> name ) ;
		}

		if( ( day + 3 ) -> number[0]  == 0 ){//設定した日 0なら当日 1なら前日
			arr = 0;

			for(int i = 0; i<3; i++){
				if( local->tm_wday == 1 && (day + 15 + i*7) -> number[0] || local->tm_wday == 2 && (day + 16 + i*7) -> number[0] || local->tm_wday == 3 && (day + 17 + i*7) -> number[0] || 
					local->tm_wday == 4 && (day + 18 + i*7) -> number[0] || local->tm_wday == 5 && (day + 19 + i*7) -> number[0] || local->tm_wday == 6 && (day + 20 + i*7) -> number[0] ||
					local->tm_wday == 0 && (day + 21 + i*7) -> number[0]){

					if(!alarm){
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//今日
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ

						arr = 2;
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//は
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
					}

					if(i == 0){     arr = 3; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えるゴミ
					else if(i == 1){arr = 4; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えないゴミ
					else if(i == 2){arr = 5; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//資源ゴミ
					while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
					Sleep(wait_time);
					alarm = true;
				}
			}
		}
		else if( ( day + 3 ) -> number[0]  == 1 ){//前日設定
			arr = 1;

			for(int i = 0; i<3; i++){
				if( local->tm_wday == 0 && (day + 15 + i*7) -> number[0] || local->tm_wday == 1 && (day + 16 + i*7) -> number[0] || local->tm_wday == 2 && (day + 17 + i*7) -> number[0] || 
					local->tm_wday == 3 && (day + 18 + i*7) -> number[0] || local->tm_wday == 4 && (day + 19 + i*7) -> number[0] || local->tm_wday == 5 && (day + 20 + i*7) -> number[0] ||
					local->tm_wday == 6 && (day + 21 + i*7) -> number[0]){

					if(!alarm){
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//明日
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ

						arr = 2;
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//は
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
					}

					if(i == 0){     arr = 3; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えるゴミ
					else if(i == 1){arr = 4; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えないゴミ
					else if(i == 2){arr = 5; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//資源ゴミ
					while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
					Sleep(wait_time);
					alarm = true;
				}
			}
		}

		for(int i = 42; i<62; i++){
			int hiduke = 1;
			bool sound = false;
			switch(local->tm_yday){
			case 0://元日
				hiduke = strcmp((day+i)->number, (day+42+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 6://七草
				hiduke = strcmp((day+i)->number, (day+43+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 9://成人の日
				hiduke = strcmp((day+i)->number, (day+44+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 33://節分
				hiduke = strcmp((day+i)->number, (day+45+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 41://建国記念日
				hiduke = strcmp((day+i)->number, (day+46+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 79://春分の日
				hiduke = strcmp((day+i)->number, (day+47+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 118://昭和の日
				hiduke = strcmp((day+i)->number, (day+48+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 122://憲法記念日
				hiduke = strcmp((day+i)->number, (day+49+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 123://みどりの日
				hiduke = strcmp((day+i)->number, (day+50+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 124://こどもの日
				hiduke = strcmp((day+i)->number, (day+51+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 160://海の日
				hiduke = strcmp((day+i)->number, (day+52+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 261://敬老の日
				hiduke = strcmp((day+i)->number, (day+53+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 265://秋分の日
				hiduke = strcmp((day+i)->number, (day+54+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 282://体育の日
				hiduke = strcmp((day+i)->number, (day+55+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 306://文化の日
				hiduke = strcmp((day+i)->number, (day+56+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 318://七五三
				hiduke = strcmp((day+i)->number, (day+57+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 326://勤労感謝の日
				hiduke = strcmp((day+i)->number, (day+58+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 356://天皇誕生日
				hiduke = strcmp((day+i)->number, (day+59+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 357://クリスマスイヴ
				hiduke = strcmp((day+i)->number, (day+60+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 358://クリスマス
				hiduke = strcmp((day+i)->number, (day+61+ch)->number);
				if( !hiduke )sound = true;
				break;
			}

			if(sound){//音声再生フラグがon
				SHandle[i-15] = LoadSoundMem( (day+i+ch) -> name ) ;
				ChangeVolumeSoundMem( volume, SHandle[i-15] ) ;
				PlaySoundMem( SHandle[i-15] , DX_PLAYTYPE_BACK ) ;
				while( CheckSoundMem( SHandle[i-15] ) == 1 ){  draw_mouse(day); draw_clock(day); ScreenFlip();}// なり終わるまでここでループ
			}
		}
	}
	InitSoundMem() ;//サウンドデータの削除
}


//Setup.cpp
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#pragma warning ( disable : 4800 )
#pragma warning ( disable : 4804 )

#define  FontSize 16
#define menu_x chara_x
#define menu_y chara_y + 64
#define menu_width 160//オプション画面の横文字の長さ  フォントサイズが16なので10文字分

int character = 0;
int ch = 0;
int chara_x = 0;
int chara_y = 0;
int clock_x = 0;
int clock_y = 0;
int wait_time = 0;
//-----------------------------------------------------------------------------
// Name: Setup_load()
// Desc: 設定読み込み関数
//-----------------------------------------------------------------------------
void Setup_load(struct dayData* day){
	char key1[8]="name000";
	char key2[8]="data000";
	static bool load = false;

	//INIファイル読み込み
	for(int i = 0; i < 36; i++){
		GetPrivateProfileString("Setup",key1,"--------", (day+i) -> name,41,"Resourse./Setup.INI");
		GetPrivateProfileString("Setup",key2,"00000"   , (day+i) -> number,6,"Resourse./Setup.INI");
		key1[6]++;
		key2[6]++;

		if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}//10の位をプラス 1の位を0に 
		if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
		if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}//100の位をプラス 10の位を0に 
		if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}

		for(int j = 0;j<5;j++){
			(day+i) -> number[j] -= '0';//アスキーコードから数字に変換
		}
	}

	character = ( day + 4 ) -> number[0] ;
	ch = character * 87;

	wait_time = (day + 6) -> number[0] * 10000 + (day + 6) -> number[1] * 1000 + (day + 6) -> number[2] * 100 + (day + 6) -> number[3] * 10 + (day + 6) -> number[4];

	chara_x = (day + 11) -> number[0] * 1000 + (day + 11) -> number[1] * 100 + (day + 11) -> number[2] * 10 + (day + 11) -> number[3];
	chara_y = (day + 12) -> number[0] * 1000 + (day + 12) -> number[1] * 100 + (day + 12) -> number[2] * 10 + (day + 12) -> number[3];
	clock_x = (day + 13) -> number[0] * 1000 + (day + 13) -> number[1] * 100 + (day + 13) -> number[2] * 10 + (day + 13) -> number[3];
	clock_y = (day + 14) -> number[0] * 1000 + (day + 14) -> number[1] * 100 + (day + 14) -> number[2] * 10 + (day + 14) -> number[3];

	//INIファイル読み込み
	if( load == false ){
		load = true;
		for(int i = 36; i < 471; i++){
			GetPrivateProfileString("Setup",key1,"--------", (day+i) -> name,41,"Resourse./Setup.INI");
			GetPrivateProfileString("Setup",key2,"00000"   , (day+i) -> number,6,"Resourse./Setup.INI");
			key1[6]++;
			key2[6]++;

			if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}//10の位をプラス 1の位を0に 
			if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
			if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}//100の位をプラス 10の位を0に 
			if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}
		}
	}
}
//-----------------------------------------------------------------------------
// Name: Setup_save()
// Desc: 設定書き込み関数
//-----------------------------------------------------------------------------
void Setup_save(struct dayData* day){
	char key1[8]="name000";
	char key2[8]="data000";
	RECT rect;
	GetWindowRect(GetMainWindowHandle(),&rect);//ウィンドウの座標を取得
	
		(day + 0) -> number[0] = (rect.left / 1000) % 10;//ウィンドウのx座標を代入
		(day + 0) -> number[1] = (rect.left / 100) % 10;
		(day + 0) -> number[2] = (rect.left / 10) % 10;
		(day + 0) -> number[3] = rect.left % 10;

		(day + 1) -> number[0] = (rect.top / 1000) % 10;//ウィンドウのy座標を代入
		(day + 1) -> number[1] = (rect.top / 100) % 10;
		(day + 1) -> number[2] = (rect.top / 10) % 10;
		(day + 1) -> number[3] = rect.top % 10;

	//INIファイル書き込み
	for(int i = 0; i < 36; i++){
		for(int j = 0;j<5;j++){
			(day+i) -> number[j] += '0';//数字からアスキーコードに変換
		}

		WritePrivateProfileString("Setup",key1, (day+i) -> name,"Resourse./Setup.INI");
		WritePrivateProfileString("Setup",key2, (day+i) -> number,"Resourse./Setup.INI");
		key1[6]++;
		key2[6]++;

		if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}
		if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
		if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}
		if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}
	}
}


//time.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dayData.h"
#include "draw_clock.h"
#include "DxLib.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

void Time(struct dayData* day){
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255
	int SHandle;

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		int hour = local->tm_hour % 12;
		switch(hour){
		case 0:
			hiduke = strcmp((day+i+ch)->name, (day+85+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+86+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+87+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+88+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+89+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+90+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+91+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+92+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+93+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+94+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 10:
			hiduke = strcmp((day+i+ch)->name, (day+95+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 11:
			hiduke = strcmp((day+i+ch)->name, (day+96+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	int min[2];
	min[0] = (local->tm_min / 10)%10;
	min[1] = local->tm_min % 10;

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(min[0]){
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+74+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+75+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+76+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+77+ch)->name);
			if( !hiduke )sound = true;
			break;	
		}		
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(min[0])PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(min[1]){
		case 0:
			if( min[0] ){
				hiduke = strcmp((day+i+ch)->name, (day+98+ch)->name);
				if( !hiduke )sound = true;
			}
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+99+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+100+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+101+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+102+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+103+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+104+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+105+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+106+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+107+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(local->tm_min)PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day+111+ch)->name ) ;//です
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
	while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); draw_clock(day); ScreenFlip(); }// なり終わるまでここでループ
	Sleep(wait_time);

	InitSoundMem() ;//サウンドデータの削除
}

Re: スレッドの生成を制御したい

Posted: 2012年5月26日(土) 11:34
by softya(ソフト屋)
コメントの件とスレッドの構成の解説(関数の関係なども詳細に)もお願いします。

Re: スレッドの生成を制御したい

Posted: 2012年5月29日(火) 01:19
by s707
PostMessage()とSendMessage()は未確認です。
コメント追加しました。

コード:

//dayData.h
struct dayData{
    char name[41];//ファイル名を入れる変数
    char number[6];
} ;


//draw_clock.h
void draw_clock(struct dayData* day);//時計描画
void draw_face(struct dayData* day);//キャラクターの顔描画
void draw_mouse(struct dayData* day);//キャラクターの口描画
void Load_Graph();//グラフィックをロード
extern int GHandle[18];


//Setup.h
void Setup_load(struct dayData* day);//設定のロード
void Setup_save(struct dayData* day);//設定のセーブ
extern int character;
extern int ch;
extern int clock_x;
extern int clock_y;
extern int chara_x;
extern int chara_y;
extern int wait_time;


//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;
}


//date.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dayData.h"
#include "draw_clock.h"
#include "DxLib.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

void date(struct dayData* day){//日付を音声再生する関数
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255

	int SHandle;
	
	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(local->tm_mon + 1){
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+63+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:			
			hiduke = strcmp((day+i+ch)->name, (day+64+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:			
			hiduke = strcmp((day+i+ch)->name, (day+65+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+66+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+67+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+68+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+69+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+70+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 10:
			hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 11:
			hiduke = strcmp((day+i+ch)->name, (day+72+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 12:
			hiduke = strcmp((day+i+ch)->name, (day+73+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day + 109 + ch) -> name ) ;//がつ
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;


	while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
	int date[2];
	date[0] = (local->tm_mday / 10)%10;//十の位
	date[1] = local->tm_mday % 10;//一の位

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(date[0]){
		case 1:
			if(date[1]){
				hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+121+ch)->name);//十日  今の音声は"じゅう"
				if( !hiduke )sound = true;
			}
			break;
		case 2:
			if(date[1]){
				hiduke = strcmp((day+i+ch)->name, (day+74+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+122+ch)->name);//二十日  今の音声は"にじゅう"
				if( !hiduke )sound = true;
			}
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+75+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(date[0])PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
		}
	}


	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(date[1]){
		case 0:
			if(date[0] == 3){
				hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
				if( !hiduke )sound = true;
			}
			break;
		case 1:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+112+ch)->name);//一日 今の音声は"いち"
				if( !hiduke )sound = true;
			}
			break;
		case 2:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+63+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+113+ch)->name);//二日
				if( !hiduke )sound = true;
			}
			break;
		case 3:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+64+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+114+ch)->name);//3日
				if( !hiduke )sound = true;
			}
			break;
		case 4:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+65+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+115+ch)->name);//4日
				if( !hiduke )sound = true;
			}
			break;
		case 5:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+66+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+116+ch)->name);//5日
				if( !hiduke )sound = true;
			}
			break;
		case 6:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+67+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+117+ch)->name);//6日
				if( !hiduke )sound = true;
			}
			break;
		case 7:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+68+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+118+ch)->name);//7日
				if( !hiduke )sound = true;
			}
			break;
		case 8:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+69+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+119+ch)->name);//8日
				if( !hiduke )sound = true;
			}
			break;
		case 9:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+70+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+120+ch)->name);//9日
				if( !hiduke )sound = true;
			}
			break;
		}	

		if(sound){//音声再生フラグがon
			if( !(date[0] && !date[1]) ){
				SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			}
			if(date[0] && date[1] || date[0] == 3){
				while( CheckSoundMem( SHandle) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
				SHandle = LoadSoundMem( (day + 110 + ch) -> name ) ;//にち
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle, DX_PLAYTYPE_BACK ) ;
			}
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(local->tm_wday){
		case 0:
			hiduke = strcmp((day+i+ch)->name, (day+78+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+79+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+80+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+81+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+82+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+83+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+84+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day + 111 + ch) -> name ) ;//です
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
	while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ	
	Sleep(wait_time);
	InitSoundMem() ;//サウンドデータの削除
}


//draw_clock.cpp
#include <time.h>
#include "DxLib.h"
#include "dayData.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

#define chara_width 64
#define needle_x clock_x + 96
#define needle_y clock_y + 96

#define FontSize 16
#define PI	3.1415926535897932384626433832795f

int GHandle[18];
int GHandle_F[5][16];

void draw_clock(struct dayData* day){//時計描画関数
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換
	
	DrawGraph( clock_x , clock_y , GHandle[0] , TRUE ) ;//文字盤
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_hour%12)*30 + (local->tm_min/2) + 180)*PI/180, GHandle[1], TRUE ) ;//短針  時間*30度%12時間 + 分/2   1分毎に0.5度づつ進む為/2
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_min*6) + 180)*PI/180, GHandle[2], TRUE ) ;//長針
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_sec*6) + 180)*PI/180, GHandle[3], TRUE ) ;//秒針
}

void draw_face(struct dayData* day){//キャラクター画像描画関数
	static int frmcnt = 0;//フレームカウント
	frmcnt++;

	//現状の数値は1199フレーム(約20秒)  数列は11990
	int blink = (day + 8) -> number[0] * 1000 + (day + 8) -> number[1] * 100 + (day + 8) -> number[2] * 10 + (day + 8) -> number[3];//目パチのスピード

	if(frmcnt % blink >= 0 && frmcnt % blink <= (day + 9) -> number[0] ){
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ 1 ] , TRUE ) ;//2枚目(目パチ) アニメーションスピードは3フレーム
	}
	else{
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ 0 ] , TRUE ) ;//通常時の顔
	}
}

void draw_mouse(struct dayData* day){//キャラクターの口のアニメーション関数
	static int frmcnt = 0;//フレームカウント
	frmcnt++;
	static int arr = 2;

	if( frmcnt % (day + 10) -> number[0] == 0){
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ arr++ ] , TRUE ) ;//3枚目からアニメーション10枚 アニメーションスピードは3フレーム
	}

	if(arr == 12)arr -= 10;
}

void Load_Graph(){//グラフィックをロードする関数
	GHandle[0] = LoadGraph( "Resourse./PNG/mojiban.png" );
	GHandle[1] = LoadGraph( "Resourse./PNG/tanshin.png");
	GHandle[2] = LoadGraph( "Resourse./PNG/cyoushin.png" );
	GHandle[3] = LoadGraph( "Resourse./PNG/byoushin.png");

	LoadDivGraph( "Resourse./PNG/face_00.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[0] ) ;
	LoadDivGraph( "Resourse./PNG/face_01.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[1] ) ;
	LoadDivGraph( "Resourse./PNG/face_02.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[2] ) ;
	LoadDivGraph( "Resourse./PNG/face_03.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[3] ) ;
	LoadDivGraph( "Resourse./PNG/face_04.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[4] ) ;
}


//plan.cpp
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#include "Setup.h"
#include <time.h>
#pragma warning ( disable : 4996 )

void plan(struct dayData* day){//予定や祝日を音声再生する関数
	int SHandle[35];
	int arr;
	int frmcnt = 0;
	frmcnt++;
	bool alarm = false;

	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換
	
	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255

	if(!alarm && frmcnt == 1){
		for(int i = 0; i < 7; i++){//先にデータロードを完了させる
			SHandle[i] = LoadSoundMem( (day + i + 36 + ch) -> name ) ;
		}

		if( ( day + 3 ) -> number[0]  == 0 ){//設定した日 0なら当日 1なら前日
			arr = 0;

			for(int i = 0; i<3; i++){
				if( local->tm_wday == 1 && (day + 15 + i*7) -> number[0] || local->tm_wday == 2 && (day + 16 + i*7) -> number[0] || local->tm_wday == 3 && (day + 17 + i*7) -> number[0] || 
					local->tm_wday == 4 && (day + 18 + i*7) -> number[0] || local->tm_wday == 5 && (day + 19 + i*7) -> number[0] || local->tm_wday == 6 && (day + 20 + i*7) -> number[0] ||
					local->tm_wday == 0 && (day + 21 + i*7) -> number[0]){

					if(!alarm){
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//今日
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ

						arr = 2;
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//は
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ
					}

					if(i == 0){     arr = 3; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えるゴミ
					else if(i == 1){arr = 4; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えないゴミ
					else if(i == 2){arr = 5; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//資源ゴミ
					while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
					Sleep(wait_time);
					alarm = true;
				}
			}
		}
		else if( ( day + 3 ) -> number[0]  == 1 ){//前日設定
			arr = 1;

			for(int i = 0; i<3; i++){
				if( local->tm_wday == 0 && (day + 15 + i*7) -> number[0] || local->tm_wday == 1 && (day + 16 + i*7) -> number[0] || local->tm_wday == 2 && (day + 17 + i*7) -> number[0] || 
					local->tm_wday == 3 && (day + 18 + i*7) -> number[0] || local->tm_wday == 4 && (day + 19 + i*7) -> number[0] || local->tm_wday == 5 && (day + 20 + i*7) -> number[0] ||
					local->tm_wday == 6 && (day + 21 + i*7) -> number[0]){

					if(!alarm){
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//明日
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ

						arr = 2;
						ChangeVolumeSoundMem( volume, SHandle[arr] ) ;
						PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;//は
						while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ
					}

					if(i == 0){     arr = 3; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えるゴミ
					else if(i == 1){arr = 4; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//燃えないゴミ
					else if(i == 2){arr = 5; ChangeVolumeSoundMem( volume, SHandle[arr] ) ; PlaySoundMem( SHandle[arr] , DX_PLAYTYPE_BACK ) ;}//資源ゴミ
					while( CheckSoundMem( SHandle[arr] ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/ ScreenFlip(); }// なり終わるまでここでループ
					Sleep(wait_time);
					alarm = true;
				}
			}
		}

		for(int i = 42; i<62; i++){
			int hiduke = 1;
			bool sound = false;
			switch(local->tm_yday){
			case 0://元日
				hiduke = strcmp((day+i)->number, (day+42+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 6://七草
				hiduke = strcmp((day+i)->number, (day+43+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 9://成人の日
				hiduke = strcmp((day+i)->number, (day+44+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 33://節分
				hiduke = strcmp((day+i)->number, (day+45+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 41://建国記念日
				hiduke = strcmp((day+i)->number, (day+46+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 79://春分の日
				hiduke = strcmp((day+i)->number, (day+47+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 118://昭和の日
				hiduke = strcmp((day+i)->number, (day+48+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 122://憲法記念日
				hiduke = strcmp((day+i)->number, (day+49+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 123://みどりの日
				hiduke = strcmp((day+i)->number, (day+50+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 124://こどもの日
				hiduke = strcmp((day+i)->number, (day+51+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 160://海の日
				hiduke = strcmp((day+i)->number, (day+52+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 261://敬老の日
				hiduke = strcmp((day+i)->number, (day+53+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 265://秋分の日
				hiduke = strcmp((day+i)->number, (day+54+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 282://体育の日
				hiduke = strcmp((day+i)->number, (day+55+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 306://文化の日
				hiduke = strcmp((day+i)->number, (day+56+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 318://七五三
				hiduke = strcmp((day+i)->number, (day+57+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 326://勤労感謝の日
				hiduke = strcmp((day+i)->number, (day+58+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 356://天皇誕生日
				hiduke = strcmp((day+i)->number, (day+59+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 357://クリスマスイヴ
				hiduke = strcmp((day+i)->number, (day+60+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 358://クリスマス
				hiduke = strcmp((day+i)->number, (day+61+ch)->number);
				if( !hiduke )sound = true;
				break;
			}

			if(sound){//音声再生フラグがon
				SHandle[i-15] = LoadSoundMem( (day+i+ch) -> name ) ;
				ChangeVolumeSoundMem( volume, SHandle[i-15] ) ;
				PlaySoundMem( SHandle[i-15] , DX_PLAYTYPE_BACK ) ;
				while( CheckSoundMem( SHandle[i-15] ) == 1 ){  draw_mouse(day); /*draw_clock(day);*/  ScreenFlip();}// なり終わるまでここでループ
			}
		}
	}
	InitSoundMem() ;//サウンドデータの削除
}


//Setup.cpp
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#pragma warning ( disable : 4800 )
#pragma warning ( disable : 4804 )

#define  FontSize 16
#define menu_x chara_x
#define menu_y chara_y + 64
#define menu_width 160//オプション画面の横文字の長さ  フォントサイズが16なので10文字分

int character = 0;
int ch = 0;
int chara_x = 0;
int chara_y = 0;
int clock_x = 0;
int clock_y = 0;
int wait_time = 0;
//-----------------------------------------------------------------------------
// Name: Setup_load()
// Desc: 設定読み込み関数
//-----------------------------------------------------------------------------
void Setup_load(struct dayData* day){
	char key1[8]="name000";
	char key2[8]="data000";
	static bool load = false;

	//INIファイル読み込み
	for(int i = 0; i < 36; i++){
		GetPrivateProfileString("Setup",key1,"--------", (day+i) -> name,41,"Resourse./Setup.INI");
		GetPrivateProfileString("Setup",key2,"00000"   , (day+i) -> number,6,"Resourse./Setup.INI");
		key1[6]++;
		key2[6]++;

		if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}//10の位をプラス 1の位を0に 
		if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
		if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}//100の位をプラス 10の位を0に 
		if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}

		for(int j = 0;j<5;j++){
			(day+i) -> number[j] -= '0';//アスキーコードから数字に変換
		}
	}

	character = ( day + 4 ) -> number[0] ;
	ch = character * 87;

	//セリフとセリフの間を決める変数
	wait_time = (day + 6) -> number[0] * 10000 + (day + 6) -> number[1] * 1000 + (day + 6) -> number[2] * 100 + (day + 6) -> number[3] * 10 + (day + 6) -> number[4];

	chara_x = (day + 11) -> number[0] * 1000 + (day + 11) -> number[1] * 100 + (day + 11) -> number[2] * 10 + (day + 11) -> number[3];
	chara_y = (day + 12) -> number[0] * 1000 + (day + 12) -> number[1] * 100 + (day + 12) -> number[2] * 10 + (day + 12) -> number[3];
	clock_x = (day + 13) -> number[0] * 1000 + (day + 13) -> number[1] * 100 + (day + 13) -> number[2] * 10 + (day + 13) -> number[3];
	clock_y = (day + 14) -> number[0] * 1000 + (day + 14) -> number[1] * 100 + (day + 14) -> number[2] * 10 + (day + 14) -> number[3];

	//INIファイル読み込み
	if( load == false ){
		load = true;
		for(int i = 36; i < 471; i++){
			GetPrivateProfileString("Setup",key1,"--------", (day+i) -> name,41,"Resourse./Setup.INI");
			GetPrivateProfileString("Setup",key2,"00000"   , (day+i) -> number,6,"Resourse./Setup.INI");
			key1[6]++;
			key2[6]++;

			if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}//10の位をプラス 1の位を0に 
			if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
			if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}//100の位をプラス 10の位を0に 
			if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}
		}
	}
}
//-----------------------------------------------------------------------------
// Name: Setup_save()
// Desc: 設定書き込み関数
//-----------------------------------------------------------------------------
void Setup_save(struct dayData* day){
	char key1[8]="name000";
	char key2[8]="data000";
	RECT rect;
	GetWindowRect(GetMainWindowHandle(),&rect);//ウィンドウの座標を取得
	
		(day + 0) -> number[0] = (rect.left / 1000) % 10;//ウィンドウのx座標を代入
		(day + 0) -> number[1] = (rect.left / 100) % 10;
		(day + 0) -> number[2] = (rect.left / 10) % 10;
		(day + 0) -> number[3] = rect.left % 10;

		(day + 1) -> number[0] = (rect.top / 1000) % 10;//ウィンドウのy座標を代入
		(day + 1) -> number[1] = (rect.top / 100) % 10;
		(day + 1) -> number[2] = (rect.top / 10) % 10;
		(day + 1) -> number[3] = rect.top % 10;

	//INIファイル書き込み
	for(int i = 0; i < 36; i++){
		for(int j = 0;j<5;j++){
			(day+i) -> number[j] += '0';//数字からアスキーコードに変換
		}

		WritePrivateProfileString("Setup",key1, (day+i) -> name,"Resourse./Setup.INI");
		WritePrivateProfileString("Setup",key2, (day+i) -> number,"Resourse./Setup.INI");
		key1[6]++;
		key2[6]++;

		if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}
		if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
		if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}
		if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}
	}
}


//time.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dayData.h"
#include "draw_clock.h"
#include "DxLib.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

void Time(struct dayData* day){//現在の時間を音声再生する関数
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255
	int SHandle;

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		int hour = local->tm_hour % 12;
		switch(hour){
		case 0:
			hiduke = strcmp((day+i+ch)->name, (day+85+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+86+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+87+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+88+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+89+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+90+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+91+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+92+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+93+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+94+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 10:
			hiduke = strcmp((day+i+ch)->name, (day+95+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 11:
			hiduke = strcmp((day+i+ch)->name, (day+96+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){ draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	int min[2];
	min[0] = (local->tm_min / 10)%10;
	min[1] = local->tm_min % 10;

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(min[0]){
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+74+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+75+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+76+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+77+ch)->name);
			if( !hiduke )sound = true;
			break;	
		}		
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(min[0])PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(min[1]){
		case 0:
			if( min[0] ){
				hiduke = strcmp((day+i+ch)->name, (day+98+ch)->name);
				if( !hiduke )sound = true;
			}
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+99+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+100+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+101+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+102+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+103+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+104+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+105+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+106+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+107+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(local->tm_min)PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day+111+ch)->name ) ;//です
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
	while( CheckSoundMem( SHandle ) == 1 ){  draw_mouse(day); /*draw_clock(day);*/  ScreenFlip(); }// なり終わるまでここでループ
	Sleep(wait_time);//セリフとセリフの間を空けるためスリープ関数を使う

	InitSoundMem() ;//サウンドデータの削除
}

Re: スレッドの生成を制御したい

Posted: 2012年5月29日(火) 10:50
by softya(ソフト屋)
やっぱり関数の関係は説明してもらえないんですね。
そこが一番重要なんですが、まぁこちらでちょっと見てみます。

Re: スレッドの生成を制御したい

Posted: 2012年5月29日(火) 11:10
by softya(ソフト屋)
見てみました。問題点と提案です。

1.あちこちにScreenFlip()があるので1カ所にする必要があります。
これはあちこちにScreenFlip()があると一定フレーム数の間メッセージ処理が行われないことになるため。
Windowsアプリで一番やってはいけないのは、処理をすぐ終了せずにループする事です。
音声が鳴り終わるまでwhileなど一番にやってはいけません。
WindowsアプリのWinProcはできるだけ短い時間(最大で数ms)で処理してすぐさまWinProcを抜ける様に設計します。

2.DXライブラリの処理はWinMainのループに集積する。WindowProcで処理している意味が全くありません。
WindowProc等ではフラグを変更するだけでDXライブラリの関数はすべでWinMainのループ内で呼び出すように変更しましょう。
while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) { ← このループから各関数を呼び出す。
音声処理も状態遷移で管理してループしないように変更して下さい。

「補足資料.11章 書いてはいけない4つの処理」
http://dixq.net/g/h_11.html

3.mythread_clockは不要。起動時のWM_CLOCKだけだと存在意義がないです。

4.mythreadの起動は多重にならないようにフラグで抑止します。

【補足】
ほぼ作り直しと成りますが悪い設計のまま取り繕うよりもキレイな設計で書きなおしたほうが勉強になりますし後々の機能追加もやりやすくなります。がんばってください。

Re: スレッドの生成を制御したい

Posted: 2012年6月17日(日) 02:10
by s707
softya(ソフト屋)様、ご返信ありがとうございます。
おかげさまでほとんどの問題が解消できました。

4.mythreadの起動は多重にならないようにフラグで抑止します。
こちらの多重起動を防ぐにはどうしたらいいでしょうか?

右クリックの度に新しいスレッドを作成するのはやめて
右クリックにあわせてスレッドの中断と再開をさせています。

ところがこの方法だと右クリックを2回以上したときに
トラックポップアップメニューが表示されなくなります。

コード:

case WM_RBUTTONDOWN:
		static int th_cn;//スレッドカウント
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		if (hThread == NULL) {
		    hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);//メニューを表示するスレッドを開始
		}else{
			if(th_cn){
				ResumeThread(hThread);//スレッド再開
				th_cn--;
			}
			else{
				SuspendThread(hThread);//スレッド中断
			    th_cn++;
			}
		}
		break;

Re: スレッドの生成を制御したい

Posted: 2012年6月17日(日) 10:36
by softya(ソフト屋)
スレッドをサスペンドするのは悪い方法だと思います。
今回は、動作中を示すvolatileなフラグ変数だけで十分な気がします。

スレッドを起動する時にフラグ変数をONにします。もしONだったら起動済みってことですね。
OFFにするのはスレッドを抜ける時です。
こうすることで多重の起動は抑止できます。

Re: スレッドの生成を制御したい

Posted: 2012年6月18日(月) 02:44
by s707
このように変更してみましたが、状況に変化なしです。

コード:

LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	static volatile bool flag = false;
	switch(uMsg) {
	case WM_RBUTTONDOWN:
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		
		if(!flag)hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);//メニューを表示するスレッドを開始
		flag = true;
		break;
	case WM_POSTENDTHREAD:
		if (WaitForSingleObject(hThread, 0) != WAIT_TIMEOUT || hDlg[0] == 0  || hDlg[1] == 0) {
			// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
			flag = false;
			DWORD ExitCode;
			ExitCode = -1;
			GetExitCodeThread(hThread, &ExitCode);
			CloseHandle(hThread);
			hThread = NULL;
		}
		else {
			// まだスレッドが終了してなかったらメッセージを投げ直す
			// ※デッドロック回避のため
			PostMessage(hWnd, WM_POSTENDTHREAD, wParam, lParam);
		}
		break;
	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return 0;
}

Re: スレッドの生成を制御したい

Posted: 2012年6月18日(月) 11:01
by softya(ソフト屋)
相変わらず
ところがこの方法だと右クリックを2回以上したときに
トラックポップアップメニューが表示されなくなります。
ってことでしょうか?

こちらでも動かせるようにソースコード全体を見せてもらった方が良いかもしれません。

Re: スレッドの生成を制御したい

Posted: 2012年6月18日(月) 20:42
by s707
そうですね。

メッセージ送信は出来るだけSendMessage関数を使う様にしました。
多かったScreenFlip関数も無くしています。
スレッド内の無駄な記述も省きました。

以前は描画関数をスレッド化させようとしましたが
現在は音声再生の方をスレッド化させて
その中でセリフの間を取るためにSleep関数を使用しています。

よろしくお願いいたします。

コード:

//dayData.h
struct dayData{
    char name[41];//ファイル名を入れる変数
    char number[6];
} ;

//draw_clock.h
void draw_clock(struct dayData* day);//時計描画
void draw_face(struct dayData* day);//キャラクター目パチのアニメーション関数
void draw_mouse(struct dayData* day);//キャラクターの口元のアニメーション関数
void Load_Graph();//グラフィックをロード
extern int GHandle[18];

//Setup.h
void Setup_load(struct dayData* day);//設定のロード
void Setup_save(struct dayData* day);//設定のセーブ
extern int character;
extern int ch;
extern int clock_x;
extern int clock_y;
extern int chara_x;
extern int chara_y;
extern int wait_time;

//date.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dayData.h"
#include "draw_clock.h"
#include "DxLib.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

int SHandle;

void date(struct dayData* day){//日付を音声再生する関数
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255

	
	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(local->tm_mon + 1){
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+63+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:			
			hiduke = strcmp((day+i+ch)->name, (day+64+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:			
			hiduke = strcmp((day+i+ch)->name, (day+65+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+66+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+67+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+68+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+69+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+70+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 10:
			hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 11:
			hiduke = strcmp((day+i+ch)->name, (day+72+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 12:
			hiduke = strcmp((day+i+ch)->name, (day+73+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){   }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day + 109 + ch) -> name ) ;//がつ
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;


	while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
	int date[2];
	date[0] = (local->tm_mday / 10)%10;//十の位
	date[1] = local->tm_mday % 10;//一の位

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(date[0]){
		case 1:
			if(date[1]){
				hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+121+ch)->name);//十日  今の音声は"じゅう"
				if( !hiduke )sound = true;
			}
			break;
		case 2:
			if(date[1]){
				hiduke = strcmp((day+i+ch)->name, (day+74+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+122+ch)->name);//二十日  今の音声は"にじゅう"
				if( !hiduke )sound = true;
			}
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+75+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(date[0])PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
		}
	}


	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(date[1]){
		case 0:
			if(date[0] == 3){
				hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
				if( !hiduke )sound = true;
			}
			break;
		case 1:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+62+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+112+ch)->name);//一日 今の音声は"いち"
				if( !hiduke )sound = true;
			}
			break;
		case 2:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+63+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+113+ch)->name);//二日
				if( !hiduke )sound = true;
			}
			break;
		case 3:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+64+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+114+ch)->name);//3日
				if( !hiduke )sound = true;
			}
			break;
		case 4:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+65+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+115+ch)->name);//4日
				if( !hiduke )sound = true;
			}
			break;
		case 5:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+66+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+116+ch)->name);//5日
				if( !hiduke )sound = true;
			}
			break;
		case 6:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+67+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+117+ch)->name);//6日
				if( !hiduke )sound = true;
			}
			break;
		case 7:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+68+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+118+ch)->name);//7日
				if( !hiduke )sound = true;
			}
			break;
		case 8:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+69+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+119+ch)->name);//8日
				if( !hiduke )sound = true;
			}
			break;
		case 9:
			if(date[0]){
				hiduke = strcmp((day+i+ch)->name, (day+70+ch)->name);
				if( !hiduke )sound = true;
			}
			else{
				hiduke = strcmp((day+i+ch)->name, (day+120+ch)->name);//9日
				if( !hiduke )sound = true;
			}
			break;
		}	

		if(sound){//音声再生フラグがon
			if( !(date[0] && !date[1]) ){
				SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			}
			if(date[0] && date[1] || date[0] == 3){
				while( CheckSoundMem( SHandle) == 1 ){  }// なり終わるまでここでループ
				SHandle = LoadSoundMem( (day + 110 + ch) -> name ) ;//にち
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle, DX_PLAYTYPE_BACK ) ;
			}
			while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
		}
	}	
	
	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(local->tm_wday){
		case 0:
			hiduke = strcmp((day+i+ch)->name, (day+78+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+79+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+80+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+81+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+82+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+83+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+84+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day + 111 + ch) -> name ) ;//です
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
	while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ	
	
	InitSoundMem() ;//サウンドデータの削除
}

//draw_clock.cpp
#include <time.h>
#include "DxLib.h"
#include "dayData.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

extern int SHandle;

#define chara_width 64
#define needle_x clock_x + 96
#define needle_y clock_y + 96

#define FontSize 16
#define PI	3.1415926535897932384626433832795f

int GHandle[18];
int GHandle_F[5][16];

void draw_clock(struct dayData* day){//時計描画関数
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	DrawGraph( clock_x , clock_y , GHandle[0] , TRUE ) ;//文字盤
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_hour%12)*30 + (local->tm_min/2) + 180)*PI/180, GHandle[1], TRUE ) ;//短針  時間*30度%12時間 + 分/2   1分毎に0.5度づつ進む為/2
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_min*6) + 180)*PI/180, GHandle[2], TRUE ) ;//長針
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_sec*6) + 180)*PI/180, GHandle[3], TRUE ) ;//秒針
}


void draw_face(struct dayData* day){
	static int frmcnt = 0;//フレームカウント
	frmcnt++;

	//現状の数値は1199フレーム(約20秒)  数列は11990
	int blink = (day + 8) -> number[0] * 1000 + (day + 8) -> number[1] * 100 + (day + 8) -> number[2] * 10 + (day + 8) -> number[3];

	if(frmcnt % blink >= 0 && frmcnt % blink <= (day + 9) -> number[0] ){
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ 1 ] , TRUE ) ;//2枚目(目パチ) アニメーションスピードは3フレーム
	}
	else{
		DrawGraph( chara_x , chara_y , GHandle_F[ character ][ 0 ] , TRUE ) ;//通常時の顔
	}
}

void draw_mouse(struct dayData* day){
	static int frmcnt = 0;//フレームカウント
	static int arr = 2;
	frmcnt++;
	
	DrawGraph( chara_x , chara_y , GHandle_F[ character ][ arr ] , TRUE ) ;//3枚目からアニメーション10枚 アニメーションスピードは3フレーム
	
	if( frmcnt % (day + 10) -> number[0] == 0){
		if( CheckSoundMem( SHandle ) == 1 )
			arr++;
		else
			arr = 11;//音声が鳴っていないときは口を閉じる
	}

	if(arr == 12)arr -= 10;
}

void Load_Graph(){//グラフィックをロードする関数
	GHandle[0] = LoadGraph( "Resourse./PNG/mojiban.png" );
	GHandle[1] = LoadGraph( "Resourse./PNG/tanshin.png");
	GHandle[2] = LoadGraph( "Resourse./PNG/cyoushin.png" );
	GHandle[3] = LoadGraph( "Resourse./PNG/byoushin.png");

	LoadDivGraph( "Resourse./PNG/face_00.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[0] ) ;
	LoadDivGraph( "Resourse./PNG/face_01.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[1] ) ;
	LoadDivGraph( "Resourse./PNG/face_02.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[2] ) ;
	LoadDivGraph( "Resourse./PNG/face_03.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[3] ) ;
	LoadDivGraph( "Resourse./PNG/face_04.png" , 16 , 4 , 4 , chara_width , chara_width , GHandle_F[4] ) ;
}

//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>
#include <time.h>
#pragma warning ( disable : 4996 )

#define APP_NAME TEXT("clock")
#define chara_width 64
#define WM_POSTENDTHREAD (WM_USER)// スレッド終了を伝えるメッセージ
#define WM_POSTENDTHREAD2 (WM_USER + 1)// スレッド終了を伝えるメッセージ
#define WM_POSTENDTHREAD3 (WM_USER + 2)// スレッド終了を伝えるメッセージ
#define WM_POSTENDTHREAD4 (WM_USER + 3)// スレッド終了を伝えるメッセージ
#define WM_MENU (WM_USER + 4)

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);

BOOL CALLBACK MyDlgProc(HWND hChild, UINT msg, WPARAM wp, LPARAM lp);
BOOL CALLBACK MyDlgProc2(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);

unsigned __stdcall mythread(void *lpx);
unsigned __stdcall mythread_sound(void *lpx);
unsigned __stdcall mythread_jihou(void *lpx);
unsigned __stdcall mythread_plan(void *lpx);

static HANDLE hThread,hThread2,hThread3,hThread4;
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_sound(void *lpx){//メニューを表示するスレッド
	date(day);//日付を再生
	Sleep(wait_time);//間をあける

	Time(day);//時刻を再生
	Sleep(wait_time);//間をあける

	plan(day);
	SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD2, 0, 0);
	return 0;
}

unsigned __stdcall mythread_jihou(void *lpx){//時報スレッド
	Time(day);
	PostMessage(GetMainWindowHandle(), WM_POSTENDTHREAD3, 0, 0);
	return 0;
}

unsigned __stdcall mythread_plan(void *lpx){//予定スレッド
	plan(day);
	SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD4, 0, 0);
	return 0;
}

BOOL CALLBACK MyDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
	static HWND ComboBox,Radio[4],Check[21];
	static int cancel_id;
	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
			Button_GetCheck(Radio[0]) ? (day + 3) -> number[0] = 1 : (day + 3) -> number[0] = 0;
			Button_GetCheck(Radio[2]) ? (day + 5) -> number[0] = 1 : (day + 5) -> number[0] = 0;

			for(int i = 0;i<21;i++){
				Button_GetCheck(Check[i]) ? (day + i + 15) -> number[0] = 1 : (day + i + 15) -> number[0] = 0;
			}

			(day + 4) -> number[0] = chara_id;

			Setup_save(day);//設定を書き込む
			Setup_load(day);//変更された設定を読み込む
			SendMessage(hWnd,WM_CLOSE,0,0);
			return TRUE;
		case IDCANCEL:
			(day + 4) -> number[0] = cancel_id;

			Setup_save(day);//設定を書き込む
			Setup_load(day);//変更された設定を読み込む
			SendMessage(hWnd,WM_CLOSE,0,0);
			return TRUE;
		case IDC_COMBO1:
			chara_id = ComboBox_GetCurSel(ComboBox);
			(day + 4) -> number[0] = chara_id;

			Setup_save(day);//設定を書き込む
			Setup_load(day);//変更された設定を読み込む
			return TRUE;
		}
		return FALSE;
	case WM_INITDIALOG:
		{

			Radio[0] = GetDlgItem(hWnd,IDC_RADIO1);
			Radio[1] = GetDlgItem(hWnd,IDC_RADIO2);
			Radio[2] = GetDlgItem(hWnd,IDC_RADIO3);
			Radio[3] = GetDlgItem(hWnd,IDC_RADIO4);

			Check[0] = GetDlgItem(hWnd,IDC_CHECKBOX1);
			Check[1] = GetDlgItem(hWnd,IDC_CHECKBOX2);
			Check[2] = GetDlgItem(hWnd,IDC_CHECKBOX3);
			Check[3] = GetDlgItem(hWnd,IDC_CHECKBOX4);
			Check[4] = GetDlgItem(hWnd,IDC_CHECKBOX5);
			Check[5] = GetDlgItem(hWnd,IDC_CHECKBOX6);
			Check[6] = GetDlgItem(hWnd,IDC_CHECKBOX7);
			Check[7] = GetDlgItem(hWnd,IDC_CHECKBOX8);
			Check[8] = GetDlgItem(hWnd,IDC_CHECKBOX9);
			Check[9] = GetDlgItem(hWnd,IDC_CHECKBOX10);
			Check[10] = GetDlgItem(hWnd,IDC_CHECKBOX11);
			Check[11] = GetDlgItem(hWnd,IDC_CHECKBOX12);
			Check[12] = GetDlgItem(hWnd,IDC_CHECKBOX13);
			Check[13] = GetDlgItem(hWnd,IDC_CHECKBOX14);
			Check[14] = GetDlgItem(hWnd,IDC_CHECKBOX15);
			Check[15] = GetDlgItem(hWnd,IDC_CHECKBOX16);
			Check[16] = GetDlgItem(hWnd,IDC_CHECKBOX17);
			Check[17] = GetDlgItem(hWnd,IDC_CHECKBOX18);
			Check[18] = GetDlgItem(hWnd,IDC_CHECKBOX19);
			Check[19] = GetDlgItem(hWnd,IDC_CHECKBOX20);
			Check[20] = GetDlgItem(hWnd,IDC_CHECKBOX21);

			ComboBox = GetDlgItem( hWnd, IDC_COMBO1);

			ComboBox_AddString(ComboBox,"A");
			ComboBox_AddString(ComboBox,"B");
			ComboBox_AddString(ComboBox,"C");
			ComboBox_AddString(ComboBox,"D");
			ComboBox_AddString(ComboBox,"E");


			cancel_id = chara_id = (day + 4)->number[0];
			ComboBox_SetCurSel(ComboBox,chara_id);

			(day + 3) -> number[0] ? Button_SetCheck(Radio[0] , BST_CHECKED) : Button_SetCheck(Radio[1] , BST_CHECKED);
			(day + 5) -> number[0] ? Button_SetCheck(Radio[2] , BST_CHECKED) : Button_SetCheck(Radio[3] , BST_CHECKED);

			for(int i = 0;i<21;i++){
				(day + i + 15) -> number[0] ? Button_SetCheck(Check[i] , BST_CHECKED) : Button_SetCheck(Check[i] , BST_UNCHECKED);
			}
			ShowWindow(hWnd, SW_NORMAL);
			return TRUE;
		}
	case WM_CLOSE:
		hDlg[0] = 0;
		PostMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
		DestroyWindow(hWnd);
		break;
	}
	return FALSE;
}

BOOL CALLBACK MyDlgProc2(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
			SendMessage(hWnd,WM_CLOSE,0,0);
			return TRUE;		
		}
		return FALSE;	
	case WM_CLOSE:
		hDlg[1] = 0;
		PostMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
		DestroyWindow(hWnd);
		break;
	}
	return FALSE;
}


LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	static int top,left;
    static volatile bool flag = false;

	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];

		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_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 ){
					if (!hThread2 && !hThread3 && !hThread4) {
						hThread2 = (HANDLE)_beginthreadex(NULL, 0, mythread_sound, NULL, 0, NULL);
					}
				}
			}
			SendMessage(GetMainWindowHandle(), WM_NCLBUTTONDOWN, HTCAPTION, 0);

			// 今回のクリック状態を保持する
			nClickPrev = nClickNow;
			break;
		}
	case WM_RBUTTONDOWN:
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);

		if(!flag)hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);//メニューを表示するスレッドを開始
        flag = true;
		break;
	case WM_POSTENDTHREAD:
		if (WaitForSingleObject(hThread, 0) != WAIT_TIMEOUT || hDlg[0] == 0  || hDlg[1] == 0) {
			// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
            flag = false;
			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 || hThread2) {
			// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
			DWORD ExitCode;
			ExitCode = -1;
			GetExitCodeThread(hThread2, &ExitCode);
			CloseHandle(hThread2);
			hThread2 = NULL;
		}
		else {
			// まだスレッドが終了してなかったらメッセージを投げ直す
			// ※デッドロック回避のため
			PostMessage(hWnd, WM_POSTENDTHREAD2, wParam, lParam);
		}
		break;
	case WM_POSTENDTHREAD3:
		if (WaitForSingleObject(hThread3, 0) != WAIT_TIMEOUT || hThread3) {
			// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
			DWORD ExitCode;
			ExitCode = -1;
			GetExitCodeThread(hThread3, &ExitCode);
			CloseHandle(hThread3);
			hThread3 = NULL;
		}
		else {
			// まだスレッドが終了してなかったらメッセージを投げ直す
			// ※デッドロック回避のため
			PostMessage(hWnd, WM_POSTENDTHREAD3, wParam, lParam);
		}
		break;
	case WM_POSTENDTHREAD4:
		if (WaitForSingleObject(hThread4, 0) != WAIT_TIMEOUT || hThread4) {
			// スレッドの終了を検知できたら戻り値を取得してハンドルをクローズ
			DWORD ExitCode;
			ExitCode = -1;
			GetExitCodeThread(hThread4, &ExitCode);
			CloseHandle(hThread4);
			hThread4 = NULL;
		}
		else {
			// まだスレッドが終了してなかったらメッセージを投げ直す
			// ※デッドロック回避のため
			PostMessage(hWnd, WM_POSTENDTHREAD4, 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:
		SendMessage(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;
}

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();//画像を読み込む

	hThread4 = (HANDLE)_beginthreadex(NULL, 0, mythread_plan, NULL, 0, NULL);

	while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
		ClearDrawScreen( );

		if(!hThread2 && !hThread3 && !hThread4)draw_face(day);//音声再生するスレッドが作成されてない時の顔は目パチ
		if(hThread2 || hThread3 || hThread4)draw_mouse(day);//音声再生スレッド中は口パク

		draw_clock(day);

		time_t timer;
		struct tm *local;
		timer = time(NULL);//現在時刻を取得
		local = localtime(&timer); //地方時に変換

		int min[2],sec[2];
		min[0] = (local->tm_min / 10)%10;
		min[1] = local->tm_min % 10;

		sec[0] = (local->tm_sec / 10)%10;
		sec[1] = local->tm_sec % 10;

		if( !min[0] && !min[1] && !sec[0] && !sec[1] && ( day + 5 ) -> number[0] ){
			if(!hThread2 && !hThread3 && !hThread4){
				hThread3 = (HANDLE)_beginthreadex(NULL, 0, mythread_jihou, NULL, 0, NULL);//時報スレッドを開始;
			}
		}
		ScreenFlip( );
	}
	DxLib_End();
	return 0;
}

//plan.cpp
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#include "Setup.h"
#include <time.h>
#pragma warning ( disable : 4996 )

extern int SHandle;

void plan(struct dayData* day){//予定や祝日を音声再生する関数
	bool alarm = false;	
	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255

	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換
	
	if(!alarm){

		for(int i = 0; i<3; i++){
			if( local->tm_wday == 1 && (day + 15 + i*7) -> number[0] || local->tm_wday == 2 && (day + 16 + i*7) -> number[0] || local->tm_wday == 3 && (day + 17 + i*7) -> number[0] || 
				local->tm_wday == 4 && (day + 18 + i*7) -> number[0] || local->tm_wday == 5 && (day + 19 + i*7) -> number[0] || local->tm_wday == 6 && (day + 20 + i*7) -> number[0] ||
				local->tm_wday == 0 && (day + 21 + i*7) -> number[0]){

					if( ( day + 3 ) -> number[0]  == 0 ){//設定した日 0なら当日 1なら前日
						SHandle = LoadSoundMem( (day + 36 + ch) -> name ); 
					}else{//前日設定
						SHandle = LoadSoundMem( (day + 37 + ch) -> name ); 
					}

					if(!alarm){//この部分は一回だけの再生
						ChangeVolumeSoundMem( volume, SHandle ) ;
						PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;//今日または明日
						while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ

						SHandle = LoadSoundMem( (day + 38 + ch) -> name ); 
						ChangeVolumeSoundMem( volume, SHandle ) ;
						PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;//は
						while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
					}

					if(i == 0){     SHandle = LoadSoundMem( (day + 39 + ch) -> name ); ChangeVolumeSoundMem( volume, SHandle ) ; PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;}//燃えるゴミ
					else if(i == 1){SHandle = LoadSoundMem( (day + 40 + ch) -> name ); ChangeVolumeSoundMem( volume, SHandle ) ; PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;}//燃えないゴミ
					else if(i == 2){SHandle = LoadSoundMem( (day + 41 + ch) -> name ); ChangeVolumeSoundMem( volume, SHandle ) ; PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;}//資源ゴミ
					while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
					Sleep(wait_time);//間をあける

					alarm = true;
			}
		}

		for(int i = 42; i<62; i++){
			int hiduke = 1;
			bool sound = false;
			switch(local->tm_yday){
			case 0://元日
				hiduke = strcmp((day+i)->number, (day+42+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 6://七草
				hiduke = strcmp((day+i)->number, (day+43+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 9://成人の日
				hiduke = strcmp((day+i)->number, (day+44+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 33://節分
				hiduke = strcmp((day+i)->number, (day+45+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 41://建国記念日
				hiduke = strcmp((day+i)->number, (day+46+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 79://春分の日
				hiduke = strcmp((day+i)->number, (day+47+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 118://昭和の日
				hiduke = strcmp((day+i)->number, (day+48+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 122://憲法記念日
				hiduke = strcmp((day+i)->number, (day+49+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 123://みどりの日
				hiduke = strcmp((day+i)->number, (day+50+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 124://こどもの日
				hiduke = strcmp((day+i)->number, (day+51+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 160://海の日
				hiduke = strcmp((day+i)->number, (day+52+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 261://敬老の日
				hiduke = strcmp((day+i)->number, (day+53+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 265://秋分の日
				hiduke = strcmp((day+i)->number, (day+54+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 282://体育の日
				hiduke = strcmp((day+i)->number, (day+55+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 306://文化の日
				hiduke = strcmp((day+i)->number, (day+56+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 318://七五三
				hiduke = strcmp((day+i)->number, (day+57+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 326://勤労感謝の日
				hiduke = strcmp((day+i)->number, (day+58+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 356://天皇誕生日
				hiduke = strcmp((day+i)->number, (day+59+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 357://クリスマスイヴ
				hiduke = strcmp((day+i)->number, (day+60+ch)->number);
				if( !hiduke )sound = true;
				break;
			case 358://クリスマス
				hiduke = strcmp((day+i)->number, (day+61+ch)->number);
				if( !hiduke )sound = true;
				break;
			}

			if(sound){//音声再生フラグがon
				SHandle = LoadSoundMem( (day + i + ch) -> name ) ;
				ChangeVolumeSoundMem( volume, SHandle ) ;
				PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
				while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
			}
		}
	}
	InitSoundMem() ;//サウンドデータの削除
}

//Setup.cpp
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#pragma warning ( disable : 4800 )
#pragma warning ( disable : 4804 )

#define  FontSize 16
#define menu_x chara_x
#define menu_y chara_y + 64
#define menu_width 160//オプション画面の横文字の長さ  フォントサイズが16なので10文字分

int character = 0;
int ch = 0;
int chara_x = 0;
int chara_y = 0;
int clock_x = 0;
int clock_y = 0;
int wait_time = 0;
//-----------------------------------------------------------------------------
// Name: Setup_load()
// Desc: 設定読み込み関数
//-----------------------------------------------------------------------------
void Setup_load(struct dayData* day){
	char key1[8]="name000";
	char key2[8]="data000";
	static bool load = false;

	//INIファイル読み込み
	for(int i = 0; i < 36; i++){
		GetPrivateProfileString("Setup",key1,"--------", (day+i) -> name,41,"Resourse./Setup.INI");
		GetPrivateProfileString("Setup",key2,"00000"   , (day+i) -> number,6,"Resourse./Setup.INI");
		key1[6]++;
		key2[6]++;

		if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}//10の位をプラス 1の位を0に 
		if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
		if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}//100の位をプラス 10の位を0に 
		if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}

		for(int j = 0;j<5;j++){
			(day+i) -> number[j] -= '0';//アスキーコードから数字に変換
		}
	}

	character = ( day + 4 ) -> number[0] ;
	ch = character * 87;

	//セリフとセリフの間を決める変数
	wait_time = (day + 6) -> number[0] * 10000 + (day + 6) -> number[1] * 1000 + (day + 6) -> number[2] * 100 + (day + 6) -> number[3] * 10 + (day + 6) -> number[4];

	chara_x = (day + 11) -> number[0] * 1000 + (day + 11) -> number[1] * 100 + (day + 11) -> number[2] * 10 + (day + 11) -> number[3];
	chara_y = (day + 12) -> number[0] * 1000 + (day + 12) -> number[1] * 100 + (day + 12) -> number[2] * 10 + (day + 12) -> number[3];
	clock_x = (day + 13) -> number[0] * 1000 + (day + 13) -> number[1] * 100 + (day + 13) -> number[2] * 10 + (day + 13) -> number[3];
	clock_y = (day + 14) -> number[0] * 1000 + (day + 14) -> number[1] * 100 + (day + 14) -> number[2] * 10 + (day + 14) -> number[3];

	//INIファイル読み込み
	if( load == false ){
		load = true;
		for(int i = 36; i < 471; i++){
			GetPrivateProfileString("Setup",key1,"--------", (day+i) -> name,41,"Resourse./Setup.INI");
			GetPrivateProfileString("Setup",key2,"00000"   , (day+i) -> number,6,"Resourse./Setup.INI");
			key1[6]++;
			key2[6]++;

			if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}//10の位をプラス 1の位を0に 
			if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
			if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}//100の位をプラス 10の位を0に 
			if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}
		}
	}
}
//-----------------------------------------------------------------------------
// Name: Setup_save()
// Desc: 設定書き込み関数
//-----------------------------------------------------------------------------
void Setup_save(struct dayData* day){
	char key1[8]="name000";
	char key2[8]="data000";
	RECT rect;
	GetWindowRect(GetMainWindowHandle(),&rect);//ウィンドウの座標を取得
	
		(day + 0) -> number[0] = (rect.left / 1000) % 10;//ウィンドウのx座標を代入
		(day + 0) -> number[1] = (rect.left / 100) % 10;
		(day + 0) -> number[2] = (rect.left / 10) % 10;
		(day + 0) -> number[3] = rect.left % 10;

		(day + 1) -> number[0] = (rect.top / 1000) % 10;//ウィンドウのy座標を代入
		(day + 1) -> number[1] = (rect.top / 100) % 10;
		(day + 1) -> number[2] = (rect.top / 10) % 10;
		(day + 1) -> number[3] = rect.top % 10;

	//INIファイル書き込み
	for(int i = 0; i < 36; i++){
		for(int j = 0;j<5;j++){
			(day+i) -> number[j] += '0';//数字からアスキーコードに変換
		}

		WritePrivateProfileString("Setup",key1, (day+i) -> name,"Resourse./Setup.INI");
		WritePrivateProfileString("Setup",key2, (day+i) -> number,"Resourse./Setup.INI");
		key1[6]++;
		key2[6]++;

		if(key1[6] == ':'){ key1[5]++; key1[6] = '0';}
		if(key2[6] == ':'){ key2[5]++; key2[6] = '0';}
		if(key1[5] == ':'){ key1[4]++; key1[5] = '0';}
		if(key2[5] == ':'){ key2[4]++; key2[5] = '0';}
	}
}

//time.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dayData.h"
#include "draw_clock.h"
#include "DxLib.h"
#include "Setup.h"
#pragma warning ( disable : 4996 )

extern int SHandle;

void Time(struct dayData* day){//現在の時間を音声再生する関数
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換

	int volume = (day + 7) -> number[0] * 100 + (day + 7) -> number[1] * 10 + (day + 7) -> number[2];//ボリュームは0~255  初期設定では255
	
	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		int hour = local->tm_hour % 12;
		switch(hour){
		case 0:
			hiduke = strcmp((day+i+ch)->name, (day+85+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+86+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+87+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+88+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+89+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+90+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+91+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+92+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+93+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+94+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 10:
			hiduke = strcmp((day+i+ch)->name, (day+95+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 11:
			hiduke = strcmp((day+i+ch)->name, (day+96+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){  }// なり終わるまでここでループ
		}
	}

	int min[2];
	min[0] = (local->tm_min / 10)%10;
	min[1] = local->tm_min % 10;

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(min[0]){
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+71+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+74+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+75+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+76+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+77+ch)->name);
			if( !hiduke )sound = true;
			break;	
		}		
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(min[0])PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){   }// なり終わるまでここでループ
		}
	}

	for(int i = 62; i<123; i++){
		int hiduke = 1;
		bool sound = false;
		switch(min[1]){
		case 0:
			if( min[0] ){
				hiduke = strcmp((day+i+ch)->name, (day+98+ch)->name);
				if( !hiduke )sound = true;
			}
			break;
		case 1:
			hiduke = strcmp((day+i+ch)->name, (day+99+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 2:
			hiduke = strcmp((day+i+ch)->name, (day+100+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 3:
			hiduke = strcmp((day+i+ch)->name, (day+101+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 4:
			hiduke = strcmp((day+i+ch)->name, (day+102+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 5:
			hiduke = strcmp((day+i+ch)->name, (day+103+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 6:
			hiduke = strcmp((day+i+ch)->name, (day+104+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 7:
			hiduke = strcmp((day+i+ch)->name, (day+105+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 8:
			hiduke = strcmp((day+i+ch)->name, (day+106+ch)->name);
			if( !hiduke )sound = true;
			break;
		case 9:
			hiduke = strcmp((day+i+ch)->name, (day+107+ch)->name);
			if( !hiduke )sound = true;
			break;
		}
		if(sound){//音声再生フラグがon
			SHandle = LoadSoundMem( (day+i+ch) -> name ) ;
			ChangeVolumeSoundMem( volume, SHandle ) ;
			if(local->tm_min)PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
			while( CheckSoundMem( SHandle ) == 1 ){   }// なり終わるまでここでループ
		}
	}

	SHandle = LoadSoundMem( (day+111+ch)->name ) ;//です
	ChangeVolumeSoundMem( volume, SHandle ) ;
	PlaySoundMem( SHandle , DX_PLAYTYPE_BACK ) ;
	while( CheckSoundMem( SHandle ) == 1 ){   }// なり終わるまでここでループ
	
	InitSoundMem() ;//サウンドデータの削除
}

Re: スレッドの生成を制御したい

Posted: 2012年6月18日(月) 21:17
by softya(ソフト屋)
動きを確認したいのでresource.hとリソース(.rc)も頂けたらと思います。
全部をzipで添付してもらったほうが早いかも知れません。

Re: スレッドの生成を制御したい

Posted: 2012年6月19日(火) 03:02
by s707
コード追加しました。

URLは画像と音声のzipです。
http://firestorage.jp/download/5c6a4393 ... 543d9ff028

コード:

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

#define IDD_DIALOG                              102
#define IDD_DIALOG2                             103
#define IDC_RADIO1                              1005
#define IDC_RADIO2                              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
#define IDM_OPTION                              1029
#define IDM_VERSION                             1031
#define IDM_EXIT                                1032
#define IDC_RADIO3                              1033
#define IDC_RADIO4                              1034



//resource.rc

#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"




//
// Menu resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
MYMENU MENU
{
    POPUP "ダミーです"
    {
        MENUITEM "オプション", IDM_OPTION
        MENUITEM "バージョン情報", IDM_VERSION
        MENUITEM "終了", IDM_EXIT
    }
}



//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOG 4294967064, 0, 224, 180
STYLE DS_3DLOOK | 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, 155, 50, 15
    PUSHBUTTON      "Cancel", IDCANCEL, 150, 155, 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
    AUTORADIOBUTTON "前日", IDC_RADIO1, 80, 80, 30, 10
    AUTORADIOBUTTON "当日", IDC_RADIO2, 160, 80, 30, 10
    GROUPBOX        "", IDC_STATIC, 5, 95, 60, 20
    LTEXT           "時報", IDC_STATIC, 10, 100, 50, 10, SS_LEFT
    AUTORADIOBUTTON "ON", IDC_RADIO3, 80, 100, 30, 10
    AUTORADIOBUTTON "OFF", IDC_RADIO4, 160, 100, 30, 10
    GROUPBOX        "", IDC_STATIC, 5, 115, 60, 20
    LTEXT           "キャラクター設定", IDC_STATIC, 10, 120, 50, 10, SS_LEFT
    COMBOBOX        IDC_COMBO1, 80, 120, 104, 69, CBS_DROPDOWN | CBS_HASSTRINGS
}



LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG2 DIALOG -136, 0, 128, 64
STYLE DS_3DLOOK | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "バージョン情報"
FONT 10, "Ms Shell Dlg"
{
    LTEXT           "DesktopClock Ver1.00", IDC_STATIC, 10, 10, 75, 15, SS_LEFT
    LTEXT           "Copyright(C) 2012 S.Ohira", IDC_STATIC, 10, 25, 105, 15, SS_LEFT
    DEFPUSHBUTTON   "OK", IDOK, 40, 45, 50, 15
}


Re: スレッドの生成を制御したい

Posted: 2012年6月19日(火) 11:37
by softya(ソフト屋)
この音声データってライセンス的に大丈夫ですか?ライセンス上マズイなら、とりあえず削除された方が良いと思います。

さて本題ですが、ざっと調べた所メニュースレッドが止まっていないのは確かなようです。
なんか全体的にスレッドする必要はないような気がするのでそこも含めて後ほど回答します。

Re: スレッドの生成を制御したい

Posted: 2012年6月19日(火) 12:16
by softya(ソフト屋)
問題はメニューを表示している所です。

コード:

            SetForegroundWindow(hWnd);
            TrackPopupMenu(hSubMenu,TPM_LEFTALIGN,pt.x,pt.y,0,hWnd,NULL);//メニュー作成
            DestroyMenu(hMenu);
これで、DestroyMenu()してしまうとスレッドで開いたウィンドウは終了する方法を失います。
DestroyMenu()する状況ならウィンドウ終了と同等に処理すべきです。

あと、前言撤回します。申し訳ないです。
スレッドに関しては、このままとします。

Re: スレッドの生成を制御したい

Posted: 2012年6月19日(火) 13:42
by s707
ご返信ありがとうございます。
データのアップロード自体は問題なく
著作権等も大丈夫です。

さっそく修正箇所を確認してみます。

Re: スレッドの生成を制御したい

Posted: 2012年6月19日(火) 21:55
by s707
修正してみました。こういうことでしょうか?
特に変化は見られませんでした。

コード:

LRESULT CALLBACK WindowProc2 (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {//メニュー関連のプロシージャ
	HMENU hMenu,hSubMenu;
	switch(uMsg) {
	case WM_CREATE:
		if( !hDlg[0] && !hDlg[1]){
			hMenu = LoadMenu(hInst,"MYMENU");
			hSubMenu = GetSubMenu(hMenu ,0);
			ClientToScreen(GetMainWindowHandle() , &pt);
			SetForegroundWindow(hWnd);
			TrackPopupMenu(hSubMenu,TPM_LEFTALIGN,pt.x,pt.y,0,hWnd,NULL);//メニュー作成
		}
		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:
		SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
		SendMessage(GetMainWindowHandle(), WM_CLOSE,0,0);
		DestroyMenu(hMenu);
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//Getmessageの返り値が0になる
		break;
	default:
		return ( DefWindowProc(hWnd , uMsg , wParam , lParam) );
	}

	return 0;
}

Re: スレッドの生成を制御したい

Posted: 2012年6月19日(火) 22:04
by softya(ソフト屋)
あぁっと、うまく伝わらなかったですね。
TrackPopupMenu()を抜けきたらDestroyMenu()するしか無いですが同時にスレッドのウィンドウとスレッドが意味をなくすのでWM_CLOSEして終了処理をしてください。
あるいは、メニューを続けたいならもう一度メニュー処理をするメッセージを作ってそれを呼び出して下さい。

Re: スレッドの生成を制御したい

Posted: 2012年6月22日(金) 21:06
by s707
下記の様に修正してみました。

右クリックでのメニュー表示はいい感じになりました。
ですが数回に一回メニューが表示されないです。

WM_COMMANDを素通りして
メニューの各種項目が選択できません。
各種項目をクリックするとスレッドが終了してしまいます。

コード:

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);
			SendMessage(hWnd, WM_CLOSE, 0, 0);
		}
		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(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
			SendMessage(GetMainWindowHandle(), WM_CLOSE,0,0);
			DestroyWindow(hWnd);
			break;
		case IDM_VERSION://バージョン情報を選択
			//バージョン情報の画面のダイアログボックスを作成
			if(!hDlg[0] && !hDlg[1])hDlg[1] = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), GetMainWindowHandle(), MyDlgProc2);
			break;
		}
		break;
	case WM_CLOSE:
		SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//Getmessageの返り値が0になる
		break;
	default:
		return ( DefWindowProc(hWnd , uMsg , wParam , lParam) );
	}

	return 0;
}

Re: スレッドの生成を制御したい

Posted: 2012年6月22日(金) 21:51
by softya(ソフト屋)
デバッガやOutputDebugString()を使ってすり抜ける条件を割り出して下さい。

(1)WM_COMMANDを素通りしてメニューの各種項目が選択できません。
(2)各種項目をクリックするとスレッドが終了してしまいます。

(1)と(2)が矛盾してますがどういう意味でしょうか?

Re: スレッドの生成を制御したい

Posted: 2012年6月22日(金) 22:07
by ISLe
関係無いかもしれませんが…。

WM_CREATEというのはCreateWindowの内部で発行されるメッセージです。
WM_CREATEに対してウィンドウプロシージャから-1を返すと、CreateWindowはウィンドウの生成に失敗したとしてNULLを返します。

WM_CREATEが発行された時点でメッセージループはまだ回っていないし、ウィンドウハンドルは一時的なものと言えるかと思います。
そんなタイミングでSetForegroundWindowやTrackPopupMenuを呼び出してもまともな動作は期待できない気がします。

Re: スレッドの生成を制御したい

Posted: 2012年6月22日(金) 22:31
by s707
softya(ソフト屋)様、ISLe様、ご返信ありがとうございます。
(1)WM_COMMANDにブレークポイントを多数仕掛けても反応しなかったです。

(2)メニュー表示後に項目をクリックすると スレッド 'Win32 スレッド' (0x1480) はコード 1 (0x1) で終了しました。 と出力されます。
  メニュー表示後にその他の座標をクリックしても同様です。左クリック右クリック関係なしです。

TrackPopupMenu等の呼び出すタイミングも考えて
OutputDebugString()も使用してデバッグ続けてみます。

Re: スレッドの生成を制御したい

Posted: 2012年6月25日(月) 02:22
by s707
WM_CREATEを消してTrackPopupMenu関数の位置を変更しました。
状況に変化なしです。

コード:

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
		{
			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);
				
				SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
				DestroyWindow(hWnd);
			}
			// メッセージを処理する
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}

	return 0;
}

Re: スレッドの生成を制御したい

Posted: 2012年6月25日(月) 10:33
by softya(ソフト屋)
ISLeさんの指摘どおりだとしたら、WM_PAINT等のウィンドウが表示されているタイミングで発行されるメッセージを使わないとうまくいかないかも知れませんが、私は関係があるともないとも断言できません。
もしかするとメニュー処理よりも先にWM_CLOSEされてしまっているのかも知れませんので、
SendMessage(hWnd, WM_CLOSE, 0, 0);
ではなく
PostMessage(hWnd, WM_CLOSE, 0, 0);
にすれば解決するかも知れません。

Re: スレッドの生成を制御したい

Posted: 2012年6月25日(月) 18:38
by s707
softya(ソフト屋)様、ご返信ありがとうございます。
PostMessage()は試していたのですが
駄目でした。

PostMessageするとダイアログが一瞬だけ
表示されてすぐ閉じてしまいます。

Re: スレッドの生成を制御したい

Posted: 2012年6月25日(月) 18:49
by softya(ソフト屋)
なるほど、SendMessageのタイミング依存で実に危ういバランスで成り立っているので起こる現象だと思いますので根本的に修正した方が良いようです。
TrackPopupMenuでTPM_RETURNCMDを指定して戻ってきた値に合わせてPostMessage()で処理。
IDM_OPTION/IDM_VERSION/IDM_EXIT以外なら自分自身をPostMessage()でWM_CLOSEする。
IDM_OPTION/IDM_VERSIONの処理の先でも処理が終わったら自分自身をPostMessage()でWM_CLOSEする。
これでどうでしょう?

Re: スレッドの生成を制御したい

Posted: 2012年6月27日(水) 03:20
by s707
変更してみました。IDM_OPTIONにブレイクポイントを設定しても反応なしです。
項目を選択してもメニューが消えるだけです。

右クリックする度に出ていたこのメッセージも出なくなってしまいました。
スレッド 'Win32 スレッド' () はコード 0 (0x0) で終了しました。

コード:

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
		{
			if( !hDlg[0] && !hDlg[1]){
				HMENU hMenu,hSubMenu;
				hMenu = LoadMenu(hInst,"MYMENU");
				hSubMenu = GetSubMenu(hMenu ,0);
				ClientToScreen(GetMainWindowHandle() , &pt);
				SetForegroundWindow(hWnd);

				UINT a = TrackPopupMenu(hSubMenu,TPM_RETURNCMD,pt.x,pt.y,0,hWnd,NULL);//メニュー作成

				if( !(a == IDM_OPTION || a == IDM_EXIT || IDM_VERSION) )
					PostMessage(hWnd, WM_CLOSE, 0, 0);
				DestroyMenu(hMenu);
			}

			// メッセージを処理する
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}

	return 0;
}


LRESULT CALLBACK WindowProc2 (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {//メニュー関連のプロシージャ
	switch(uMsg) {
	case WM_CREATE:
		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);
			PostMessage(hWnd, WM_CLOSE, 0, 0);
			break;
		case IDM_EXIT://終了を選択			
			Setup_save(day);//設定を書き込む
			SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
			SendMessage(GetMainWindowHandle(), WM_CLOSE,0,0);
			DestroyWindow(hWnd);
			break;
		case IDM_VERSION://バージョン情報を選択
			//バージョン情報の画面のダイアログボックスを作成
			if(!hDlg[0] && !hDlg[1])hDlg[1] = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), GetMainWindowHandle(), MyDlgProc2);
			PostMessage(hWnd, WM_CLOSE, 0, 0);
			break;
		default:
			DestroyWindow(hWnd);
		}
		break;
	case WM_CLOSE:
		SendMessage(GetMainWindowHandle(), WM_POSTENDTHREAD, 0, 0);// スレッド終了を伝えるメッセージを親ウィンドウに投げる
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//Getmessageの返り値が0になる
		break;
	default:
		return ( DefWindowProc(hWnd , uMsg , wParam , lParam) );
	}

	return 0;
}

Re: スレッドの生成を制御したい

Posted: 2012年6月27日(水) 10:04
by softya(ソフト屋)
こちらの案の内容を理解されていますのでしょうか?
大半が誤実装か実装漏れしているようです。

(1)TrackPopupMenuでTPM_RETURNCMDを指定して戻ってきた値に合わせてPostMessage()で処理。
TPM_RETURNCMDではメッセージがWindowProcに飛ばないと言う仕様を理解されていますか?

(2)IDM_OPTION/IDM_VERSION/IDM_EXIT以外なら自分自身をPostMessage()でWM_CLOSEする。
if文にミスがあります。

(3)IDM_OPTION/IDM_VERSIONの処理の先でも処理が終わったら自分自身をPostMessage()でWM_CLOSEする。
CreateDialogの直後にWM_CLOSEして大丈夫ですか?
今回の件もですがウィンドウの処理の流れをちゃんと意識して下さい。
流れの理解が出来ていないので、ちゃんと処理できな事態に陥っているわけですから理解することは非常に重要ですよ。