Reputation: 5725
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
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
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
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
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
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