繁体   English   中英

获取 IntPtr 指向的数组的大小

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM