2012-06-26 3 views
2

Я использую MSScriptControl в C#. Я хотел бы передать класс из сценария хосту. Упрощенный пример: Javascript:C# MSScriptControl Pass Class to Function

function Fx(n) { 
    this.name = n; 
} 
var fx = new Fx("test"); 
rfx.DoEffect(fx); 

C#:

[ComVisible(true)] 
public class Rfx { 
    public void DoEffect(object fx) { 
     // Try to read fx.name 
    } 
} 

Мой вопрос: Как я могу получить данные из объекта (что C# отчеты как System .__ ComObject). Я попробовал технику предложил here, но он не работает:

public void DoEffect(object fx) 
{ 
    System.Reflection.FieldInfo[] myFields = fx.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); 
    Console.WriteLine("FieldInfo length = " + myFields.Length); 
    for (int i = 0; i < myFields.Length; i++) 
    { 
     Console.WriteLine("The value of {0} is: {1}", myFields[i].Name, myFields[i].GetValue(fx)); 
    } 
} 

myFields.Length является 0.

+0

Вместо использования System.Reflection, вам необходимо получить ITypeInfo из системы. Runtime.InteropServices: – Mangist

ответ

1

Строительство от кода Mangist, это работает:

using System; 
using System.Runtime.InteropServices; 
using ComTypes = System.Runtime.InteropServices.ComTypes; 

public class ComHelper 
{ 
    public static string GetValue(object comObj, string name) 
    { 
     if (comObj == null) 
      return String.Empty; 

     if (!Marshal.IsComObject(comObj)) 
      //The specified object is not a COM object 
      return String.Empty; 

     IDispatch dispatch = comObj as IDispatch; 
     if (dispatch == null) 
      //The specified COM object doesn't support getting type information 
      return String.Empty; 

     try 
     { 
      int language_id = 0; 
      int DISPATCH_METHOD = 0x1; 
      int DISPATCH_PROPERTYGET = 0x2; 

      int[] displayIDs = new int[1]; 
      Guid empty = Guid.Empty; 
      string[] names = new string[] { name }; 
      dispatch.GetIDsOfNames(ref empty, names, names.Length, language_id, displayIDs); 
      System.Runtime.InteropServices.ComTypes.DISPPARAMS dspp = new System.Runtime.InteropServices.ComTypes.DISPPARAMS(); 
      System.Runtime.InteropServices.ComTypes.EXCEPINFO ei = new System.Runtime.InteropServices.ComTypes.EXCEPINFO(); 
      IntPtr[] arg_err = new IntPtr[10]; 
      object result; 
      if (1 == displayIDs.Length) 
      { 
       dispatch.Invoke(displayIDs[0], ref empty, language_id, (ushort)(DISPATCH_METHOD | DISPATCH_PROPERTYGET), ref dspp, out result, ref ei, arg_err); 
       return result.ToString(); 
      } 
      return String.Empty; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      return String.Empty; 
     } 
    } 
} 

I сделал это ранее в C++, чтобы я мог скопировать код, но я все еще намокаю ноги на C#.

0
using System; 
using System.Runtime.InteropServices; 
using ComTypes = System.Runtime.InteropServices.ComTypes; 

namespace ComUtils 
{ 
    public class ComHelper 
    { 
     /// <summary> 
     /// Returns a string value representing the type name of the specified COM object. 
     /// </summary> 
     /// <param name="comObj">A COM object the type name of which to return.</param> 
     /// <returns>A string containing the type name.</returns> 
     public static string GetTypeName(object comObj) 
     { 

      if (comObj == null) 
       return String.Empty; 

      if (!Marshal.IsComObject(comObj)) 
       //The specified object is not a COM object 
       return String.Empty; 

      IDispatch dispatch = comObj as IDispatch; 
      if (dispatch == null) 
       //The specified COM object doesn't support getting type information 
       return String.Empty; 

      ComTypes.ITypeInfo typeInfo = null; 
      try 
      { 
       try 
       { 
        // obtain the ITypeInfo interface from the object 
        dispatch.GetTypeInfo(0, 0, out typeInfo); 
       } 
       catch (Exception ex) 
       { 
        //Cannot get the ITypeInfo interface for the specified COM object 
        return String.Empty; 
       } 

       string typeName = ""; 
       string documentation, helpFile; 
       int helpContext = -1; 

       try 
       { 
        //retrieves the documentation string for the specified type description 
        typeInfo.GetDocumentation(-1, out typeName, out documentation, 
         out helpContext, out helpFile); 
       } 
       catch (Exception ex) 
       { 
        // Cannot extract ITypeInfo information 
        return String.Empty; 
       } 
       return typeName; 
      } 
      catch (Exception ex) 
      { 
       // Unexpected error 
       return String.Empty; 
      } 
      finally 
      { 
       if (typeInfo != null) Marshal.ReleaseComObject(typeInfo); 
      } 
     } 
    } 

    /// <summary> 
    /// Exposes objects, methods and properties to programming tools and other 
    /// applications that support Automation. 
    /// </summary> 
    [ComImport()] 
    [Guid("00020400-0000-0000-C000-000000000046")] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    interface IDispatch 
    { 
     [PreserveSig] 
     int GetTypeInfoCount(out int Count); 

     [PreserveSig] 
     int GetTypeInfo( 
      [MarshalAs(UnmanagedType.U4)] int iTInfo, 
      [MarshalAs(UnmanagedType.U4)] int lcid, 
      out ComTypes.ITypeInfo typeInfo); 

     [PreserveSig] 
     int GetIDsOfNames( 
      ref Guid riid, 
      [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] 
      string[] rgsNames, 
      int cNames, 
      int lcid, 
      [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); 

     [PreserveSig] 
     int Invoke( 
      int dispIdMember, 
      ref Guid riid, 
      uint lcid, 
      ushort wFlags, 
      ref ComTypes.DISPPARAMS pDispParams, 
      out object pVarResult, 
      ref ComTypes.EXCEPINFO pExcepInfo, 
      IntPtr[] pArgErr); 
    } 
} 
+0

Спасибо. Это не делало то, что мне нужно, но поставило меня в правильном направлении. –

1

С момента введения dynamic, можно рассматривать COM объектов в динамике, в вашем примере вы могли бы просто сделать:

dynamic fx = scriptControl.Run("youFunction"); 
string name = fx.name;