web-dev-qa-db-ja.com

C / C ++でDLLをコンパイルし、別のプログラムから呼び出す

シンプルでシンプルなDLLを作成して、1つまたは2つの関数をエクスポートし、別のプログラムから呼び出してみます...これまで見てきたどこでも、複雑な問題のために、物事を一緒にリンクする方法、私もしていない奇妙な問題 始まった まだ存在することに気づくために...私はただ始めたいです。

DLLを作成します。これは、

int add2(int num){
   return num + 2;
}

int mult(int num1, int num2){
   int product;
   product = num1 * num2;
   return product;
}

私はMinGWでコンパイルしていますが、Cでこれを行いたいのですが、C++でそれを行う際に実際の違いがある場合は、それらも知りたいです。私はそのDLLを別のC(およびC++)プログラムにロードし、それからそれらの関数を呼び出す方法を知りたい。ここでの私の目標は、少しDLLをいじった後、 Visual BasicにDLLをロードすることにより、C(++)コードのVBフロントエンドを作成します(Visual Studio 6があり、それらのオブジェクトのフォームとイベントを作成したいだけです)フォーム、DLLを呼び出します)。

Gcc(/ g ++)を呼び出してDLLを作成する方法を知っておく必要がありますが、エクスポートファイルを作成(/生成)する方法と、DLL(たとえば、VB front-endからポインタ/参照によって引数を取ることができますか?DLLまたは?VBそしてそれを呼び出す?)から「関数ポインタ」(私はそれが可能かどうかさえ知りません)を取りますか?私は渡すことができないことをかなり確信していますDLLのバリアント...しかし、それは私が本当に知っているすべてです。

もう一度更新する

さて、私はそれをgccでコンパイルして、実行したdllを作成する方法を見つけました

gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--out-implib,libmessage.a

そして、別のプログラムでそれをロードして機能をテストしましたが、うまく機能しました、アドバイスに感謝しますが、このようにVB6でロードしようとしました

Public Declare Function add2 Lib "C:\c\dll\mydll.dll" (num As Integer) As Integer

次に、フォームからadd2(text1.text)を呼び出しましたが、実行時エラーが発生しました。

「DLL C:\ c\dll\mydll.dllのエントリポイントadd2が見つかりません」」

これは、DLL用にコンパイルしたコードです。

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

EXPORT int __stdcall add2(int num){
  return num + 2;
}

EXPORT int __stdcall mul(int num1, int num2){
  return num1 * num2;
}

ただし、このようにCプログラムから呼び出すとうまくいきました。

#include<stdio.h>
#include<windows.h>

int main(){

  HANDLE ldll;
  int (*add2)(int);
  int (*mul)(int,int);

  ldll = LoadLibrary("mydll.dll");
  if(ldll>(void*)HINSTANCE_ERROR){
    add2 = GetProcAddress(ldll, "add2");
    mul = GetProcAddress(ldll, "mul");
    printf("add2(3): %d\nmul(4,5): %d", add2(3), mul(4,5));
  } else {
    printf("ERROR.");
  }

}

何か案は?

それを解決しました

前の問題を解決するには、次のようにコンパイルする必要がありました。

gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--add-stdcall-alias

vB6でこのAPI呼び出しを使用します

Public Declare Function add2 Lib "C:\c\dll\mydll" _
    (ByVal num As Integer) As Integer

ByValまたはByRefを明示的に指定することを忘れないことを学びました-渡した引数のアドレスを取得していましたが、-3048のように見えました。

56
Carson Myers

MinGWを使用してDLLを構築することに関して、ここにいくつかの非常に簡単な指示があります。

まず、DLLの呼び出し元が使用できるように、関数をエクスポート用にマークする必要があります。これを行うには、次のように変更します(たとえば)

__declspec( dllexport ) int add2(int num){
   return num + 2;
}

次に、関数がfuncs.cというファイルにあると仮定して、それらをコンパイルできます。

gcc -shared -o mylib.dll funcs.c

-sharedフラグは、gccにDLLを作成するように指示します。

DLLが実際に関数をエクスポートしたかどうかを確認するには、無料の Dependency Walker ツールを入手し、それを使用してDLLを調べます。

DLLのビルドに必要なすべてのフラグなどを自動化する無料のIDEについては、MinGWで非常にうまく機能する優れた Code :: Blocks を見てください。 。

Edit:このテーマの詳細については、記事 Creating a MinGW DLL for with with Visual Basic MinGW Wikiで。

24
anon

方法は次のとおりです。

.hで

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

extern "C" // Only if you are using C++ rather than C
{    
  EXPORT int __stdcall add2(int num);
  EXPORT int __stdcall mult(int num1, int num2);
}

.cppで

extern "C" // Only if you are using C++ rather than C
{    
EXPORT int __stdcall add2(int num)
{
  return num + 2;
}


EXPORT int __stdcall mult(int num1, int num2)
{
  int product;
  product = num1 * num2;
  return product;
}
}

このマクロは、モジュール(つまり、.cppファイル)に、dllを外部に提供していることを伝えます。あなたの.hファイルを含む人々は同じ関数をインポートしたいので、インポートするようにリンカに伝えるとしてEXPORTを販売します。プロジェクトのコンパイルオプションにBUILD_DLLを追加する必要があります。プロジェクトに明らかに固有の名前に変更する必要がある場合があります(dllがdllを使用する場合)。

また、 。defファイルを作成して関数の名前を変更する を作成し、名前の難読化を解除する必要がある場合があります(C/C++はこれらの名前をマングルします)。 このブログエントリ は、それに関する興味深い開始点かもしれません。

独自のカスタムdllをロードするのは、システムdllをロードするのと同じです。 DLLがシステムパス上にあることを確認してください。C:\ windows \またはアプリケーションの作業ディレクトリは、dllを置く簡単な場所です。

7
Tom Leys

違いは1つだけです。気をつけたり、マングリングでC++に名前を付ける必要があります。ただし、Windowsでは、1)DLL 2)からエクスポートされる関数を決定する)に注意する必要があります。エクスポートされたすべてのシンボルをリストする、いわゆる.defファイルを記述します。

Windowsでは、コンパイル中にDLLを使用する必要があります

__declspec(dllexport)

しかし、それを使用している間は__declspec(dllimport)を書く必要があります

だからそれを行う通常の方法は次のようなものです

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

多くの場合、EXPORTという名前が付けられているため、命名はやや混乱します。あなたの場合、あなたは(上記の#defineで)書くでしょう

int DLL_EXPORT add .... int DLL_EXPORT mult ...

共有ライブラリの構築中にプリプロセッサディレクティブBUILD_DLLを追加する必要があることに注意してください。

よろしく

5
Friedrich

C++ dllを記述するときに注意することは、名前のマングリングです。 CとC++の相互運用性が必要な場合は、dll内から非マングルCスタイル関数をエクスポートすることをお勧めします。

DLLを使用するには2つのオプションがあります

  • Libファイルを使用してシンボルをリンクするか、コンパイル時の動的リンクを使用します
  • LoadLibrary()または適切な関数を使用してライブラリをロードし、関数ポインター(GetProcAddress)を取得して呼び出します-ランタイム動的リンク

ただし、2番目の方法に従う場合、クラスのエクスポートは機能しません。

4
dirkgently

VB6の場合:

C関数を__stdcallとして宣言する必要があります。そうしないと、「無効な呼び出し規約」タイプのエラーが発生します。その他の質問について:

VBフロントエンドからのポインター/参照によって引数を取ることができますか?

はい、ByRef/ByVal修飾子を使用します。

DLLはフロントエンドで理論関数を呼び出すことができますか?

はい、AddressOfステートメントを使用します。前にdllに関数ポインタを渡す必要があります。

または、VBから呼び出して?)

はい、AddressOfステートメントを使用します。

更新(さらに質問が表示されました:)):

それをVBにロードするには、通常の方法(winsock.ocxまたは他のランタイムをロードするために行うことですが、代わりにDLL)を見つける)を行うか、API呼び出しを行いますかモジュールに?

次のように、VB6コードでAPI関数をデカールする必要があります。

Private Declare Function SHGetSpecialFolderLocation Lib "Shell32" _
   (ByVal hwndOwner As Long, _
    ByVal nFolder As Long, _
    ByRef pidl As Long) As Long
3
Arvo