I have an in-process COM server FooObject.dll that I no longer have the source code for, but would like to write a new implementation in unmanaged C++ using the same interface. I'm using Visual Studio 2019 latest update.
How do I do this?
So far I set up a project like this:
FooObject.tlb
using the instructions in https://stackoverflow.com/a/42074044/1505939 .FooObject.idl
from FooObject.tlb
using OleView.exe.I have tried the following things (individually)
Under "Source Files", rightclick -> Add Existing Item -> FooObject.idl
.
ATLProject1_i.c
and .h
to be regenerated containing only the definitions from FooObject.idl
, and then dllmain.h
failed to compile since it referenced LIBID_ATLProject1Lib
which used to be in ATLProject1_i.c
but wasn't now. So I guess this is not the intended approach.FoOObject.idl
and removing ATLProject1.idl
, which again built successfully and even allows registering with regsvr32
which registers all the same classes (can see it via the type library browser in OleView); but there's still no implementation and creating an object in a test container gives 80040154 as if it were not registered.Add #import "FooObject.dll
to the top of ATLProject1.cpp
, under the include
s . The project compiles without error but no import files are generated.
Add importlib "FooObject.idl"
to the ATLProject1.idl file. Again it compiles without error but doesn't generate any import files.
Manually create import files with midl /header FooObject.h /env win32 FooObject.idl
. This did create import files, and I can include them with #include "FooObject.h"
and get no errors.
In all the last 3 cases there are no errors but it's not clear how to generate the implementation code for the CoClasses in FooObject.idl
, like would appear if I went "Add New Item" and chose an ATL Simple Object to add. So I'm not sure how to get from here to the point where I can start writing code for the bodies of the functions in the objects I'm trying to create.
(My previous experience was with using a non-Microsoft vendor whose editor just let you add any CoClass from the registry and it'd generate the skeleton code).
ATL is great, but you should avoid creating project with the ATL wizards. That wizard hasn't been updated in Visual Studio since the 90's. It's easy to set a DLL com server with ATL in a blank project.
Start with an empty Win32 DLL project in Visual Studio. (Use the "Desktop Wizard Project")
Add a new source file, "MyFooObject.cpp" as follows. This is a minimal COM DLL project.
#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
struct DECLSPEC_UUID("DEADBEEF-FFFF-EEEE-DDDD-CCCCBBBBAAAA") IFooObject: public IUnknown
{
virtual HRESULT __stdcall DoSomething() = 0;
};
class MyModule : public CAtlDllModuleT<MyModule>
{
};
class DECLSPEC_UUID("ABBADABA-1111-2222-3333-444455556666") MyFooObject :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<MyFooObject>,
public IFooObject
{
public:
DECLARE_NO_REGISTRY();
BEGIN_COM_MAP(MyFooObject)
COM_INTERFACE_ENTRY(IFooObject)
END_COM_MAP()
// IFooObject
HRESULT __stdcall DoSomething() override;
};
HRESULT MyFooObject::DoSomething()
{
MessageBoxA(NULL, "Something just happened", "COM sample", MB_OK);
return S_OK;
}
OBJECT_ENTRY_AUTO(__uuidof(MyComClass), MyComClass);
Here's how you modify your steps to make use of the above:
Run MIDL on the IDL file your previous extracted. This should create a header file with the interface declaration as a C++ class. For a COM DLL project, you can ignore the proxy/stub code generated. You just want the header file that MIDL generated: FooObject.h
that has the class declarations of your interface
Copy FooObject.h to your source code directory. Add #include "FooObject.h" to the list of includes after
#include <atlcom.h>` above.
Remove the declaration of IFooObject that I've already provided since it's now declared in FooObject.h
Remove "DoSomething" from the declaration MyFooObject and replace with the public methods declared by IFooObject. Do not attempt to implement AddRef, Release, or QueryInterface.
Replace the definition of MyFooObject::DoSomething() with methods you declared in step 4.
Build your project.
You have to do the COM registry stuff yourself.