Any CPU P/Invoke With C# "Unions": Part One

C Unions For Not C Developers

I was playing around with the Windows API SendInput() method from the User32.dll the other day and the damn thing would not work on my primary 64 bit Windows Development machine. I would boot into 32 bit Vista and everything would work as I expected. I would load the app on 32 bit XP and, again, everything worked as expected. I did some forum searching and the most helpful thing I found was a post telling another user with the same problem that it was a UPI (?) issue in Vista and their app (even though being run as administrator) just didn't have the permissions necessary for SendInput to do its thing. SendInput is documented to not return an error when you run into a UPI issue, so that explained why I was getting correct returns, but it seemed fishy that an elevated process would not have the privilege necessary to execute SendInput correctly.

Then I found it, but not specifically "it". The issue has to do with the way you have to spoof C++ Unions in C# and the bitness of the OS.

First a little background.

In C/C++ there are unions. Unions allow you to have a structure with a data member that is either/or among a number of different structures. This is possible because of the pointer math abilities in C/C++. If you don't know what this means, don't fret.

struct Structure1
{
 int s1a;
 int s1b;
 int s1c;
};
struct Structure2
{
 int s2a;
 int s2b;
 int s2c;
};

struct Structure3
{
 int s3a;
 int s3b;
 int s3c;
};

union Structure
{
 Structure1 s1;
 Structure2 s2;
 Structure3 s3;
};

What we have here are three structures (Structure1, Structure2 and Structure3), they each contain 3 integers, but they are all labeled differently, however in memory they have the same layout; byte 0 of an instance of Structure1 is the first of 4 bytes that comprise an integer, as is byte 0 of Structure2 and byte 0 of Structure 3. Structures in C++ are laid out explicitly by default in memory (that's what LayoutKind.Explicit does in C#, maps the members of the struct to specific spots relative to the beginning of the struct in memory, more on this later). We also have a union called Structure. What this means is that Structure is big enough to hold any of these structs and you can use pointer arithmetic to get to the value (assuming you know what kind of value is stored. You can also refer to any member of Structure and it's corresponding child members.

#include <stdlib.h>
#include <stdio.h>
#include "structs.h"
int main()
{ 
 //An instance of the Union.
 Structure myStruct;

 //An instance of Structure1.
 Structure1 struct1;

 //Initialize the instance of Structure1.
 struct1.s1a = 0;
 struct1.s1b = 3;
 struct1.s1c = 6;

 //Initialize the Structure1 member of Structure.
 myStruct.s1 = struct1;

 //These should all print the same thing because
 //myStruct.s1 is the same memory as myStruct.s2, is the same
 //memory as myStruct.s3, and Structure1, Structure2, and 
 //Structure3 have the same layout in memory (int,int,int).
 printf("Struct1 a: %d\n",myStruct.s1.s1a);
 printf("Struct2 a: %d\n",myStruct.s2.s2a);
 printf("Struct3 a: %d\n\n",myStruct.s3.s3a);

 return 0;
}

In our example above we are setting only the Structure1 member of our Structure union and the values are actually the same for each member of the union (Structure2 and Structure3). If we add the following code before the end of the method you'll notice that any change applied to any member of union is applied to all members of the union at that memory location (in our case the 4th byte because s2b is the second integer in Structure2.)

//If we change the value of myStruct.s2.s2b to 2
myStruct.s2.s2b = 2;

//And then check the value of myStruct.s1.s1b, it should now 
//be 2.  That happens because s2.s2b in the union points to 
//the same location as s1.s1b in the union.
printf("Struct 1 b: %d\n", myStruct.s1.s1b);
printf("Struct 3 b: %d\n", myStruct.s3.s3b);

I hope you understand the concepts behind C Unions, if you are having trouble I would suggest copying the above code into C project, compile it, run it, change variables, add print statements following the basic format I've used and repeat to try to wrap your mind around unions. Even if you don't KNOW the first thing about C this will compile and should work with a little bit of effort. This is very important to understanding what is coming up next with the C# hoops you need to jump through to get a union construct to work with platform invoke, especially on x86 and x64 processors with only one executable.

Comments