[英]Cannot cast com object to Control
我正在嘗試在clr 2.0中調用clr 4.0 contorl,我有三個類。 我的問題是類2中的那一行c.Add(x)。
這行拋出錯誤
Unable to cast object of type 'System.__ComObject' to type 'System.Windows.Forms.Control'.
堆棧跟蹤
at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
at Net4ToNet2Adapter.IClassAdapter.LoadRyderControl(Int32 atacode, Int32 eventid, Control c)
at Net2Assembly.RyderQuestion..ctor() in C:\Users\casmith\Desktop\C#\Net2Assembly\RyderQuestion.cs:line 28
at Net2Assembly.Program.Main() in C:\Users\casmith\Desktop\C#\Net2Assembly\Program.cs:line 17
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
在我看來,它無法從對象訪問控件。
第1類:Net 2 CLR
namespace Net2Assembly
{
public partial class RyQuestion : Form
{
private IClassAdapter _ryderControl;
public RyQuestion()
{
InitializeComponent();
var classAdapterType = Type.GetTypeFromProgID("Net4ToNet2Adapter.MyClassAdapter");
var classAdapterInstance = Activator.CreateInstance(classAdapterType);
var myClassAdapter = (IClassAdapter)classAdapterInstance;
_ryControl = myClassAdapter;
myClassAdapter.LoadRyControl(17, 291457,this.Panel1);
}
public void LoadQuestionsTC()
{
_ryControl.LoadQuestionsTC();
}
public void LoadQuestionsCloseout()
{
_ryControl.LoadQuestionsCloseout();
}
}
}
第2類:我的CLR 4組件
namespace Net4Assembly
{
public class RyderControlWrapper
{
private WindowsFormsApplication3.RyCriticalPath _ryControl;
public void LoadRyControl(int atacode, int eventid,Control c)
{
WindowsFormsApplication3.RyderCriticalPath x = new WindowsFormsApplication3.RyCriticalPath(atacode, 2945784);
_ryControl = x;
c.Add(x); //Bad line :(
}
public void LoadQuestionsTC()
{
_ryControl.LoadQuestionsTC();
}
public void LoadQuestionsCloseout()
{
_ryControl.LoadQuestionsCloseout();
}
}
}
3類:網絡4到網絡2適配器
namespace Net4ToNet2Adapter
{
public class MyClassAdapter : IClassAdapter
{
private RyControlWrapper _rcWrapper = new RyControlWrapper();
public void LoadRyControl(int atacode, int eventid,Control c)
{
_rcWrapper.LoadRyControl(atacode, eventid,c);
}
public void LoadQuestionsTC()
{
_rcWrapper.LoadQuestionsTC();
}
public void LoadQuestionsCloseout()
{
_rcWrapper.LoadQuestionsCloseout();
}
}
}
namespace Net4ToNet2Adapter
{
[ComVisible(true)]
public interface IClassAdapter
{
void LoadRyderControl(int atacode, int eventid, Control c);
void LoadQuestionsTC();
void LoadQuestionsCloseout();
}
}
問題是您要混合兩種Control
類型,一種來自.NET 2,另一種來自.NET4。這根本無法完成。 您不能在兩個不同的CLR之間傳遞托管對象,就像它們是同一類型一樣,這就是為什么必須首先使用COM的原因。 托管Control
對象在ComObject中被“包裝”,但是無法將其轉換為新的Control
類型,這就是為什么看到此異常的原因。 (有可能把這個對象Control
,有一些沉重的代理,但它會帶來更多的問題,這將解決-但我稍后會研究這種可能性)
那么該怎么辦? 您可以將RyderCriticalPath
放入.NET 2程序集中,並使其實現放置在適配器程序IRyderCriticalPath
的接口IRyderCriticalPath
。 在.NET 2程序集中創建它的實例,並將其作為接口傳遞給LoadRyControl
。 不要通過Control
。 移動c.Add(x);
調用方法(.NET 2)。
當然,這就是我對您提供的代碼的處理方式,但要點是,您必須僅將托管對象作為接口傳遞,僅公開控制它所需的方法。
編輯:
如所承諾的,我已經探究了代理Control
對象的可能性。 是的,這是可能的,但並不完全。 只能代理“可移動”類型。 因此,除了可序列化類型之外,您無法訪問不可刪除類型的任何屬性。 因此,您仍應使用原始解決方案,因為這不適用於您的問題(但對其他人可能有用):
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Windows.Forms;
namespace Net4ToNet2Adapter
{
[ComVisible(true)]
[Guid("E36BBF07-591E-4959-97AE-D439CBA392FB")]
public interface IMyClassAdapter
{
void DoNet4Action( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ProxyMarshaler))] Control c);
}
[ComVisible(true)]
[Guid("9F973534-E089-4C22-A481-54403B97DED9")]
public interface IProxyProvider
{
Type Type{get;}
object Instance{get;}
object Invoke(string method, Type[] signature, object[] args);
}
public class ProxyMarshaler : ICustomMarshaler
{
private static readonly ProxyMarshaler instance = new ProxyMarshaler();
public static ICustomMarshaler GetInstance(string cookie)
{
return instance;
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
return Marshal.GetIUnknownForObject(new ProxyProvider(ManagedObj));
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
IProxyProvider prov = (IProxyProvider)Marshal.GetObjectForIUnknown(pNativeData);
return new ComProxy(prov).GetTransparentProxy();
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.Release(pNativeData);
}
public void CleanUpManagedData(object ManagedObj)
{
ComProxy proxy = (ComProxy)RemotingServices.GetRealProxy(ManagedObj);
proxy.Dispose();
}
public int GetNativeDataSize()
{
return -1;
}
private class ProxyProvider : IProxyProvider
{
public Type Type{get; private set;}
public object Instance{get; private set;}
public ProxyProvider(object instance)
{
Instance = instance;
Type = instance.GetType();
}
public object Invoke(string method, Type[] signature, object[] args)
{
MethodInfo mi = Type.GetMethod(method, signature);
if(mi == null || mi.IsStatic) throw new NotSupportedException();
DeproxyArgs(args);
object ret = mi.Invoke(Instance, args);
ProxyArgs(args);
return ProxyValue(ret);
}
public static bool IsProxyable(Type t)
{
return t.IsInterface || typeof(MarshalByRefObject).IsAssignableFrom(t) || t == typeof(object);
}
public static void DeproxyArgs(object[] args)
{
for(int i = 0; i < args.Length; i++)
{
args[i] = DeproxyValue(args[i]);
}
}
public static void ProxyArgs(object[] args)
{
for(int i = 0; i < args.Length; i++)
{
args[i] = ProxyValue(args[i]);
}
}
public static object DeproxyValue(object val)
{
var pp = val as IProxyProvider;
if(pp != null)
{
if(val is ProxyProvider) return pp.Instance;
else return ComProxy.GetProxy(pp);
}
return val;
}
public static object ProxyValue(object val)
{
ComProxy proxy = ComProxy.GetProxy(val);
if(proxy != null)
{
return proxy.Provider;
}else if(val != null && ProxyProvider.IsProxyable(val.GetType()))
{
return new ProxyProvider(val);
}
return val;
}
}
private sealed class ComProxy : RealProxy, IDisposable
{
public IProxyProvider Provider{get; private set;}
public ComProxy(IProxyProvider provider) : base(provider.Type == typeof(object) ? typeof(MarshalByRefObject) : provider.Type)
{
Provider = provider;
}
public static object GetProxy(IProxyProvider provider)
{
return new ComProxy(provider).GetTransparentProxy();
}
public static ComProxy GetProxy(object proxy)
{
if(proxy == null) return null;
return RemotingServices.GetRealProxy(proxy) as ComProxy;
}
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage msgCall = msg as IMethodCallMessage;
if(msgCall != null)
{
object[] args = msgCall.Args;
try{
ProxyProvider.ProxyArgs(args);
object ret = Provider.Invoke(msgCall.MethodName, (Type[])msgCall.MethodSignature, args);
ProxyProvider.DeproxyArgs(args);
ret = ProxyProvider.DeproxyValue(ret);
return new ReturnMessage(ret, args, args.Length, msgCall.LogicalCallContext, msgCall);
}catch(TargetInvocationException e)
{
return new ReturnMessage(e.InnerException, msgCall);
}catch(Exception e)
{
return new ReturnMessage(e, msgCall);
}
}
return null;
}
~ComProxy()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
if(disposing)
{
Marshal.FinalReleaseComObject(Provider);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
}
它使用IProxyProvider
接口,該接口支持遠程調用對象上的方法,透明地代理所有參數和返回值。 它添加了一個處理所有這些的自定義封送處理程序,只需將其添加到MarshalAs
屬性中,它將處理傳遞或接收的所有可移動對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.