2014-06-27 51 views
1

在C#C#我有一个数据类型byte[],其欲填在使用C++函数,它返回char*获取字节[]从在C++中的char *

的C++函数(在ImageData.dll

char* pMemoryBuffer = NULL; 
char* LoadData(const char *fileName) 
{ 
    // processing pMemoryBuffer ... 
    return pMemoryBuffer; 
} 

导入本地的dll到C#:

[DllImport(".\\Modules_Native\\ImageData.dll", EntryPoint = "LoadData")] 
    private extern static byte[] LoadData(string fileName); 

C#中的byte[]数据

byte[] buffer = new byte[256*256]; 
buffer = LoadData("D:\\myPic.tif"); 

显然它还没有工作,但它提出了我想要做的想法。所以我想知道如何做这项工作,以及做到这一点的正确方法是什么。非常感谢您的教育。

+0

它不知道C#数组必须多大。 – prq

+0

查看线程中的更新。大小已初始化。 – Ono

+0

你可以通过指定它的“不工作”来改善你的问题吗?我不是下来的选民,但这可能是原因。 – jmstoker

回答

5

试试这个

// c++ 

    void LoadData(unsigned char* *pMemoryBuffer, const char *fileName) 
    { 
     // processing pMemoryBuffer ... 
     *pMemoryBuffer = resutss; 

    } 

导入本地的dll到C#:

[DllImport(".\\Modules_Native\\ImageData.dll", EntryPoint = "LoadData")] 
private extern static void LoadData(out IntPtr data, string fileName); 

当函数返回的数据将指向数组,你可以阅读使用Marshal类的内容。我想你会copy it to a new byte arraŸ。

byte[] buffer = new byte[256*256]; 
buffer = Marshal.Copy(LoadData(buffer ,"D:\\myPic.tif"), buffer , 0, buffer.Length); 
+0

你的'Marshal.Copy'例子对于返回的指针是正确的。如果您可以更改C代码以使输出缓冲区成为参数,那么请不要使用'IntPtr'和'Marshal.Copy'。 –

+0

所以,感谢您复制我的答案,甚至没有做出积极的调整 –

+1

你有什么将无法工作,你需要一个'IntPtr'返回值来使'Marshal.Copy'片段工作。 –

1

我不确定,但我的直觉说,你不能在字节数组中指定一个char *,就像你不能在C++本身中一样。你可以在C#中使用IntPtr(可能不是非常有用),或者,你可以传递一个byte []缓冲区和一些字节来写入。换句话说,我觉得有以下将工作:

char* pMemoryBuffer = NULL; 
int size = 0; 
int seek = 0; 
bool LoadData(const char* filename) 
{ 
    // load filename 
    // set seek = 0 
    // set size to data size 
} 

int ReadData(char* buffer, int nBytesToRead) 
{ 
    // nCopyBytes = min(nBytesToRead, size - seek) 
    // copy nCopyBytes from pMemoryBuffer+seek to buffer 
    // seek += nCopyBytes 
    // return nCopyBytes 
} 

从C#中,你会使用这样的:

byte[] buffer = new byte[256*256]; 
LoadData("foo.tif"); 

int bytesRead = ReadData(buffer, 256*256); 

很抱歉,如果您特别想避免做这样的事情。

+0

'out'关键字在这里不合适,数组是引用类型,并且已经通过p/invoke作为指针传递。 –

+0

@BenVoigt我看到了,谢谢你指出了这一点。 – Patrick87

1

这应做到:

[DllImport(@".\Modules_Native\ImageData.dll")] 
private extern static IntPtr LoadData(string fileName); 

byte[] buffer = new byte[256*256]; 
buffer = Marshal.Copy(LoadData("D:\\myPic.tif"), buffer, 0, buffer.Length); 

但是,它不会释放内存。希望C(++)库在下次调用时自动释放它,否则会提供释放函数。

一个更好的办法是使用调用者分配的缓冲区,那么你就只是做:

byte[] buffer = new byte[256*256]; 
LoadData("D:\\myPic.tif", buffer); 

为此,C(++)代码,将需要改变

int LoadData(const char *fileName, char* pMemoryBuffer) 
{ 
    // processing pMemoryBuffer ... 
    return 1; // if success 
} 

和p/Invoke的声明

[DllImport(@".\Modules_Native\ImageData.dll")] 
private extern static int LoadData(string fileName, byte[] buffer); 
+1

那么,我的答案或 –

+0

@moez:不,它不是。你展示了如何创建一个'out IntPtr'参数,我认为这是一个坏主意,所以我将它改进为一个新的答案。你根本没有展示如何使用调用者提供的缓冲区。而且你没有提到让库在返回缓冲区中释放的问题。 –

+0

@moez:此外,每个人都可以看到我的答案出现在您的编辑之前......所以我认为很清楚这些想法正在流向哪个方向(我不会指责您被盗,我留下了一条评论中的更正,因为我邀请你使用它,但你没有正确地做) –