170 likes | 292 Views
Lecture 11. Dynamic link libraries. Differences between static libraries and DLLs. In static library code is added to the executable. In DLL, the code is loaded when the program is loaded or at program request
E N D
Lecture 11 Dynamic link libraries
Differences between static libraries and DLLs • In static library code is added to the executable. • In DLL, the code is loaded when the program is loaded or at program request • DLL has special initialization function (DllMain), which is executed when the DLL is loaded or unloaded • In static library, every non-static function is accessible to applications • In DLL only exported functions are accessible to Applications
Advantages to using DLLs • Reusable code can be put in DLL and save disk space • Program resources can be put in DLL and enable translation of the program to different languages by only replacing the resource DLL • DLL can be modified without recompiling applications using this DLL. The only restriction is that exported function parameters, return values and order of exported functions cannot change (but new exported functions can be added)
Difficulties/problems in using DLLs • The application has access only to functions and variables exported from the DLL • functions that are not exported behave like static function in regular ‘lib’ file, they can only be accessed by functions in the DLL, they cannot be accessed by the application • DLL does not have access to variables and functions of the application. The data must be passed as function arguments • DLL and application share the same memory space, so it is possible to pass pointers from the application to the DLL. • The memory allocated by the DLL must be released inside the DLL.
DLL related tasks • Using DLLs • Implicit linking • Explicit linking • Using resources located in DLLs • Creating DLLs • Exporting functions from DLL • Adding resources to DLL
Using DLLs: implicit linking • Implicit linking is the easiest way of using DLL • All Windows API functions are inside system DLLs and applications implicitly link to them • Implicit linking requires special import library (normal library with .lib extension) • Import library should be shipped with the DLL (import libraries for system DLLs are included with Visual Studio)
Implicit linking example • Application that uses GetOpenFileName • must include Commdlg.h • must link with commdlg32.lib import library • When GetOpenFileName is called: • GetOpenFileName from import library is called • Import library loads commdlg32.dll • Import library calls function from the DLL
Implicit linking • With implicit linking, the functions are in fact in normal .lib files • Import libraries are very small, because they only load the DLL and execute the function from the DLL • If you don’t add import library to the project, you will get linker error: unresolved external symbol • If the DLL is not present when the application is running, the application will not start
Implicit linking • By default Visual C++ includes import libraries for system DLLs
When to use explicit linking • When you are not sure if the DLL will be present when your application is executed • When you are using resource only DLL (DLL that contains only resources and does not export any functions) • If you don’t know the name of the DLL (for example the name of the DLL is loaded from the configuration file)
Using resource DLLs • Load the DLL using LoadLibrary • LoadLibrary returns handle to the DLL • Use DLL handle to load resources from the DLL (instead of hInstance – application instance handle) • Every function that loads resources takes handle to application or DLL. The resources are loaded either from the .EXE file or from the .DLL file
Example: resource DLL HINSTANCE hResourceInstance = NULL; int APIENTRY WinMain( ... ) { MSG msg; HACCEL hAccelTable; hResourceInstance = LoadLibrary( "resource.dll" ); if ( !hResourceInstance ) { return FALSE; } // Initialize global strings LoadString(hResourceInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hResourceInstance, IDC_DLLTEST, szWindowClass, MAX_LOADSTRING);
Explicitly linking to the DLL HMODULE hDll = LoadLibrary( "DLL1.DLL" ); int (*pFunc)(); if ( hDll != NULL ) { pFunc = (int (*)())GetProcAddress( hDll, "exportedFunc" ); if ( pFunc != NULL ) { int res = pFunc(); } FreeLibrary( hDll ); }
Loading DLL explicitly • If the library cannot be loaded, our application can continue (the LoadLibrary function will fail), this is not possible with implicit linking, • We have to obtain function address using GetProcAddress function. This function can also fail (if such function is not found in DLL). • Function arguments and return value is not checked at compilation-time (it is also not checked at run-time, if you call exported function with wrong argument types, the results can be unpredictable) • In the example above, we locate the function by name. It is also possible to load the function by so called ordinal-number. In such case, you have to use the MAKEINTRESOURCE( ordinal_number ) instead of function name. Getting function address by ordinal numbers is faster than by name, but it requires that the ordinal number of the function does not change. • Once you get function address, you can call this function any number of times until you unload the library. • When you free the library and load it once more, you have to get function addresses one more time. When you unload the library, all internal DLL variables are lost.
Writing DLLs • Only exported functions can be called directly from your application. There are two ways to export a function: • you can use the dllexport directive, e.g: Only exported functions can be called directly from your application. __declspec( dllexport ) void ExportedFunc(); • you can put function name in the .DEF file. If you want to control ordinal numbers, than you should use the .DEF file. Otherwise, it is safe to use the dllexport directive. • DLL and the application are mapped into the same memory area, i.e. you can safely pass pointers from your application to DLL and from DLL to application. This also applies to functions: you can pass pointer to function from application to DLL and than call application function from DLL (or call DLL non-exported function from application if you have its address). • If two copies of DLL are used by two different applications at the same time, than each copy of the DLL is mapped to address space of its calling process, i.e. from the DLL you can only access memory of the application that loaded the DLL • General protection faults inside DLL will cause entire application to close
Sample DLL BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // This is an example of an exported function. extern “C” __declspec(dllexport) int exportedFunc(void){ return 0; }