Wednesday, March 17, 2010

Marshal double dereferenced strings in C#

I have been working on some interesting bits and pieces of software that involve the use of C# on Windows Mobile. Specifically, I am using the DMProcessConfigXML() function call to feed an XML provisioning document in to Windows Mobile to change settings on the device.

Today I ran across the need to make full use of the function to query existing settings. To date, I had only pushed data in, I didn't have a need to actually read anything back out.

Where is where it gets fun. The data that is returned is defined as "LPWSTR* ppszwXMLout". Marshaling simple data types in C# isn't terribly hard, but a pointer to a pointer!? Such things are the crazy constructs of a C programmer! After digging around, I found a sample on jaredpar's blog that showed how to marshal a double dereferenced pointer to an integer. I figured getting a string would be similar, except the final step would be to marshal a string, instead of an int. Lucky for me, it really is that simple.

For more on the gory details, I would suggest clicking on the list to jaredpar's blog. He describes the details well, so I won't bother repeating his work. Instead, here is a quick bit of code that shows the difference for dealing with a string instead of an int :


public void queryProxyData()
{
IntPtr outptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
string query = "";

if (DMProcessConfigXML(query, 1, outptr) == 0)
{
// See if we can demarshal that crazy thing!
IntPtr newPtr = (IntPtr)Marshal.PtrToStructure(outptr, typeof(IntPtr));
string xmlData = Marshal.PtrToStringUni(newPtr);
Debug.WriteLine(xmlData);
Marshal.FreeHGlobal(newPtr);
}

Marshal.FreeHGlobal(outptr);
}


Pretty simple, huh? I can safely say this is a much better solution that a previous one that I found!

Friday, March 12, 2010

Well, isn't this QT... (Building 64-bit binaries on Windows 32-bit)

For a project that I work on, we have a 32-bit build "server" running on Windows XP Professional. We are starting to expand this project to support 64-bit systems. No problem, right? Visual Studio has cross-compilers for x64 machines. So, we can still use our 32-bit system to build 64-bit binaries.

Umm.. Sure... Something like that.. I spent a rather long weekend trying to figure out how to do this very thing. The problem that I ran in to is the UI for the project uses the QT libraries.

I started off trying to build the x64 QT libraries using the x64 compilers on a Windows XP development machine. I didn't get very far in the process before I hit a dead end. The build would bail out when it attempted to run qmake.exe. After beating my head on it for a bit, I realized that the build system that QT uses expects to compile tools like qmake, and then execute them to complete the rest of its build process. So, the build process would build qmake for the x64 architecture, then attempt to run it, which obviously wouldn't work. (Remember, I was on a 32 bit system.)

I suspect that someone that wanted to badly enough could work around this with various types of trickery. But, I happened to have an x64 machine kicking around my house, so I just built it on that machine, and then decided to try to move it to the 32-bit build system. The x64 build went smoothly when it was done on an x64 machine. (Imagine that!)

Of course, once I moved my shiny new x64 libraries over to the Windows XP build machine, nothing worked. It didn't work because all of the .exe files that were used to handle the QT magic were 64 bit binaries! So, to get things working, I had to find a way around it.

Since the tools that are used in compiling QT programs basically take some type of data (usually XML) and translate it to code that can be compiled. The code that is generated is nothing more than a text file that is then fed in to a compiler. So, it seemed that I might be able to replace some of the .exe files that QT was attempting to call, and end up with something that worked, even if it was something the QT guys would turn up their noses at.

My first attempt was to copy all of the .exe files from the /bin/ directory of a 32-bit install over the .exe files in the /bin/ directory of the 64-bit install. After doing this, I kicked off a build and waited to see what blew up so I could figure out how to fix it. To my surprise, the project built without complaining.

I figured it couldn't POSSIBLY be THAT easy. But, it looks like it is. The binary that was built seems to work on x64 versions of Windows when cross-compiled from a 32-bit version of Windows.