Windows Mobile開発・VS2005のMFC上では、DS_MODALFRAMEスタイルのダイアログは生成できない (2008-07-31)
前回の記事(2008-07-27)にも書いたとおり、開発環境をeVC++4.0(eMbedded Visual C++ 4.0)からVS2005(Visual Studio 2005)に変更した際に、いろいろと細かい点でソースコードの移行に苦しんだわけですが、その中の一つを紹介します。
非常に単純な話で、ダイアログリソースでDS_MODALFRAMEスタイルを指定した場合、CDialog::DoModal()などでのダイアログ生成時に実行時エラーになります。表示されるはずのダイアログが表示されず、見た目上は何も起きないように見えます。eVC++4.0ではこのような現象は起きなかったので、原因がわかるまでは戸惑いました。
MFCのソースを追いかけてみれば一目瞭然。VS2005のMFCでの該当ソース(dlgcore.cpp)は以下のとおり。
// create modeless dialog AfxHookWindowCreate(this); #ifdef _WIN32_WCE int aygshellUIModel = AfxGetAygshellUIModel(); if ((aygshellUIModel == PocketPC || aygshellUIModel == Smartphone) && (lpDialogTemplate->style & DS_MODALFRAME)) { // Fail DS_MODALFRAME can't be set for Pocket PC and Smartphone TRACE(traceAppMsg, 0, _T("ERROR: dialog template has DS_MODALFRAME set, which is not supported for Pocket PC and Smartphone\n")); return FALSE; } // CreateDialogIndirect is a macro, so just the last parameter can't be preprocessed differently hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate, pParentWnd->GetSafeHwnd(), AfxDlgProcEx); #else // _WIN32_WCE hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate, pParentWnd->GetSafeHwnd(), AfxDlgProc); #endif // _WIN32_WCE
これに対して、eVC++4.0のMFCのソースでは以下のようになっています。こちらは、DS_MODALFRAMEスタイルが指定された際にエラーにするのではなく、DS_MODALFRAMEスタイルを除去しているようです。
// create modeless dialog AfxHookWindowCreate(this); #if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 300) if (lpDialogTemplate->style & DS_MODALFRAME) { LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lpDialogTemplate; DWORD dwResult; MEMORY_BASIC_INFORMATION mbiMemory; memset (&mbiMemory, 0, sizeof(MEMORY_BASIC_INFORMATION)); dwResult = VirtualQuery (lpTemplate, &mbiMemory, sizeof(MEMORY_BASIC_INFORMATION)); if (sizeof(MEMORY_BASIC_INFORMATION) == dwResult) { if (mbiMemory.Protect == PAGE_READWRITE) { lpTemplate->style &= ~DS_MODALFRAME; } else if (mbiMemory.Protect == PAGE_READONLY) { // Mark the dialog template as read-write. VirtualProtect(lpTemplate, sizeof(DLGTEMPLATE), PAGE_READWRITE, &dwResult); lpTemplate->style &= ~DS_MODALFRAME; } } } #endif hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate, pParentWnd->GetSafeHwnd(), WCE_IF(wce_FirstDlgProc, AfxDlgProc));
ところでこのソースコードですが、かなり無理やりにDS_MODALFRAMEスタイルを除去しようとしているコードに見えますが、これって大丈夫なのでしょうか……?