[Mono-list] InteropServices: DllNotFoundException...?

Jonathan Pryor jonpryor@vt.edu
Sun, 23 May 2004 00:01:32 -0400


On Thu, 2004-05-20 at 17:47, Simon Ask Ulsnes wrote:
<snip/>
> Of course, I'm using InteropServices to interact with a C library. I 
> made a few wrapper functions in the library, and the basic ones (such as 
> checking the library version and such) work well. But after I added the 
> latest (GetKeyNames and GetKeyXML), loading the library starts shouting 
> Exceptions - namely DllNotFoundException. Yes, the library is in place.

So, it worked at one point, but when you wrapped GetKeyNames and
GetKeyXML, *then* it started to fail?  Is this correct?

What's possible is that you're encountering the mix of two issues.  The
first issue is that, IIRC, when DllNotFoundException is thrown it only
contains the *initial* library that the runtime attempted to load, *not*
the actual library which couldn't found.

Meaning if libA.so depends on libB.so, libA.so is present but libB.so
isn't, DllNotFoundException will give the error stating that libA.so
couldn't be found.

I believe this will be fixed in the next release of Mono.

The second issue is basically the first: one of the dependent libraries
likely can't be found.

Run "ldd libsector.so", and make sure that *all* dependent libraries can
be found.

> I'm think I'm making a mistake in writing the C library part properly, 
> but what exactly is it I'm doing wrong?

I'm not entirely sure why you're seeing DllNotFoundException; see above
for a possible explanation.

However, there is another issue present: strings.  Your DllImport
declarations specify that System.String is the return type.  This will
cause the runtime to attempt to free the strings returned by those
functions.  IIRC, Mono will use g_free() to free that memory.  If those
strings weren't allocated by g_malloc(), this could lead to heap
corruption.

Even worse, it's not portable.  .NET uses CoTaskMemAlloc() and
CoTaskMemFree() to handle memory returned in this fashion, which I
assume GPGME won't be using.

The solution is simple: don't use strings.  Use System.IntPtr and use
System.Runtime.InteropServices.Marshal.PtrToStringAnsi():

	[DllImport("libsecstor.so")]
	private static extern IntPtr GetKeyNames();

	private static string RealGetKeyNames ()
	{
		IntPtr r = GetKeyNames ();
		string s = Marshal.PtrToStringAnsi (r);
		// Free `r' as appropriate
	}

If the string returned by GetKeyNames() is in UTF-8, you may need
alternate processing.  Seeing how Gtk# does this would be useful.

See http://www.jprl.com/~jon/interop.html for more information.

 - Jon