tags:

views:

613

answers:

2

When I create a signature that refers to user32.dll for example should I be building this with user64.dll if the target is a 64-bit computer?

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(
    IntPtr hWndRemove,
    IntPtr hWndNewNext);

Currently this isn't a problem as I'm targeting only 32-bit due to a library from a vendor (Progress OpenEdge) which only provide 32-bit libraries to access their database.

I don't currently have a 64-bit windows computer to see if this is the case.

+4  A: 

Despite the naming convention, user32.dll (and other 32... dlls) are actually 64 bit on 64 bit machines. These are the historical names for the dlls, and have been kept that way regardless of the changes to the underlying architecture. Have a read of this page to get more details.

Pete OHanlon
My goodness gracious me, the way that page describes how the filesystems view changes between 64/32 bit applications is rather scary to see. Thank you very much for your answer Pete.
Brett Ryan
You're welcome. I'm glad to help.
Pete OHanlon
+2  A: 

You should not need to change the signature/name of the DLL that you link to when calling in to USER32.DLL functions.

Despite the naming convention, on a 64-bit Windows machine, the USER32.DLL file that sits in [Windows]\System32 is actually a 64-bit DLL. The real 32-bit version of USER32.DLL actually sits in a folder called [Windows]\SysWow64.

Please see this question for further info.

The one thing you'll probably need to be most careful of is the datatypes that you pass in as parameters to the various Windows API functions. For example, the "SendMessage" function within USER32.DLL has a specific requirement with at least one of it's parameters (according to the page on P/Invoke).

It's signature is:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

and notes 2 & 3 below clearly state:

2) NEVER use "int" or "integer" as lParam. Your code WILL crash on 64-bit windows. ONLY use IntPtr, a "ref" structure, or an "out" structure.

3) NEVER use "bool", "int", or "integer" as the return value. Your core WILL crash on 64-bit windows. ONLY use IntPtr. It's not safe to use bool - pInvoke cannot marshal an IntPtr to a boolean.

This "caveat" appears to be specific to this particular function (SendMessage), although it's something I would pay particular attention to when calling into any Windows API functions.

CraigTP
Thank you for that Craig, that's great. I have one question, why does `System.Windows.Forms.Message.Msg` have a type of `int`. Only asking because that would be used in `Msg` for `SendMsg`, previously in that same signature I had been using `int`.
Brett Ryan
@Brett - That's good question, and I don't know the exact answer, however, it may be to do with the fact the SendMessage signature takes the Msg param as a UInt32, and a .NET Int is always 32bits (irrespective of underlying windows platform), whereas an IntPtr structure is designed to reflect the underlying windows platform (i.e. it's a 32 bit structure on 32bit Windows, but a 64bit structure on 64bit Windows). Must admit, this is just a guess on my behalf. I'd be interested to know the exact answer myself.
CraigTP
Yeah, I figured that; the interesting thing however, is that it is a `int` and not a `uint` since `UInt32` and `Int32` have different upper/lower bounds, however, anyone sending something outside of 0 - Int32.MaxValue would be in error anyway. Just an observation really :)
Brett Ryan
@Brett @Craig The difference is that uint is not a CLR type, while int is.
Daniel Rose