这是核心问题:我有一个在单独的AppDomain中使用COM互操作的.NET应用程序.COM的东西似乎是将程序集加载回默认域,而不是从中调用COM内容的AppDomain.
我想知道的是:这是预期的行为,还是我做错了导致这些COM相关程序集被加载到错误的AppDomain中?请参阅以下情况的更详细说明......
该应用程序由3个程序集组成: - 主EXE,应用程序的入口点. - common.dll,只包含一个接口IController(采用IPlugin风格) - controller.dll,包含一个实现IController和MarshalByRefObject的Controller类.此类完成所有工作并使用COM interop与另一个应用程序进行交互.
主要EXE的相关部分如下所示:
AppDomain controller_domain = AppDomain.CreateDomain("Controller Domain");
IController c = (IController)controller_domain.CreateInstanceFromAndUnwrap("controller.dll", "MyNamespace.Controller");
result = c.Run();
AppDomain.Unload(controller_domain);
Run Code Online (Sandbox Code Playgroud)
common.dll只包含以下两件事:
public enum ControllerRunResult{FatalError, Finished, NonFatalError, NotRun}
public interface IController
{
ControllerRunResult Run();
}
Run Code Online (Sandbox Code Playgroud)
controller.dll包含这个类(也调用COM互操作的东西):
public class Controller: IController, MarshalByRefObject
Run Code Online (Sandbox Code Playgroud)
首次运行应用程序时,Assembly.GetAssemblies()看起来像预期的那样,在两个AppDomain中都加载了common.dll,并且只将controller.dll加载到控制器域中.在调用c.Run()之后,我看到与COM互操作内容相关的程序集已加载到默认的AppDomain中,而不是在发生COM互操作的AppDomain中.
为什么会发生这种情况?
如果你有兴趣,这里有一些背景知识:
最初这是一个AppDomain应用程序.它与之接口的COM东西是一个服务器API,它在长时间使用时不稳定.当COM东西发生COMException(没有关于其原因的有用诊断信息)时,整个应用程序必须重新启动才能再次使用COM连接.只需重新连接到COM应用服务器,就会再次导致COM异常.为了解决这个问题,我试图将COM互操作内容移动到一个单独的AppDomain中,这样当神秘的COMExceptions出现时,我可以卸载发生它的AppDomain,创建一个新的并再次启动,所有这些都无需手动重启应用程序.无论如何,这就是理论......
我有一个COM类在一个应用程序中CMyCOMServer实现IMyInterface,两个都具有正确的GUID.CMyCOMServer::QueryInterface如果请求IUnknown或IMyInterface,则返回S_OK(并将其自身转换为正确的类型),否则返回E_NOINTERFACE.
在同一台PC上的另一个应用程序中,我打电话给:
HRESULT hr = ::CoCreateInstance(__uuidof(CMyCOMServer), 0, CLSCTX_SERVER,
__uuidof(IMyInterface ),(void **)&pInterface);
Run Code Online (Sandbox Code Playgroud)
它返回E_NOINTERFACE.所以我认为我做错了什么并添加了一个断点CMyCOMServer::QueryInterface.我发现在CoCreateInstance调用时,QueryInterface会针对不同的接口多次触发:
(IMyInterface *)this预期设置为接口指针所以我的困惑是为什么调用CoCreateInstance给我留下一个NULL指针并返回E_NOINTERFACE代码,当COM服务器应用程序显然返回我要求的接口?
编辑:我的客户端应用程序在启动时调用CoInitialize(NULL),这没有任何区别.
一个客户想要从VB6使用我们的.NET DLL.它们旨在支持反向互操作,所有工作都很好......除了:在两个不同的目录中有两个单独的VB6程序.似乎有必要做一个:
这是客户的观察,也得到了RegAsm文档的支持:
使用Regasm.exe注册程序集后,可以将其安装在全局程序集缓存中,以便可以从任何COM客户端激活它.如果程序集仅由单个应用程序激活,则可以将其放在该应用程序的目录中.
我对这一点感到困惑.
第一点困惑:
据我所知,COM运行时使用Prog ID/Class ID定位DLL.当我在类ID条目的注册表中查看时,我在CodeBase键中看到了.NET DLL的完整路径.为什么使用Prog ID/Class ID的COM程序无法使用CodeBase找到.NET DLL?
第二点困惑:
GAC特定于.NET.它如何参与解析COM引用?
我期待通过使用插件架构扩展现有的应用程序.应用程序ID是用Delphi编写的,但我希望能够以最好的工作方式实现各种语言的各种插件.目前我们拥有Delphi,C#和Java技能,并且希望能够以所需的任何语言实现插件.
有谁知道可以用来实现这个的示例系统?
我假设我可以在特定的COM接口上进行标准化,并且实现该接口的任何东西都可以是插件.
有没有人有任何指针?
谢谢
这是我之前的问题的后续内容,但您不需要阅读它来理解那个问题.
我正在设计.NET中的接口,它将从COM应用程序(主要是VB6,但Visual C++ 6也是一种可能性)中使用,我想使用Collection类型作为接口中方法的参数和返回类型.
问题:
当VB6内置集合类型(数组,集合,字典)通过互操作时会发生什么?我目前的猜测是:
System.ArrayMicrosoft.VisualBasic.CollectionSystem.Collections.Hashtable那是对的吗?
IEnumerable,ICollection,IList,IDictionary?我是否能够在VB6中执行For Each迭代这些接口?我应该使用接口的通用或非通用变体吗?我试图用一个新的.net来模仿一个旧的vb6 dll.模仿必须是完美的,以便呼叫者不知道他们正在使用新的.dll.
我有一种好奇心.在VB6中,它在对象库中具有以下内容:
Property BankList(Index As Long) As String
Run Code Online (Sandbox Code Playgroud)
但AFAIK属性这不能在.net中完成吗?
我能得到的最接近的是创建一个展示该行为的函数,然后COM类型从Property转到Method.
任何人都可以建议我如何使用属性创建该签名?
我想在我的.Net4.0 dll中加载一个.NET 2.0 dll.我确实搜索了解决方案并找到了'useLegacyV2RuntimeActivationPolicy'属性,我可以将其添加到我的app.config中,如此URL:混合模式程序集是针对版本'v1.1.4322'构建的
但问题是,在我的情况下,我试图在我的4.0 DLL中使用.net2.0 dll,而不是在4.0 exe中.原因是这个4.0 dll然后在Excel中用作自动化插件.
目前,当我从Excel处理我的.NET 4.0 API(为一个功能加载2.0 dll)时,我得到'混合模式2.0 dll无法在4.0运行时加载',这是可以理解的,因为COM加载了4.0 CLR,因此无法加载2.0 dll.
不知何故,我需要使我的4.0 DLL加载2.0运行时.我尝试将app.config添加到4.0 dll但我猜只有.exe默认读取app.config才能加载clr.这是我在4.0 dll项目中的app.config中所拥有的,但没有用.
<?xml version="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<runtime>
<NetFx40_LegacySecurityPolicy enabled="true"/>
</runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)
如何解决此问题以使我的.NET 4.0 DLL能够使用.NET 2.0 DLL?
谢谢,玛尼
我正在.NET中创建一个包装类(VB.NET,因为它发生但与C#同样相关),它暴露给COM,我试图包装的一个属性是Variant.我以为我只能使用一个Object,但是我收到一个错误:
Public Property FieldValue([vFieldID As Object = -1]) As Object不能作为属性'让'暴露给COM.您将无法使用"Let"语句从Visual Basic 6.0为此属性分配非对象值(如数字或字符串).*
我的财产声明如下:
Public Property FieldValue(Optional ByVal vFieldID As Object = -1) As Object
Get
Return _objVAccess.FieldValue(vFieldID)
End Get
Set(ByVal value As Object)
_objVAccess.FieldValue = value
End Set
End Property
Run Code Online (Sandbox Code Playgroud)
我的属性实际上从数据库返回一个值,可以是整数,字符串,日期等,因此它不是 COM方面的对象.是否有任何解决方法允许属性让?
在Windows API Code Pack for .NET Framework中,COM Interop接口的许多方法都使用MethodImplAttribute例如:
internal interface IShellItem
{
[PreserveSig]
[MethodImpl(
MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
HResult BindToHandler(
[In] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid,
[Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);
Run Code Online (Sandbox Code Playgroud)
MethodImplOptions.InternalCall价值文件说:
调用是内部的,也就是说,它调用在公共语言运行库中实现的方法.
指定方法实现由运行时提供.
但是,如果我理解正确,这两种说法都是正确的.据MSDN称,它IShellItem是在shell32.dll中实现的.shell32.dll不是CLR的一部分.有趣的是,并非所有方法都有MethodImplAttribute.IShellFolder是,IShellLinkW不,IShellLibrary做,IPersistStream不等.
为什么MethodImplAttribute应用于某些COM Interop接口?在这种情况下它意味着什么?它如何修改互操作的行为?
当Visual Studio未作为管理员启动时,此代码在版本r调试中运行没有问题.
Marshal.GetActiveObject("Outlook.Application");
Run Code Online (Sandbox Code Playgroud)
但是,当我以管理员身份启动Vs并在调试中运行相同的行时,我收到以下错误:
System.Runtime.InteropServices.COMException
Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
Run Code Online (Sandbox Code Playgroud)
我怎样才能解决这个问题.