调用从c#中获取char**的C dll函数

本文关键字:dll 函数 char 获取 调用 | 更新日期: 2023-09-27 18:16:44

我有一个C dll,它导出一个函数,看起来像这样:

void GetSectionData(TCHAR name [], char **Address, DWORD * Size)

函数获取一个名称,并在分配了*Size字节后返回地址。下面是如何在C中使用该函数的示例:

char *addr[64]:
DWORD Size[64];
TCHAR name[260];
sprintf( name, "myDll.dll);
GetSectionAddress(name, &addr[index],&Size[index]);

我想在没有unsafe的c#中使用这个dll函数。
我的函数声明应该使用DllImport属性,但我不知道如何声明参数,主要是地址和大小参数(我假设名称可以声明为StringBuilder):

[DllImport("myDll.dll")]
public static extern void GetSectionData(?)

调用从c#中获取char**的C dll函数

一般来说,您的pinvoke签名将是

static extern void GetSectionData(string name, out string address, out int size);

但:

  • 在' address '参数中,您可能需要通过[MarshalAs]属性和适当的SizeIndex值指示与'size'的关系。如果您将'out string'更改为'out char[]',那么肯定需要,但如果您使用字符串并且返回的字符串是正常的null终止字符串,我认为这将是不必要的
  • 如果函数为address数组分配内存,您可能会遇到一些问题,因为使用该函数将假设调用者必须知道如何释放它。请参阅https://stackoverflow.com/a/1932956/717732或https://stackoverflow.com/a/12274007/717732 -主要问题是有很多方法来分配缓冲区(包括基于堆栈的临时数组…),调用者将很难猜测。特别是在p/invoke中使用的编组器,因为它不了解您的代码。

根据Reflector的说法,. net框架内部实现这一点的方式是将StringBuilder实例传递给char**参数,而其他(数字)指针通常作为IntPtr传递。一个很好的例子是FormatMessage,它具有以下签名:

DWORD WINAPI FormatMessage(
  _In_      DWORD dwFlags,
  _In_opt_  LPCVOID lpSource,
  _In_      DWORD dwMessageId,
  _In_      DWORD dwLanguageId,
  _Out_     LPTSTR lpBuffer,
  _In_      DWORD nSize,
  _In_opt_  va_list *Arguments
);

Microsoft.Win32.SafeNativeMethods下定义为

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr arguments);

System.ComponentModel.Win32Exception,调用这个方法,执行

int error = 0; //Error code, for example
StringBuilder lpBuffer = new StringBuilder(0x100);
SafeNativeMethods.FormatMessage(0x3200, NativeMethods.NullHandleRef, error, 0, lpBuffer, lpBuffer.Capacity + 1, IntPtr.Zero)

如果您想提取size参数,您可以定义一个不安全的方法,并实际使用类型int*作为size参数。

[DllImport("myDll.dll")]GetSectionData(StringBuilder名称,ref IntPtr地址,ref int32大小);