CWnd 作为 ActiveX 控件,在 C++ 中没有 .dll 或 .ocx 文件?
亲爱的 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 的调用已经完成,并且在没有断言的情况下默默失败 如果有的话那就太好了。有人知道这是哪里吗?
我的核心问题是,在这种情况下,通常 MFC 会照顾是否正确 注册控件,即使它不在 .dll 或 .ocx 项目中,并且它必须已工作 过去就是这样。我在某处读到,带有 DialogTemplate 的 CreateDlgIndirect 是一种方法 无需 .dll 或 .ocx 文件即可创建 ActiveX 控件。在上面的堆栈中,这被称为, 也是如此,但不是针对 ActiveX 控件,而是针对对话。
有谁知道更多关于这个问题以及如何解决它? 如果我确实必须手动注册控件,例如使用 regsvr32.exe 或通过源代码, 有没有没有 .dll 或 .ocx 文件的方法?或者我必须将 ActiveX 组件重新打包在 他们自己的项目(无论如何,什么会更加基于组件/模块化)?
我希望我的问题描述足够准确,我将非常感谢任何答案。 亲切的问候。
Dear MFC/ActiveX/COM cracks, I have 'inherited' the source of an old MFC application (originally created with Visual Studio 6)
which builds and runs so far in VS 2010, but has embedded some ActiveX controls as source code, apparently generated by the
Visual Studio wizard (.h and .cpp files, see below);
however not in an own subproject so that a .dll or .ocx file are generated.
Here is the relevant part of the header file of one such control:
#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
Note that this class inherits from CWnd and not some
OCX class. But since all MFC windows are COM components (as I read somewhere) and this is generated
code it should have worked some time ago. I also read that this may be really a migration gap
which occurred somewhere before 2005.
Also note the DECLARE_DYNCREATE, so I think this is late binding, using the IDispatch interface.
So MFC will call a Create() function for us.
The above control is used via aggregation by an encompassing CDialog (also created with VS wizard):
//... analysedlg.h - leading auto-generated stuff omitted
class CAnalyseDlg : public CDialog
{
CChartfx m_chhrtfx;
//... enum for resource ID, DoDataExchange, message map, other members…
}
The dialog, in turn, is embedded in a view class of the application (again, via a member variable) and
created by invoking DoModal() in a menu item event handler.
So, when I click on the corresponding menu item, I get an m_hWnd NULL assertion and when hitting
'retry' in the popped up dialogue, the following stack (excerpt):
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++
In the VS debug output there are the following lines:
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.
So apparently the call to CoCreateInstance had already been done and silently failed without an assertion
which would have been nice to have had. Does anybody know where this is?
My central question is whether it is correct that in this case normally MFC would take care for
registering the control even if it is not in an .dll or .ocx project and that it must have worked
like this in the past. I read somewhere that CreateDlgIndirect with a DialogTemplate is a way of
creating ActiveX controls without needing a .dll or .ocx file. In the above stack, this is called,
too, but not for the ActiveX control, but for the dialogue instead.
Does anyone know more about this issue and how to fix it?
If I do have to manually register the controls, e.g. using regsvr32.exe or via source code,
is there a way without .dll or .ocx files? Or do I have to repackage the ActiveX components in
their own projects (what would be more component-based/modular anyway)?
I hope my problem description is precise enough and I would be very thankful for any answer.
Kind regards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我刚刚在使用旧的 ActiveX 控件时遇到了这个问题。显然它是公寓线程的,我试图用 COINIT_MULTITHREADED 调用 CoInitializeEx() 。
I've just run into this when using an old ActiveX control. Apparently it was apartment threaded and I was trying to call CoInitializeEx() with COINIT_MULTITHREADED.