C#编组(C#调用C++ DLL)

问题描述:

请问你们能帮我解决下面的问题吗?我有一个C++函数DLL,它将被另一个C#应用程序调用。其中一个我需要的功能是如下:C#编组(C#调用C++ DLL)

unsigned long makeArray(unsigned char* sendArr, unsigned long sendArrLen, unsigned char *recvArr, unsigned long *recvArrLen); 

我写在C#下面的代码:

[DllImport("test.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern ulong makeArray(byte[] sendArr, ulong sendArrLen, byte[] recvArr, ulong recvArrLen); 

    private byte[] MakeArray() 
    { 
     byte[] arrSend = new byte[] { 0x00, 0x12, 0x34 }; 

     ulong nRecvArrLen = 0; 
     byte[] arrRecv = null; // assign in c++ dll function (variable size) 

     if(makeArray(arrSend, (ulong)arrSend.Length, arrRecv, nRecvArrLen) == 1) 
     { 
      return arrRecv; 
     } 

     return null; 
    } 

不幸的是,上面的代码是不工作... 我可以知道我怎么能传递一个指向C++ func的指针?如果这是不可能的,是否有任何解决方法?

谢谢。

你的'test.dll'在哪里?我认为这是一个路径问题...

该文件必须位于以下目录中的一个..

[%SystemRoot%] (Windows directory) 
[%SystemRoot%]\system32\(32 bit) or 
[%SystemRoot%]\sysWOW64\(64 bit) 
The same location with your executable file 
PATH variable 

或者,它可以是一个类型不匹配......指 [site]

我在c/C++在Windows上将ulsha类型的csharp与unsigned __int64匹配。

C#代码的声明有点改变。

[DllImport(@"testdll.dll", CallingConvention = CallingConvention.Cdecl)] 
    static extern ulong makeArray 
    (
    byte[] sendArr, 
    ulong sendArrLen, 
    [Out] byte[] recvArr, 
    ref ulong recvArrLen 
    ); 

这里是testdll.cpp ABD testdll.h我测试

#include "testdll.h" 

unsigned __int64 makeArray(
    unsigned char* sendArr, 
    unsigned __int64 sendArrLen, 
    unsigned char *recvArr, 
    unsigned __int64 *recvArrLen 
) 
{ 
    int i; 

    for(i=0; i < sendArrLen; i++) 
    { 
     recvArr[i] = sendArr[i]; 
    } 

    memcpy(recvArrLen, &sendArrLen, sizeof(unsigned __int64)); 

    return i; 
} 

testdll.h代码。

#pragma once 

#ifdef EXPORT_TESTDLL 
#define TESTDLL_API __declspec(dllexport) 
#else 
#define TESTDLL_API __declspec(dllimport) 
#endif 

extern "C" TESTDLL_API unsigned __int64 makeArray(
    unsigned char* sendArr, 
    unsigned __int64 sendArrLen, 
    unsigned char *recvArr, 
    unsigned __int64 *recvArrLen 
); 

最后,如下控制台应用程序的C#代码,调用本地DLL函数在C++中 - 在控制台上testdll.dll 打印项目。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 

     [DllImport(@"testdll.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern ulong makeArray(byte[] sendArr, ulong sendArrLen, [Out] byte[] recvArr, ref ulong recvArrLen); 

     static byte[] MakeArray() 
     { 
      byte[] arrSend = new byte[] { 0x00, 0x12, 0x34 }; 
      ulong nRecvArrLen = 0; 
      ulong ret = 0; 
      byte[] arrRecv = new byte[3]; // assign in c++ dll function (variable size) 

      try 
      { 
       if ((ret = makeArray(arrSend, (ulong)arrSend.Length, arrRecv, ref nRecvArrLen)) > 0) 
       { 
        if(arrRecv != null) 
         Console.WriteLine("nRecvArrLen2============>" + arrRecv.Length); 


        return arrRecv; 
       } 

      } 
      catch (DllNotFoundException dne) 
      { 
       Console.WriteLine("============> dll not found...."); 
      } 


      return null; 
     } 


     static void Main(string[] args) 
     { 
      byte[] retbytes = MakeArray(); 

      if (retbytes != null) 
      { 
       Console.WriteLine("=====LEN=======>" + retbytes.Length); 

       for (int i = 0; i < retbytes.Length; i++) 
        Console.WriteLine("====ITEM========>" + retbytes[i]); 
      } 
      else 
       Console.WriteLine("=====NULL=======>"); 


     } 
    } 
} 

enter image description here

+0

错误是 “System.AccessViolationException”。而不是“EntryPointNotFoundException”。 –

+0

你的标题中是否有extern关键字?像extern“C”__declspec(dllexport) – tommybee

在MSVC unsigned long是一个32位无符号整数,因此应该将其映射到System.UInt32 .NET类型中,对应于C#中的uint关键字。

C#ulong是一个无符号的64位整数,对应于MSVC的unsigned __int64unsigned long long

在C#PInvoke声明中,我应该使用ref映射unsigned long *recvArrLen参数,因为您通过指针具有间接级别。

似乎arrRecv数组参数应该由调用者(在你的情况下是C#)分配,并由DLL函数填充。

如果DLL函数分配缓冲区,则应该添加另一个间接级别(unsigned char **recvArr),并且您应该提供一种释放分配内存的方式(例如,该DLL也应该导出释放函数)。

我会尝试的东西像这样的PInvoke:

[DllImport("test.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern uint makeArray(
    byte[] sendArr, 
    uint sendArrLen, 
    [Out] byte[] recvArr, 
    ref uint recvArrLen 
);