I want to P/Invoke to GetWindowLongPtr and SetWindowLongPtr, and I'm seeing conflicting information about them.
Some sources say that, on 32-bit platforms, GetWindowLongPtr is just a preprocessor macro that calls GetWindowLong, and GetWindowLongPtr doesn't exist as an entry point in user32.dll. For example:
So these sources seem to indicate that the *Ptr entry points simply aren't there in the version of user32.dll that ships with, say, 32-bit Windows 7.
But I see no indication of this in the MSDN documentation. According to MSDN, SetWindowLongPtr supersedes SetWindowLong, plain and simple. And according to the requirements section of the SetWindowLongPtr page, it appears that SetWindowLongPtr has been in user32.dll since Windows 2000 (both client and server editions). Again, no mention of the entry points being missing in 32-bit OSes.
I suspect that the truth is somewhere in between: that when you tell the C++ compiler to target older OSes (i.e., to compile something that will run on Win9x and NT4), then the header files declare SetWindowLongPtr as a macro that calls SetWindowLong, but the entry point probably does exist in Windows 2000 and later and you'll get it directly (instead of the macro) if you tell the compiler to target those platforms. But that's just a guess; I don't really have the resources or the knowhow to dig in and verify it.
It's also possible that the target platform plays a role -- that if you compile your app for the x86 platform, then you shouldn't call SetWindowLongPtr on a 64-bit OS. Again, I know enough to think of the question, but I don't know how to find the answer. MSDN seems to suggest that SetWindowLongPtr is always correct.
Can anyone tell me whether it's safe to simply P/Invoke to SetWindowLongPtr and be done with it? (Assume Windows 2000 and later.) Would P/Invoking to SetWindowLongPtr give me the correct entry point:
I'd recommend you deal with this the way Windows Forms does it internally:
public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex)
{
if (IntPtr.Size == 4)
{
return GetWindowLong32(hWnd, nIndex);
}
return GetWindowLongPtr64(hWnd, nIndex);
}
[DllImport("user32.dll", EntryPoint="GetWindowLong", CharSet=CharSet.Auto)]
private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint="GetWindowLongPtr", CharSet=CharSet.Auto)]
private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex);
C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
SetWindowLongPtr
/GetWindowLongPtr
._WIN64
is defined, they are functions; when it's not, they are #define
'd to SetWindowLong
/GetWindowLong
.This implies that 32-bit OSes may not have SetWindowLongPtr
/GetWindowLongPtr
as an actual function, so it would appear that the comment on pinvoke.net is correct.
Update (more clarification on _WIN64):
_WIN64
is defined by the C/C++ compiler when compiling 64-bit code (that will only run on a 64-bit OS). So this means that any 64-bit code using SetWindowLongPtr
/GetWindowLongPtr
will use the actual functions, but any 32-bit code using them will use SetWindowLong
/GetWindowLong
instead. This includes 32-bit code running on a 64-bit OS.
To emulate the same behavior in C#, I recommend checking IntPtr.Size
as done by pinvoke.net; that tells you whether you're running 32-bit or 64-bit code. (Keeping in mind that 32-bit code may run on a 64-bit OS). Using IntPtr.Size
in managed code emulates the same behavior as _WIN64
does for native code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With