我正在研究一个无需私有注册的WinSxS的配置,它简单地提供了程序集清单文件,以缝合Delphi可执行文件(COM客户端)和。NET(C#)COM可见DLL在部署和运行时一起使用。
我已经研究了MSDN上提供的文档
"Interoperating with Unmanaged Code"
,关于
"
COM Callable Wrapper
"
和
"
How to: Configure .NET Framework-Based COM Components for Registration-Free Activation
"
特别地。
经过一个多星期的研究,在文档不足的循环中(重新)指导,我决定把我的第一个问题放在这里。
计划的部署结构如下所示:
./install-root
ââââProgramSuite1
â ââââbin
â â DelphiNativeCOMClient1.exe
â â DelphiNativeCOMClient1.exe.config
â â DelphiNativeCOMClient2.exe
â â DelphiNativeCOMClient2.exe.config
â | ...
â â
â ââââdata
â ...
ââââProgramSuite2
â ââââbin
â â DelphiNativeCOMClient3.exe
â â DelphiNativeCOMClient3.exe.config
â â DelphiNativeCOMClient4.exe
â â DelphiNativeCOMClient4.exe.config
â | ...
â â
â ââââdata
â ...
ââââSharedLibs
ââââMyCompany.Libs.Set1
â MyCompany.Libs.Set1.manifest
â SomeManagedCOMServerA.dll
â SomeNativeCOMServerB.dll
â SomeNativeCOMServerC.dll
â
ââââMyCompany.Libs.Set2
MyCompany.Libs.Set2.manifest
SomeManagedCOMServerB.dll
SomeNativeCOMServerX.dll
SomeManagedCOMServerA.dll
下面是一个关于Delphi本机可执行文件和C#实现的简短草图。NET COM服务器DLL(我省略了本机COM服务器的示例,因为这些东西已经很好地工作了,而且是毫无疑问的)。
我主要遵循
"Registration-Free Activation of COM Components: A Walkthrough"
. 主要区别在于,我使用的是Delphi,而不是C、C++或旧的VB作为
出生地的
客户
TestDllConsoleApp.exe
TestDllConsoleApp.dpr
program TestDllConsoleApp;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
DllTests.Common,
WinApi.ActiveX,
WinApi.Windows,
// These were generated using the tlbimplib tool
CSharpCOMDll_TLB in 'CSharpCOMDll_TLB.pas',
mscorlib_TLB in 'mscorlib_TLB.pas';
var
comInterface1 : ICOMInterface1;
comInterface2 : ICOMInterface2;
intf1CoClass : _COMImplClass1;
intf2CoClass : _COMImplClass2;
res : HRESULT;
coInitializeRes : integer;
begin
//Initialize COM
coInitializeRes := CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
if (coInitializeRes <> S_OK) and (coInitializeRes <> S_FALSE) then begin
System.ExitCode := 1;
Exit(); // GUARD
end;
try
try
intf1CoClass := CoCOMImplClass1.Create();
res := intf1CoClass.QueryInterface(IID_ICOMInterface1,comInterface1);
System.WriteLn(comInterface1.GetModuleName());
intf2CoClass := CoCOMImplClass2.Create();
res := intf2CoClass.QueryInterface(IID_ICOMInterface2,comInterface2);
System.WriteLn(comInterface2.GetModuleName());
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
finally
//Uninitialize COM
CoUninitialize();
end;
end.
TestDllConsoleApp.manifest
(嵌入资源ID 1)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity name="MyCompany.Software.Application" processorArchitecture="x86" version="1.0.0.0" type="win32" />
<description>A native COM client application.</description>
<asmv3:trustInfo>
<asmv3:security>
<asmv3:requestedPrivileges>
<asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
</asmv3:requestedPrivileges>
</asmv3:security>
</asmv3:trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and Windows Server 2016 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
<!-- Windows 8.1 and Windows Server 2012 R2 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 8 and Windows Server 2012 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 7 and Windows Server 2008 R2 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows Vista and Windows Server 2008 -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
</application>
</compatibility>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="MyCompany.Libs.Set1" version="1.0.0.0" processorArchitecture="x86" />
</dependentAssembly>
</dependency>
</assembly>
TestDllConsoleApp.exe.config
(部署在与可执行文件相同的文件位置)
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="..\..\SharedLibs"/>
</assemblyBinding>
</runtime>
</configuration>
CSharpCOMDll.dll
(将部署在
SharedLibs\MyCompany.Libs.Set1
目录)
Assemblyinfo.cs
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
[assembly: AssemblyTitle ("CSharpCOMDll")]
[assembly: AssemblyProduct ("CSharpCOMDll")]
[assembly: AssemblyCopyright ("Copyright 2018")]
[assembly: ComVisible (true)]
[assembly: AssemblyVersion ("1.0.0.0")]
[assembly: Guid ("045d53ab-a9e4-4036-a21b-4fe0cf433065")]
COMImplClass1。反恐精英
// Using namespaces ...
namespace CSharpCOMDll
{
[Guid("6BDAF8DD-B0CF-4CBE-90F5-EA208D5A2BB0")]
public interface ICOMInterface1
{
string GetModuleName();
}
[Guid("4CD39F25-0EB9-4CD0-9B4C-6F5DB5C14805")]
public class COMImplClass1 : ICOMInterface1
{
public string GetModuleName()
{
return typeof(COMImplClass1).Module.FullyQualifiedName;
}
}
}
COMImplClass2。反恐精英
// Using namespaces ...
namespace CSharpCOMDll
{
[Guid("BE69E9C7-1B37-4CA8-A3C1-10BFA9230940")]
public interface ICOMInterface2
{
string GetModuleName();
}
[Guid("067E5980-0C46-49C7-A8F0-E830877FB29C")]
public class COMImplClass2 : ICOMInterface2
{
public string GetModuleName()
{
return typeof(COMImplClass1).Module.FullyQualifiedName;
}
}
}
CSharpCOMDll.manifest
(嵌入到资源ID为2的DLL中)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type="win32"
processorArchitecture="x86"
name="CSharpCOMDll"
version="1.0.0.0" />
<clrClass
clsid="{4CD39F25-0EB9-4CD0-9B4C-6F5DB5C14805}"
progid="CSharpCOMDll.COMImplClass1"
threadingModel="Both"
name="CSharpCOMDll.COMImplClass1"
runtimeVersion="v4.0.30319">
</clrClass>
<clrClass
clsid="{067E5980-0C46-49C7-A8F0-E830877FB29C}"
progid="CSharpCOMDll.COMImplClass2"
threadingModel="Both"
name="CSharpCOMDll.COMImplClass2"
runtimeVersion="v4.0.30319">
</clrClass>
</assembly>
最后是从
TestDllConsoleApp。显示
dependency
条目:
MyCompany.Libs.Set1.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="MyCompany.Libs.Set1" version="1.0.0.0" processorArchitecture="x86" />
<file name="CSharpCOMDll.dll">
<comClass
clsid="{4CD39F25-0EB9-4CD0-9B4C-6F5DB5C14805}"
threadingModel="Both"
/>
<comClass
clsid="{067E5980-0C46-49C7-A8F0-E830877FB29C}"
threadingModel="Both"
/>
<comInterfaceProxyStub
name="ICOMInterface1"
iid="{6BDAF8DD-B0CF-4CBE-90F5-EA208D5A2BB0}"
proxyStubClsid32="????"
/>
<comInterfaceProxyStub
name="ICOMInterface2"
iid="{BE69E9C7-1B37-4CA8-A3C1-10BFA9230940}"
proxyStubClsid32="????"
/>
</file>
</assembly>
看起来我已经成功了一半,但仍然无法诊断出实际问题。
目前有两种类型的故障(
请注意
,即在可执行文件旁边部署托管COM服务器DLL,而不是引用已解析的清单目录,可以正常工作,并且符合预期):
-
我完全删除
proxyStubClsid32
全局清单中的属性:
-
启动可执行文件会导致异常
EOleSysError: Error in dll, clsid = {4CD39F25-0EB9-4CD0-9B4C-6F5DB5C14805}
-
调试异常会导致
HRESULT
价值
Error in the DLL (Exception from HRESULT: 0x800401F9 (CO_E_ERRORINDLL))
-
我提供
proxyStubClsid32
全局清单中的属性:
-
我不确定该属性实际需要哪个GUID。
正如文档中所提到的,它自然似乎是一个对应的“co类ID”(
CLSID
)如中所述
comClass
元素
clsid
属性
-
或者,我尝试从生成的
,pas
在那里归档。
这两种变体都给我留下了一个非常无用的错误,可以通过
sxstrace
工具
1.
:
...
INFORMATION: Manifestdatei ".\install-root\SharedLibs\MyCompany.Libs.Set1\MyCompany.Libs.Set1.MANIFEST" wird analysiert.
INFORMATION: Die Manifestsdefinitionsidentität ist ",processorArchitecture="x86",type="win32",version="1.0.0.0"".
FEHLER: Bei der Generierung des Aktivierungskontextes ist ein Fehler aufgetreten.
Beendet die Generierung des Aktivierungskontextes.
请注意,没有任何简明的错误/信息消息,如
... cannot resolve assembly XY ...
在
激活上下文生成
搞砸了。有大量的参考文献表明了这种特殊的错误情况。
还有到处都提到失踪
Visual C++可再发行框架
在这里没有帮助。我是从德尔福打来的,那是不一样的。
-
再次尝试引用
CSharpCOMDll。动态链接库
显式地(可执行清单中的另一个依赖项),并将其放入
SharedLibs
已成功创建
激活上下文
,但失败时出现与以前略有不同的异常
EOleSysError: Cannot find file, clsid = {4CD39F25-0EB9-4CD0-9B4C-6F5DB5C14805}
这里有没有人知道如何直接做我想做的事情,或者可以另外做什么(除了
sxstrace公司
)更深入地诊断问题。
我几乎可以肯定,必须能够提供
部署
这样地。
TL;博士;
-
是否有可能提供如上所述的部署结构,并维护特定的。NET COM服务器DLL是否位于引用的可执行文件位置之外?
更新:
今天进一步研究,我意识到(尽管术语非常相似),解决
激活上下文
使用专用SxS并解析的位置。用于COM可调用包装器实例化的NET DLL是两种完全不同且独立的机制。我主要是从这两个和更多的
Jufeng Zhang's
精彩而深入的解释博客文章:
定位未注册用户的问题。NET程序集(托管COM服务器DLL)是,这只会发生在应用程序部署目录及其下。
使用任何方法,如指定
<codebase>
或
<probing>
配置中的元素
<runtime>
指向目录外部的节
.config
文件已部署,根本无法工作。
我使用Sysinternals Process Monitor和Fusion log viewer工具验证了
2.
.
我不会把它作为最后的答案,因为我会在下一步尝试如何欺骗它。NET机制来定位托管COM服务器DLL,使用程序集清单或本机DLL指定依赖项和
<探测(>);
/
<代码库(&G);
元素重定向定位机制。
作为最后手段(原文如此!)似乎甚至可以提供您自己的定制
appDomainManagerAssembly
和
appDomainManagerType
在应用程序配置中的
<运行时(>);
要素
更新II:
恐怕我们得去管理
AppDomain
我们从本机CLR主机使用CLR API。
需要进一步调查。我在这里找到了一个很有希望的资源:
"Customizing the Microsoft .NET Framework Common Language Runtime"
1)
请原谅德国错误信息。我手头没有英文版的编译器。但谷歌提供的翻译应该能很好地工作。
2)
因此,关于诊断问题的更好工具的问题,可以认为已经解决了。