Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Calling librsvg functions from C#

Posted on 2009-07-06
5
Medium Priority
?
1,654 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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 1500 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

NEW Veeam Agent for Microsoft Windows

Backup and recover physical and cloud-based servers and workstations, as well as endpoint devices that belong to remote users. Avoid downtime and data loss quickly and easily for Windows-based physical or public cloud-based workloads!

Question has a verified solution.

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

Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
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 viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

597 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