A 64-bit 32-bit Dilemma

I recently ran into an interesting situation that I was able to solve through code. The project was to create a document migration tool, something I’ve done many times, so it seemed pretty straightforward. I was moving documents and metadata from a 3rd party content management system to SharePoint 2007. I was developing on a 32-bit OS on a machine provided by my client. The source system had an API, albeit 32-bit COM. There was some example code in their SDK for VB6, so at least there was something. It was easy enough to create a .Net wrapper to that COM DLL and figure out the API. The SharePoint code was not too difficult either, something I’ve done before. In this case I had to use the API, not the web services because I wanted to keep the original file created/modified dates from the source system. You can’t set those using the web services. Therefore, the tool is forced to run on the SharePoint server (this is important factor for the upcoming dilemma). Luckily the source system was accessible remotely.

Works on My Machine

Of course, in my dev environment everything works great. So I copy my app to a SharePoint server to test in an environment more like production. It crashes immediately with a COM exception:

 Retrieving the COM class factory for component with CLSID {FDD9199A-1BB4-4433-B9E1-D550D3118676} failed due to the following error: 80040154.

What?? After a little research I determine the problem: the SharePoint server is 64-bit. My .Net code was compiled for any CPU, so it ran as 64-bit on the server, while it was 32-bit on my dev box. When compiled for 64-bit, it can’t access the 32-bit COM DLL (there might be a solution for this, I didn’t find it). I went back, and forced the code to compile for 32-bit. The app soared right past the error for the COM DLL, but came to a screeching halt when trying to access the SharePoint API. If SharePoint is installed on a 64-bit server, the code has to run compiled for 64-bit in order to access the API. Now you see the dilemma. I have to use a 32-bit only COM DLL and a 64-bit app for accessing SharePoint. I can’t skirt the issue using the SharePoint web services because I need functionality only available in the API.

My Solution

I decided on using two applications, one compiled for 32-bit which accesses the source system and fetches the data, and a second one compiled for 64-bit to access the SharePoint API. Five years ago I probably would have done the same thing, and write the data to an XML file from the first app, and then launch the second app and read the data from the file. There were hundreds of thousands of documents to migrate, all that disk access would be a performance killer. But now that I have WCF, I could do this much more elegantly.

32-64solution[1]

The 32-bit app contained the UI, and was able to use the 32-bit COM DLL to fetch documents and metadata. Once it had a logical set of data in memory, it used WCF with named pipes as the transport protocol to pass the data structure to the second app. The second app was 64-bit, and launched by the first app as a process using the System.Diagnostics namespace. It communicated just fine with the SharePoint API. The second app had no GUI, but I kept the console window for writing messages and to provide a way to manually exit the app in case things went awry. The first app kept a handle on the process that launched the second app, so that when a user closed the first app, it could close the second app for  the user.

WCF was a good fit for this dilemma. The only issue I encountered was managing the message size, because WCF expects you to configure a maximum size for that. Of course configuring WCF is not that easy, but you only have to do it once. I was pleased that I could make a mex endpoint in the 64-bit app, and then use Visual Studio to make a Service reference to it from the 32-bit app, and the configuration comes out for named pipes even though the mex endpoint was http. Another feature I didn’t know but managed to discover. In the end, the process is seamless to the user, and does what I need without much disk access to slow it down.