2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "DllLoaderContainer.h"
26 #include "Win32DllLoader.h"
28 #include "DllLoader.h"
29 #include "dll_tracker.h" // for python unload hack
30 #include "filesystem/File.h"
31 #include "utils/URIUtils.h"
32 #include "utils/StringUtils.h"
33 #include "utils/log.h"
36 #define ENV_PARTIAL_PATH "special://xbmcbin/system/;" \
37 "special://xbmcbin/system/players/mplayer/;" \
38 "special://xbmcbin/system/players/dvdplayer/;" \
39 "special://xbmcbin/system/players/paplayer/;" \
40 "special://xbmcbin/system/python/;" \
41 "special://xbmc/system/;" \
42 "special://xbmc/system/players/mplayer/;" \
43 "special://xbmc/system/players/dvdplayer/;" \
44 "special://xbmc/system/players/paplayer/;" \
45 "special://xbmc/system/python/"
47 #if defined(TARGET_DARWIN)
48 #define ENV_PATH ENV_PARTIAL_PATH \
49 ";special://frameworks/"
51 #define ENV_PATH ENV_PARTIAL_PATH
54 //Define this to get loggin on all calls to load/unload of dlls
58 using namespace XFILE;
60 LibraryLoader* DllLoaderContainer::m_dlls[64] = {};
61 int DllLoaderContainer::m_iNrOfDlls = 0;
62 bool DllLoaderContainer::m_bTrack = true;
64 void DllLoaderContainer::Clear()
68 HMODULE DllLoaderContainer::GetModuleAddress(const char* sName)
70 return (HMODULE)GetModule(sName);
73 LibraryLoader* DllLoaderContainer::GetModule(const char* sName)
75 for (int i = 0; m_dlls[i] != NULL && i < m_iNrOfDlls; i++)
77 if (stricmp(m_dlls[i]->GetName(), sName) == 0) return m_dlls[i];
78 if (!m_dlls[i]->IsSystemDll() && stricmp(m_dlls[i]->GetFileName(), sName) == 0) return m_dlls[i];
84 LibraryLoader* DllLoaderContainer::GetModule(HMODULE hModule)
86 for (int i = 0; m_dlls[i] != NULL && i < m_iNrOfDlls; i++)
88 if (m_dlls[i]->GetHModule() == hModule) return m_dlls[i];
93 LibraryLoader* DllLoaderContainer::LoadModule(const char* sName, const char* sCurrentDir/*=NULL*/, bool bLoadSymbols/*=false*/)
95 LibraryLoader* pDll=NULL;
97 if (IsSystemDll(sName))
99 pDll = GetModule(sName);
101 else if (sCurrentDir)
103 CStdString strPath=sCurrentDir;
105 pDll = GetModule(strPath.c_str());
110 pDll = GetModule(sName);
115 pDll = FindModule(sName, sCurrentDir, bLoadSymbols);
117 else if (!pDll->IsSystemDll())
122 CLog::Log(LOGDEBUG, "Already loaded Dll %s at 0x%x", pDll->GetFileName(), pDll);
130 LibraryLoader* DllLoaderContainer::FindModule(const char* sName, const char* sCurrentDir, bool bLoadSymbols)
132 if (URIUtils::IsInArchive(sName))
135 CStdString newName = "special://temp/";
136 newName += url.GetFileName();
137 CFile::Cache(sName, newName);
138 return FindModule(newName, sCurrentDir, bLoadSymbols);
141 if (CURL::IsFullPath(sName))
142 { // Has a path, just try to load
143 return LoadDll(sName, bLoadSymbols);
146 else if (strcmp(sName, "xbmc.so") == 0)
147 return LoadDll(sName, bLoadSymbols);
149 else if (sCurrentDir)
150 { // in the path of the parent dll?
151 CStdString strPath=sCurrentDir;
154 if (CFile::Exists(strPath))
155 return LoadDll(strPath.c_str(), bLoadSymbols);
158 // in environment variable?
159 CStdStringArray vecEnv;
161 #if defined(TARGET_ANDROID)
162 CStdString systemLibs = getenv("XBMC_ANDROID_SYSTEM_LIBS");
163 StringUtils::SplitString(systemLibs, ":", vecEnv);
164 CStdString localLibs = getenv("XBMC_ANDROID_LIBS");
165 vecEnv.insert(vecEnv.begin(),localLibs);
167 StringUtils::SplitString(ENV_PATH, ";", vecEnv);
169 LibraryLoader* pDll = NULL;
171 for (int i=0; i<(int)vecEnv.size(); ++i)
173 CStdString strPath=vecEnv[i];
174 URIUtils::AddSlashAtEnd(strPath);
177 CLog::Log(LOGDEBUG, "Searching for the dll %s in directory %s", sName, strPath.c_str());
182 // Have we already loaded this dll
183 if ((pDll = GetModule(strPath.c_str())) != NULL)
186 if (CFile::Exists(strPath))
187 return LoadDll(strPath.c_str(), bLoadSymbols);
190 // can't find it in any of our paths - could be a system dll
191 if ((pDll = LoadDll(sName, bLoadSymbols)) != NULL)
194 CLog::Log(LOGDEBUG, "Dll %s was not found in path", sName);
198 void DllLoaderContainer::ReleaseModule(LibraryLoader*& pDll)
202 if (pDll->IsSystemDll())
204 CLog::Log(LOGFATAL, "%s is a system dll and should never be released", pDll->GetName());
208 int iRefCount=pDll->DecrRef();
213 CLog::Log(LOGDEBUG, "Releasing Dll %s", pDll->GetFileName());
216 if (!pDll->HasSymbols())
223 CLog::Log(LOGINFO, "%s has symbols loaded and can never be unloaded", pDll->GetName());
228 CLog::Log(LOGDEBUG, "Dll %s is still referenced with a count of %d", pDll->GetFileName(), iRefCount);
233 LibraryLoader* DllLoaderContainer::LoadDll(const char* sName, bool bLoadSymbols)
237 CLog::Log(LOGDEBUG, "Loading dll %s", sName);
240 LibraryLoader* pLoader;
242 if (strstr(sName, ".so") != NULL || strstr(sName, ".vis") != NULL || strstr(sName, ".xbs") != NULL
243 || strstr(sName, ".mvis") != NULL || strstr(sName, ".dylib") != NULL || strstr(sName, ".framework") != NULL || strstr(sName, ".pvr") != NULL)
244 pLoader = new SoLoader(sName, bLoadSymbols);
246 #elif defined(_WIN32)
248 pLoader = new Win32DllLoader(sName);
251 pLoader = new DllLoader(sName, m_bTrack, false, bLoadSymbols);
255 CLog::Log(LOGERROR, "Unable to create dll %s", sName);
259 if (!pLoader->Load())
268 bool DllLoaderContainer::IsSystemDll(const char* sName)
270 for (int i = 0; m_dlls[i] != NULL && i < m_iNrOfDlls; i++)
272 if (m_dlls[i]->IsSystemDll() && stricmp(m_dlls[i]->GetName(), sName) == 0) return true;
278 int DllLoaderContainer::GetNrOfModules()
283 LibraryLoader* DllLoaderContainer::GetModule(int iPos)
285 if (iPos < m_iNrOfDlls) return m_dlls[iPos];
289 void DllLoaderContainer::RegisterDll(LibraryLoader* pDll)
291 for (int i = 0; i < 64; i++)
293 if (m_dlls[i] == NULL)
302 void DllLoaderContainer::UnRegisterDll(LibraryLoader* pDll)
306 if (pDll->IsSystemDll())
308 CLog::Log(LOGFATAL, "%s is a system dll and should never be removed", pDll->GetName());
312 // remove from the list
313 bool bRemoved = false;
314 for (int i = 0; i < m_iNrOfDlls && m_dlls[i]; i++)
316 if (m_dlls[i] == pDll) bRemoved = true;
317 if (bRemoved && i + 1 < m_iNrOfDlls)
319 m_dlls[i] = m_dlls[i + 1];
325 m_dlls[m_iNrOfDlls] = NULL;
331 void DllLoaderContainer::UnloadPythonDlls()
333 // unload all dlls that python24.dll could have loaded
334 for (int i = 0; m_dlls[i] != NULL && i < m_iNrOfDlls; i++)
336 char* name = m_dlls[i]->GetName();
337 if (strstr(name, ".pyd") != NULL)
339 LibraryLoader* pDll = m_dlls[i];
345 // last dll to unload, python24.dll
346 for (int i = 0; m_dlls[i] != NULL && i < m_iNrOfDlls; i++)
348 char* name = m_dlls[i]->GetName();
350 #ifdef HAVE_LIBPYTHON2_6
351 if (strstr(name, "python26.dll") != NULL)
353 if (strstr(name, "python24.dll") != NULL)
356 LibraryLoader* pDll = m_dlls[i];
358 while (pDll->DecrRef() > 1) pDll->DecrRef();
360 // since we freed all python extension dlls first, we have to remove any associations with them first
361 DllTrackInfo* info = tracker_get_dlltrackinfo_byobject((DllLoader*) pDll);
364 info->dllList.clear();