Archived

This topic is now archived and is closed to further replies.

Paradigm Shift 2000

DLL LoadLibrary() question

Recommended Posts

I''ve implemented some basic container-class file-loaders in a DLL for two reasons, to make them easier to upgrade, and so that the loader code is only loaded when it needs to be used and unloaded when it''s done. It seems like linking my projects to the import library satisfies the first condition, but the DLL is being attached when the application starts and detached when it ends, which is pretty typical behaviour, but not the behaviour I''m looking for. I was looking into the LoadLibrary() and FreeLibrary() functions for loading the DLLs on demand. I never programmed a DLL entry point into the DLL to begin with, and it has never given me a problem when using it with the import library. My question is this: If I use LoadLibrary() and FreeLibrary() to load the DLL, must I provide a DLL entry point, even if it does absolutely nothing? I suppose the cause behind this question refers to whether or not I can utilize my DLL the way it is with LoadLibrary() and FreeLibrary(), or must I recompile the DLL with an entry point? Paradigm Shift 2000

Share this post


Link to post
Share on other sites
gilady    122
Hi,
I believe you can compile a dll without an entry point (unless it is an MFC Dll which need the Dll main entry point). you must be aware that if you use any class/function that appear in the dll, directly, the project will link to the dll.
-- gilad

Share this post


Link to post
Share on other sites
synopsis    122
Hi,

What you want to do is loading the DLL dynamically, if I got that right, which means that you do not want to use a .lib-file. Well, it isn''t that hard:

The DLL has to _export_ functions if you want to use them in another program. (This is only partially correct, see later). To export a function, do the following:

  extern "C" __declspec(dllexport) void* __cdecl AnyFunction(void);  


Let''s go through this code step by step.
extern "C" tells the compiler not to use name mangling, a technique used by C++ to be able to resolve the correct function when overloading is used.

__declspec(dllexport) is MS-Specific, but DLLs are too. It tells the compiler to export the function.

void* is just an example return type, but note that it has to appear in front of the calling convention.

__cdecl tells the compiler to use the standard C-Calling convention. A calling convetion determines whether the caller or the called has to clear up the stack, and so forth, take it as is.

That function is then exported. To get it in your main Program, just do the following:

  
HMODULE hModule = LoadLibrary("mydll.dll");
void*(*PFNANYFUNCTION)(void) = 0;
PFNANYFUNCTION = GetProcAddress(hModule, "AnyFunction");


As it is somewhat annoying to type that stuff for every function you export, you can create an instance of class in your DLL, that is derived from a pure-virtual class (a class that contains pure virtual functions only). The main program does only have knowledge about that pure virtual class, so that it is not neccessary to have *anything* needed in the DLL given to the main program, things such as 3rd party libraries.

quote:

be aware that if you use any class/function that appear in the dll, directly, the project will link to the dll.


Well, depends on compiler I guess, but MSVC++ does not do this, if there is no dependency between the two projects. It just gives you an error, because the function is unknown. You may, of course, not use .lib-files or have the depencies set, because the dependencies use the lib file if neccessary.

Hope that helps.

Share this post


Link to post
Share on other sites
Well, you have to export the functions regardless when compiling the DLL even if you plan on using the import library, don''t you? All of my container classes are compiled with the __declspec(dllexport) storage class identifier, and included in my applications with a different header file which replaces it with __declspec(dllimport) so that it will automatically import the functions in the import library. My question was more one of usage than definition. See, how I understand it, if you compile your application with the import library, the application code automatically loads the library dynamically on application startup and releases it when the application closes. This is fine, but I want more control over when the library is loaded and released. This way, I only load code for the file-loader classes when they need to be used (at initialization time to attach the resources to my progam and when the resources need to be restored due to surfaces/buffers lost) and free them when I''m done using them, as opposed to loading the code at the beginning of the program and releasing it at the end.

I know I don''t need to provide a dll entry point if I use the import library, but do I need to provide a dll entry point in the DLL if I use LoadLibrary() to load the DLL instead?

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Actually, I have a slightly different question now. Let''s say I use LoadLibrary() to load the DLL that contains my file loader container classes and I want to create an empty instance of DDBITMAP and load in a .ddb file with its corresponding Load() function. Do I need to use GetProcAddress() to retrieve the addresses of the class member functions, and if so, how would I do this? The MSVC++ documentation is surprisingly sparse on this topic.

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Shannon Barber    1681
You would have to take the name mangling into account when loading the class methods from the dll, and manually reconstruct the v-tables to instance the class, to do it that way.

You want to do what PS2000 suggested, and make a dll export that instances a class and returns a pointer to it. Then you just need one common header with the class declaration in it to share between the program and the dll.

This is one of the things COM does, if you want to look into that after you understand how dynamic dll loading works. Crude&Rude ATL Tutorial found here

Share this post


Link to post
Share on other sites
Oh, wait a minute. I think I get it. You mean, I should create a function in the DLL that returns a pointer to a file-loader, so I don''t have to manually recreate the v-table for the file-loader class. Maybe something along these lines?

  
CFile* __declspec(dllexport) GetFileObject(unsigned long class_id)
{
switch(class_id)
{
case BMP:
CBmp * bitmap = new CBmp;
return bitmap;
case DDB:
CDdb * ddbitmap = new CDdb;
return ddbitmap;
case WAV:
CWav * wave = new CWav;
return wave;
default:
break;
}
return NULL;
}


I would still need to get the proc address of this function regardless, after loading the library. If I extern "C" {} the function, the compiler won''t mangle the name, so would this code work then:

  
typedef CFile* (__cdecl* LPFACTORYFUNC)(unsigned long);
HINSTANCE hdllmodule = LoadLibrary("fileload.dll");
LPFACTORYFUNC lpfnFactory = GetProcAddress(hdllmodule, "GetFileObject");
if(!lpfnFactory)
exit(1);
CBmp * bitmapfile = lpfnFactory(BMP);
bitmapfile.Load("foo.bmp");
// rectify bitmap image to surface

delete bitmapfile;
FreeLibrary(hdllmodule);


Paradigm Shift 2000

Share this post


Link to post
Share on other sites
S1CA    1418
Yep, similar to what we do with some of our stuff.

extern "C" gets a bit messy, much easier is to use a .DEF file:

  
LIBRARY MyDLLsName

EXPORTS
GetFileObject @1
AnotherFunction @2
AndYetAnotherOne @3

SECTIONS
.data READ WRITE


Call that file the same name as your DLL, but with a .DEF extension, then Add it to your ptoject. Voila - no mangled names for the exported functions in your def.

--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Share this post


Link to post
Share on other sites
Sturm    124
Just to add a question, the .def file works fine for functions, but how would you export a class? Or a pointer to the class inside the dll?

-- Sturm

Share this post


Link to post
Share on other sites