我试着像这样投射它:
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;
}
答案 0 :(得分:2)
在看了msdn之后,我注意到UIntPtr
和IntPtr
都有void*
指针转换。
IntPtr a = ....;
UIntPtr b = (UIntPtr)a.ToPointer();
此时您需要不安全的代码。避免这种情况的唯一方法是使用unchecked
关键字并使用非指针类型进行转换(也使用here)。
两个指针之间没有转换的原因可能是UIntPtr
IntPtr
之类的{{1}}没有固定大小,因为它们是特定于平台的(see)。
答案 1 :(得分:0)
我发现BitConverter
最可靠,因为它在使用VB.NET时也有效,它不允许从签名到无符号值的溢出:
new UIntPtr(BitConverter.ToUInt64(BitConverter.GetBytes(handleIntPtr.ToInt64), 0))
答案 2 :(得分:0)
为什么不对32位指针执行unchecked((IntPtr)(int)uintPtr)
,或对64位指针执行unchecked((IntPtr)(long)uintPtr)
?运行良好(并且比其他解决方案更快)。
答案 3 :(得分:0)
IntPtr
可以包含与UIntPtr
一样多的值。两者都具有相同的位数。
溢出是算术的概念。 Arithemtic永远不会在句柄上执行。这个概念在这里不适用。
在整个BCL IntPtr
中是句柄的标准类型。到处使用IntPtr
。
该网站说:
将IntPtr更改为UIntPtr:当使用IntPtr调用句柄时,您将遇到溢出。如果您希望在32位和64位平台上正常工作,UIntPtr是正确的选择。
他的代码可能是以溢出的方式在类型之间进行转换。这只是他的迷信。他改变了一些事情。其中一个下摆使它工作。他现在认为这是IntPtr
改变,但它是另一回事。
此外,这一选择无助于确定流程的位数。
答案 4 :(得分:0)
一种非常简单的解决方案,不需要不安全的代码,只需将指针先转换为long类型,然后再转换为UIntPtr。
IntPtr ptr = …;
UIntPtr Uptr = (UIntPtr)(long)ptr;