无法从自定义域解包 COM 实例
Impossible to unwrap COM instance from custom domain
我正在尝试从自定义域在 COM 组件内部进行调用。
问题是当我尝试打开我的 ObjectHandle 时抛出序列化异常。
但是如果我使用当前的 AppDomain 创建实例,它就可以工作....
异常信息:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in ConsoleApp1.exe
Additional information: Type 'MyAddin.Main' in assembly 'MyAddin, Version=2019.0.1.5, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
还有我的代码:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string addinPath = "C:\sources\MyAddin\bin\x64\Debug\MyAddin.dll";
string addinFolder = "C:\sources\MyAddin\bin\x64\Debug\";
string addinConfigPath = "C:\sources\MyAddin\bin\x64\Debug\MyAddin.dll.config";
System.AppDomainSetup setup = new System.AppDomainSetup();
setup.ApplicationBase = addinFolder;
setup.ConfigurationFile = addinConfigPath;
setup.ApplicationName = "MyAddin.dll";
string strClsid = "{2616ad89-f4d1-4dc7-9d9d-a5de101b9085}"; // CLSID of my COM addin
System.AppDomain customDomain = System.AppDomain.CreateDomain(strClsid, null, setup);
// The type of domain is System.Runtime.Remoting.Proxies.__TransparentProxy}
// The type of custom domain is
System.Type addinComType = System.Type.GetTypeFromCLSID(System.Guid.Parse(strClsid));
System.Runtime.Remoting.ObjectHandle addinInstanceObjectHandle = customDomain.CreateComInstanceFrom(addinPath, addinComType.FullName);
System.Object addinInstance = addinInstanceObjectHandle.Unwrap(); //Throw the Serialization exception when create COM instance from customDomain
// But working if I did System.AppDomain.CurrentDomain.CreateComInstanceFrom
System.Reflection.MethodBase myMethod = addinInstance.GetType().GetMethod("connectToEwAPI");
System.Object[] parameters = { null };
myMethod.Invoke(addinInstance, parameters);
}
}
}
所以我做了一些蠢事?
你知道我错过了什么吗?
在此先感谢您的帮助
编辑
我试过更基本的汇编。
所以我有一个只有这段代码的 C# 程序集
namespace ClassLibrary2
{
public class Class1
{
public Class1()
{
}
public string MyMethod() => "OK";
}
}
而我的exe代码就是
static void Main(string[] args)
{
string basePath = @"C:\source\MyAddin\ConsoleApp1\ClassLibrary2\bin\Debug";
string dllName = @"ClassLibrary2";
string typeName = "ClassLibrary2.Class1";
string dllFullpath = $"{basePath}\{dllName}.dll";
try
{
ObjectHandle objectHandle = AppDomain.CurrentDomain.CreateInstanceFrom(dllFullpath, typeName);
Object addinObject = objectHandle.Unwrap();
var myAddinMethod = addinObject.GetType().GetMethod("MyMethod");
string result = myAddinMethod.Invoke(addinObject, null) as string; // Working
AppDomainSetup setup = new AppDomainSetup()
{
ApplicationBase = basePath,
ApplicationName = dllName,
ConfigurationFile = dllName + ".dll.config",
PrivateBinPath = basePath
};
AppDomain customDomain = AppDomain.CreateDomain("MyDomain", null, setup);
ObjectHandle objectHandleFromCustomDomain = customDomain.CreateInstanceFrom(dllFullpath, typeName);
Object addinObjectFromCustomDomain = objectHandleFromCustomDomain.Unwrap(); // Exception thrown
var myAddinMethodFromCustomDomain = addinObjectFromCustomDomain.GetType().GetMethod("MyMethod");
string resultFromCustomDomain = myAddinMethodFromCustomDomain.Invoke(myAddinMethodFromCustomDomain, null) as string;
}
catch(Exception e)
{
var t = e.Message; // Exception thrown: 'System.Runtime.Serialization.SerializationException' by objectHandleFromCustomDomain.Unwrap()
}
}
如您所见,它适用于默认域,但不适用于自定义域....
你有什么想法吗?
如果你想跨 AppDomain
边界访问一个对象,你需要做以下两件事之一:
制作 class Serializable
,例如通过添加 [Serializable]
属性。在这种情况下,对象的副本被序列化并跨越 AppDomain
边界传递。您调用的任何成员都将在副本上,不会影响原始对象。
使 class 派生自 MarshalByRefObject。在这种情况下,对该对象的引用会跨 AppDomain 边界进行编组,您调用的任何成员都会影响其原始 AppDomain 中的对象。
我正在尝试从自定义域在 COM 组件内部进行调用。 问题是当我尝试打开我的 ObjectHandle 时抛出序列化异常。
但是如果我使用当前的 AppDomain 创建实例,它就可以工作....
异常信息:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in ConsoleApp1.exe
Additional information: Type 'MyAddin.Main' in assembly 'MyAddin, Version=2019.0.1.5, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
还有我的代码:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string addinPath = "C:\sources\MyAddin\bin\x64\Debug\MyAddin.dll";
string addinFolder = "C:\sources\MyAddin\bin\x64\Debug\";
string addinConfigPath = "C:\sources\MyAddin\bin\x64\Debug\MyAddin.dll.config";
System.AppDomainSetup setup = new System.AppDomainSetup();
setup.ApplicationBase = addinFolder;
setup.ConfigurationFile = addinConfigPath;
setup.ApplicationName = "MyAddin.dll";
string strClsid = "{2616ad89-f4d1-4dc7-9d9d-a5de101b9085}"; // CLSID of my COM addin
System.AppDomain customDomain = System.AppDomain.CreateDomain(strClsid, null, setup);
// The type of domain is System.Runtime.Remoting.Proxies.__TransparentProxy}
// The type of custom domain is
System.Type addinComType = System.Type.GetTypeFromCLSID(System.Guid.Parse(strClsid));
System.Runtime.Remoting.ObjectHandle addinInstanceObjectHandle = customDomain.CreateComInstanceFrom(addinPath, addinComType.FullName);
System.Object addinInstance = addinInstanceObjectHandle.Unwrap(); //Throw the Serialization exception when create COM instance from customDomain
// But working if I did System.AppDomain.CurrentDomain.CreateComInstanceFrom
System.Reflection.MethodBase myMethod = addinInstance.GetType().GetMethod("connectToEwAPI");
System.Object[] parameters = { null };
myMethod.Invoke(addinInstance, parameters);
}
}
}
所以我做了一些蠢事? 你知道我错过了什么吗?
在此先感谢您的帮助
编辑
我试过更基本的汇编。 所以我有一个只有这段代码的 C# 程序集
namespace ClassLibrary2
{
public class Class1
{
public Class1()
{
}
public string MyMethod() => "OK";
}
}
而我的exe代码就是
static void Main(string[] args)
{
string basePath = @"C:\source\MyAddin\ConsoleApp1\ClassLibrary2\bin\Debug";
string dllName = @"ClassLibrary2";
string typeName = "ClassLibrary2.Class1";
string dllFullpath = $"{basePath}\{dllName}.dll";
try
{
ObjectHandle objectHandle = AppDomain.CurrentDomain.CreateInstanceFrom(dllFullpath, typeName);
Object addinObject = objectHandle.Unwrap();
var myAddinMethod = addinObject.GetType().GetMethod("MyMethod");
string result = myAddinMethod.Invoke(addinObject, null) as string; // Working
AppDomainSetup setup = new AppDomainSetup()
{
ApplicationBase = basePath,
ApplicationName = dllName,
ConfigurationFile = dllName + ".dll.config",
PrivateBinPath = basePath
};
AppDomain customDomain = AppDomain.CreateDomain("MyDomain", null, setup);
ObjectHandle objectHandleFromCustomDomain = customDomain.CreateInstanceFrom(dllFullpath, typeName);
Object addinObjectFromCustomDomain = objectHandleFromCustomDomain.Unwrap(); // Exception thrown
var myAddinMethodFromCustomDomain = addinObjectFromCustomDomain.GetType().GetMethod("MyMethod");
string resultFromCustomDomain = myAddinMethodFromCustomDomain.Invoke(myAddinMethodFromCustomDomain, null) as string;
}
catch(Exception e)
{
var t = e.Message; // Exception thrown: 'System.Runtime.Serialization.SerializationException' by objectHandleFromCustomDomain.Unwrap()
}
}
如您所见,它适用于默认域,但不适用于自定义域....
你有什么想法吗?
如果你想跨 AppDomain
边界访问一个对象,你需要做以下两件事之一:
制作 class
Serializable
,例如通过添加[Serializable]
属性。在这种情况下,对象的副本被序列化并跨越AppDomain
边界传递。您调用的任何成员都将在副本上,不会影响原始对象。使 class 派生自 MarshalByRefObject。在这种情况下,对该对象的引用会跨 AppDomain 边界进行编组,您调用的任何成员都会影响其原始 AppDomain 中的对象。