Ian
Ian

Reputation: 5725

How can I convert IntPtr to UIntPtr?

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;
    }

Upvotes: 5

Views: 6487

Answers (5)

Iorpim
Iorpim

Reputation: 177

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;

Upvotes: 1

usr
usr

Reputation: 171218

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.

Upvotes: 0

xamid
xamid

Reputation: 493

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).

Upvotes: 0

Felix K.
Felix K.

Reputation: 6281

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 ).

Upvotes: 2

Paul B.
Paul B.

Reputation: 2524

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))

Upvotes: 0

Related Questions