簡體   English   中英

無法將com對象轉換為控件

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM