【问题标题】:CDialog::Create fails for dialog with ActiveX control带有 ActiveX 控件的对话框的 CDialog::Create 失败
【发布时间】:2012-10-28 20:00:54
【问题描述】:

我有一个模块可以创建一个包含 ActiveX 控件的无模式对话框。该模块是 MFC EXE 应用程序的一部分,对话框的创建工作正常。最近,我将模块移出到 ATL/COM 服务器,并将对话框资源从 EXE 复制到 COM 服务器。尝试使用 CDialog::Create() 创建无模式对话框时发生错误。

我调试到CDialog::Create 并注意到它在::CreateDialogIndirect() 中失败,它返回NULLGetLastError 返回0。我在对话框资源属性中将“No Fail Create”标志更改为 True,并获得了有关错误的更多详细信息。问题发生在DDX_Control 宏中对话框的DoDataExchange() 中。这将使用控件的资源 ID 调用 CDataExchange::PrepareCtrl(),如下所示:

HWND CDataExchange::PrepareCtrl(int nIDC)
{
   ASSERT(nIDC != 0);
   ASSERT(nIDC != -1); // not allowed
   HWND hWndCtrl;
   COleControlSite* pSite = NULL;
   m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
   if (hWndCtrl == NULL)
   {
      // Could be a windowless OCX
      pSite = m_pDlgWnd->GetOleControlSite(nIDC);
      if (pSite == NULL)
      {
         TRACE(traceAppMsg, 0, "Error: no data exchange control with ID 0x%04X.\n", nIDC);
         ASSERT(FALSE);
         AfxThrowNotSupportedException();
      }
   }
   m_idLastControl = nIDC;
   m_bEditLastControl = FALSE; // not an edit item by default

   return hWndCtrl;
}

对函数m_pDlgWnd->GetOleControlSite() 的调用因传递的资源ID 而失败。顺便说一下,资源 ID 是控件的 ID。

关于为什么这在 EXE 中有效而在 COM 服务器中失败的任何建议?

【问题讨论】:

    标签: mfc cdialog com-server


    【解决方案1】:

    前几天遇到了类似的问题。将控件从一个对话框资源复制到另一个。事实上,您不能像使用其他 MFC 控件那样将 ActiveX 控件从一个对话框复制到另一个对话框。对于 ActiveX 控件,rc 文件包含一个 DLGINIT 部分。例如,我有一个带有 IE WebBrowser 控件的表单:

    IDD_ONLINE_REPORTVIEW_FORM DIALOGEX 0, 0, 320, 200
    STYLE DS_SETFONT | DS_CONTROL | WS_CHILD
    FONT 8, "MS Sans Serif", 0, 0, 0x0
    BEGIN
        CONTROL         "",IDC_EXPLORER1,"{8856F961-340A-11D0-A96B-00C04FD705A2}",WS_TABSTOP,7,61,299,77
    END
    

    在 rc 文件的下方,有一个 DLGINIT 部分:

    IDD_ONLINE_REPORTVIEW_FORM DLGINIT
    BEGIN
        IDC_EXPLORER1, 0x376, 160, 0
    0x0000, 0x0000, 0x004c, 0x0000, 0x2e68, 0x0000, 0x0ceb, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x004c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 
    0x0000, 0xd0e0, 0x0057, 0x3573, 0x11cf, 0x69ae, 0x0008, 0x2e2b, 0x6212, 
    0x0008, 0x0000, 0x0000, 0x0000, 0x004c, 0x0000, 0x1401, 0x0002, 0x0000, 
    0x0000, 0x00c0, 0x0000, 0x0000, 0x4600, 0x0080, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0
    END
    

    打开 rc 文件的源并搜索您的控件 ID。搜索 DLGINIT 部分并将其复制到您的新对话框中

    【讨论】:

      【解决方案2】:

      我遇到了完全相同的问题。就我而言,问题原来是我没有调用 AfxEnableControlContainer()。我在我的应用的 InitInstance 成员函数中添加了一个调用,它解决了问题。

      【讨论】:

        【解决方案3】:

        就我而言,我在调用时输入了错误的对话框 ID

        BOOL Create(UINT nID, CWnd * pWnd);
        

        DoDataExchange() 上失败了。

        【讨论】:

          【解决方案4】:

          这是另一种情况,可以得到相同的调试断言警告(错误:没有 ID 为 dlgdata:line 40 的数据交换控制):

          例如如果您通过虚函数 CDialogExExample::Create(CONTROL_ID, ..) 创建 CDialogExExample 的对话框实例,而 CONTROL_ID 与 CDialogExample 头文件中的 IDD_EXAMPLE(enum{ IDD = IDD_EXAMPLE};) 不一致......那么可以添加控件总是失败。

          这里是an inspiring link from msdn

          可能对某人有帮助:)

          PS:这种情况可能和@Hank Chang 的回答一样

          【讨论】:

            【解决方案5】:

            在我的例子中,我有一个 MFC 对话框,它通过 ActiveX 托管 .Net UI 控件。

            调试后发现DoModal失败返回-1,GetLastError返回0。

            经过一天的调试,原来是.Net Assemblies 版本不匹配问题。这会导致 OLE 控件实例化失败。

            WinDBG 摘录:

            (21b0.71cc):CLR 异常 - 代码 e0434352(第一次机会) OLE 控件的 CoCreateInstance {EE3C4329-83A8-4DD8-A74C-680AC01AC593} 失败了。

            结果代码:0x80131040

            HRESULT 值 0x80131040 含义:

            找到的程序集的清单定义与程序集引用不匹配。

            【讨论】:

              【解决方案6】:

              在出现确切错误后我找到的解决方案是检查头文件中的类定义。 假设类是

              然后在下面的代码中

              class CNewDlg : public CMyBaseDlg
              {
                  DECLARE_DYNAMIC(CNewDlg)
              public:
                  CNewDlg(CWnd* pParent = NULL);   // standard constructor
                  virtual ~CNewDlg();
              
                  // Dialog Data
                  enum { IDD = IDD_MYNEWDIALOGID };
              

              检查线路:

              enum { IDD = IDD_MYNEWDIALOGID };
              

              确保您拥有正确的 ID。您遇到的错误可能是由于从先前创建的控件/对话框的另一个头文件中复制和粘贴代码而没有更新此 ID。

              这应该与 .rc 文件中对话框的定义相匹配。例如:

              IDD_MYNEWDIALOGID DIALOGEX 0, 0, 445, 314
              

              【讨论】:

              • 这不是问题。正如 OP 中所解释的,对话框 确实 被创建(提供适当的标志),因此 IDD 枚举是正确的。问题在于创建 ActiveX 控件。
              • MFC 中的对话框分两步创建。 MFC 首先构造本机对话框,传入对话框的资源 ID。成功后,它将使用 MFC 类实例(在 DDX_Control 中实现)对本机控件进行子类化。 OP 已经验证,第一步成功,所以他们肯定传递了正确的对话 ID。传递错误的 ID 会出现相同的错误这一事实并不能成为问题的答案。这是对另一个问题的回答。
              • 我根据经验发布了我的答案。 OP中描述的错误可能有很多原因,我发布的解决方案对我有用。如果我的解决方案也适用于他,我建议允许 @user1756114 发表评论。
              猜你喜欢
              • 1970-01-01
              • 2014-10-06
              • 1970-01-01
              • 1970-01-01
              • 2013-04-27
              • 1970-01-01
              • 2010-10-17
              • 2019-06-21
              • 2010-09-18
              相关资源
              最近更新 更多