如何加载COM DLL模块并将其接口公开为进程外服务器

时间:2012-07-06 10:05:37

标签: com windows-services atl

我有一个基于ATL服务VC ++ 2010模板的进程外服务器。现在我不会通过动态加载包含其自己的COM类的其他dll来扩展其COM接口。 要加载的DLL基于ATL DLL VC ++ 2010模板,包含一个简单的ATL对象“IMModule”。我更改了相应的.rgs文件,通过添加LocalServer部分和服务器的AppID,将类从dll连接到EXE服务器,如下所示:

HKCR
{
  NoRemove CLSID
  {
    ForceRemove {59276614-A811-4D27-B131-514656E643D3} = s 'IMModule Class'
    {
      ForceRemove Programmable
      LocalServer32 = s 'path to the service exe'
      {
    val ServerExecutable = s 'path to the service exe'
      }
      TypeLib = s '{250685C7-CBD3-4FF8-A3A6-2AF668794CFC}'
      Version = s '1.0'
      val AppID = s '{7EFD508A-53C6-4EA0-B21A-D29277B86CBC}'
    }
  }
}

在加载dll后服务调用的dll init()方法中,我调用CoRegisterClassObject来注册IMModule类对象。但我不知道如何获取IUnknown接口指针(CoRegisterClassObject的第二个参数)。我尝试了以下方法:

CIMModule::_ClassFactoryCreatorClass* pClassFak = 
    new CIMModule::_ClassFactoryCreatorClass;
IUnknown* pUnk;
HRESULT hr =
pClassFak->CreateInstance(CIMModule::_ClassFactoryCreatorClass::CreateInstance, 
                            IID_IIMModule, (LPVOID*)&pUnk);

但是对CreateInstance的调用因E_NOINTERFACE而失败。 那么,如何注册我在一个dll中实现的IMModule类,以便从我的进程外服务器可用于COM客户端?

2 个答案:

答案 0 :(得分:1)

在Roman.R的帮助下,我得到了我需要的行为。我不能说谢谢你,@ roman-r。我会准确地描述我的所作所为,所以也许有人可以回溯这些步骤并给我一些回应。

首先,我创建了一个基于ATL的Windows服务(名为UmbrellaService)。在UmbrellaService中,我添加了一个名为Control的简单ATL对象,并添加了方法:

 FindMeAnInterface(BSTR moduleName, IDispatch** ppDispach);

使用VC ++向导完成所有操作。然后我通过添加:

修复了Control.rgs文件
 val AppID = s '%APPID%'

为什么VC ++在经历了17年的演变之后仍然存在这样的错误? (看到 CoCreateInstance does not start or connect to ATL COM service) 然后我创建了一个名为MyModule的ATL-dll项目,带有一个“模块” 简单的ATL-Object里面。 Module类有一个方法

testMethod (LONG a, LONG b, LONG* sum)"

MyModule dll已注册为进程内服务器。此外,DLL有一些类 这使得dll成为我需要的插件。

在UmbrellaService的PreMessageLoop方法中,MyModule dll将加载LoadLibrary,并通过GetProcAddress获取工厂创建方法的地址。工厂创建方法返回一个依赖于插件的FactoryClass,它充当插件入口点。这是我独立于COM的插件机制。

现在通过UmbrellaService接口从插件dll导出模块接口,我做了以下操作:在FactoryClass上添加方法:

IDispatch* getInterface();

在getInterface方法中,我调用

CoCreateInstance(__uuidof(Module), NULL , CLSCTX_INPROC_SERVER , __uuidof(IDispatch), (VOID**) &pDispatch); 

并返回获得的IDispatch接口。在将传递给FindMeAnInterface的名称与FactoryClass提供的名称进行比较之后,在UmbrellaService的Control :: FindMeAnInterface方法内调用FactoryClass :: getInterface方法。 FindMeAnInterface将当时获得的IDispatch指针返回给客户端。

在客户端,我从UmbrellaService导入tlb文件,从适当的插件dll导入tlb。我按如下方式调用testMethod:

IControlPtr pControl(__uuidof(Control));
_bstr_t moduleName("Module");
IDispatchPtr moduleDisp = pControl->FindMeAnInterface(moduleName);
IModulePtr pModule(moduleDisp );
LONG res = pModule->testMethod(42,23);

这一切确实有效,但我不确定这是否可行。我错过了引用计数吗?插件DLL会被加载两次吗?第一次通过我的插件机制,第二次通过CoCreateInstance?还有什么我应该注意的吗?

感谢您的帮助!

答案 1 :(得分:0)

到目前为止我找不到我的代码。但我确实检查了一个我最喜欢的网站,即代码项目。它曾经很受欢迎,特别是像COM这样的旧技术(是的,它是)。我希望你已经确信你必须使用COM而不是新的WFC或其他技术。

请检查好的文档和示例代码@ ATL COM EXE doc。我相信我使用这个网页作为我过去项目的开始。

祝你好运,玩得开心。