16

共有ライブラリ/dllから関数を呼び出す最も簡単で安全な方法は何ですか?私は主にLinuxでこれを行うことに興味がありますが、プラットフォームに依存しない方法があればもっと良いでしょう。

fooユーザーが自分のバージョンを共有ライブラリにコンパイルした場合に、次の作業を行う方法を示すサンプルコードを誰かが提供できますか?

// function prototype, implementation loaded at runtime:
std::string foo(const std::string);

int main(int argc, char** argv) {
  LoadLibrary(argv[1]); // loads library implementing foo
  std::cout << "Result: " << foo("test");
  return 0;
}

ところで、私は共有lib(foo.so)をコンパイルする方法を知っています、実行時にそれをロードする簡単な方法を知る必要があります。

4

3 に答える 3

27

注:ライブラリ呼び出しの周りにC ++オブジェクト(この場合はSTL文字列)を渡します。このレベルには標準のC++ ABIがないため、C ++オブジェクトを渡さないようにするか、ライブラリとプログラムの両方が同じコンパイラ(理想的には同じマシン上の同じコンパイラ)でビルドされていることを確認してください。構成関連のサプライズ。)

ライブラリコード内でエクスポートされたメソッドを宣言することextern "C"を忘れないでください。

上記のことを言ったので、ここにあなたが達成したいと言ったことを実装するいくつかのコードがあります:

typedef std::string (*foo_t)(const std::string);
foo_t foo = NULL;

...

# ifdef _WIN32
  HMODULE hDLL = ::LoadLibrary(szMyLib);
  if (!hDll) { /*error*/ }
  foo = (foo_t)::GetProcAddress(hDLL, "foo");
# else
  void *pLib = ::dlopen(szMyLib, RTLD_LAZY);
  if (!pLib) { /*error*/ }
  foo = (foo_t)::dlsym(pLib, "foo");
# endif
  if (!foo) { /*error*/ }

  ...

  foo("bar");

  ...

# ifdef _WIN32
  ::FreeLibrary(hDLL);
# else
  ::dlclose(pLib);
# endif

これをさらに抽象化できます:

#ifdef _WIN32
#include <windows.h>
typedef HANDLE my_lib_t;
#else
#include <dlfcn.h>
typedef void* my_lib_t;
#endif

my_lib_t MyLoadLib(const char* szMyLib) {
# ifdef _WIN32
  return ::LoadLibraryA(szMyLib);
# else //_WIN32
  return ::dlopen(szMyLib, RTLD_LAZY);
# endif //_WIN32
}

void MyUnloadLib(my_lib_t hMyLib) {
# ifdef _WIN32
  return ::FreeLibrary(hMyLib);
# else //_WIN32
  return ::dlclose(hMyLib);
# endif //_WIN32
}

void* MyLoadProc(my_lib_t hMyLib, const char* szMyProc) {
# ifdef _WIN32
  return ::GetProcAddress(hMyLib, szMyProc);
# else //_WIN32
  return ::dlsym(hMyLib, szMyProc);
# endif //_WIN32
}

typedef std::string (*foo_t)(const std::string);
typedef int (*bar_t)(int);
my_lib_t hMyLib = NULL;
foo_t foo = NULL;
bar_t bar = NULL;

...

  if (!(hMyLib = ::MyLoadLib(szMyLib)) { /*error*/ }
  if (!(foo = (foo_t)::MyLoadProc(hMyLib, "foo")) { /*error*/ }
  if (!(bar = (bar_t)::MyLoadProc(hMyLib, "bar")) { /*error*/ }

  ...

  foo("bar");
  bar(7);

  ...

  ::MyUnloadLib(hMyLib);
于 2010-03-29T13:33:54.690 に答える
1

LoadLibraryは、DLLをロードするためのWindows関数です。GetProcAddressを使用して、シンボルの存在を確認できます。Linux / Unixでは、dlopen / dlsymが必要です。クロスプラットフォームでこれを行うには、プリプロセッサを使用してこれらのメソッドのいずれかを呼び出す関数を作成できます。つまり、次のようになります。

int loadlibrary(char* library)
{
#ifdef _WIN32
    /* do windows code */

#endif
#ifdef _LINUX
    /* do linux code */

#endif
}

これは、この種のことを達成するための1つの方法です。関数の特定のプラットフォーム実装用に、独自のソースツリーに別のヘッダーを含めることによってもそれを行うことができます。これはおそらくより良い方法です。いずれの場合も、基盤となるAPIから抽象化するという考え方です。

于 2010-03-29T13:27:18.593 に答える
0

Linuxでは、 dlsymを使用する必要があります。ページの最後にある例を参照してください。ウィンドウ上:GetProcAddress

于 2010-03-29T13:24:22.957 に答える