【问题标题】:Getting the size of the array pointed to by IntPtr获取 IntPtr 指向的数组的大小
【发布时间】:2014-01-03 21:53:48
【问题描述】:

我有一个使用 pinvoke 从 C# 项目调用的本机 C++ 函数。

extern "C" _declspec(dllexport) void GetCmdKeyword( wchar_t** cmdKeyword, uint  pCmdNum )
{
 int status = 1;
 int       count     = 0;
 int       i         = 0;

 if( cmdKeyword == NULL )
      return ERR_NULL_POINTER;

 //search command in command list by letter from 'A' to 'Z'
 count = sizeof( stCommandList ) / sizeof( COMMANDLIST ) ;

 for ( i = 0 ; i < count && status != 0; i++ )
 {
      if ( pCmdNum != stCommandList[i].ulCommand )
           continue;
      *cmdKeyword = &stCommandList[i].CommandKeyWord[0];
      status = 0 ;
 }

}

其中 stCommandList 是 COMMANDLIST 类型的结构,CommandKeyWord 成员是 char 数组。

要从 C# 调用这个函数,我需要传递什么参数? cmdKeyword 应该填充到 C# 端的 char 数组或字符串中,即我需要复制 ptr 指向 C# 文件中的 int 数组的位置的内容。如果我知道长度,我可以使用 Marshal.Copy 来做同样的事情。我现在该怎么做?另外,我不希望使用不安全的。 Globalsize 对此有帮助吗?

【问题讨论】:

  • 没有fun的界面更多信息,无从得知。如果您不能 100% 确定内存是使用 GlobalAlloc() 分配的,则不能使用 GlobalSize。如果您对fun 了解更多,可能会有提示,例如标记值。
  • 这就是为什么几乎每个使用数组指针also 的c++ 函数都使用数组长度的原因。没有办法知道!
  • 您应该做的是在托管代码中分配数组并将其传递给本机代码以让本机代码填充它。对于 int 元素,在托管端是 int[],在本机端是 int*。如果 int** 是正确的解决方案,我会感到非常惊讶。

标签: c# pinvoke intptr


【解决方案1】:

您无法从指针推断长度。该信息必须作为一个单独的值与指向数组的指针一起传递。

我想知道你为什么使用原始的IntPtr 而不是 C# 数组。我认为您接受的先前问题的答案具有您需要的代码:Pinvoking a native function with array arguments


好的,看问题的编辑,实际情况有点不同。该函数返回一个指向以空字符结尾的宽字符数组的指针。你的 pinvoke 应该是:

[DllImport(...)]
static extern void GetCmdKeyword(out IntPtr cmdKeyword, uint pCmdNum);

这样称呼它:

IntPtr ptr;
GetCmdKeyword(ptr, cmdNum);
string cmdKeyword = Marshal.PtrToStringUni(ptr);

【讨论】:

  • 对不起,它是 int 数组。我使用 IntPtr 而不是 c# 数组,因为在您之前的回答中,如果我需要获取 C++ 函数中指针指向的新内存位置,我需要使用 out IntPtr 而不是 ref int[]
  • 哦不,现在我让你感到困惑。是的,在本机方面 int* 现在删除了冒犯性的评论。我认为答案是正确的。
  • 我觉得我很有耐心。不要使用ref ushort[]。并且不要使用int**。这有太多的间接性。而且你不能指望本机代码生成一个新的ushort[]。使用我的回答中的代码,您的其他问题与我的回答链接在这里。您根本不应该期望本机代码分配数组。谁来释放它?
  • 变量是什么?指向字符数组的指针,空终止?如果是这样,分配是如何完成的。静态的还是堆外的?如果是后者,调用者如何解除分配?如果我对 re 变量类型含义的假设是准确的,那么它将作为 IntPtr ptr 传递,并且您使用 Marshal.PtrToStringUni(ptr) 读取该值
  • 这取决于。 C++ 运行时堆需要本机代码来导出释放器。或者,像 COM 堆或 GlobalAlloc 这样的共享堆将允许调用方解除分配。
猜你喜欢
  • 2018-02-15
  • 2012-10-09
  • 1970-01-01
  • 2021-07-23
  • 2022-01-02
  • 2012-07-20
相关资源
最近更新 更多