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

如何加载COM dll模块并将其接口公开为进程外服务器,com,windows-services,atl,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-51

我有一个基于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}'
    }
  }
}
IControlPtr pControl(__uuidof(Control));
_bstr_t moduleName("Module");
IDispatchPtr moduleDisp = pControl->FindMeAnInterface(moduleName);
IModulePtr pModule(moduleDisp );
LONG res = pModule->testMethod(42,23);
在加载dll后由服务调用的dll init()方法中,我调用CoreRegisterClassObject来注册IMModule类对象。但是我不知道如何获得IUnknown接口指针(CoRegisterClassObject的第二个参数)。我尝试了以下方法:

CIMModule::_ClassFactoryCreatorClass* pClassFak = 
    new CIMModule::_ClassFactoryCreatorClass;
IUnknown* pUnk;
HRESULT hr =
pClassFak->CreateInstance(CIMModule::_ClassFactoryCreatorClass::CreateInstance, 
                            IID_IIMModule, (LPVOID*)&pUnk);
但是调用CreateInstance失败,没有接口。
那么,如何注册在dll中实现的IMModule类,以便从进程外服务器向COM客户端提供?

我目前找不到我的代码。但我确实查看了我最喜欢的网站之一,代码项目。它曾经很受欢迎,尤其是像COM这样的老技术(是的,它是)。我希望您已经确信您必须使用COM而不是新的WFC或其他技术

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


祝你好运,玩得开心。

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

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

 FindMeAnInterface(BSTR moduleName, IDispatch** ppDispach);
这就是VC++向导的全部内容。然后,我通过添加以下内容修复了Control.rgs文件:

 val AppID = s '%APPID%'
为什么经过17年的发展,VC++仍然存在这样的漏洞?(见 ) 然后我创建了一个ATL dll项目,名为MyModule,带有一个“模块” 里面有一个简单的ATL对象。模块类有一个方法

testMethod (LONG a, LONG b, LONG* sum)"
MyModule dll已注册为进程内服务器。此外,dll还有一些类 这使得dll成为一个插件,因为我需要它

在雨伞服务的PreMessageLoop方法中,MyModule dll将使用LoadLibrary加载,并通过GetProcAddress获得工厂创建方法的地址。factory creation方法返回作为插件入口点的依赖于插件的FactoryClass。这是我的COM独立插件机制

现在要通过Umbrella服务接口从插件dll导出模块接口,我执行了以下操作:在FactoryClass上添加方法:

IDispatch* getInterface();
在getInterface方法中,我调用

CoCreateInstance(__uuidof(Module), NULL , CLSCTX_INPROC_SERVER , __uuidof(IDispatch), (VOID**) &pDispatch); 
并返回获得的IDispatch接口。将传递给FindMeAnInterface的名称与FactoryClass提供的名称进行比较后,将在雨伞服务的Control::FindMeAnInterface方法内调用FactoryClass::getInterface方法。FindMeAnInterface返回随后获得的指向客户端的IDispatch指针

在客户端,我从Umbrella服务导入tlb文件,并从适当的插件dll导入tlb。我调用testMethod如下:

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}'
    }
  }
}
IControlPtr pControl(__uuidof(Control));
_bstr_t moduleName("Module");
IDispatchPtr moduleDisp = pControl->FindMeAnInterface(moduleName);
IModulePtr pModule(moduleDisp );
LONG res = pModule->testMethod(42,23);
这一切确实有效,但我不确定这是否是一种方法。我是否错过了一些关于参考计数的内容?插件DLL会被加载两次吗?第一次是通过我的插件机制,第二次是通过CoCreateInstance?还有什么我应该注意的吗


谢谢你的帮助

您使用一组接口实现了一些COM类。是否希望此类通过动态加载的模块以某种方式实现其他接口?简短回答:否。长回答:COM服务器本身不会提供任何COM接口。服务器将加载向客户端提供COM接口的模块(实现为DLL)。IMModule类是此类模块DLL的一部分。启动时,服务器加载并初始化模块。据我所知,DLL必须在初始化期间在服务器的上下文中注册IMModule COM类。这就是调用CreateInstance失败的地方。如果服务器本身没有公开任何接口,则会重新加载模块并使用其接口。您不需要为此进行任何特殊注册,只需定期注册COM服务器的coclass和类型库。我更改了tite,希望它现在更清晰。您的主“伞”服务器应公开为进程外服务器,并且在其ineterface中将有一个方法
FindMeAnInterface(,IDispatch**ppDispatch)
伞形服务器将通过它返回模块的接口。模块将具有常规接口,它们只需要其可封送的接口(即使用typelibrary或代理/存根类),就可以在进程边界之外提供。