C# COM客户端通过Windows服务无法访问C++ COM服务器 我有一个C类和方法,我已经蒸馏了,除了分配COM对象和执行对一个进程外的C++ COM服务器的调用之外,什么也不做。p> eFilm.IEFilm eFilmInterface = (eFilm.IEFilm)Activator.CreateInstance(Type.GetTypeFromProgID("EFilm.Document", true)); eFilmInterface.oleCloseAllWindows();

C# COM客户端通过Windows服务无法访问C++ COM服务器 我有一个C类和方法,我已经蒸馏了,除了分配COM对象和执行对一个进程外的C++ COM服务器的调用之外,什么也不做。p> eFilm.IEFilm eFilmInterface = (eFilm.IEFilm)Activator.CreateInstance(Type.GetTypeFromProgID("EFilm.Document", true)); eFilmInterface.oleCloseAllWindows();,c#,.net,visual-studio-2012,windows-7,com,C#,.net,Visual Studio 2012,Windows 7,Com,当我以登录用户身份在命令行上执行此代码时,将生成权限不足错误。如果我提升它或运行一个提升的外壳,它工作正常。它试图访问的COM服务器是我在登录到用户后启动的独立应用程序 相反,我尝试在Windows服务中执行相同的操作。该服务是VS2012 C windows服务模板的基本实现,我将其标记为.Net 4.0,任何CPU或x86都会出现相同的故障。在服务的OnStart实现过程中,我尝试在STA线程中进行上述调用,尽管它在OnStart方法本身中出现了相同的问题: protected overri

当我以登录用户身份在命令行上执行此代码时,将生成权限不足错误。如果我提升它或运行一个提升的外壳,它工作正常。它试图访问的COM服务器是我在登录到用户后启动的独立应用程序

相反,我尝试在Windows服务中执行相同的操作。该服务是VS2012 C windows服务模板的基本实现,我将其标记为.Net 4.0,任何CPU或x86都会出现相同的故障。在服务的OnStart实现过程中,我尝试在STA线程中进行上述调用,尽管它在OnStart方法本身中出现了相同的问题:

protected override void OnStart(string[] args)
{
    var staThread = new Thread(this.OnStartSTA);
    staThread.SetApartmentState(ApartmentState.STA);
    staThread.Start();
}

private void OnStartSTA(object threadState)
{
    eFilm.IEFilm eFilmInterface = (eFilm.IEFilm)Activator.CreateInstance(Type.GetTypeFromProgID("EFilm.Document", true));
    eFilmInterface.oleCloseAllWindows();
}
CreateInstance调用失败,但出现以下异常:

System.Runtime.InteropServices.COMException (0x80080005): Retrieving the COM class factory for component with CLSID {C8CF03E4-FD1F-11D3-8C03-0080C8D3C5D3} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
我尝试过在活动会话中从同一用户更改服务帐户,一直到本地系统。我也犯了同样的错误。我已让服务验证CLSID是否存在于其注册表视图中。我在服务器的日志中没有发现任何错误,尽管我没有代码或调试符号。windows应用程序日志可能显示完全相同的错误,因为它通过链式抛出一直传递出去。我尝试将GetTypeFromProgID切换到远程版本并引用localhost,但它会生成相同的错误

此外,如果我获取应用程序的命令行版本,并通过生成服务包装器,则会得到完全相同的错误

我不确定出了什么问题,也没有很好的计划来继续调试。我所能想到的只是用户上下文的一些问题,但这似乎是COM应该能够做到的。另一个选项是服务器注册中缺少一些密钥信息。在这个过程中

编辑:

经过进一步调查,对COM服务器的调用似乎导致尝试在服务运行的任何用户上下文(而不是活动用户上下文)中启动该服务器的新副本。我试着模仿那个用户,但没有改变任何事情。如果我使用用户凭据运行服务,您只会在任务管理器和流程资源管理器中看到为同一用户运行的应用程序的两个副本。我怀疑这与服务器的构建或配置方式有关

有一件事我觉得很有趣,即使我启动服务时使用本地系统模拟COM调用作为活动用户,COM服务器也会作为系统而不是用户启动

编辑2:

浏览COM/DCOM设置时,DCOM应用程序ID中似乎有一个。我的服务器从未注册过AppID节


我已经在AppID部分手动入侵了AppID和CLSID,但似乎没有修复它。它仍然会在服务的上下文中生成流程,尽管流程的大小不会增长到正常情况下的完整大小。

好的,所以答案似乎是正确的。因为我没有这个服务器的AppID,所以我必须生成一个。我需要采取以下步骤来解决此问题:

为AppID生成新的GUID。启动开发人员提示符并键入guidgen.exe。这将打开一个对话框。选择注册表格式选项并将此GUID复制到某个位置。 打开一个文本编辑器,创建一个.reg文件导入注册表。您将需要如下所示的行。将新的GUID替换为1中的GUID,将服务器的CLSID替换为服务器的ProgID中的CLSID

Windows注册表编辑器5.00版

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{YOUR_NEW_GUID}] RunAs=交互式用户

[HKEY\U LOCAL\U MACHINE\SOFTWARE\Classes\CLSID\{SERVER\U CLSID}] AppID={E33A55D3-6743-4F3B-AA90-BB07B9BA3836}

如果您的操作系统是64位的,而您的服务器是32位的应用程序,则通过\Windows\syswow64\regedit.exe file.reg将file.reg从步骤2更改为您的文件来执行32位的regedit。这将在不同的syswow64位置正确安装它们。否则只需使用regedit.exe file.reg

理论上,这应该可以做到。现在,您可以通过以管理员身份执行oleview.exe来确认是否发生了这种情况。如果您有相同的问题,您需要在创建AppID之前检查是否已经有注册到该服务器的AppID。如果是这样,您可能只需要使用oleview并在那里编辑它

在oleview.exe中,在对象类>所有对象下查找组件。选择此选项,然后在右侧的工作窗口中选择Implementation选项卡,您现在应该可以看到生成的新AppID GUID。在“激活”选项卡下,您应该看到已选中“作为交互式用户启动”