Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
DllOpen.cpp 6.64 KiB
#include <string>
#include <iostream>

/*
 If the OS is Windows then LoadLibrary, GetProcAddress and FreeLibrary are used. 
 Some casting to HINSTANCE is required.
 Shared library name is of the form *.dll. 

 If the OS is Linux then dlopen, dlsym and dlclose are used.
 Shared library name is of the form lib*.so.
*/
#if _WIN32
#define _WIN32_WINNT 0x0510
#include <windows.h>
//#include <strsafe.h>
#else
#include <dlfcn.h>
#endif /* _WIN32 */

#include "MantidKernel/Strings.h"
#include "MantidKernel/DllOpen.h"
#include "MantidKernel/Logger.h"

namespace Mantid
{
namespace Kernel
{

// Get a reference to the logger
Logger& DllOpen::log = Logger::get("DllOpen");

/* Opens the shared library after appending the required formatting,
 * i.e. libName.so for Linux and Name.dll for Windows.
 * Calls the correct implementation based on the current O/S.
 * @param libName :: Name of the library.
 * @return Pointer to library (of type void).
 **/
void* DllOpen::OpenDll(const std::string& libName)
{
  std::string str = LIB_PREFIX + libName + LIB_POSTFIX;
  return OpenDllImpl(str);
}

/* Opens the shared library after appending the required formatting,
 * i.e. libName.so for Linux and Name.dll for Windows.
 * Calls the correct implementation based on the current O/S.
 * @param libName :: Name of the library.
 * @param filePath :: The location on the library.
 * @return Pointer to library (of type void).
 **/
void* DllOpen::OpenDll(const std::string& libName, const std::string& filePath)
{
  std::string str = filePath + PATH_SEPERATOR + LIB_PREFIX + libName
    + LIB_POSTFIX;
  return OpenDllImpl(str);
}

/* Retrieves a function from the opened library.
 * Calls the correct implementation based on the current O/S.
 * @param libName :: Name of the library.
 * @param funcName :: The name of the function to retrieve.
 * @return Pointer to the function (of type void).
 **/
void* DllOpen::GetFunction(void* libName, const std::string& funcName)
{
  return GetFunctionImpl(libName, funcName);
}

/* Closes an open library.
 * Calls the correct implementation based on the current O/S.
 * @param libName :: Name of the library.
 **/
void DllOpen::CloseDll(void* libName)
{
  CloseDllImpl(libName);
}

/** Converts a file name (without directory) to a undecorated library name.
 * e.g. MyLibrary.dll or libMyLibary.so would become MyLibrary.
 * @param fileName :: The filename (with extension) to convert
 * @return The converted libName, or empty string if the conversion was not possible.
 **/
const std::string DllOpen::ConvertToLibName(const std::string& fileName)
{
  //take a copy of the input string
  std::string retVal = fileName;

  if ((retVal.find(LIB_PREFIX) == 0 ) && (retVal.find(PATH_SEPERATOR)
    == std::string::npos))
  {
    //found
    retVal = retVal.substr(LIB_PREFIX.size(), retVal.size()
      - LIB_PREFIX.size());
  }
  else
  {
    //prefix not found
    return "";
  }

  if (retVal.rfind(LIB_POSTFIX) == (retVal.size()-LIB_POSTFIX.size()))
  {
    //found
    retVal = retVal.substr(0, retVal.size()-LIB_POSTFIX.size());
  }
  else
  {
    //postfix not found
    return "";
  }
  return retVal;
}

/* Adds a directory to the dll cearch path
 **/
void DllOpen::addSearchDirectory(const std::string& dir)
{
  addSearchDirectoryImpl(dir);
}

#if _WIN32
const std::string DllOpen::LIB_PREFIX = "";
const std::string DllOpen::LIB_POSTFIX = ".dll";
const std::string DllOpen::PATH_SEPERATOR = "\\";

/* Opens the Windows .dll file.
 * @param filePath :: Filepath of the library.
 * @return Pointer to library (of type void).
 **/
void* DllOpen::OpenDllImpl(const std::string& filePath)
{
  void* handle = LoadLibrary(filePath.c_str());
  if (!handle)
  {

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM |
      FORMAT_MESSAGE_IGNORE_INSERTS,
      NULL,
      dw,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR) &lpMsgBuf,
      0, NULL );

    // Display the error message and exit the process
    size_t n = lstrlen((LPCTSTR)lpMsgBuf) + 40;

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, n*sizeof(TCHAR));
    //        StringCchPrintf((LPTSTR)lpDisplayBuf, 
    //          LocalSize(lpDisplayBuf) / sizeof(TCHAR),
    //          TEXT("failed with error %d: %s"), 
    //          dw, lpMsgBuf); 
    _snprintf((char*)lpDisplayBuf, n, "failed with error %d: %s", dw, lpMsgBuf);
    log.error()<<"Could not open library " << filePath << ": " << (LPCTSTR)lpDisplayBuf << std::endl;

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
  }
  return handle;
}

/* Retrieves a function from the opened .dll file.
 * Only works if the function has been declared as extern 'C'.
 * @param libName :: Name of the library.
 * @param funcName :: The name of the function to retrieve.
 * @return Pointer to the function (of type void).
 **/
void* DllOpen::GetFunctionImpl(void* libName, const std::string& funcName)
{
  return (void*)GetProcAddress((HINSTANCE)libName, funcName.c_str());
}

/* Closes an open .dll file.
 * @param libName :: Name of the library.
 **/
void DllOpen::CloseDllImpl(void* libName)
{
  FreeLibrary((HINSTANCE)libName);
}

/* Adds a directory to the dll cearch path
 **/
void DllOpen::addSearchDirectoryImpl(const std::string& dir)
{
  SetDllDirectory(dir.c_str());
}

#else

const std::string DllOpen::LIB_PREFIX = "lib";
// Shared libraries end in "so" on linux, "dylib" on the Mac
#ifdef __linux__
const std::string DllOpen::LIB_POSTFIX = ".so";
#elif defined __APPLE__
const std::string DllOpen::LIB_POSTFIX = ".dylib";
#endif

const std::string DllOpen::PATH_SEPERATOR = "/";

/* Opens the Linux .so file
 * @param filePath :: Filepath of the library.
 * @return Pointer to library (of type void).
 **/
void* DllOpen::OpenDllImpl(const std::string& filePath)
{
  void* handle = dlopen(filePath.c_str(), RTLD_NOW | RTLD_GLOBAL);
  if (!handle)
  {
    log.error("Could not open library " + filePath + ": " + dlerror());
  }
  return handle;
}

/* Retrieves a function from the opened library.
 * Only works if the function has been declared as extern 'C'.
 * @param libName :: Name of the library.
 * @param funcName :: The name of the function to retrieve.
 * @return Pointer to the function (of type void).
 **/
void* DllOpen::GetFunctionImpl(void* libName, const std::string& funcName)
{
  return dlsym(libName, funcName.c_str());
}

/* Closes an open .so file.
 * @param libName :: Name of the library.
 **/
void DllOpen::CloseDllImpl(void* libName)
{
  dlclose(libName);
}

/* Adds a directory to the dll cearch path
 **/
void DllOpen::addSearchDirectoryImpl(const std::string& dir)
{
  (void) dir; //Avoid compiler warning
}

#endif /* _WIN32 */

} // namespace Kernel
} // namespace Mantid