[Mono-list] P/Invoke, Mono, .NET and Windows XP funny platform

Jonathan Pryor jonpryor at vt.edu
Fri Jun 10 07:29:28 EDT 2005


Your fundamental problem is that you're targeting Windows XP.

Ha ha only serious.  (A colloquialism for "that's funny, but I'm serious
too...")

The slightly longer explanation is here:

	http://www.mono-project.com/Interop_with_Native_Libraries#Windows_DLL_Search_Path

The real explanation is that Win32 is broken when it comes to supporting
multiple different versions of the "same" library.  Absolutely,
fundamentally, *broken*.  More to the point, it doesn't support this AT
ALL -- you can only have ONE version of any given library in use at any
point in time.

Win32 has three issues you're running into:

 1. No built-in versioning support for libraries, as noted above.
    Which is to say, if you load C:\Windows\System32\OLE32.dll, you 
    can't say that you want version 1 or version 2 of that library, 
    you get whichever version is at C:\Windows\System32\OLE32.dll.

 2. This doesn't mean you can't have multiple different versions 
    installed.  It just means that each different version needs to 
    reside in a different directory, which leaves you the option of
    (a) always specifying a full (or relative) directory for your
    library, or (b) accepting the default path and placing your library
    into an appropriate location.

    So if you didn't like Microsoft's OLE32.DLL, you could place a copy
    into your application's directory, and *that* one would get loaded.

    Alas, this means you can have the scenario you're describing, where
    both mono and your app bundle glib.  This is unfortunate, because of
    issue (3).

 3. Win32 doesn't keep track of the full path name to a library.  It 
    only remembers the basename of the library.

    Translation:  If you LoadLibrary() C:\mono\glib.dll, Win32 will know
    that it's loaded "glib.dll".  If you then LoadLibrary() 
    C:\yourapp\glib.dll, Win32 will hand you back a handle to 
    C:\mono\glib.dll, because they both share the same basename 
    (glib.dll) -- C:\yourapp\glib.dll is NOT loaded.

    Win32 doesn't operate on full paths.  This is a feature (in certain 
    contexts, anyway -- it's what allows you to provide your own version
    of OLE32.dll, or any other system library, and have it be used).

So, to answer your questions...

On Thu, 2005-06-09 at 19:23 +0200, Francis Brosnan Blázquez wrote:
> * Any application which p/invokes libraries that are also provided by
> mono must compile its native dll versions against the mono dll or it
> is posible to compile these ones against, for example, a glib not
> provided by the mono installer?

Is it possible?  Yes.  But to use your version of glib and not mono's
version, you'd need to alter the library search order for mono to ensure
it loads your version of glib and not mono's.

This probably is bad, because it will effect every application started
with mono, and your glib might not be compatible with mono's glib, which
would (likely) kill mono instantly.

So it's possible, but it's not advisable. :-)

Plus, it'll use extra disk space, so it would be nicer to use mono's
glib anyway...

Alternatively, name your glib.dll with a different basename, e.g. af-
arch-glib.dll, and rebuild all your libraries against this basename.

> * What happens if the mono runtime detects a P/Invoke over a library
> A.dll which depends on B.dll and then another P/Invoke over the
> library C.dll which depends on B'.dll knowing that B.dll and B'.dll
> are the same library but not the same file?

Mono isn't in control of library loading, Win32 is.  (Mono uses GLib's
g_module API, which in turn uses LoadLibrary().)

So, what would Win32 do?  It would load A.dll (as found through the
normal DLL search path), would look for and load B.dll (ditto), and when
C.dll was loaded it would see that B.dll was already loaded, and not
load a new one, so C.dll would get the *first* B.dll that was ever
loaded.

In short, don't do that. :-)

(I'm not entirely sure why this works for you on Linux either, unless
you depend on a different version of glib than mono does, in which case
you'd bring in a different .so-name.  However, given that Linux/ELF
doesn't require a symbol to come from a given library, and instead
matches a symbol reference to ANY MATCHING SYMBOL within the address
space, I fail to see how, if B.so.2 is already loaded, when C.so.1 is
loaded and brings in B.so.3, you could ensure that C.so.1 actually uses
the functions in B.so.3 and not B.so.2, since the dynamic linker should
find the B.so.2 symbols first...  Madness, I say. :-)

 - Jon




More information about the Mono-list mailing list