///////////////////////////////////////////////////////////////////////////// // DynaLib.cpp | Implementation of the TCDynaLib class used to wrap the // loading of DLL's and resolving a set of API's that may or may not exist // at runtime. // #include "pch.h" #include "..\Inc\TCLib.h" #include "DynaLib.h" ///////////////////////////////////////////////////////////////////////////// // TCDynaLib ///////////////////////////////////////////////////////////////////////////// // Group=Construction / Destruction ///////////////////////////////////////////////////////////////////////////// // When using the default constructor, the LoadLibrary member function must // be used to load a DLL. TCDynaLib::TCDynaLib() : m_hinst(NULL) { } ///////////////////////////////////////////////////////////////////////////// // Parameters: // pszLibName - The name of the DLL to be loaded into this instance. // // Remarks: // When using the second form of the constructor, use the IsLibraryLoaded // method to determine if the library was successfully loaded. TCDynaLib::TCDynaLib(LPCTSTR pszLibName) : m_hinst(NULL) { // Attempt to load the specified library LoadLibrary(pszLibName); } ///////////////////////////////////////////////////////////////////////////// // If a DLL is loaded into this instance, it is freed. TCDynaLib::~TCDynaLib() { CLock lock(this); if (NULL != m_hinst) FreeLibrary(m_hinst); } ///////////////////////////////////////////////////////////////////////////// // Group=Attributes ///////////////////////////////////////////////////////////////////////////// // Description: Determines if a library is loaded. // // Return Value: true if a DLL is loaded into this instance, otherwise false. bool TCDynaLib::IsLibraryLoaded() { CLock lock(this); return NULL != m_hinst; } ///////////////////////////////////////////////////////////////////////////// // Description: Determines if a library is loaded and a set of API exports // have been resolved. // // Return Value: true if a DLL is loaded into this instance and all required // API exports can be resolved, otherwise false. // // Remarks: A derived class can override this method using the following set // of macros: // + TCDynaLib_BEGIN_REQUIRED_MAP // + TCDynaLib_REQUIRED_FUNCTION // + TCDynaLib_END_REQUIRED_MAP bool TCDynaLib::IsLibraryLoadedAndResolved() { return IsLibraryLoaded(); } ///////////////////////////////////////////////////////////////////////////// // Group=Operations ///////////////////////////////////////////////////////////////////////////// // Description: Loads the specified dynamic link library (DLL). // // Parameters: // pszLibName - The name of the DLL to be loaded into this instance. // // Return Value: true if the DLL was successfully loaded into this instance. // false if an error occurred. // // Remarks: Each instance can be associated with only one DLL. Once // LoadLibrary has been called, either directly or indirectly (using the // second form of the constuctor), subsequent attempts to call this method // will fail. bool TCDynaLib::LoadLibrary(LPCTSTR pszLibName) { bool bResult = false; __try { // Lock the object Lock(); // LoadLibrary can only be successfully called once assert(!m_hinst); // Load the specified library and indicate whether it was loaded or not bResult = NULL != (m_hinst = ::LoadLibrary(pszLibName)); } __except(1) { bResult = false; } // Unlock the object Unlock(); // Return the last result return bResult; } ///////////////////////////////////////////////////////////////////////////// // Description: Attempts to resolve the specified API export name. // // Parameters: // pszFn - The API export name to be resolved. This parameter is // intentionally an ANSI string because the Win32 ::GetProcAddress API // does not accept Unicode strings. // chDecoration - The calling convention used to decorate the exported // name. See the remarks for possible values. // cbArgs - The number of bytes of arguments passed to the export. This is // only used when the __stdcall or __fastcall calling convention decoration // is specified 's' or 'f'. // // Return Value: The function pointer of the resolved export if successful, // otherwise NULL. // // Remarks: This method will always fail if no DLL has been loaded. // // The possible values for the /chDecoration/ parameter are as follows: // 'c' - Decorated according to the __cdecl calling convention. // 's' - Decorated according to the __stdcall calling convention. // 'f' - Decorated according to the __fastcall calling convention. // // Typically, this function is not called directly, but rather, used by the // TCDynaLib_Fn macros. // // See Also: TCDynaLib::LoadLibrary, TCDynaLib_Fn macros FARPROC TCDynaLib::GetProcAddress(LPCSTR pszFn, char chDecoration, int cbArgs) { // Apply the specified name decoration char* szDecorated = (char*)_alloca(strlen(pszFn) + 8); switch (tolower(chDecoration)) { case 'c': { sprintf(szDecorated, "_%s", pszFn); break; } case 's': { sprintf(szDecorated, "_%s@%d", pszFn, cbArgs); break; } case 'f': { sprintf(szDecorated, "@%s@%d", pszFn, cbArgs); break; } default: strcpy(szDecorated, pszFn); } // Resolve the address of the specified function name return GetProcAddress(szDecorated); } FARPROC TCDynaLib::GetProcAddress(LPCSTR pszFn) { // Get the library instance handle HINSTANCE hinst; { CLock lock(this); hinst = m_hinst; } // Can't resolve if library couldn't be loaded if (NULL == hinst) return NULL; // Resolve the address of the specified function name return ::GetProcAddress(m_hinst, pszFn); } ///////////////////////////////////////////////////////////////////////////// // Group=Implementation ///////////////////////////////////////////////////////////////////////////// // {Secret} // Description: Called internally when an unresolved API is invoked and // cannot be resolved in the loaded DLL. void TCDynaLib::FunctionNotFound(LPCSTR pszFn) { LPCSTR pszFmt = "TCDynaLib: Function \"%s\" could not be resolved\n"; LPSTR pszMsg = LPSTR(_alloca(strlen(pszFmt) + strlen(pszFn))); sprintf(pszMsg, pszFmt, pszFn); OutputDebugStringA(pszMsg); assert(pszMsg); }