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;
}
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 ).
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))
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).
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.
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;
Related
I am using DLL runtime which is made with C language into C#.
I came across below statement.
typedef void *JCCP_PROPERTY_HANDLE;
In function it is being used as:
JCCP_RESULT __JCCP_FUNCTION__ jccpGetProperty(
JCCP_HANDLE hjccp,
const char *name,
JCCP_PROPERTY_HANDLE *phproperty);
Now I want to call jccpGetProperty() method in my C# code.
Can anybody tell how can I pass third parameter(JCCP_PROPERTY_HANDLE *phproperty) to function from C#.
I tried with below code but not working.
Extern Method:
[DllImport(DLL_NAME, EntryPoint = "_jccpGetProperty", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jccpGetProperty(IntPtr hjccp, string name, ref IntPtr JCCP_PROPERTY_HANDLE);
Usage
IntPtr handle = IntPtr.Zero;
string tag = "server.version";
var result = jccpGetProperty(hjccp, tag, ref handle);
Can anybody help me in this?
IntPtr is the correct type mapping for void*. The native type void* is generally used for an opaque pointer, and that is mapped to IntPtr in C#.
Those parts of the p/invoke declaration that we can verify are correct. The unverifible parts are:
The calling convention. You believe that it is cdecl, but we can't check.
The return type. You believe it to be pointer sized. Again we cannot check. My guess is that a 32 bit integer, int or uint is more likely. That would make a difference in a 64 bit process.
The values passed to the function. It's perfectly possible that the function is declared correctly, but you are passing invalid values.
Because you only showed partial code and details, it's hard to say much more. You will have to verify all the parts of the program that we cannot.
I suggest that you start with working C or C++ code and translate that, looking for the first point of deviation in behaviour between that code and your C# translation.
I'm calling SetupDiGetDeviceInterfaceDetail() here and the SP_DEVICE_INTERFACE_DETAIL_DATA structure is not marshaling correctly. The structures definition can be found here. I've tried using the definition for this structure from PInvoke.net, here, but to no avail.
So far, when the call to the function succeeds (i.e. the marshaler doesn't throw an error), the return value is 1784 (INVALID_USER_BUFFER). The kicker is, when this code executes from a 32-bit process on my box, all of this works just fine. When it's run in a 64-bit process, I have this problem.
My current SetupDiGetInterfaceDetailData() signature looks like this:
[DllImport(#"c:\Windows\System32\SetupApi.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool SetupDiGetDeviceInterfaceDetail(
SafeHandleZeroOrMinusOneIsInvalid deviceInfoSet,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
IntPtr deviceInterfaceDetailData,
uint deviceInterfaceDetailDataSize,
IntPtr requiredSize,
IntPtr deviceInfoData);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public UInt32 cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DevicePath;
}
Currently, I am allocating memory with Marshal.AllocHGlobal() and writing/reading data from that buffer using the Marshal.* family of functions.
For reference, this is what I'm doing:
public string GetPathToDevice(SafeHandleZeroOrMinusOneIsInvalid hDevList,
SP_DEVICE_INTERFACE_DATA devIntfData)
{
uint sizeNeeded = 0;
// get's the size needed
SetupApi.SetupDiGetDeviceInterfaceDetailData(hDevList,
ref devIntfData,
IntPtr.Zero,
0,
ref sizeNeeded,
IntPtr.Zero);
IntPtr pBuffer = Marshal.AllocHGlobal((int)(sizeNeeded + 4)); // +4 for cbSize
SetupApi.SetupDiGetDeviceInterfaceDetailData(hDevList,
ref devIntfData,
pBuffer,
sizeNeeded,
IntPtr.Zero,
IntPtr.Zero);
// copy bytes from unmanaged space in pBuffer to a manged byte array
// free unmanaged memory
return theStringParsedFromByteArray;
}
As I mentioned, I've tried defining a structure as outlined by PInvoke.net for SP_DEVICE_INTERFACE_DETAIL_DATA (see above link) and made a new PInvoke method signature to handle that. When running from the 64-bit system, I get the same issue, i.e. the function returns 1784. The reason seems to be that references in C#, when running in a 64-bit runtime, are 8-byte aligned (found that in another StackOverflow article). I've tried various layouts to that structure trying to force the layout (using explicit and field offset) to a 4-byte aligned struct, but that didn't work for me either. I had compile time problems.
I have tried using various decorations to the PInvoke method sigature parameters. Such as, MarshalAs(UnmanagedType.LPStruct) to which I'm continually pairing improperly. I'm now to the point that I need help with this.
What I really don't understand is why it's happening at all. Even if it does work on my box when running in a 32-bit runtime, wouldn't a 64-bit runtime simply connect me to the correct 64-bit versions of the Setup API? What's the problem?
Thanks for any help,
Andy
Problem is solved
The good thing is, it's solved now, the irritating thing is I don't like fixing things within an hour or two of posting here. So, the problem was indeed that it was a 64 bit issue. The error code from Marshal.GetLastWin32Error() was telling me the problem. The cbSize value was incorrect. I changed it to 8 and everything works now.
Please, someone, explain to me why the size is now 8 on 64 bits? The structure is now above (a commenter asked me to include it). The structure consists of two members, a single DWORD and a TCHAR[ANYSIZE_ARRAY]. ANYSIZE_ARRAY evaluates to 1, TCHAR is always a WCHAR if Unicode and a char otherwise. A DWORD is always a 32-bit quantity (4 bytes) and a single TCHAR for Unicode is 2 bytes. So, 4 + 2 = 6. Why is it 8? Is this because of byte alignment for that structure in 64-bits? I'd really like to understand this.
At any rate, setting the cbSize member to 8 for 64 bit, and 6 for 32 bit, works and I'm able to use the structure defined above instead of the raw memory allocating/deallocating and marshaling.
I also fell over this problem, because i copied the code from this answer: https://stackoverflow.com/a/2937588/1070906
which has an error in the struct definition.
Maybe you did the same mistake.
Looking at the definition of SP_DEVINFO_DATA at http://msdn.microsoft.com/en-us/library/windows/hardware/ff552344(v=vs.85).aspx it's last parameter is a pointer, not an uint as in the other post.
Since i changed the struct definition to:
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
/// <summary>Size of the structure, in bytes.</summary>
public uint cbSize;
/// <summary>GUID of the device interface class.</summary>
public Guid ClassGuid;
/// <summary>Handle to this device instance.</summary>
public uint DevInst;
/// <summary>Reserved; do not use.</summary>
public IntPtr Reserved;
}
it works!
Marshall.SizeOf(new SP_DEVINFO_DATA ()) returns 32 now instead of 28 and my serial ports are shown.
This is the first time ever that I'll be using SafeHandle.
I need to call this P/Invoke method that needs an UIntPtr.
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(
UIntPtr hKey,
string subKey,
int ulOptions,
int samDesired,
out UIntPtr hkResult);
This UIntPtr will be derived from .NET's RegistryKey class. I will be using the method above to convert the RegistryKey class to an IntPtr so I can use the above P/Invoke:
private static IntPtr GetRegistryKeyHandle(RegistryKey rKey)
{
//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
if (fieldInfo != null)
{
SafeHandle handle = (SafeHandle)fieldInfo.GetValue(rKey);
//Get the unsafe handle
IntPtr dangerousHandle = handle.DangerousGetHandle();
return dangerousHandle;
}
}
Questions:
Is there a better way to write this without using "unsafe" handles?
Why are unsafe handles dangerous?
The RegistryKey has a handle property. So you can use
private static IntPtr GetRegistryKeyHandle(RegistryKey rKey)
{
return rKey.Handle.DangerousGetHandle();
}
This is potentially dangerous, because the pointer you are getting may not be valid anymore when you are using it. Quote from MSDN
Using the DangerousGetHandle method can pose security risks because, if the handle has been marked as invalid with SetHandleAsInvalid, DangerousGetHandle still returns the original, potentially stale handle value. The returned handle can also be recycled at any point. At best, this means the handle might suddenly stop working. At worst, if the handle or the resource that the handle represents is exposed to untrusted code, this can lead to a recycling security attack on the reused or returned handle. For example, an untrusted caller can query data on the handle just returned and receive information for an entirely unrelated resource. See the DangerousAddRef and the DangerousRelease methods for more information about using the DangerousGetHandle methodsafely.
What you are doing is in fact dangerous. The RegistryKey object you use can get garbage collected and finalized while you are using the IntPtr. Which makes the handle value invalid which makes your code randomly fail. Well, okay, random failure is not exactly dangerous but it does open the door to a handle recycle attack if you in fact keep a hold of the handle for an extended period of time. The random failure mode ought to be enough to inspire you to do something about it.
Make your pinvoke declaration look like this:
[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
internal static extern int RegOpenKeyEx(SafeRegistryHandle key, string subkey,
int options, int sam, out SafeRegistryHandle result);
So you can consistently use the safe handle wrapper class. Adjust the reflection code accordingly.
First a background question:
In general, what is the difference between int and IntPtr? My guess is that it is an actual object rather than a value like an int or byte is. Assuming that is true:
So they are not the same. Yet I see handles represented as both.
IntPtr: Control.Handle
int (or uint): A PInvoke can be setup to return an int and it works just fine:
[DllImport("coredll.dll", SetLastError = true)]
public static extern int GetForegroundWindow();
private string GetActiveWindow()
{
const int nChars = 256;
int handle = 0;
StringBuilder Buff = new StringBuilder(nChars);
handle = CoreDLL.GetForegroundWindow();
if (CoreDLL.GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return "";
}
So, int vs IntPtr? Does it matter for handles? Can you use either?
int is 32 bits long. IntPtr is as long as a pointer for your architecture. Therefore, a pointer can be stored into an int only on 32 bit systems, while it can always be stored in an IntPtr.
Notice that your "int as a return value" example does not use an int to hold a pointer, but just to hold a numeric value. This does not mean that an int is automatically the correct size though: the author of that P/Invoke signature should have gone to the documentation for GetForegroundWindow and see that it returns a HWND.
Then, from windef.h in the Platform SDK (or this MSDN page) we can see that a HWND is a HANDLE which is a PVOID which is... a pointer!
Therefore, as far as I can tell, that signature is wrong, as the size of the return value of GetForegroundWindow depends on the architecture. Thus, it should also be an IntPtr.
Update:
While it can be inferred from the above, I think it's worthwhile to explicitly point out that:
Erroneously using int instead of IntPtr in 32-bit applications will never cause a problem, even if they run on 64-bit Windows; since most applications are 32-bit at this point in time, this will let you get away such mistakes very often.
Erroneously using int instead of IntPtr in 64-bit applications is not guaranteed to cause problems, since it is quite possible that in practice the values being encountered will fit in the 32 bits of the int. This further lessens the probability that a mistake will manifest as an application error.
Therefore, for an error to actually manifest there are three conditions that have to be satisfied at the same time:
An int is used where an IntPtr should be.
The executable image is 64-bit.
A value returned by some PInvoke call and stored as an int is actually larger than 32 bits.
I have a Window handle Picker and it says my handle is 0094167C.
When I declare the variable in c# the letter in this code gives an error.
How to declare?
public const IntPtr WinHandle = 0094167C;
You know that the handle will typically change with each application and/or system start? This means your constant is subject to failure anyway.
If, however, you really want to assign a constant other than zero to an IntPtr (which would be IntPtr.Zero), the documentation states that there are constructors that take Int32, Int64 or Void* as parameter.
As OregonGhost points out you probably don't want to do that for a windows handle. However, for a IntPtr in general, what you can do is this static readonly fields:
static readonly IntPtr TenK = new IntPtr(1024 * 10000);
I'd like to add to AgnosticOracle's answer.
In addition to constant-like static-readonly IntPtr/UIntPtr variables, you can use nint and nuint which are backed by IntPtr and UIntPtr, respectively.
These types can have integer and unsigned integer values assigned to them and can also be defined as constants.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#native-sized-integers