April 6, 2008

.NET managed printing - a real slug

At my work we have had a document rendering and printing service for a while.
The service first renders those Reporting Services reports in a queue and then prints them out when needed.
The printing classes of the service I wrote in 100% managed C#. At that time I was not aware of the peroformance penalties that the PrintDocument class had.
Everything began when my boss assigned me a task for implementing new features in our existing printing service for the newly purchased and very advanced printers. Firstly, the users should have a "follow me" function. Then, the serive must handle to printing to pre-defined media type(s), rather than to a specific paper tray.

The .NET framework does not provide the posibility to print to a specified media type since that functionality is device-dependent, so I started my research work by contacting Ricoh, the printer manufacturer. I got the API and the device driver to communicate with the printer devices.
After translating thousands of lines of code from C/C++ to C# I could build an assembly that I could use to select the Ricoh user defined media types. Partial success! But I would be dissapointed by the way .NET differs between managed Enhanced Metafile handles from unmanaged ones. Just EMF handles, I thought. Soon I realized that I could not use the Enhanced MetaFile handle, obtained by a call to the GetHenhmetafile method of the MetaFile class to be passed as a parameter to the PlayEnhMetaFile API function. By the way, I discovered a bug in the MetaFile class and submitted it to Microsoft.

Finally, in order to get my new classes work properly I had to make several calls to undocumented GdiPlus functions, mix some data in unsafe contexts and wrap some API native functions. After all, a document that took 113 seconds to be printed is now ready after 11 seconds. Unbelievable, 10 times faster!!!

Now we have a printing service that works in turbo mode and Ricoh will get the complete API code for the .NET framework free of charge so other developers rapidly can use it in their .NET projects.