// Copyright (C) 2003-2008 Dolphin Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ /* All plugins from Core > Plugins are loaded and unloaded with this class when Dolpin is started and stopped. */ #include // System #ifdef _WIN32 #include #else #include #include #endif #include "Common.h" // Local #include "FileUtil.h" #include "StringUtil.h" #include "DynamicLibrary.h" DynamicLibrary::DynamicLibrary() { library = 0; } // Gets the last dll error as string const char *DllGetLastError() { #ifdef _WIN32 return GetLastErrorMsg(); #else // not win32 return dlerror(); #endif // WIN32 } /* Loads the dll with LoadLibrary() or dlopen. This function is called on start to scan for plugin, and before opening the Config and Debugging windows. It is also called from core to load the plugins when the emulation starts. Returns 0 on failure and 1 on success TODO: think about implementing some sort of cache for the plugin info. */ int DynamicLibrary::Load(const char* filename) { INFO_LOG(COMMON, "DL: Loading dynamic library %s", filename); if (!filename || strlen(filename) == 0) { ERROR_LOG(COMMON, "DL: Missing filename to load"); return 0; } if (IsLoaded()) { INFO_LOG(COMMON, "DL: library %s already loaded", filename); return 1; } #ifdef _WIN32 library = LoadLibrary(filename); #else // RTLD_NOW: resolve all symbols on load // RTLD_LOCAL: don't resolve symbols for other libraries library = dlopen(filename, RTLD_NOW | RTLD_LOCAL); #endif DEBUG_LOG(COMMON, "DL: LoadLibrary: %s(%p)", filename, library); if (!library) { fprintf(stderr, "DL: Error loading DLL %s: %s", filename, DllGetLastError()); ERROR_LOG(COMMON, "DL: Error loading DLL %s: %s", filename, DllGetLastError()); return 0; } library_file = filename; INFO_LOG(COMMON, "DL: Done loading dynamic library %s", filename); return 1; } /* Frees one instances of the dynamic library. Note that on most systems use reference count to decide when to actually remove the library from memory. Return 0 on failure and 1 on success */ int DynamicLibrary::Unload() { INFO_LOG(COMMON, "DL: Unloading dynamic library %s", library_file.c_str()); int retval; if (!IsLoaded()) { // library != null ERROR_LOG(COMMON, "DL: Unload failed for %s: not loaded", library_file.c_str()); PanicAlert("DL: Unload failed %s: not loaded", library_file.c_str()); return 0; } DEBUG_LOG(COMMON, "DL: FreeLibrary: %s %p\n", library_file.c_str(), library); #ifdef _WIN32 retval = FreeLibrary(library); #else retval = dlclose(library)?0:1; #endif if (! retval) { ERROR_LOG(COMMON, "DL: Unload failed %s: %s", library_file.c_str(), DllGetLastError()); } library = 0; INFO_LOG(COMMON, "DL: Done unloading dynamic library %s", library_file.c_str()); return retval; } // Returns the address where symbol funcname is loaded or NULL on failure void* DynamicLibrary::Get(const char* funcname) const { void* retval; INFO_LOG(COMMON, "DL: Getting symbol %s: %s", library_file.c_str(), funcname); if (!library) { ERROR_LOG(COMMON, "DL: Get failed %s - Library not loaded"); return NULL; } #ifdef _WIN32 retval = GetProcAddress(library, funcname); #else retval = dlsym(library, funcname); #endif if (!retval) { ERROR_LOG(COMMON, "DL: Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), DllGetLastError()); } INFO_LOG(COMMON, "DL: Done getting symbol %s: %s", library_file.c_str(), funcname); return retval; }