バッファーサイズフリー ファイル開くダイアログ クラス

[ 目的 ]

複数選択でファイル開くダイアログを使用する場合、OPENFILENAME::lpstrFile メンバーに指定するバッファーはいくらだったら十分なサイズなのか非常に悩ましいところです。もしユーザーがファイルを決定した時点で動的にバッファーを確保できれば大変便利ではないでしょうか。そこでバッファーサイズを自動調整するファイル開くダイアログを作成しました。

[ 手法 ]

::GetOpenFileName() を利用します。

ユーザーがOKボタンを押すかリターンキーを押した時点で、必要なバッファーサイズを調らべ足りなければ新たに確保します。


バッファーを確保した後の処理がWindows 9X 系と NT 系で異なります Windows 9X 系
OPENFILENAME::lpstrFile と nMaxFile メンバーに新たに必要なバッファーへのアドレスとサイズを代入するだけで簡単に済みます。この点は MSDN にも明記されていました ( Ref: How To Handle FNERR_BUFFERTOOSMALL in Windows 95 ) 。 Windows NT 系
思考錯誤の結果、OPENFILENAME は変更せずに、新たに確保したバッファーにパスとファイル名をコピーすることにしまし、::GetOpenFileName() の戻り値がエラーになった時点で、OPENFILENAME::lpstrFile と新バッファーを入れ替えることにしました。

[ ポイント ]

Windows 9X と NT の判別の仕方

/* OSVERSIONINFO::dwPlatformId が VER_PLATFORM_WIN32_WINDOWS なら 9X 系, VER_PLATFORM_WIN32_NT なら NT 系となります。*/
OSVERSIONINFO ovi = { 0 };
ovi.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ) ;
::GetVersionEx ( &ovi ) ;

OKボタンとリターンキーの検出

ファイル開くダイアログに IDOK が送られてくる場合と、リストコントロールに VK_RETURN が送られる場合がありますので、サブクラス化してメッセージを処理します。ただしここで言うダイアログは、フックしたダイアログではなくその更に親ダイアログを示しています。またリストビューは親ダイアログの孫ウィンドウに当たることです。さらに気をつけなければならないのは、リストコントロールのハンドルはフォルダが変わるごとに変化してしまうことです。

新しいスタイルでは、ツールの表示メニューより「縮小版」を選んだ場合には LVS_ICON スタイルのリストコントロールがもう一つ別に発生しますので、これも処理する必要があります。


フォルダーが変わるごとに変化するリストコントロールのハンドルの求め方

フックダイアログのウィンドウプロシーシャで、CDN_FOLDERCHANGE メッセージを受け取ったときにリストコントロールのハンドルを求め直します。このとき以前のハンドルに対応するウィンドウは破棄されていますので、リストコントロールを再度サブクラス化を行います。

case WM_NOTIFY:
if ( ( ( LPOFNOTIFY ) lp ) ->hdr.code == CDN_FOLDERCHANGE ) {
hListView = ::GetDlgItem ( ::GetDlgItem ( ::GetParent ( lpon->hdr.hwndFrom ) , lst2 ) , 1 ) ;
// ハンドルが変化したなら、リストコントロールをサブクラス化し直す処理を記述
}
break;

必要なバッファーサイズの求め方

HWND hMainDlg; // 親ダイアログのハンドル

// フォルダーへのパスの格納に必要なバッファーサイズを求める
CommDlg_OpenSave_GetFolderPath ( hMainDlg, NULL, 0 ) ) ;

// ファイルの格納に必要なバッファーサイズを求める
CommDlg_OpenSave_GetSpec( hMainDlg, NULL, 0 ) ;

ファイルの格納に必要なバッファーサイズの求め方の留意点

CommDlg_OpenSave_GetSpec の戻り値はバイト数ではなく文字数のため、マルチバイト文字の場合TCHAR 単位サイズが得られません。このためマルチバイト文字数を別途リストコントロールより検出し、必要なバッファサイズに加算しました。そのためエディットコントロール(新しいスタイルではコンボボックス)への入力を禁止としました。

サンプルプログラム ( MultiOfn 13KB )