【问题标题】:How can I convert IntPtr to UIntPtr?如何将 IntPtr 转换为 UIntPtr?
【发布时间】:2011-12-06 08:32:33
【问题描述】:

我试着像这样投射它:

UIntPtr x = (UIntPtr)intPtr;

...但是编译器对此不太满意并返回了编译错误。

我需要进行转换,因为RegOpenKeyEx 的 P/Invoke 签名需要 UIntPtr:

  [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
  public static extern int RegOpenKeyEx(
    UIntPtr hKey,
    string subKey,
    int ulOptions,
    int samDesired,
    out UIntPtr hkResult);

为了获得句柄,我使用了 SafeHandle.DangerousHandle(),它返回一个 IntPtr:

   /// <summary>
    /// Get a pointer to a registry key.
    /// </summary>
    /// <param name="registryKey">Registry key to obtain the pointer of.</param>
    /// <returns>Pointer to the given registry key.</returns>
    IntPtr _getRegistryKeyHandle(RegistryKey registryKey)
    {
        //Get the type of the RegistryKey
        Type registryKeyType = typeof(RegistryKey);

        //Get the FieldInfo of the 'hkey' member of RegistryKey
        System.Reflection.FieldInfo fieldInfo =
            registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

        //Get the handle held by hkey
        SafeHandle handle = (SafeHandle)fieldInfo.GetValue(registryKey);

        //Get the unsafe handle
        IntPtr dangerousHandle = handle.DangerousGetHandle();
        return dangerousHandle;
    }

【问题讨论】:

  • 您尝试了什么以及为什么需要转换?
  • 只需用IntPtr 定义RegOpenKeyEx 而不是UIntPtr
  • 根据该站点:“将 IntPtr 更改为 UIntPtr:使用 IntPtr 调用句柄时,您将遇到溢出。如果您希望它在 32 和 64 上正常工作,UIntPtr 是正确的选择位平台。”
  • @Ian - 什么网站?除非它是微软的网站,否则我不会相信来源。 IntPtr 的大小取决于您使用的是 x86 还是 x64 操作系统。考虑到 C# 和 VB.NET 被编译到同一个 CLR 中,我应该指出,只有 C# 采用 UIntPtr,这看起来很奇怪。
  • @Ian:听起来不对。 IntPtr 可以保存任何有效的指针值,即使是那些设置了高位的指针。无论如何,您不能对句柄值进行算术运算。

标签: c#


【解决方案1】:

查看 msdn 后,我注意到 UIntPtrIntPtr 都有 void* 指针转换。

IntPtr a = ....;
UIntPtr b = (UIntPtr)a.ToPointer();

此时您需要不安全的代码。避免这种情况的唯一方法是使用unchecked 关键字并使用非指针类型进行转换(也使用here)。

两个指针之间没有转换的原因可能是UIntPtrIntPtr 一样没有固定大小,因为它们是特定于平台的(see)。

【讨论】:

    【解决方案2】:

    我发现BitConverter 最可靠,因为它在使用不允许从有符号值溢出到无符号值的 VB.NET 时也有效:

    new UIntPtr(BitConverter.ToUInt64(BitConverter.GetBytes(handleIntPtr.ToInt64), 0))
    

    【讨论】:

      【解决方案3】:

      为什么不简单地在 32 位指针上执行 unchecked((IntPtr)(int)uintPtr),或在 64 位指针上执行 unchecked((IntPtr)(long)uintPtr)?运行良好(并且比其他解决方案更快)。

      【讨论】:

        【解决方案4】:

        IntPtr 可以保存与UIntPtr 一样多的值。两者的位数相同。

        溢出是一个算术概念。永远不会在句柄上执行算术运算。这个概念在这里不适用。

        在整个 BCL 中IntPtr 是句柄的标准类型。在任何地方使用IntPtr

        网站说:

        将 IntPtr 更改为 UIntPtr:使用 IntPtr 调用句柄时,您将遇到溢出。如果您希望它在 32 位和 64 位平台上正常工作,UIntPtr 是正确的选择。

        可能他的代码以溢出的方式在类型之间进行转换。这只是他的一种迷信。他改变了一些东西。下摆之一使它起作用。他现在认为这是 IntPtr 的变化,但这是另外一回事。

        而且,这个选择与过程的琐碎无关。

        【讨论】:

          【解决方案5】:

          一个非常简单的解决方案,不需要不安全的代码,就是先将指针转换为 long,然后再转换为 UIntPtr。

          IntPtr ptr = …;
          UIntPtr Uptr = (UIntPtr)(long)ptr;
          

          【讨论】:

          • 老实说,这是最好的答案。由于 UInt64 可以存储 UInt32.MaxValue,它应该可以正常工作。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-08-16
          • 1970-01-01
          • 2012-10-21
          • 2017-09-09
          • 2013-08-12
          • 2010-09-07
          • 2016-12-07
          相关资源
          最近更新 更多