Using PInvoke with GDI+ just isn't an easy thing to do. System.Drawing.dll must have some *magic* I don't know about.
[Edit] Looks like the exception is actually from me being stupid and not realizing the full scheme for starting GDI+. Turns out you have to call GdiplusStartup and GdiplusShutdown, something that System.Drawing does for you automatically. Throwing this into the mix for my application below causes my NullReferenceException to disappear. So what is causing the failure over in ASP .NET land that my friend was seeing?
I've been playing with my ImageFast library lately. When I first used the library I compiled and loaded it into a project where I was also making use of the System.Drawing namespace. The library just worked, quickly loaded files without all of the validation crap, and enabled a much more responsive application. I tried importing the library into a stand-alone application today, and low and behold, it crashes out. Here is a simple repro scenario for me:
using System;
using System.Runtime.InteropServices;
public class LockImageAndLoad {
[DllImport("gdiplus.dll", CharSet=CharSet.Unicode)]
public static extern int GdipLoadImageFromFile(string filename, out IntPtr image);
private static void Main(string[] args) {
IntPtr pimg = IntPtr.Zero;
GdipLoadImageFromFile(args[0], out pimg);
}
}
Doesn't make sense that that would fail, but it does. I get a NullReferenceException which means GdipLoadImageFromFile isn't getting bound somehow. I'm taking the binding is failing because it can't find gdiplus.dll, and why should it, since gdiplus.dll is one of those special SOB's that doesn't exist in C:\Windows\System32 and is instead buried under C:\Windows\WinSxS.
Hum, so it is possible that a policy file could get me access to the old GDI+ I thought. I looked around for a policy file that would enable System.Drawing.dll to bind to GDI+ and I couldn't find one. I've given up on that. Just to prove System.Drawing.dll has some magical link, you can run the following code and it will work.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
public class LockImageAndLoad {
[DllImport("gdiplus.dll", CharSet=CharSet.Unicode)]
public static extern int GdipLoadImageFromFile(string filename, out IntPtr image);
private static void Main(string[] args) {
Bitmap b = new Bitmap(500, 500);
IntPtr pimg = IntPtr.Zero;
GdipLoadImageFromFile(args[0], out pimg);
}
}
I'll get to the bottom of this one way or another, but perhaps some others have experienced the problem. At least one of my friends has actually seen the NullReferenceException appear on his web server when trying to use GDI+ through System.Drawing.dll. That means even System.Drawing.dll might sometimes lose the magic required to resolve gdiplus.dll.
Oddly enough basic fixes simply don't seem to work. I can't add one of the GDI+ dll's to my path. I can't simply drop it into my program's running directory. Somewhere, something is happening that prevents me from gaining access to the library. There may be some hot-fix issues, I've always thought that might be the case. There are 3 versions of GDI+ installed in the WinSxS directories. I'd love for someone to point out how gdiplus.dll is getting resolved through the PInvoke implementation, why placing dll's in the current directory don't get loaded, and any number of other strange things that I've pointed out.