コマンドラインアプリ(あるいはコンソールアプリ)から、セレクションダイアログを使いたい、というか、コマンドラインから使うときとウインドウから使う時に共通の関数として作りたくなったので、どうやったらいいかちょっと調べてみた。どうせWindows上で動くのだし、リソースも書かなきゃいけないのだから、普通に WinMain のあるウインドウアプリとして作成して、非表示にするというのが順当な手のような気がするが、ここはあえて main から呼んでみた。
どうやら、以下のような感じで処理すると、任意のダイアログを作成して、処理した後に戻ってこれる。
hDlgWnd = CreateDialog( NULL, (LPCTSTR)IDD_DIALOG1, NULL, (DLGPROC)DialogProc );
ShowWindow( hDlgWnd, SW_SHOW );
UpdateWindow( hDlgWnd );
while( 1 ){
BOOL ret;
ret = GetMessage( &msg, NULL, 0, 0 );
// ret == 0 : msg == WM_QUIT
// ret == -1: error
if( ret == 0 || ret == -1 ){
break;
}else{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
ダイアログ上で発生するイベントを処理するためのプロシージャ(DialogProc)は、別途必要。最初は、インスタンスと親ウィンドウをNULLにすりゃ適当に動いてくれるかと思ったのだけど、そうは問屋が卸さなかった。ダイアログがメッセージを処理できない状態になるらしく、砂時計が回りっぱなし。DialogProcからDefWindowProcを呼んでもみたが、そうすると今度はDialogProcですべてのmsgを処理しないといけなくなる。それにDialogProcの作法としても不適切になるし。
結局のところは、WinMain がやってるのと同じように、main の中で自前でループを作ってメッセージを処理させればよいようだ。ダイアログから PostQuitMessage を投げることでループを抜けられる。
インスタンスと親ウインドウをNULLにするってことはルートウインドウの直下にできることになると思うのだけど、PostQuitMessage が投げられているのに処理を終わらないことに問題はないのかというのがちょっと気がかり。
そう思って、コマンドプロンプトのインスタンスハンドルとウインドウハンドルを取得してからやってみたんだけど、CreateDialogの方を指定することに見かけ上の問題はなかった。コマンドプロンプトのスレッドキューに閉じているという点ではこちらの方が良いのかもしれない。
実際のところはどうなんだろう?
ちなみに、コンソールのインスタンスハンドルの取得の方法はこちら。コマンドプロンプトのタイトルを一時的に変更して、FindWindow をしている。
インスタンスハンドルは GetModuleHandle で取得できる。
- Windows previous versions documentation | Microsoft Docs
- Windows previous versions documentation | Microsoft Docs
- Windows previous versions documentation | Microsoft Docs
- Windows previous versions documentation | Microsoft Docs
- Windows previous versions documentation | Microsoft Docs
- Windows previous versions documentation | Microsoft Docs