Win32 Programming Lesson 20: Advanced DLL Techniques Where are we? We’ve looked at DLLs from a build/link/execute perspective But there are many different tricks you can use to get more “bang for your buck” Explicit DLL Loading To use a DLL, a process must load it We’ve looked at doing this implicitly via load and runtime and building in the calls Can be done when the application is running too The beauty of this technique is that you don’t need to know too much about the DLL at compile time Explicit Loading Simple to accomplish via LoadLibrary: HINSTANCE LoadLibrary(PCTSTR pszDLLPat hName); HINSTANCE LoadLibraryEx( PCTSTR pszDLLPathName, HANDLE hFile, DWORD dwFlags); HINSTANCE is a pointer to the virtual memory where the DLL is mapped Parameters hFile: Reserved for future use – must be NULL dwFlags: combination of DONT_RESOLVE_DLL_REFERENCES, LOAD_LIBRARY_AS_DATAFILE, and LOAD_WITH_ALTERED_SEARCH_ PATH Implications DONT_RESOLVE_DLL_REFERENCES LOAD_LIBRARY_AS_DATAFILE Don’t execute DllMain or automatically load other DLLs needed by this one Useful if you want to load an .exe file without executing it LOAD_WITH_ALTERED_SEARCH_ PATH Changes the order in which directories are searched in order to load the DLL Explicitly unloading the DLL BOOL FreeLibrary(HINSTANCE hInstanceDLL); And also: VOID FreeLibraryAndExitThread( HINSTANCE hinstDll, DWORD dwExitCode); Why? And of course, this is all predicated on usage counts… Other Explicit calls Can check to see if a DLL is already loaded via: HINSTANCE GetModuleHandle(PCTSTR pszModuleNa me); Would use like this: HINSTANCE hinstDll = GetModuleHandle("MyLib"); // DLL extension assumed if (hinstDll == NULL) { hinstDll = LoadLibrary("MyLib"); // DLL extension assumed } You can also… Get the full path of a loaded DLL DWORD GetModuleFileName( HINSTANCE hinstModule, PTSTR pszPathName, DWORD cchPath); Second Once a DLL has been explicitly loaded you need to get the address of the functions you want FARPROC GetProcAddress( HINSTANCE hinstDll, PCSTR pszSymbolName); Where pszSymbolName is either: The name e.g. “MyFunc” The resource number MAKEINTRESOURCE(2) Warning! If you use the name, it can be slow, as you must search through the names of all exported things If you use the second function, GetProcAddress can return a non NULL value even though it has failed… DLLs (startup) A DLL can have a DllMain function which is called upon startup This routine isn’t required – you implement it if you need it Note the name is case sensitive. If you use DLLMain you’re not going to get called Code Example BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad ){ switch (fdwReason) { case DLL_PROCESS_ATTACH: // The DLL is being mapped into the process's address space. break; case DLL_THREAD_ATTACH: // A thread is being created. break; case DLL_THREAD_DETACH: // A thread is exiting cleanly. break; case DLL_PROCESS_DETACH: // The DLL is being unmapped from the process's address space. break; } return(TRUE); // Used only for DLL_PROCESS_ATTACH } hInst hInstance passed in is where the DLL got loaded – usually stored for later use in a Global Remember though that when your DllMain is running, other DLLs may not have initialized. Thus, don’t call other DLLs within your DllMain Delay-loading a DLL You can opt to delay load an implicitly-linked DLL Beneficial because: Faster startup – you can save time initializing DLLs later when you need them Backward compatibility – you can avoid calling missing functions and handle the error yourself Function Forwarding You can forward an exported function from one DLL to another // Function forwarders to functions in DllWor k #pragma comment(linker, "/export:SomeFunc =DllWork.SomeOtherFunc") Pretty simple eh? Known DLLs Life isn’t fair… some DLLs get special treatment Look at: HKEY_LOCAL_MACHINE\SYSTEM\CurrentC ontrolSet\Control\Session Manager\KnownDLLs These DLLs always load from the same place Version Independence We are all familiar with DLL Versioning problems Can fix using .local files. If a file called calc.exe.local exists, for example, in the directory in which calc.exe resides, DLLs are loaded from that directory first For new systems think about Side-by-Side assemblies (see here) Rebasing DLLs When a module loads, it has a preferred base address it would like to load at However, that address is not always going to be available If a module is relocated, internal structures have to be “fixed up” to deal with this new location (why?) This is slow Instead You can use the rebasing tool to modify the DLLs so that this relocation is done on disk, and not on the fly Don’t ever ever *ever* rebase system DLLs Binding a DLL Similar in some senses to Rebasing Improves performance Saves the system having to fix up the module import section What can we do with it? This Assignment Not due until April 26th – that’s over two weeks NO MERCY on people who say on the 19th “I’m stuck!” This is somewhat tricky I suggest you start work on it immediately… We will look at your code in a week in SVN and assign some points for what you’ve done Calls… I want you to be able to intercept the following Winsock system calls: connect send recv closesocket You should be able to launch an arbitrary monitored process (specified on the Command line) You should be able to display the calls to connect, send, recv and closesocket along with their parameters Have fun I strongly suggest you read Ch 22.