Boost logo

Boost :

From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2004-07-23 05:18:08


Vladimir Prus <ghost_at_[hidden]> writes:

>> 1) Often you need to write progams that need to work on different versions
>> of a particular OS, with later versions having additional API calls that
>> you could use.
>
>> void MyAPIStub()
>> {
>> static imported_function<void()> apiFunc( "ApiFunc", "OSLib" );
>>
>> if ( !apiFunc )
>> {
>> // do something here
>> }
>>
>> apiFunc();
>
> I think this is reasonable use case. I wanted something similiar recently. I
> have a library which calls user-provided 'userinit' function. To allow the
> user to not provide the function, the library has its own definition. So,
> when the library's version is called, it call 'dlsym' to find the 'next'
> definition of 'userinit' and if it exists, calls it.
>
> But I'm afraid this semantic (find the next definition of symbol) is
> Unix-specific. I'm not even sure if two symbols with the same names in
> different DLLs are allowed on Windows.

On Windows the symbols from each DLL are entirely independent. However, you
can specify at link time that certain symbols resolve to those from specific
DLLs --- e.g. C++ standard library synbols resolve to the C++ runtime DLL. If
you try and import the same symbol from two DLLs at link time, then there is a
name clash.

At runtime, you can get the address of a function in a DLL if you know the
name of the function (or its ordinal number) and the name of the DLL. This
allows you to have the same function implemented in many DLLs
(e.g. application plug-ins which all export the same names for use by the
application).

There is no concept of "next definition" --- you have to explicitly specify
the DLL to search for the symbol.

> I'm more interested in nice interface to declare plugins. For example, on
> Unix static initialisers in a library are run when it's opened, so you can
> do something like this:
>
> extern std::map<std::string, Codegen*> codegens;
> // defined somewhere in application
>
> class Codegen1 {};
> class Codegen2 {};
>
> RegisterHelper<Codegen1> X(codegens, "1");
> RegisterHelper<Codegen1> X(codegens, "2");
>
> But will this work for Windows? Can DLL have unresolved external references?
> Are static initializers run when DLL is opened?

When a DLL is opened, Windows will implicitly call the exported initialization
function. Whether or not your compiler uses this to run static initializers is
up to the compiler vendor.

You cannot have "unresolved" external references under Windows. You must
specify that a given symbol is found in a given DLL either at link time or at
runtime, as described above.

If you want to have a "codegens" variable used by all the DLLs, then you
probably ought to put it in a specific shared DLL, which is then referenced by
all the others.

e.g.

codegens.dll --- contains definition of codegens from above
mainapp.exe --- uses codegens from codegens.dll

plugin1.dll --- references codegens from codegens.dll
plugin2.dll --- references codegens from codegens.dll

HTH,

Anthony

-- 
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk