0

亲爱的 MFC/ActiveX/COM 破解,我已经“继承”了一个旧的 MFC 应用程序(最初使用 Visual Studio 6 创建)的源代码,它在 VS 2010 中构建和运行,但嵌入了一些 ActiveX 控件作为源代码,显然是生成的通过 Visual Studio 向导(.h 和 .cpp 文件,见下文);但是不在自己的子项目中,以便生成 .dll 或 .ocx 文件。以下是此类控件的头文件的相关部分:

#if !defined(AFX_CHARTFX_H__F8A080E0_0647_11D4_92B0_0000E886CDCC__INCLUDED_)
#define AFX_CHARTFX_H__F8A080E0_0647_11D4_92B0_0000E886CDCC__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

// NOTE: Do not modify the contents of this file.  If this class is regenerated by
//  Microsoft Visual C++, your modifications will be overwritten.

/////////////////////////////////////////////////////////////////////////////
// CChartfx wrapper class

class CChartfx : public CWnd
{
protected:
    DECLARE_DYNCREATE(CChartfx)
public:
    CLSID const& GetClsid()
    {
        static CLSID const clsid
            = { 0x8996b0a1, 0xd7be, 0x101b, { 0x86, 0x50, 0x0, 0xaa, 0x0, 0x3a, 0x55, 0x93 } };
        return clsid;
    }
    virtual BOOL Create(LPCTSTR lpszClassName,
        LPCTSTR lpszWindowName, DWORD dwStyle,
        const RECT& rect,
        CWnd* pParentWnd, UINT nID,
        CCreateContext* pContext = NULL)
    { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }

    BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
        const RECT& rect, CWnd* pParentWnd, UINT nID,
        CFile* pPersist = NULL, BOOL bStorage = FALSE,
        BSTR bstrLicKey = NULL)
    { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,
        pPersist, bStorage, bstrLicKey); }
    //rest of header file omitted

请注意,此类继承自 CWnd 而不是某些 OCX 类。但由于所有 MFC 窗口都是 COM 组件(正如我在某处读到的那样),而且这是生成的代码,它应该在一段时间前就可以工作了。我还读到这可能是 2005 年之前发生的迁移差距。还要注意 DECLARE_DYNCREATE,所以我认为这是后期绑定,使用 IDispatch 接口。所以 MFC 会为我们调用一个 Create() 函数。

上述控件通过包含 CDialog 的聚合使用(也使用 VS 向导创建):

//... analysedlg.h  - leading auto-generated stuff omitted
class CAnalyseDlg : public CDialog
{
  CChartfx m_chhrtfx;
  //... enum for resource ID, DoDataExchange, message map, other members…
}

反过来,对话框嵌入在应用程序的视图类中(同样,通过成员变量),并通过在菜单项事件处理程序中调用 DoModal() 来创建。

因此,当我单击相应的菜单项时,我会得到一个 m_hWnd NULL 断言,并且在弹出的对话框中点击“重试”时,会出现以下堆栈(摘录):

mfc100d.dll!COleControlContainer::FillListSitesOrWnds(_AFX_OCC_DIALOG_INFO * pOccDlgInfo)  line 925 + 0x23 Bytes    C++
mfc100d.dll!COccManager::CreateDlgControls(CWnd * pWndParent, const char * lpszResourceName, _AFX_OCC_DIALOG_INFO * pOccDlgInfo)  line 410  C++
mfc100d.dll!CDialog::HandleInitDialog(unsigned int __formal, unsigned int __formal)  line 715 + 0x22 Bytes  C++
mfc100d.dll!CWnd::OnWndMsg(unsigned int message, unsigned int wParam, long lParam, long * pResult)  line 2383 + 0x11 Bytes  C++
mfc100d.dll!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam)  line 2087 + 0x20 Bytes    C++
mfc100d.dll!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  line 257 + 0x1c Bytes  C++
mfc100d.dll!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  line 420    C++
mfc100d.dll!AfxWndProcBase(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  line 420 + 0x15 Bytes   C++
user32.dll!766162fa()   
[missing frames omitted by me]  
mfc100d.dll!CWnd::CreateDlgIndirect(const DLGTEMPLATE * lpDialogTemplate, CWnd * pParentWnd, HINSTANCE__ * hInst)  line 366 + 0x2a Bytes    C++
mfc100d.dll!CDialog::DoModal()  line 630 + 0x20 Bytes   C++

在 VS 调试输出中有以下几行:

CoCreateInstance of OLE control {8996B0A1-D7BE-101B-8650-00AA003A5593} failed.
>>> Result code: 0x80040154
>>> Is the control is properly registered?
Warning: Resource items and Win32 Z-order lists are out of sync. Tab order may be not defined well. 

因此,显然对 CoCreateInstance 的调用已经完成,并且在没有断言的情况下默默地失败了,这本来是很好的。有人知道这是哪里吗?

我的核心问题是,在这种情况下,即使控件不在 .dll 或 .ocx 项目中,MFC 通常会注意注册控件是否正确,并且它过去一定是这样工作的。我在某处读到,带有 DialogTemplate 的 CreateDlgIndirect 是一种无需 .dll 或 .ocx 文件即可创建 ActiveX 控件的方法。在上面的堆栈中,它也被调用,但不是为 ActiveX 控件,而是为对话。

有谁知道更多关于这个问题以及如何解决它?如果我必须手动注册控件,例如使用 regsvr32.exe 或通过源代码,有没有没有 .dll 或 .ocx 文件的方法?或者我是否必须在他们自己的项目中重新打包 ActiveX 组件(无论如何,还有什么是基于组件/模块化的)?

我希望我的问题描述足够准确,我会非常感谢任何答案。亲切的问候。

4

1 回答 1

0

我刚刚在使用旧的 ActiveX 控件时遇到了这个问题。显然它是单元线程的,我试图用 COINIT_MULTITHREADED 调用 CoInitializeEx()。

于 2014-01-31T00:50:06.993 回答