One Note Jam

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スタイルを除去しようとしているコードに見えますが、これって大丈夫なのでしょうか……?

posted at 2008-07-31 | Permalink

© 2004-2008 ENDO