Solved

Calling librsvg functions from C#

Posted on 2009-07-06
5
1,449 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

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…
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

762 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

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now