none
VC调用C#.NET的DLL的函数时,如何取得结构体和数组数据? RRS feed

  • 问题

  • 以前从来没有接触过COM,所以也不知道标题该怎么写,大概问题就是,我在.NET那边做了这样一个接口和类:

    namespace TestDll
    {
      [Guid("7D877FE6-47AD-4376-8027-766BC25B1CC3")]
      public interface ICalculator
      {
        Data GetData();
        Data[] GetAllData();
      }
    
      public class Data
      {
        public int left;
        public double right;
      }
    
      [ClassInterface(ClassInterfaceType.None)]
      [Guid("1EC5C1DA-0188-445a-8D03-47DCF992B743")]
      public class Calculator : ICalculator
      {
        public Calculator() { }
        public Data GetData()
        {
          Data data = new Data();
          data.left = 55;
          data.right = 11.1234;
          return data;
        }
    
        public Data[] GetAllData()
        {
          Data[] data = new Data[2];
          data[0].left = 11;
          data[0].right = 11.1234;
          data[1].left = 22;
          data[1].right = 22.2345;
          return data;
        }
      }
    }
    
    


    包装成COM生成tlb文件后从VC++程序import,然后这样进行了调用:

     

    int _tmain(int argc, _TCHAR* argv[])
    {
    
      HRESULT hRes = CoInitialize(NULL);
    
      TestDll::ICalculatorPtr pCal;
    
      hRes = pCal.CreateInstance(__uuidof(TestDll::Calculator));
    
      long lResult = 0;
    
      if(hRes == S_OK)
      {
        pCal->GetData();
        pCal->GetAllData();
      }
    
      CoUninitialize();
    }
    

    编译是通过了,现在的问题就是,如何使用pCal->GetData();和pCal->GetAllData();把结构体和结构体数组的数据取到?我看GetData()的返回类型是TestDll::_DataPtr,就试着声明了这个类型的变量来接返回值,但是接到后去没找到把数据取出来的方法……而GetAllData()一运行就报错,更别说取数据了,郁闷……
    对COM完全是一头雾水,希望大家能帮帮忙,谢谢!

    2011年8月30日 5:28

答案

  • 试了一下用SafeArray取数据,还是失败了。按照如下方法使用,结果异常,错误消息是“0x80028019 Old format or invalid type library. ”

    SAFEARRAY* mOut= NULL;
    
    hRes = SafeArrayAllocDescriptor(1, &mOut);
    mOut->cbElements = sizeof(struct Data);
    mOut->rgsabound[0].cElements = 2;
    mOut->rgsabound[0].lLbound = 0;
    mOut->fFeatures=FADF_AUTO;
    hRes = SafeArrayAllocData(mOut);
    
    mOut = pCal->GetAllData();
    
    


    如果不分配空间,就传一个指针进去,也是一样的错误……

    研究了半天,终于找到一个方法,就是C#返回一个结构体,而结构体内又包含一个自定义的结构体数组,只不过声明的时候用:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public IntPtr[] data;
    

    然后在C#的函数被调用时,用以下方法分配空间以及把结构体封装进指针:

    myarray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(Data));
    Marshal.StructureToPtr(data[0], myarray[0], false);
    myarray[1] = Marshal.AllocHGlobal(Marshal.SizeOf(Data));
          Marshal.StructureToPtr(data[1], myarray[1], false);
    

    这样在VC这边自动生成的结构体会把data成员当作long型传递,最后再把long型强转为结构体指针,终于能把数据接收到了。

    • 已标记为答案 XjAcKs 2011年9月1日 9:25
    2011年9月1日 9:23

全部回复

  • 研究了一天,发现只要在C#这边吧class Data改成struct data,VC就自动把结构体导入进来,可以直接使用了,不过数组的情况还是不行,返回的是一个SAFEARRAY指针,得继续研究研究……
    2011年8月31日 6:35
  • 你好,

     

    由于COM不能直接使用数组。因此,您需要使用SafeArray来帮助您进行数据传递。

    COM已经提供了一整套相关接口用以处理SafeArray。你可以从以下地址获取更多信息:http://msdn.microsoft.com/en-us/library/ms221145(v=VS.85).aspx

    SafeArray 几乎可以用来存贮所有类型的数据,您可以通过以下参数来设定SafeArray中存储的类型:http://msdn.microsoft.com/en-us/library/ms256088.aspx

     

    希望我的建议能够帮助您解决您的问题

     


    Rob Pan [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年9月1日 7:18
  • 试了一下用SafeArray取数据,还是失败了。按照如下方法使用,结果异常,错误消息是“0x80028019 Old format or invalid type library. ”

    SAFEARRAY* mOut= NULL;
    
    hRes = SafeArrayAllocDescriptor(1, &mOut);
    mOut->cbElements = sizeof(struct Data);
    mOut->rgsabound[0].cElements = 2;
    mOut->rgsabound[0].lLbound = 0;
    mOut->fFeatures=FADF_AUTO;
    hRes = SafeArrayAllocData(mOut);
    
    mOut = pCal->GetAllData();
    
    


    如果不分配空间,就传一个指针进去,也是一样的错误……

    研究了半天,终于找到一个方法,就是C#返回一个结构体,而结构体内又包含一个自定义的结构体数组,只不过声明的时候用:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public IntPtr[] data;
    

    然后在C#的函数被调用时,用以下方法分配空间以及把结构体封装进指针:

    myarray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(Data));
    Marshal.StructureToPtr(data[0], myarray[0], false);
    myarray[1] = Marshal.AllocHGlobal(Marshal.SizeOf(Data));
          Marshal.StructureToPtr(data[1], myarray[1], false);
    

    这样在VC这边自动生成的结构体会把data成员当作long型传递,最后再把long型强转为结构体指针,终于能把数据接收到了。

    • 已标记为答案 XjAcKs 2011年9月1日 9:25
    2011年9月1日 9:23