无法访问服务应用程序中的 COM 对象

COM-object in service application cannot be accessed

我正在开发一个带有 COM 对象的服务应用程序(OPC 数据访问 2.05 服务器)。我有这个注册我的对象的代码,它在安装后执行:

procedure TOPCService.ServiceAfterInstall(Sender: TService);
var
  lcHResult:     HRESULT;
  lcCLSIDString: String;
begin
  ComServer.UpdateRegistry(True);

  lcCLSIDString:=GUIDToString(CLASS_TestOPCServerDA2);

  ComObj.CreateRegKey('AppID\'+lcCLSIDString,                             '',      'Test OPC Server DA2');
  ComObj.CreateRegKey('AppID\'+Application.ExeName,                       'AppId', lcCLSIDString);
  ComObj.CreateRegKey('CLSID\'+lcCLSIDString+'\VersionIndependentProgID', '',      C_TEST_OPC_DA2_SERVER_NAME);

  <opc server registration stuff>

  RegisterAsService(lcCLSIDString, Name);
end;

服务和 COM 对象已在系统中正确注册,因此我可以在 OLE/COM 对象查看器(以及 OPC 客户端)中的 SCM 和 COM 对象中看到我的服务。 COM 对象本身如下所示:

type
  TTestOPCServerDA2 = class(TAutoObject, ITestOPCServerDA2, IConnectionPointContainer, IOPCServer, IOPCCommon, IOPCItemProperties, IOPCBrowseServerAddressSpace)

其工厂注册码:

initialization
  TAutoObjectFactory.Create(ComServer, TTestOPCServerDA2, Class_TestOPCServerDA2, ciMultiInstance, tmApartment);

问题是当我尝试 CoCreateInstance(CLASS_TestOPCServerDA2)(通过 CreateComObject 包装器)时,我冻结了 120 秒,之后出现 0x80080005 (CO_E_SERVER_EXEC_FAILURE) 错误。在 SCM 和任务管理器中,我看到我的服务在请求 COM 对象时启动,但没有其他任何反应。如果我停止服务并再次尝试,服务将再次启动,所以我假设 Windows 知道我的 COM 对象、它的可执行文件以及可执行文件是一项服务的事实。 我还尝试更改我的服务在 运行 下的用户(与调用应用程序相同),但这没有帮助。 我错过了什么?

编辑 1. 我创建了新项目并摆脱了 OPC(仅保留 COM 支持)以隔离问题,所以现在我的 class 看起来像这样:

type
  TTestCOMServer = class(TAutoObject, ITestCOMServer)
  end;
...
initialization
  TAutoObjectFactory.Create(ComServer, TTestCOMServer, Class_TestCOMServer, ciMultiInstance, tmApartment);

和服务线程:

procedure TCOMService.ServiceExecute(Sender: TService);
begin
  while (not Terminated) do
  begin
    ReportStatus;
    ServiceThread.ProcessRequests(False);

    Sleep(25);
  end;

问题仍然存在:当我尝试 CoCreateInstance 时,没有任何反应并且调用应用程序挂起 120 秒。 但是! 如果我进行 1 处更改:取消注释 Application.DelayInitialize := True; 在 dpr 中,COM 对象创建良好并调用应用程序不再冻结!是服务执行线程(不是服务主线程)处理 COM 请求吗?

编辑2. 看来只需要DelayInititalization。可以使用 False 参数调用 ProcessRequests 并且睡眠可以占有一席之地 - 我一定没有正确重建我的项目。 所以,我认为我的问题的答案是在 DPR 文件中取消注释 Application.DelayInitialize := True; 。 Delphi 自动生成相关文本,但它仅提及 Windows 2003 服务器条件,而我的 OS 是 Windows 10.

就我而言(Delphi XE3 在 Windows 10 Pro 下)我不得不取消注释

Application.DelayInitialize := True;

在民主共和国。此更改后,正确创建 COM 对象。