int vs IntPtr when you have a handle? - c#

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.

Related

Marshalling a complex structure from C# to C

I'm reading all about structure marshalling between C and C# in 64bit environment without success.
What I need to do is to pass the structure
typedef struct DescStructTa
{
char* pszNa;
unsigned long ulTId;
char* pszT;
unsigned short usRId;
unsigned long ulOff;
unsigned long ulSi;
char szAcc[2];
unsigned char bySSize;
} DescStruct;
from a C# application to a C DLL not made by us calling the method
MT_DLL_DECL long GetAll(UINTPTR ulHandler, DescStruct **ppList, unsigned long *pulNumS);
After long search I wrote the following code:
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct PlcSymbolDescStruct
{
[MarshalAs(UnmanagedType.LPStr)]
string pszNa;
UInt32 ulTId;
[MarshalAs(UnmanagedType.LPStr)]
string pszT;
[MarshalAs(UnmanagedType.U2)]
ushort usRId;
UInt32 ulOff;
UInt32 ulSi;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
string szAcc;
[MarshalAs(UnmanagedType.U1)]
byte bySSize;
}
[DllImport("DataSource.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.U8)]public static extern long GetAll(ulong ulHandler, out DescStruct [] ppList,
out uint pulNumS);
Unfortunately this is still giving me a heap corruption.
If I try to pack less than 8 it gives (as expected) an access violation, but I expected this to work and I'm not able to figure out what could be wrong.
Any suggestion?
Thanks in advance!
I’m not sure you need Pack = 8. The default packing appears to be more or less compatible between C# and C++.
The szAcc field probably uses Unicode. To switch, specify CharSet=CharSet.Ansi in your [StructLayout]
Finally, if your C API has that double pointer to the array of them, you have to allocate that memory in a special way, either CoTaskMemAlloc or LocalAlloc, forgot which one.
It’s easier, also more efficient, to implement 2 functions instead. One to obtain the required size of the array. Another one to write them into caller-allocated buffer, a single pointer in C++ as opposed to double pointer, and UnmanagedType.LPArray in C#.
Update
allocation should not be necessary since the documentation states that the call returns a pointer to it's internal data structure
The runtime doesn’t know what was written in that documentation, attempts to free anyway, and crashes. You can use out IntPtr in C# API, and marshal manually.
If you have modern .NET, use unsafe, cast the IntPtr to PlcSymbolDescStruct* raw pointer, and construct ReadOnlySpan<PlcSymbolDescStruct> from that raw pointer.
if you’re stuck with old desktop .NET, call Marshal.PtrToStructure<PlcSymbolDescStruct> in a loop, incrementing the pointer by Marshal.SizeOf<PlcSymbolDescStruct>() bytes between loop iterations. No need to use unsafe code in this case.

Difference between IntPtr and UIntPtr

I was looking at the P/Invoke declaration of RegOpenKeyEx when I noticed this comment on the page:
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.
This doesn't make much sense to me: both IntPtr and UIntPtr are supposed to represent pointers so their size should match the bitness of the OS - either 32 bits or 64 bits. Since these are not numbers but pointers, their signed numeric values shouldn't matter, only the bits that represent the address they point to. I cannot think of any reason why there would be a difference between these two but this comment made me uncertain.
Is there a specific reason to use UIntPtr instead of IntPtr? According to the documentation:
The IntPtr type is CLS-compliant, while the UIntPtr type is not. Only the IntPtr type is used in the common language runtime. The UIntPtr type is provided mostly to maintain architectural symmetry with the IntPtr type.
This, of course, implies that there's no difference (as long as someone doesn't try to convert the values to integers). So is the above comment from pinvoke.net incorrect?
Edit:
After reading MarkH's answer, I did a bit of checking and found out that .NET applications are not large address aware and can only handle a 2GB virtual address space when compiled in 32-bit mode. (One can use a hack to turn on the large address aware flag but MarkH's answer shows that checks inside the .NET Framework will break things because the address space is assumed to be only 2GB, not 3GB.)
This means that all correct virtual memory addresses a pointer can have (as far as the .NET Framework is concerned) will be between 0x00000000 and 0x7FFFFFFF. When this range is translated to signed int, no values would be negative because the highest bit is not set. This reinforces my belief that there's no difference in using IntPtr vs UIntPtr. Is my reasoning correct?
Fermat2357 pointed out that the above edit is wrong.
UIntPtr and IntPtr are internal implemented as
private unsafe void* m_value;
You are right both simply only managing the bits that represent a address.
The only thing where I can think about an overflow issue is if you try to perform pointer arithmetics. Both classes support adding and subtracting of offsets. But also in this case the binary representation should be ok after such an operation.
From my experience I would also prefer UIntPtr, because I think on a pointer as an unsigned object. But this is not relevant and only my opinion.
It seems not make any difference if you use IntPtr or UIntPtr in your case.
EDIT:
IntPtr is CLS-compliant because there are languages on top of the CLR which not support unsigned.
This, of course, implies that there's no difference (as long as someone doesn't try to convert the values to integers).
Unfortunately, the framework attempts to do precisely this (when compiled specifically for x86). Both the IntPtr(long) constructor, and the ToInt32() methods attempt to cast the value to an int in a checked expression. Here's the implementation seen if using the framework debugging symbols.
public unsafe IntPtr(long value)
{
#if WIN32
m_value = (void *)checked((int)value);
#else
m_value = (void *)value;
#endif
}
Of course, the checked expression will throw the exception if the value is out of bounds. The UIntPtr doesn't overflow for the same value, because it attempts to cast to uint instead.
The difference between IntPtr\UIntPtr is the same as the differences found between: Int32\UInt32 (ie, it's all about how the numbers get interpreted.)
Usually, it doesn't matter which you choose, but, as mentioned, in some cases, it can come back to bite you.
(I'm not sure why MS chose IntPtr to begin with(CLS Compliance, etc,.), memory is handled as a DWORD(u32), meaning it's unsigned, thus, the preferred method should be UIntPtr, not IntPtr, right?)
Even: UIntPtr.Add()
Seems wrong to me, it takes a UIntPtr as a pointer, and an 'int' for the offset. (When, to me, 'uint' would make much more sense. Why feed a signed value to an unsigned method, when, more than likely the code cast it to 'uint' under the hood. /facepalm)
I would personally prefer UIntPtr over IntPtr simply because the unsigned values match the values of the underlying memory which I'm working with. :)
Btw, I'll likely end up creating my own pointer type(using UInt32), built specifically for working directly with memory. (I'm guessing that UIntPtr isn't going to catch all the possible bad memory issues, ie, 0xBADF00D, etc, etc,. Which is a CTD waiting to happen... I'll have to see how the built in type handles things first, hopefully, a null\zero check is properly filtering out stuff like this.)

Marshalling dynamic structures in 32 and 64 bit runtimes

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.

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

Convert/Port PDWORD code in C#

I'm converting some code from C++ to C#, and I need some insight on how to deal with lines like these:
PDWORD rgb32_data = (PDWORD) malloc(640*480*4);
From what I understand, the PDWORD type represents an unsigned integer (32bit). What would be a good C# strategy to implement a similar structure?
EDIT: I figured out that I need to use an IntPtr to replace the PDWORD, but the IntPtr would hold a single value as opposed to many values as in an array. Any C# suggestions?
EDIT2: Uint[]s don't work for me - unfortunately, the only way I can make the program compile, with all its dependencies, is when I enter an IntPtr as a the argument, not an IntPtr[].
Thanks.
EDIT - I've marked the solution, in addition I needed to do the following:
Since I needed an IntPtr cast, I added this code
IntPtr rgb32_ptr;
GCHandle handle = GCHandle.Alloc(rgb32_data, GCHandleType.Pinned);
try
{
rgb32_ptr = handle.AddrOfPinnedObject();
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
to get an IntPtr to the same.
According to MSDN, PDWORD is defined as:
typedef DWORD* PDWORD;
So it's a pointer to a DWORD, which MSDN also says is an unsigned 32-bit integer - in other words, a uint.
Note that your line of C++ code allocates memory for an array of 640 * 480 = 307,200 DWORDs.
You could translate this directly as:
uint[] rgb32_data = new uint[640 * 480];
But the code might really want to use it as just a series of bytes in memory, so you might instead want to use a byte array
byte[] rgb32_data = new byte[640 * 480 * 4];
and use the methods in the BitConverter class (especially the ToInt32() method) if you think that is closer to how the original program handles the data.
You can use unsafe pointers and Marshal.AllocHGlobal()
Program()
{
unsafe
{
IntPtr ptr = Marshal.AllocHGlobal(640 * 480 * 4);
uint* ptr2 = (uint*)ptr.ToPointer();
for (int i = 0; i < 640*480; i++)
{
ptr2[i] = 0;
}
Marshal.FreeHGlobal(ptr);
}
}
PDWORD is a pointer to a 32-bit unsigned integer. In C#, that would be ref uint32. Or IntPtr if you're on the 32-bit runtime.
It depends on how you're going to use it. If you're passing it to unmanaged code, then I'd suggest the ref UInt32. If you're using it for memory allocation (the return value from a Windows API function that allocates memory, for example), then you'd want to use IntPtr.
PDWORD is a pointer to a DWORD. There are a few options to convert the code to C# depending on how it will be used.
For the DWORD itself you can use System.UInt32 as an equivalent. Marshal.AllocHGlobal might be a possibility as a replacement, but we would need to see how it's going to be used. Are you accessing the memory yourself or maybe passing it to another unmanaged function?

Categories

Resources