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.

Published Thursday, May 13, 2004 10:29 PM by Justin Rogers
Filed under: ,

Comments

Monday, May 17, 2004 8:26 AM by TrackBack

# NullReferenceException = LoadFromFile( ... ) ;

Monday, May 17, 2004 3:44 PM by Nat

# re: Using PInvoke with GDI+ just isn't an easy thing to do. System.Drawing.dll must have some *magic* I don't know about.

using System;
using System.Runtime.InteropServices;
using System.Threading;

[StructLayout(LayoutKind.Sequential)]
struct StartupInput
{
// Fields
public int GdiplusVersion;
public IntPtr DebugEventCallback;
public bool SuppressBackgroundThread;
public bool SuppressExternalCodecs;

// Methods
public static StartupInput GetDefault()
{
StartupInput s = new StartupInput();
s.GdiplusVersion = 1;
s.SuppressBackgroundThread = false;
s.SuppressExternalCodecs = false;
return s;
}

}

[StructLayout(LayoutKind.Sequential)]
struct StartupOutput
{
// Fields
public IntPtr hook;
public IntPtr unhook;

}

public class LockImageAndLoad
{
[DllImport("gdiplus.dll", CharSet=CharSet.Unicode)]
public static extern int GdipLoadImageFromFile(string filename, out IntPtr image);

[DllImport("gdiplus.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
private static extern int GdiplusStartup(out IntPtr token, ref StartupInput input, out StartupOutput output);

[DllImport("gdiplus.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
private static extern void GdiplusShutdown(IntPtr token);

private static void Main(string[] args)
{
IntPtr ptr1;
StartupOutput output;
StartupInput input = StartupInput.GetDefault();
GdiplusStartup(out ptr1, ref input, out output);
try
{
IntPtr pimg = IntPtr.Zero;
GdipLoadImageFromFile(@"c:\windows\Rhododendron.bmp", out pimg);
}
finally
{
GdiplusShutdown(ptr1);
}

}
}
Monday, May 17, 2004 6:05 PM by Justin Rogers

# re: Using PInvoke with GDI+ just isn't an easy thing to do. System.Drawing.dll must have some *magic* I don't know about.

Yeah, I quickly figured that out and posted the more complete ImageFast library.

http://weblogs.asp.net/justin_rogers/articles/131704.aspx
Wednesday, March 24, 2010 10:18 AM by Caimile

# re: Using PInvoke with GDI+ just isn't an easy thing to do. System.Drawing.dll must have some *magic* I don't know about.

Badly need your help. Thanks, keep up the good work. Help me! Need information about: Ingredients in alavert. I found only this - <a href="genericalavert.info/.../">alavert pregnant</a>. Alavert, petersburg in the sun of the view of the tauride palace. Alavert, dane fletcher is the happy bay on trial and instructions. Waiting for a reply :rolleyes:, Caimile from Slovakia.

Leave a Comment

(required) 
(required) 
(optional)
(required)