ncbidll.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:10k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbidll.cpp,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 19:09:00  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.20
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbidll.cpp,v 1000.5 2004/06/01 19:09:00 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author: Vladimir Ivanov, Denis Vakatov
  35.  *
  36.  * File Description:
  37.  *   Portable DLL handling
  38.  *
  39.  */
  40. #include <ncbi_pch.hpp>
  41. #include <corelib/ncbidll.hpp>
  42. #include <corelib/ncbifile.hpp>
  43. #if defined(NCBI_OS_MSWIN)
  44. #  include <corelib/ncbi_os_mswin.hpp>
  45. #elif defined(NCBI_OS_UNIX)
  46. #  ifdef HAVE_DLFCN_H
  47. #    include <dlfcn.h>
  48. #  endif
  49. #else
  50. #  error "Class CDll defined only for MS Windows and UNIX platforms"
  51. #endif
  52. BEGIN_NCBI_SCOPE
  53. // Platform-dependent DLL handle type definition
  54. struct SDllHandle {
  55. #if defined(NCBI_OS_MSWIN)
  56.     HMODULE handle;
  57. #elif defined(NCBI_OS_UNIX)
  58.     void*   handle;
  59. #endif
  60. };
  61. CDll::CDll(const string& name, ELoad when_to_load, EAutoUnload auto_unload,
  62.            EBasename treate_as)
  63. {
  64.     x_Init(kEmptyStr, name, when_to_load, auto_unload, treate_as);
  65. }
  66. CDll::CDll(const string& path, const string& name, ELoad when_to_load,
  67.            EAutoUnload auto_unload, EBasename treate_as)
  68. {
  69.     x_Init(path, name, when_to_load, auto_unload, treate_as);
  70. }
  71. CDll::~CDll() 
  72. {
  73.     // Unload DLL automaticaly
  74.     if ( m_AutoUnload ) {
  75.         try {
  76.             Unload();
  77.         } catch(CException& e) {
  78.             NCBI_REPORT_EXCEPTION("CDll destructor", e);
  79.         }
  80.     }
  81.     delete m_Handle;
  82. }
  83. void CDll::x_Init(const string& path, const string& name, ELoad when_to_load, 
  84.            EAutoUnload  auto_unload, EBasename treate_as)
  85. {
  86.     // Init members
  87.     m_Handle = 0;
  88.     m_AutoUnload = auto_unload == eAutoUnload;
  89.     string x_name = name;
  90. #if defined(NCBI_OS_MSWIN)
  91.     NStr::ToLower(x_name);
  92. #endif
  93.     // Process DLL name
  94.     if (treate_as == eBasename  &&  
  95.         name.find_first_of(":/\") == NPOS &&
  96. #if defined(NCBI_OS_MSWIN)
  97.         !CDirEntry::MatchesMask(name.c_str(),"*.dll")
  98. #elif defined(NCBI_OS_UNIX)
  99.         !CDirEntry::MatchesMask(name.c_str(),"lib*.so") &&
  100.         !CDirEntry::MatchesMask(name.c_str(),"lib*.so.*")
  101. #endif
  102.         ) {
  103.         // "name" is basename
  104. #if defined(NCBI_OS_MSWIN)
  105.         x_name = x_name + ".dll";
  106. #elif defined(NCBI_OS_UNIX)
  107.         x_name = "lib" + x_name + ".so";
  108. #endif
  109.     }
  110.     m_Name = CDirEntry::ConcatPath(path, x_name);  
  111.     // Load DLL now if indicated
  112.     if (when_to_load == eLoadNow) {
  113.         Load();
  114.     }
  115. }
  116. void CDll::Load(void)
  117. {
  118.     // DLL is already loaded
  119.     if ( m_Handle ) {
  120.         return;
  121.     }
  122.     // Load DLL
  123. #if defined(NCBI_OS_MSWIN)
  124.     HMODULE handle = LoadLibrary(m_Name.c_str());
  125. #elif defined(NCBI_OS_UNIX)
  126. #  ifdef HAVE_DLFCN_H
  127.     void* handle = dlopen(m_Name.c_str(), RTLD_LAZY | RTLD_GLOBAL);
  128. #  else
  129.     void* handle = 0;
  130. #  endif
  131. #endif
  132.     if ( !handle ) {
  133.         x_ThrowException("CDll::Load");
  134.     }
  135.     m_Handle = new SDllHandle;
  136.     m_Handle->handle = handle;
  137. }
  138. void CDll::Unload(void)
  139. {
  140.     // DLL is not loaded
  141.     if ( !m_Handle ) {
  142.         return;
  143.     }
  144.     // Unload DLL
  145. #if defined(NCBI_OS_MSWIN)
  146.     BOOL unloaded = FreeLibrary(m_Handle->handle);
  147. #elif defined(NCBI_OS_UNIX)
  148. #  ifdef HAVE_DLFCN_H
  149.     bool unloaded = dlclose(m_Handle->handle) == 0;
  150. #  else
  151.     bool unloaded = false;
  152. #  endif
  153. #endif
  154.     if ( !unloaded ) {
  155.         x_ThrowException("CDll::Unload");
  156.     }
  157.     delete m_Handle;
  158.     m_Handle = 0;
  159. }
  160. CDll::TEntryPoint CDll::GetEntryPoint(const string& name)
  161. {
  162.     // If DLL is not yet loaded
  163.     if ( !m_Handle ) {
  164.         Load();
  165.     }
  166.     // Add leading underscore on Darwin platform
  167. #if defined(NCBI_OS_DARWIN)
  168.     const string entry_name = "_" + name;
  169. #else
  170.     const string entry_name = name;
  171. #endif
  172.     TEntryPoint entry;
  173.     // Return address of entry (function or data)
  174. #if defined(NCBI_OS_MSWIN)
  175.     FARPROC ptr = GetProcAddress(m_Handle->handle, entry_name.c_str());
  176. #elif defined(NCBI_OS_UNIX)
  177.     void* ptr = 0;
  178. #  if defined(HAVE_DLFCN_H)
  179.     ptr = dlsym(m_Handle->handle, entry_name.c_str());
  180. #    if defined(NCBI_OS_DARWIN)
  181.     // Try again without the underscore, since 10.3 and up don't need it.
  182.     if ( !ptr ) {
  183.         ptr = dlsym(m_Handle->handle, entry_name.c_str() + 1);
  184.     }
  185. #    endif
  186. #  endif
  187. #else
  188.     void* ptr = 0;
  189. #endif
  190.     entry.func = (FEntryPoint)ptr;
  191.     entry.data = ptr;
  192.     return entry;
  193. }
  194. void CDll::x_ThrowException(const string& what)
  195. {
  196. #if defined(NCBI_OS_MSWIN)
  197.     char* ptr = NULL;
  198.     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
  199.                   FORMAT_MESSAGE_FROM_SYSTEM | 
  200.                   FORMAT_MESSAGE_IGNORE_INSERTS,
  201.                   NULL, GetLastError(), 
  202.                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  203.                   (LPTSTR) &ptr, 0, NULL);
  204.     string errmsg = ptr ? ptr : "unknown reason";
  205.     LocalFree(ptr);
  206. #elif defined(NCBI_OS_UNIX)
  207. #  ifdef HAVE_DLFCN_H
  208.     const char* errmsg = dlerror();
  209.     if ( !errmsg ) {
  210.         errmsg = "unknown reason";
  211.     }
  212. #  else
  213.     const char* errmsg = "No DLL support on this platform.";
  214. #  endif
  215. #endif
  216.     NCBI_THROW(CCoreException, eDll, what + " [" + m_Name +"]: " + errmsg);
  217. }
  218. CDllResolver::CDllResolver(const string& entry_point_name)
  219. {    
  220.     m_EntryPoinNames.push_back(entry_point_name);
  221. }
  222. CDllResolver::CDllResolver(const vector<string>& entry_point_names)
  223. {
  224.     m_EntryPoinNames = entry_point_names;
  225. }
  226. CDllResolver::~CDllResolver()
  227. {
  228.     Unload();
  229. }
  230. bool CDllResolver::TryCandidate(const string& file_name)
  231. {
  232.     try {
  233.         CDll* dll = new CDll(file_name, CDll::eLoadNow, CDll::eAutoUnload);
  234.         CDll::TEntryPoint p;
  235.         SResolvedEntry entry_point(dll);
  236.         ITERATE(vector<string>, it, m_EntryPoinNames) {
  237.             string entry_point_name;
  238.             
  239.             const string& dll_name = dll->GetName();
  240.             
  241.             if (!dll_name.empty()) {
  242.                 string base_name;
  243.                 CDirEntry::SplitPath(entry_point_name, 0, &base_name, 0);
  244.                 NStr::Replace(*it, "${basename}", base_name, entry_point_name);
  245.             }
  246.             
  247.             // Check for the BASE library name macro
  248.             
  249.             if (entry_point_name.empty())
  250.                 continue;
  251.             p = dll->GetEntryPoint(entry_point_name);
  252.             if (p.data) { 
  253.                 entry_point.entry_points.push_back(SNamedEntryPoint(entry_point_name, p));
  254.             }
  255.         } // ITERATE
  256.         if (entry_point.entry_points.empty()) {
  257.             delete dll;
  258.             return false;
  259.         }
  260.         m_ResolvedEntries.push_back(entry_point);
  261.     } 
  262.     catch (CCoreException& ex)
  263.     {
  264.         if (ex.GetErrCode() != CCoreException::eDll)
  265.             throw;
  266.         return false;
  267.     }
  268.     return true;
  269. }
  270. void CDllResolver::Unload()
  271. {
  272.     NON_CONST_ITERATE(TEntries, it, m_ResolvedEntries) {
  273.         delete it->dll;
  274.     }
  275.     m_ResolvedEntries.resize(0);    
  276. }
  277. END_NCBI_SCOPE
  278. /*
  279.  * ===========================================================================
  280.  * $Log: ncbidll.cpp,v $
  281.  * Revision 1000.5  2004/06/01 19:09:00  gouriano
  282.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.20
  283.  *
  284.  * Revision 1.20  2004/05/14 13:59:27  gorelenk
  285.  * Added include of ncbi_pch.hpp
  286.  *
  287.  * Revision 1.19  2004/02/05 18:41:25  ucko
  288.  * GetEntryPoint: Darwin may or may not need a leading underscore, so try
  289.  * it both ways.
  290.  *
  291.  * Revision 1.18  2003/12/09 13:06:44  kuznets
  292.  * Supported dll base name in entry point resolution (CDllResolver)
  293.  *
  294.  * Revision 1.17  2003/12/01 16:39:15  kuznets
  295.  * CDllResolver changed to try all entry points
  296.  * (prev. version stoped on first successfull).
  297.  *
  298.  * Revision 1.16  2003/11/19 13:50:42  ivanov
  299.  * GetEntryPoint() revamp: added GetEntryPoin_[Func|Data]()
  300.  *
  301.  * Revision 1.15  2003/11/12 17:40:54  kuznets
  302.  * + CDllResolver::Unload()
  303.  *
  304.  * Revision 1.14  2003/11/10 15:28:46  kuznets
  305.  * Fixed misprint
  306.  *
  307.  * Revision 1.13  2003/11/10 15:05:04  kuznets
  308.  * Reflecting changes in hpp file
  309.  *
  310.  * Revision 1.12  2003/11/06 13:00:12  kuznets
  311.  * +CDllResolver
  312.  *
  313.  * Revision 1.11  2002/12/19 20:27:09  ivanov
  314.  * Added DLL name to an exception description in the x_ThrowException()
  315.  *
  316.  * Revision 1.10  2002/09/19 20:05:42  vasilche
  317.  * Safe initialization of static mutexes
  318.  *
  319.  * Revision 1.9  2002/07/15 18:17:24  gouriano
  320.  * renamed CNcbiException and its descendents
  321.  *
  322.  * Revision 1.8  2002/07/11 14:18:26  gouriano
  323.  * exceptions replaced by CNcbiException-type ones
  324.  *
  325.  * Revision 1.7  2002/07/01 16:44:14  ivanov
  326.  * Added Darwin specific: use leading underscores in entry names
  327.  *
  328.  * Revision 1.6  2002/05/28 20:01:20  vakatov
  329.  * Typo fixed
  330.  *
  331.  * Revision 1.5  2002/05/23 22:24:07  ucko
  332.  * Handle the absence of <dlfcn.h> better.
  333.  *
  334.  * Revision 1.4  2002/04/11 21:08:02  ivanov
  335.  * CVS log moved to end of the file
  336.  *
  337.  * Revision 1.3  2002/03/25 18:10:00  ucko
  338.  * Make errmsg const to accommodate platforms (FreeBSD at least) where
  339.  * dlerror returns const char*.
  340.  *
  341.  * Revision 1.2  2002/01/16 18:48:57  ivanov
  342.  * Added new constructor and related "basename" rules for DLL names. 
  343.  * Polished source code.
  344.  *
  345.  * Revision 1.1  2002/01/15 19:05:28  ivanov
  346.  * Initial revision
  347.  *
  348.  * ===========================================================================
  349.  */