5

I tried casting it like so:

UIntPtr x = (UIntPtr)intPtr;

... but the Compiler is not very happy with it and returned a compile error.

I need to do the conversion because the P/Invoke signature for RegOpenKeyEx requires a UIntPtr:

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

In order to get a handle, I am using SafeHandle.DangerousHandle() which returns an 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;
    }
ThinkingStiff
  • 64,767
  • 30
  • 146
  • 239
Ian
  • 5,625
  • 11
  • 57
  • 93
  • 2
    what did you try and why do you need to convert? – Davide Piras Dec 06 '11 at 08:34
  • Edited my question above to answer your questions. – Ian Dec 06 '11 at 08:44
  • 4
    Just define `RegOpenKeyEx` with `IntPtr` instead of `UIntPtr`. – leppie Dec 06 '11 at 08:44
  • 2
    According to the site: "Changed IntPtr to UIntPtr: When invoking with IntPtr for the handles, you will run into an Overflow. UIntPtr is the right choice if you wish this to work correctly on 32 and 64 bit platforms." – Ian Dec 06 '11 at 08:45
  • 1
    @Ian - What site? Unless its Microsoft's website I wouldn't trust the source. The size of IntPtr depends on if your working on a x86 or x64 operating system. I should point out only the C# takes a UIntPtr which seems odd, considering C# and VB.NET are compiled into the same CLR. – Security Hound Dec 06 '11 at 11:56
  • How did you solve your problem? Did my answer help? – Felix K. May 21 '12 at 11:20
  • 1
    @Ian: That sounds wrong. `IntPtr` can hold any valid pointer value, even those with the high bit set. You can't do arithmetic on handle values anyway. – Ben Voigt Aug 30 '14 at 20:29
  • any reason why you are using Win32 API yourself to open the reg key and not using the .NET Framework to open reg keys via the Microsoft.Win32 namespace which has .NET classes but is a wrapper for Win32 API ops? – Ahmed ilyas Jan 10 '15 at 10:26

5 Answers5

2

After taking a look at msdn i noticed that both, UIntPtr and IntPtr, have the void* pointer conversion.

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

At this point you need unsafe code. The only way to avoid this is using the unchecked keyword and convert by using non-pointer types ( used here too ).

The reason why there is no conversion between the two pointers might be that UIntPtr like IntPtr does not have a fixed size because they are platform specific( see ).

Community
  • 1
  • 1
Felix K.
  • 6,201
  • 2
  • 38
  • 71
0

I found BitConverter to be most reliable as it also works when using VB.NET which does not allow overflows from signed to unsigned values:

new UIntPtr(BitConverter.ToUInt64(BitConverter.GetBytes(handleIntPtr.ToInt64), 0))
Paul B.
  • 2,394
  • 27
  • 47
0

Why don't you do simply do unchecked((IntPtr)(int)uintPtr) on 32 bit pointers, or unchecked((IntPtr)(long)uintPtr) on 64 bit pointers? Works well (and faster than the other solutions).

xamid
  • 440
  • 11
  • 25
0

IntPtr can hold as many values as UIntPtr. Both have the same number of bits.

Overflow is a concept of arithmetic. Arithemtic is never performed on handles. This concept does not apply here.

In the entire BCL IntPtr is the standard type for handles. Use IntPtr everywhere.

The site says:

Changed IntPtr to UIntPtr: When invoking with IntPtr for the handles, you will run into an Overflow. UIntPtr is the right choice if you wish this to work correctly on 32 and 64 bit platforms.

Probably, his code was converting between types in an overflowing way. This is just a superstitious belief of his. He changed a few things. One of hem made it work. He now thinks it was the IntPtr change but it was something else.

Also, this choice has nothing to to bit the bitness of the process.

usr
  • 168,620
  • 35
  • 240
  • 369
0

A much, much simpler solution, that does not require unsafe code, is to simply first cast the pointer to a long, and then to UIntPtr.

IntPtr ptr = …;
UIntPtr Uptr = (UIntPtr)(long)ptr;
Iorpim
  • 167
  • 2
  • 9
  • Honestly this is the best answer. Since UInt64 can store UInt32.MaxValue, it should work appropriately. – Tayab Jun 17 '21 at 14:58