Solved

Calling librsvg functions from C#

Posted on 2009-07-06
5
1,526 Views
Last Modified: 2013-11-25
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

0
Comment
Question by:cacliffo
  • 2
5 Comments
 
LVL 12

Expert Comment

by:williamcampbell
ID: 24788440
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
 

Author Comment

by:cacliffo
ID: 24788756
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
 
LVL 11

Accepted Solution

by:
Agarici earned 500 total points
ID: 24837782
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
 

Author Comment

by:cacliffo
ID: 24851507
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

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

861 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question