使用SAFEARRAY进行C ++ C#

时间:2014-04-15 13:48:52

标签: c# c++ interop safearray

我正在尝试使用C#编写的库的C ++。为此,我被告知要使用COM Interop,我对此知之甚少。 我试图以一种方式传递一维数组并返回一维数组,但我的返回数组最终只是满了零。 为了简化这个论坛的问题,我简化了我的程序:我甚至没有传递输入数组。

我的C#程序看起来像这样

using System;
using System.Runtime.InteropServices;

namespace FillArray
{
    [ComVisible(true)]
    [Guid("DABAEF7C-D2B8-4769-98C8-1AF211EF7D48")]
    public interface IFillArray
    {
        int fillTheArrayWithSquares(int[] array);
    }

    [ComVisible(true)]
    [Guid("124A66FD-CED3-4a8e-B0F0-BAA88B421E97")]
    public class Class1: IFillArray
    {
        public int fillTheArrayWithSquares(int[] array)
        {
            int len = array.Length;
            int i;
            for (i = 0; i < len; i++)
                array[i] = i * i;

            return len;
        }
    }
}

在同一解决方案中,我有一个C ++客户端,如下所示:

#import "D:\dev\CSharp\FillArray\FillArray\bin\Release\FillArray.tlb" raw_interfaces_only
#include "stdafx.h"
using namespace FillArray;

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = CoInitialize(NULL);
    long retval;
    IFillArrayPtr pIFillArray(__uuidof(Class1));
    SAFEARRAY *output;
    SAFEARRAYBOUND  BoundOutput;
    BoundOutput.cElements = 10;
    BoundOutput.lLbound = 0;
    output = SafeArrayCreate(VT_I4, 1, &BoundOutput);
    int *p_output_contents;
    HRESULT hrFill  = pIFillArray->fillTheArrayWithSquares( output, &retval);
    HRESULT hrOutput = SafeArrayAccessData(output, (void HUGEP**)&p_output_contents);
    if(SUCCEEDED(hrFill) && SUCCEEDED(hrOutput))
    {

    for(int i = 0; i < 10; i++)
        printf("%d ",p_output_contents[i]);
    printf("\n");
    printf("retval = %d\n",retval);
    SafeArrayUnaccessData(output);// not robust error handling
    SafeArrayDestroy(output);//not robust error handling logic
    }

    CoUninitialize();

    return 0;
}

我已经将C ++项目配置为使用/ clr:oldsyntax,因为我正在修改一篇推荐它的旧文章。不幸的是,在VS 2008(我正在使用)中看起来这已被弃用了,我将无法将其移植到VS2013。 所以我有两个问题: 1)为什么我的C ++应用程序打印10个零? 2)如何更新我的语法以避免/ clr:oldsyntax。

还有一句话:我在一些讨论中看到C#数组与SAFEARRAYS不对应,但类型的选择是Intellisense告诉我应该使用的。 THX。

1 个答案:

答案 0 :(得分:2)

首先,VS中有两种类型的C ++项目:

  1. 原生C ++项目,默认情况下不带/ clr选项。
  2. C ++ / CLI项目,默认使用/ clr选项。 C ++ / CLI可以访问本机和托管世界,因此如果您想使用C#DLL,只需添加此DLL作为参考并直接使用它,在这种情况下您不需要COM。
  3. 如果本机C ++项目想要使用C#DLL,一种方法是通过COM,另一种方法是使用C ++ CLI项目作为桥梁。

    如果你使用COM,那么你必须处理容易出错的SAFEARRAY。至于你的问题1,你使用SAFEARRAY作为out参数,这很复杂。我建议你只需将函数fillTheArrayWithSquares的定义更改为:

    public int[] fillTheArrayWithSquares( )
    

    因此它将返回SAFEARRAY到C ++代码,SAFEARRAY的长度已包含在SAFEARRAY中。