How do you create a COM DLL in Visual Studio 2008?

2019-02-02 17:20发布

问题:

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?

Edit: Sorry, forgot to mention I'm using C++.

回答1:

To create a new ATL COM project you can proceed as follow:

  1. File/New Project
  2. Visual C++/ATL/ATL Project
  3. Customize it settings, and press finish when done

You have created a new dll, but it is empty, to add a COM object you can do this:

  1. Project/Add Class
  2. Visual C++/ATL/ATL simple object, press add
  3. Give the name you want (like MyObject), and press finish to add it

If you want that an object implement an interface

  1. In the class view select the object class (CMyObject)
  2. Right click/Add/Implement Interface...
  3. You can select which Interface will implement
    1. From an .idl file already in your projects files
    2. From a .tlb/.dll/.exe which have a type library embedded
    3. From an object already registered
  4. When done press finish

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.

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.

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.



回答2:

You need to write a function called DllGetClassObject and 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.

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.

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.

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.

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.

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.



回答3:

When you build the solution, it automatically registers the dll. And also it creates two files _i.c and .h file.

To test the dll create the sample application:

  1. Create sample Win32 application. Include the _i.c and .h in the cpp file of the win32 application which has main function

  2. Call CoInitialize();

  3. Declare a interface pointer CComPtr pMyInterface = NULL; // where IMyInterface is declared in _i.c

  4. Create the instance pMyInterface.CoCreateInstance(CLSID_MyClass); // CLSID_MyClass is GUID representing the
    CoClass

  5. Call the APIs present in the Interface

  6. Call CoUnInitialize();