ページ 11

ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 07:43
by taketoshi
現在、マウスカーソルから光を放出するソフトウェアを書いています。

タスクトレイにアイコンを格納し、
右クリックでそこからポップアップメニューを開くようにしています。

カーソルを動かしたときにCreateWindowEx関数でレイヤードウインドウ次々に作成しているのですが
子ウインドウ作成時(エフェクト放出時)に開いているポップアップメニューが閉じられてしまいます。

この現象は他のソフトウェアのポップアップウインドウでは起こってないので
ウインドウメッセージのやり取りか?とも思っています。

ポップアップメニューを維持し続ける方法はあるでしょうか?
改善策が見つからなければ右クリックでダイアログ作成に逃げるしかないかと思っています。

何か気になるところがありましたらご指摘ください。お願いします。
開発中のソフトウェアも添付させていただきます。

コード:

/////////////////////////////////////////////////////////////////////////////////////////////////////
//関数名			:MakeMenu関数
//機能				:右クリックメニューを作成する
//引数				:
//戻り値			:
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CIconShell::MakeMenu(HWND hWnd2){

	POINT pt;
	//右クリックメニューを作る

	GetCursorPos(&pt);
	TrackPopupMenu(hSub,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd2,NULL);

	return;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//関数名			:CreateChild
//機能				:子ウインドウを描写して初期設定を行い画像を描写する
//引数				:親ウインドウのハンドルとLPARAM
//戻り値			:
/////////////////////////////////////////////////////////////////////////////////////////////////////
int CEffect::CreateChild(HWND hParentWnd,LPARAM lp,DATA *WndData){

	POINT pt;

	HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr(hParentWnd,GWL_HINSTANCE);

	//LPARAMから構造体の取得
	MSLLHOOKSTRUCT *pmh;
	pmh = (MSLLHOOKSTRUCT *)lp;

	if(hParentWnd == NULL){
		MSE("親ウインドウのハンドルが取得できません");
		throw CError();
	}

	//子ウインドウを描写する
	WndData->hChild = CreateWindowEx(WS_EX_LAYERED|WS_EX_TRANSPARENT,"STATIC",
		NULL,
		WS_POPUP|WS_VISIBLE,
		(pmh->pt.x) - (nWidth / 2),(pmh->pt).y - (nHeight / 2),0,0,hParentWnd,NULL,hInst,NULL);


	if(WndData->hChild == NULL){
		MSE("子ウインドウを生成できません");
		throw CError();
	}

	//ウインドウのパラメーター初期設定
	GetCursorPos(&pt);	//カーソル位置の取得
	WndData->nAlpha = 255;	//アルファ値を設定
	//加速度を設定
	WndData->nAccY = 2;
	WndData->nAccX = rand() % 5 + 1;
	WndData->nFirstAccY = rand() % 3 + 5;
	//座標の初期化
	WndData->wndSize.cx = nWidth;
	WndData->wndSize.cy = nHeight;
	//座標の初期化
	WndData->wndPos.x = pt.x - (WndData->wndSize.cx / 2);
	WndData->wndPos.y = pt.y - (WndData->wndSize.cy / 2);
	//放出方向の決定
	WndData->bRetrunFlag = rand() % 2;
	//描写フラグの設定
	WndData->bReleaseFlag = true;
	//ここまで

	//ここから作成した子ウインドウにエフェクト画像を初期描写する
	if(nWidth == 0 || nHeight == 0){
		MSE("画像情報が取得できませんでした");
		throw CError();
	}

	// ウィンドウの形状をビットマップに合わせて変更
	SetWindowPos(WndData->hChild, HWND_TOPMOST, 0, 0, nWidth, nHeight, SWP_NOMOVE | SWP_NOZORDER);
	//常に最前面に描写
	//ここをフラグ調整して外せば放出先がデスクトップオンリーになります
    SetWindowPos(WndData->hChild,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);

	// 各種デバイスコンテキストの取得
	hsdc   = GetDC(0);                      // デスクトップのデバイスコンテキスト(色情報指定用)
	hdc    = GetDC(WndData->hChild);         // このウィンドウのデバイスコンテキスト
	hmemdc = CreateCompatibleDC(hdc);       // hdcの互換デバイスコンテキスト

	// デバイスコンテキストにおけるレイヤの位置
	POINT po;
	po.x = po.y = 0;

	// レイヤードウィンドウの指定
	BLENDFUNCTION blend;
	blend.BlendOp = AC_SRC_OVER;
	blend.BlendFlags = 0;
	blend.SourceConstantAlpha = WndData->nAlpha; // 不透明度(レイヤードウィンドウ全体のアルファ値)
	blend.AlphaFormat = AC_SRC_ALPHA;

	// 画像を描画をする
	hOldObj = SelectObject(hmemdc, hBitmap);
	BitBlt(hdc, 0, 0, nWidth, nHeight, hmemdc, 0, 0, SRCCOPY|CAPTUREBLT);

	//レイヤードウィンドウの更新
	if (0 == UpdateLayeredWindow(WndData->hChild, hsdc, &WndData->wndPos, &WndData->wndSize, hmemdc, &po, 0, &blend, ULW_ALPHA)) {
		MSE("レイヤーが更新できませんでした");
		throw CError();
	}else{
		//ShowWindow(WndData->hChild,SW_NORMAL);
	}

	SelectObject(hmemdc, hOldObj);
	DeleteDC(hmemdc);
	ReleaseDC(WndData->hChild, hdc);
	ReleaseDC(0, hsdc);

	return 0;
}


Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 11:34
by softya(ソフト屋)
肝心のメッセージのPostとかの部分がないみたいですが。

Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 11:42
by taketoshi
>softyaさん

メインループはこのように記述しています

コード:


int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{

	CMainWindow *cw;

	cw = new CMainWindow();
	cw->CreateMainWindow();

	BOOL bRet;
	MSG msg;

	while((bRet = GetMessage(&msg,NULL,0,0)) != 0)
	{
		if (bRet == -1)
		{
			break;
		}
		else
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	delete cw;

	return (int)msg.wParam;
}

子ウインドウ作成時のメッセージをスルーすればポップアップウインドウに影響を与えないのではないか?と思っていますが
今の知識では組み方がちょっと分からなくて困っています。

ウインドウプロシージャ内のメッセージを飛ばすような処理を書いたり試行錯誤していましたがうまくいっていません。

Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 12:05
by softya(ソフト屋)
ふと思いつきましたが、ポップアップメニューはフォーカスが外れた時に閉じている気がするのでHWND_TOPMOSTが怪しい気がします。

Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 12:51
by taketoshi
最前面に表示する関数を外してみましたがダメでした。

もうこうなると仕様や設計の問題でしょうか


動く形でファイルを添付させていただきます。
自分でも色々調べていますが、何かお気づきの点がありましたらご指摘くださると有難いです。

Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 14:47
by softya(ソフト屋)
CEffect::CreateChildでCreateWindowExした時点でpopupメニューが閉じられるみたいです。
なので、popupメニュー中はCEffect::CreateChildを禁止するぐらいしか手が無いですね。

Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年4月28日(土) 15:01
by taketoshi
メッセージフックを引っ掛けて、CreateWindowExの直前に出すメッセージを捕まえて
そこをスルーしようかと試行錯誤していますがこちらもなかなか上手くいっておりません・・・。

>なので、popupメニュー中はCEffect::CreateChildを禁止するぐらいしか手が無いですね。
なるほど。その手がありました。
盲点といえば盲点でした。そのアイディア頂きます。

Re: ポップアップメニューが強制的に閉じられてしまう(WINAPIの質問です)

Posted: 2012年5月06日(日) 14:04
by taketoshi
こんな形でメッセージを処理してフラグを立てることにより
ポップアップメニューを表示中はエフェクトの放出を抑える方法をとることにしました。
しかしこんなウインドウメッセージもあるんですねぇ。勉強になりました。

ありがとうございました

コード:

	static bool bRe = true;

	case WM_MOUSEMOVE:
		if(bRe == true){
		CEfe.ReleaseEffect(hWnd,lParam);
		}
		break;
	//タスクトレイメッセージの処理
	case WM_TrayMessage:
		switch(lParam)
		{
			//右クリックメニューを作る
			case WM_RBUTTONDOWN:
				CIco->MakeMenu(hWnd);
				break;
			//暫定的な終了処理あとで消して
			case WM_LBUTTONDOWN:
				SendMessage(hWnd,WM_DESTROY,0,0);
				break;
			default:
				break;
		}
		break;
	case WM_EXITMENULOOP:
		bRe = true;
		break;
	case WM_ENTERMENULOOP:
		bRe = false;
		break;