DLL 中 COM 对话框的自动化






4.79/5 (20投票s)
2004年4月29日
4分钟阅读

114615

2250
DLL 中 COM 对话框的自动化
引言
长期以来,我一直希望能够重用对话框,而无需担心资源 ID、DLL、头文件和库。 我希望 MFC 和 COM 能够解决这个问题,但从未找到一篇好的文章来解释如何做到这一点。 有几本书和文章是关于 COM、MFC、ATL、组件的,但我从未找到一本能够告诉我如何在 COM DLL 中放置一个 COM 对话框,并让我通过自动化来管理它的书。 我终于找到了一个简单的过程,并在这里分享这个过程。
我发现您可以创建对话框资源,为它们创建新的类,并为它们启用自动化,但您无法创建它们的实例。 我不确定为什么,因为它们是从CCmdTarget
派生的。 本文介绍了如何创建一个 COM 自动化对话框,您可以从任何 COM 客户端(即 VB 或 VC++)启动并控制它。
下面是一个 UML 图,显示了这个简单原型的组件和测试应用程序架构以及所涉及的相关操作。
创建保存组件的 MFC COM DLL
创建一个新的 MFC DLL 项目
确保它是一个使用共享 MFC DLL 的 Regular DLL,并确保选中“Automation”。 这将为 DLL 创建必要的入口点以进行注册。
创建要自动化的对话框
现在,向项目添加一个对话框资源。 添加一个按钮并双击它。 告诉类向导创建一个新类。
创建对话框并确保选中“Automation”单选按钮。 请注意,您无法启用“Createable by type ID”。 这给我带来了很多问题,我们稍后会看到如何解决它。
例如,将事件处理程序添加到按钮按下事件
void CMyComDlg::OnPressMe() { // TODO: Add your control notification handler code here AfxMessageBox("Pressed"); }
现在,您可以将自动化控件添加到对话框。 使用类向导最容易。 选择“Add Method”
向自动化处理程序添加一些实现以调用相同的按钮处理程序,例如
void CMyComDlg::PressMe() { // TODO: Add your dispatch handler code here OnPressMe(); }
创建 COM 对话框工厂
此时,可以在对话框外部看到此 COM 对话框,但您无法创建它的实例。 为了解决这个问题,我们添加一个可以动态创建的对象。 例如,使用类向导添加一个从CCmdTarget
派生的新类。 确保选中Createable by type ID。
单击“确定”。 我注意到 Dev Studio 中有一个错误,有时,接口不会显示出来。 要使其显示,只需关闭项目并重新打开即可。 这应该可以解决它。
否则,使用类向导为新工厂添加一个新的 Automation 接口。
请注意,返回类型为LPDISPATCH
。 这是通过 COM 将对话框从 DLL 传递到 COM Automation 客户端的关键。 在实现中,您通过 COM 将分派接口指针返回给客户端。
////////////////////////////////////////////////////////// // CComDialogFactory message handlers #include "MyComDlg.h" LPDISPATCH CComDialogFactory::GetDialog() { // Yes this is a leak, the *dlg would be a member of the class. CMyComDlg *dlg = new CMyComDlg(); // Set the argument as true to increase the ref count return dlg->GetIDispatch(TRUE); }
构建项目。
在 DLL 上运行 regsvr32.exe 以注册组件。
Visual Basic 客户端
现在,您可以创建一个 VB 项目来使用此对话框并轻松控制它。
创建一个 VB Exe 项目,选择“项目引用”并浏览到新编译的类型库(TLB 文件)。
向 VB 窗体添加一个按钮和一个处理程序。 下面的代码创建工厂,然后创建对话框。 请注意,对话框没有显示,您必须添加一个“DoModal
”或显示对话框自动化方法才能实现此目的。
Private Sub Command1_Click()
' create the factory
Dim factory As ComDlgInDll.ComDialogFactory
Set factory = New ComDlgInDll.ComDialogFactory
' allocate the dialog
Dim dlg As ComDlgInDll.MyComDlg
' let the factory make it
Set dlg = factory.GetDialog
' press the dialog button.
dlg.PressMe
End Sub
Visual C++ 客户端
VC++ 客户端并不那么简单。 创建一个新的 MFC 项目(Doc/view、对话框,随便),添加一个菜单或按钮和一个处理程序。 您必须确保在 OnInitDialog
或 InitInstance
中初始化 COM 库,如果 MFC 项目没有为您执行此操作。
HRESULT hrx; hrx = CoInitialize(NULL); ASSERT( SUCCEEDED( hrx ) );
以及一个类似的调用来关闭库 OnDestory
或 ExitInstance
CoUninitialize();
要使用该组件,您可以这样做
// Import the COM type library #import "..\Debug\ComDlgInDll.tlb" no_namespace void CTestAppDlg::OnButton1() { // TODO: Add your control notification handler code here HRESULT hrx; // Use smart pointers to create an instance of the factory IComDialogFactoryPtr pFactory; hrx = pFactory.CreateInstance( __uuidof(ComDialogFactory) ); ASSERT( SUCCEEDED( hrx ) ); if ( SUCCEEDED( hrx ) ) { // Get the factory to show the dialog IMyComDlgPtr pDlg; pDlg = pFactory->GetDialog(); // And activate the button through COM pDlg->PressMe(); } }
结论
至此,您有了一个真正可重用的对话框组件,它具有定义的接口,您可以通过任何 COM 客户端访问这些接口。 无需担心复制头文件和 cpp 文件,确保您的资源 ID 不重叠以及合并或管理资源文件。 只有 DLL 和类型库。
本文中的代码具有最小的错误检查,仅用于说明目的。 该代码已在 VC++ 6.0 SP5、Win 2K SP4 上进行了测试