Interop und P-Invoke: Haarig, wenn mans richtig machen will


Thomas Wölfer
Thomas Wölfer

17. Februar 2005


Ich habe hier ja schon häufiger über P/Invoke geschrieben, und dabei auch Beispiele gebracht, wie man Windows APIs per P/Invoke von C# aus aufrufen kann. Im Fall der SendMessage() API sieht das wie folgt aus:

public static extern int SendMessage( IntPtr hWnd, System.Int32 msg, System.Int32 wParam, IntPtr lParam );

Nur - leider ist das nicht richtig. Beziehungsweise: Nicht ganz richtig. Lässt man die Sache so übersetzen und laufen, dann geht das ohne das geringste Problem. Im Code versteckt sich aber ein böses Problem für die Zukunft. Und diese Zukunft kommt in Form von Win64, also dem 64bit Windows daher.

Das Problem ist dabei die Tatsache, das der Code vermutlich auch einmal für Win64 übersetzt wird - und dann gibts Ärger. Parameter und Returnwert der SendMessage() API sind nämlich platformabhängig.

So, wie der Prototyp aber hingeschrieben ist, ist der Returnwert ein int (Int32). Und der ist auf der 64bit Platform 4 Byte breit , die native Deklaration der API unter Win64 besagt aber, das der Returnwert 8 Byte groß ist. Verdammt ärgerlich.

Um das zu lösen kann man das MarshalAs Attribut verwenden. Das geht dankbarerweise relativ einfach (auch wenn ich froh bin sowas nicht allzu oft zu brauchen). Die sowohl für Win32 als auch für Win64 korrekte Deklaration sieht folgendermassen aus:


public static extern IntPtr SendMessage( IntPtr hWnd, [MarshalAs(UnmanagedType.I4)]System.Int32 msg, IntPtr wParam, IntPtr lParam );