[英]Getting the size of the array pointed to by IntPtr
我有一个本地 C++ function 我使用 pinvoke 从 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# 调用这个 function,我需要通过什么 arguments? cmdKeyword 应填充到 C# 端的 char 数组或字符串中,即我需要复制 ptr 指向 C# 文件中的 int 数组的位置的内容。 如果我知道长度,我可以使用 Marshal.Copy 来做同样的事情。 我现在该怎么做? 另外,我不希望使用不安全的。 Globalsize在这方面有帮助吗?
您不能从指针推断长度。 该信息必须作为单独的值与指向数组的指针一起传递。
我想知道为什么您使用原始IntPtr
而不是C#数组。 我认为您对之前的问题所接受的答案具有所需的代码: 使用数组参数调用本机函数 。
好吧,查看对问题的编辑,实际情况有所不同。 该函数返回一个指向以空字符终止的宽字符数组的指针。 您的个人称呼应该是:
[DllImport(...)]
static extern void GetCmdKeyword(out IntPtr cmdKeyword, uint pCmdNum);
这样称呼它:
IntPtr ptr;
GetCmdKeyword(ptr, cmdNum);
string cmdKeyword = Marshal.PtrToStringUni(ptr);
您无法从指针推断长度。
只要使用GlobalAlloc()
、 LocalAlloc()
或HeapAlloc()
API 分配指针,您绝对可以在 Windows 平台上执行此操作(尽管后者有点复杂)。
重要提示:请记住,memory 块的大小可能大于分配 memory 时请求的大小。
这是一个关于如何查找使用Marshal.AllocHGlobal()
或Marshal.StringToHGlobalUni()
分配的 memory 块大小的示例,它们都在内部使用LocalAlloc()
:
namespace HGlobalSizeTest
{
using System;
using System.Runtime.InteropServices;
internal static class WinAPI
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern UIntPtr LocalSize(IntPtr hMem);
internal static UInt64 HGlobalSize(IntPtr hMem)
{
return LocalSize(hMem).ToUInt64();
}
}
internal static class Program
{
static void Main(string[] args)
{
string TestString = "Test string!\0With embedded null character!";
IntPtr TestStringPtr = Marshal.StringToHGlobalUni(TestString);
UInt64 cb = WinAPI.HGlobalSize(TestStringPtr);
Marshal.FreeHGlobal(TestStringPtr);
Console.WriteLine($" TestString length = {TestString.Length}");
Console.WriteLine($" TestStringPtr bytes = {cb}");
Console.WriteLine($" TestStringPtr length = {cb >> 1}");
Console.ReadKey();
}
}
}
代码仅用于演示目的,为简洁起见省略了所有错误检查。 不要在生产中按原样使用。
最后,请注意,不推荐使用GlobalAlloc()
和LocalAlloc()
以支持HeapAlloc
,因为 HeapAlloc 的开销要小得多,因此这在实践中的使用非常有限,并且在知道非托管 memory 大小是必需的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.