Calling librsvg functions from C#

So i'm trying to make a C# wrapper around librsvg for a web app where we need to rasterize svgs on the server. Below is some simple test code I'm trying to get to working, but there's a few problems:
1.) After the call to rsvg_pixbuf_from_file_at_size, both the IntPtrs are still 0. One of them should be getting set to something, whether that is a GdkPixbuf* or a GError*, right?

2.) The call to gdk_pixbuf_save causes an AccessViolationException ("Attempted to read or write protected memory. This is often an indication that other memory is corrupt."). I would expect the function call to fail given that i'm not passing it a legit handle, but I'm still not sure why i'm getting that exception. The weird thing is that if I allocate some memory to that error IntPtr with Marshal.AllocCoTaskMem(), it stops this exception from being thrown, but the prototype of the function makes it look like it would be writing to that error pointer directly.

Any ideas?

Here's the prototype for rsvg_pixbuf_from_file_at_size():
GdkPixbuf*  rsvg_pixbuf_from_file_at_size   (const gchar *file_name,
                                             gint width,
                                             gint height,
                                             GError **error);

And here's the prototype for gdk_pixbuf_save():
gboolean            gdk_pixbuf_save                     (GdkPixbuf *pixbuf,
                                                         const char *filename,
                                                         const char *type,
                                                         GError **error,
                                                         ...);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool SetDllDirectory(string pathname);
 
        [DllImport("libgobject-2.0-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern void g_type_init(); 
 
        [DllImport("librsvg-2-2.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr rsvg_pixbuf_from_file_at_size(string file_name, int width, int height, out IntPtr error);
 
        [DllImport("librsvg-2-2.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr rsvg_handle_new();
 
        [DllImport("librsvg-2-2.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool rsvg_handle_write(IntPtr handle, byte[] buf, int count, out IntPtr error);
 
        [DllImport("libgdk_pixbuf-2.0-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error);  
 
 
        public static void RasterizeSvg(string fileName)
        {
            bool callSuccessful = SetDllDirectory("C:\\Program Files\\GIMP-2.0\\bin");
            if (!callSuccessful)
            {
                throw new Exception("Could not set DLL directory");
            }
            g_type_init();
            IntPtr error;
            IntPtr result = rsvg_pixbuf_from_file_at_size(fileName, 100, 100, out error);
            if (error != IntPtr.Zero)
            {
                throw new Exception(Marshal.ReadInt32(error).ToString());
            }
            callSuccessful = gdk_pixbuf_save(result,@"C:\test.png", "png", out error);
            if (!callSuccessful)
            {
                throw new Exception(Marshal.ReadInt32(error).ToString());
            }
        }

Open in new window

cacliffoAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

williamcampbellCommented:
1) IntPtr may not be the correct type what is the true definition of this function?
2) This error can be misleading it means an uncaught exception is being thrown ... turn on Exceptions  under "Debug /Exceptions" in the main menu and see what the exception is  ...
0
cacliffoAuthor Commented:
1.) The prototype is in my first post, the actual function just passes the error argument along to g_set_error() (a glib function) if there are any errors. Here's the documentation for that function:

void                g_set_error                         (GError **err,
                                                         GQuark domain,
                                                         gint code,
                                                         const gchar *format,
                                                         ...);

Does nothing if err is NULL; if err is non-NULL, then *err must be NULL. A new GError is created and assigned to *err.

So since i'm passing an IntPtr by reference, err should be non null and that IntPtr should be getting assigned to the address of a GError object (not that I can really do anything with that in C#).

2.) It was already set to break on all exceptions. I'm still getting the same one (AccessViolationException).
0
AgariciCommented:
most probably your pInvoke definitions and the way you pass parameters between C# and unmanaged have some bugs

please have a look at this site:http://pinvoke.net/
they have a custom visual studio add-in

also this one may be helpfull: http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120

hth,
A.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
cacliffoAuthor Commented:
Fixed. Basically I had to remove the CharSet attribute from the DllImport statement for rsvg_pixbuf_from_file_at_size (don't know why, though), and use C#'s undocumented __arglist keyword: http://community.bartdesmet.net/blogs/bart/archive/2006/09/28/4473.aspx

Working code attached.
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool SetDllDirectory(string pathname);
 
        [DllImport("libgobject-2.0-0.dll", SetLastError = true)]
        static extern void g_type_init(); 
 
        [DllImport("librsvg-2-2.dll", SetLastError = true)]
        static extern IntPtr rsvg_pixbuf_from_file_at_size(string file_name, int width, int height, out IntPtr error);
 
        [DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error, __arglist);
 
 
 
        public static void RasterizeSvg(string fileName)
        {
            bool callSuccessful = SetDllDirectory("C:\\Program Files\\GIMP-2.0\\bin");
            if (!callSuccessful)
            {
                throw new Exception("Could not set DLL directory");
            }
            g_type_init();
            IntPtr error;
            IntPtr result = rsvg_pixbuf_from_file_at_size(fileName, -1, -1, out error);
            if (error != IntPtr.Zero)
            {
                throw new Exception(Marshal.ReadInt32(error).ToString());
            }
            callSuccessful = gdk_pixbuf_save(result,@"C:\test.png", "png", out error, __arglist(null));
            if (!callSuccessful)
            {
                throw new Exception(error.ToInt32().ToString());
            }
        }

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.