【问题标题】:Passing a C++ array to a C# function将 C++ 数组传递给 C# 函数
【发布时间】:2018-11-14 03:21:56
【问题描述】:

我正在尝试使用 C# 库轻松地将原始像素数组转换为 PNG 文件。我使用 C++ 和 OpenGL 编写了我的初始程序,所以最好的方法是使用 COM 将我的 C++ 像素数组传递给 C# dll,并使 C# dll 将它们保存为 PNG 文件。我可以轻松地将值传递给 C#,但我无法快速弄清楚如何将非托管 C++ 数组传递给 C#。我读过您可以使用 SAFEARRAYS 或进行某种编组和解组。无论如何,我不确定他们。这是我的 C# 代码,

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace PNG_Creator_DLL
{
[ComVisible(true)]
public interface IPicturesAndMovies
{
    //int Add(int a, int b);
    int CreatePNG(UInt16[] imagery_data);
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class PNG_Create_Class: IPicturesAndMovies
{
    public int CreatePNG(UInt16[] imagery_data)
    {


        //create the images directory
        Directory.CreateDirectory("images");

        String fileName = "images\\PNG_test_nmr" + "_0000.png";
        var pngStream = new FileStream(fileName, FileMode.Create);

        readImage(imagery_data, pngStream, 384, 288);  //create the png frame
        pngStream.Close();
        fileName = "images\\PNG_test_nmr" + "_" + "0001" + ".png";
        pngStream = new FileStream(fileName, FileMode.Create);

        pngStream.Close();
        File.Delete(fileName);


        return 0;
    }

    private Boolean readImage(UInt16[] imagery_data, Stream pngStream, Int32 width, Int32 height)
    {


        var bmp = new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray16, null);
        Int32 bytesPerPixel = bmp.Format.BitsPerPixel / 8;
        Int32Rect drawRegionRect = new Int32Rect(0, 0, bmp.PixelWidth, bmp.PixelHeight);


        Int32 stride = bmp.PixelWidth * bytesPerPixel;
        bmp.WritePixels(drawRegionRect, imagery_data, stride, 0);

        PngBitmapEncoder enc = new PngBitmapEncoder();
        enc.Frames.Add(BitmapFrame.Create(bmp));
        enc.Save(pngStream);

        return true;
    }
 }
}

这是我的 C++ 代码,它使用 COM 并尝试将数组传递给 C# dll

#include "stdafx.h"
#include <Windows.h>
#import "..\x64\Release\dllFiles\PNG_Creator_DLL.tlb" no_namespace

int main()
{
unsigned short* imagery_data = new unsigned short[384 * 288];
unsigned short temp_sum = 0;
for (int index_row = 0; index_row < 288; index_row++)
{
    temp_sum = 0;
    for (int index_col = 0; index_col < 384; index_col++)
    {

        imagery_data[index_row * 384 + index_col] = temp_sum;
        temp_sum = (unsigned short)(temp_sum + 160);
    }
}

CoInitialize(NULL);

IPicturesAndMoviesPtr obj;
obj.CreateInstance(__uuidof(PNG_Create_Class));
printf("Create      = %d\n", obj->CreatePNG(imagery_data));

CoUninitialize();
return 0;
}

我在以下位置收到 C2664 编译器错误 printf("Create = %d\n", obj->CreatePNG(imagery_data));

它说“long IPicturesAndMovies::CreatePNG(SAFEARRAY *)”:无法将参数 1 从“unsigned short *”转换为“SAFEARRAY *”

关于如何解决它的任何想法?

【问题讨论】:

标签: c# c++ dll com


【解决方案1】:

尝试如下所述。它可能会起作用

//YOUR ARRAY NEEDS TO BE CONVERTED TO SAFE ARRAY
unsigned short* imagery_data = new unsigned short[384 * 288];

//DECLARE A SAFE ARRAY POINTER
SAFEARRAY *psa;  


//AS THE REQUIRED IS UInt16[] - USE VT_UI2 
//LOWER BOUND  = 0
//UPPER BOUND = 110592 (384 * 288)
psa = SafeArrayCreateVector(VT_UI2, 0, 110592);  //REFER DOCUMENTATION

unsigned short *pData;  
HRESULT hr = SafeArrayAccessData(psa, (void **)&pData); //REFER DOCUMENTATION
memcpy(pData, imagery_data, 110592*sizeof(unsigned short));  
SafeArrayUnaccessData(psa);//REFER DOCUMENTATION

然后使用psa通过。

使用完毕后,请致电SafeArrayDestroy 进行清理。

SafeArrayDestroy(psa);

上面的代码是从下面的链接中提取并缩短的。

https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/dotnet/how-to-marshal-a-safearray-for-adonet-cpp-cli.md

【讨论】:

  • 谢谢 xanatos.... msdn.microsoft.com/en-us/library/windows/desktop/… 这个链接有很好的信息,在页面底部,表格有安全信息
  • 感谢您的帮助;看来您正在将 unsigned int 发送到 C#。有没有办法直接使用 SAFEARRAY 直接将 unsinged shorts 传递给 C#?
  • @nmr 代码正在传递unsigne short now :-) 请注意,您可以直接在缓冲区pData 中工作,而不是写入imagery_data 然后复制发给pData
  • 我认为它现在可以工作了。谢谢您的帮助! SafeArrayAccessData 和 SaveArrayUnaccessData 有什么区别?
  • @nmr 一个是“on”,另一个是“off” :-) 一些描述是here
猜你喜欢
  • 2013-06-26
  • 2014-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多