我试图从C++中以C#编写的库中使用。为此,我被告知使用COM Interop,对此我知之甚少。
我试图以一种方式传递一个1D数组并获得一个1D数组,但是我的返回数组最终只是充满零。
为了简化该论坛的问题,我简化了程序:我什至不传递输入数组。

我的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++ Client,看起来像这样:
#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告诉我应该使用的类型。
谢谢。

最佳答案

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

  • 本机C++项目,默认情况下不带/ clr选项。
  • C++ / CLI项目,默认情况下带有/ clr选项。 C++ / CLI可以访问本机和托管世界,因此,如果要使用C#DLL,只需将此DLL添加为引用并直接使用,在这种情况下就不需要COM。

  • 如果本机C++项目要使用C#DLL,则一种方法是通过COM,另一种方法是将C++ CLI项目用作桥梁。

    如果使用COM,则必须处理SAFEARRAY,这很容易出错。关于问题1,您使用SAFEARRAY作为out参数,这很复杂。我建议您仅将函数fillTheArrayWithSquares的定义更改为:
    public int[] fillTheArrayWithSquares( )
    

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

    09-19 19:09