C++ 如何在 Visual Studio 2008 中创建 COM DLL?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/465345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you create a COM DLL in Visual Studio 2008?
提问by Mark Ingram
It's been ages since I've written a COM dll. I've made a couple of classes now, that inherit from some COM interfaces, but I want to test it out. I know I have to put a GUID somewhere and then register it with regsvr32, but what are the steps involved?
自从我编写 COM dll 以来已经有很长时间了。我现在已经创建了几个类,它们继承自一些 COM 接口,但我想对其进行测试。我知道我必须在某处放置一个 GUID,然后用 regsvr32 注册它,但是涉及的步骤是什么?
Edit: Sorry, forgot to mention I'm using C++.
编辑:抱歉,忘了提及我正在使用 C++。
回答by Ismael
To create a new ATL COM project you can proceed as follow:
要创建一个新的 ATL COM 项目,您可以按照以下步骤操作:
- File/New Project
- Visual C++/ATL/ATL Project
- Customize it settings, and press finish when done
- 文件/新项目
- Visual C++/ATL/ATL 项目
- 自定义设置,完成后按完成
You have created a new dll, but it is empty, to add a COM object you can do this:
您已经创建了一个新的 dll,但它是空的,要添加一个 COM 对象,您可以这样做:
- Project/Add Class
- Visual C++/ATL/ATL simple object, press add
- Give the name you want (like MyObject), and press finish to add it
- 项目/添加类
- Visual C++/ATL/ATL 简单对象,按添加
- 给出你想要的名称(如 MyObject),然后按完成添加它
If you want that an object implement an interface
如果你希望一个对象实现一个接口
- In the class view select the object class (CMyObject)
- Right click/Add/Implement Interface...
- You can select which Interface will implement
- From an .idl file already in your projects files
- From a .tlb/.dll/.exe which have a type library embedded
- From an object already registered
- When done press finish
- 在类视图中选择对象类 (CMyObject)
- 右键单击/添加/实现接口...
- 您可以选择要实现的接口
- 来自项目文件中已有的 .idl 文件
- 从嵌入了类型库的 .tlb/.dll/.exe
- 从已经注册的对象
- 完成后按完成
PS: It is much easier to create a new ATL project with the same name in a different folder, and add the files you have customized. The wizard does several tasks and create several customized files.
PS:在不同的文件夹中新建一个同名的ATL项目,并添加你自定义的文件要容易得多。该向导执行多项任务并创建多个自定义文件。
For larger projects that are difficult to add file by file, I do the same but instead of adding my files to the new project I start copying the settings from the new projects to the old one, and adding any additional file that the wizard has created and fixing headers like stdafx.h to merge the new settings.
对于难以逐个文件添加的大型项目,我会这样做,但我没有将文件添加到新项目中,而是开始将设置从新项目复制到旧项目,并添加向导创建的任何其他文件并修复 stdafx.h 之类的标题以合并新设置。
PPS: If you want that your dll to support MFC, instead of selecting ATL Project you have to select MFC/MFC Dll. When you add the ATL Simple Object the wizard will ask to add ATL support to the project.
PPS:如果你想让你的 dll 支持 MFC,你必须选择 MFC/MFC Dll 而不是选择 ATL Project。添加 ATL 简单对象时,向导将要求向项目添加 ATL 支持。
回答by Daniel Earwicker
You need to write a function called DllGetClassObjectand export it. That function is responsible for allocating a "class factory", which you also have to write, and which is in turn capable of allocating instances of your COM object. It has to implement IClassFactory.
您需要编写一个名为DllGetClassObject的函数并将其导出。该函数负责分配一个“类工厂”,您也必须编写它,然后它又能够分配您的 COM 对象的实例。它必须实现IClassFactory。
It's not too hard to do. The alternative is to use ATL (see xhantt's answer) which in theory does this for you, but in practice it's a real mess. Somehow it manages to encapsulate the complexity of COM inside an abstraction layer that is even more complicated. Good luck trying to move an object between DLLs for example.
做起来并不难。另一种方法是使用 ATL(请参阅 xhantt 的答案),理论上它可以为您执行此操作,但在实践中却是一团糟。不知何故,它设法将 COM 的复杂性封装在一个更复杂的抽象层中。祝你好运,例如,尝试在 DLL 之间移动对象。
But you could run the ATL wizard just to see an example of how to declare DllGetClassObject
. Implementing IClassFactory
is very easy - just one method that news-up an object.
但是您可以运行 ATL 向导来查看如何声明DllGetClassObject
. 实现IClassFactory
非常简单——只是一种更新对象的方法。
Then you need to register your DLL - i.e. put keys into the registry. The regsvr32
tool cannot do this without further help from you. You have to write and export another function called DllRegisterServer, which does all the hard work. All that regsvr32
does is load the DLL, look up DllRegisterServer
and call it.
然后您需要注册您的 DLL - 即把密钥放入注册表中。如果regsvr32
没有您的进一步帮助,该工具将无法执行此操作。您必须编写并导出另一个名为DllRegisterServer 的函数,它完成所有繁重的工作。所有这一切regsvr32
确实是加载DLL,查找DllRegisterServer
和调用它。
Again, ATL has a way of implementing this for you, but it does it by reading a kind of script full of registry modification instructions, stored in an .rgs file that gets embedded into your DLL's resources. If you accidentally put any kind of syntax error into this file, the registration fails silently.
同样,ATL 有一种为您实现这一点的方法,但它通过读取一种充满注册表修改指令的脚本来实现,这些脚本存储在嵌入到您的 DLL 资源中的 .rgs 文件中。如果您不小心将任何类型的语法错误放入此文件,注册将无声无息地失败。
So again, you may actually find it simpler to write a few lines of code to tweak the registry yourself. Here are the details.
因此,您实际上可能会发现自己编写几行代码来调整注册表更简单。这是详细信息。
If you used C# instead, you wouldn't have any of these problems. Everything is encapsulated very cleanly. It actually works much better than C++ as a tool for developing COM objects.
如果您改用 C#,则不会遇到任何这些问题。一切都封装得非常干净。作为开发 COM 对象的工具,它实际上比 C++ 好得多。
回答by Vinay
When you build the solution, it automatically registers the dll. And also it creates two files _i.c and .h file.
构建解决方案时,它会自动注册 dll。它还创建了两个文件 _i.c 和 .h 文件。
To test the dll create the sample application:
要测试 dll,请创建示例应用程序:
Create sample Win32 application. Include the _i.c and .h in the cpp file of the win32 application which has main function
Call CoInitialize();
Declare a interface pointer CComPtr pMyInterface = NULL; // where IMyInterface is declared in _i.c
Create the instance pMyInterface.CoCreateInstance(CLSID_MyClass); // CLSID_MyClass is GUID representing the
CoClassCall the APIs present in the Interface
Call CoUnInitialize();
创建示例 Win32 应用程序。在具有main函数的win32应用程序的cpp文件中包含_i.c和.h
调用 CoInitialize();
声明一个接口指针 CComPtr pMyInterface = NULL; // 其中 IMyInterface 在 _i.c 中声明
创建实例 pMyInterface.CoCreateInstance(CLSID_MyClass); // CLSID_MyClass是表示GUID
的CoClass调用接口中存在的 API
调用 CoUnInitialize();