无法访问服务应用程序中的 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 对象。
我正在开发一个带有 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 对象。