CDialog::Create fails for dialog with ActiveX cont

2019-02-18 07:33发布

问题:

I have a module that creates a modeless dialog containing an ActiveX control. This module was part of an MFC EXE application and the creation of the dialog worked fine. Recently, I moved the module out into an ATL/COM server and copied the dialog resource from the EXE into the COM server. When trying to create the modeless dialog using CDialog::Create() an error happens.

I debugged into CDialog::Create and noticed that it fails in ::CreateDialogIndirect() which returns NULL and GetLastError returns 0. I changed the "No Fail Create" flag to True in the dialog resource properties and I get more details into the error. The problem happens in the dialog's DoDataExchange() within the DDX_Control macro. This calls into the CDataExchange::PrepareCtrl() with the control's resource ID as follows:

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;
}

The call to the function m_pDlgWnd->GetOleControlSite() fails for the resource ID passed. By the way, the resource ID is the control's ID.

Any suggestions on why this works inside the EXE and fails in the COM server?

回答1:

I had exactly the same problem. In my case the problem turned out to be that I hadn't called AfxEnableControlContainer(). I added a call to that in my app's InitInstance member function and it fixed the problem.



回答2:

Had a similar problem just the other day. Copied a control from one dialog resource to another. As it happened, you can't just copy an ActiveX control from one dialog to another the way you do with other MFC controls. For an ActiveX control the rc file contains a DLGINIT section. For example I have a form with an IE WebBrowser control:

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

and below in the rc file, there is a DLGINIT section:

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

Open the rc file's source and search for your control ID. Search for DLGINIT section and copy it to your new dialog



回答3:

In my case, I put a wrong Dialog ID while calling

BOOL Create(UINT nID, CWnd * pWnd);

so failed on DoDataExchange().



回答4:

Here is another situation where one can get the same Debug Assersion Warnings(Error: no data exchange control with ID dlgdata:line 40):

e.g. if you create a dialog instance of CDialogExExample by virtual function CDialogExExample::Create(CONTROL_ID, ..), while the CONTROL_ID is inconstant with the IDD_EXAMPLE(enum{ IDD = IDD_EXAMPLE};) in CDialogExExample header file....then one could add control fails always.

Here's an inspiring link from msdn !

may be helpful to somebody:)

PS:this situation maybe same with @Hank Chang's answer



回答5:

In my case, I had a MFC dialog which hosts .Net UI control through ActiveX.

Upon debugging i found, DoModal failed and returned -1 and GetLastError gave 0.

After a day of debugging, it turned out to be .Net Assemblies version mismatch issue. This lead to OLE control instantiation failure.

WinDBG excerpt:

(21b0.71cc): CLR exception - code e0434352 (first chance) CoCreateInstance of OLE control {EE3C4329-83A8-4DD8-A74C-680AC01AC593} failed.

Result code: 0x80131040

HRESULT value 0x80131040 meaning :

The located assembly's manifest definition does not match the assembly reference.



回答6:

The solution I have found after having that exact error was to check the class definition in the header file. Assuming the class is

Then in the following code

class CNewDlg : public CMyBaseDlg
{
    DECLARE_DYNAMIC(CNewDlg)
public:
    CNewDlg(CWnd* pParent = NULL);   // standard constructor
    virtual ~CNewDlg();

    // Dialog Data
    enum { IDD = IDD_MYNEWDIALOGID };

check the line:

enum { IDD = IDD_MYNEWDIALOGID };

making sure you have the correct ID. The error you are getting might be a result of copying and pasting code from another header file of a previously created control / dialog without updating this ID.

That should match the definition of the dialog in your .rc file. For example:

IDD_MYNEWDIALOGID DIALOGEX 0, 0, 445, 314