最近更新したページ
2013-10-20
2013-09-29
2013-09-23
2012-01-07
2011-11-09
2011-10-23
2011-10-09
2011-10-01
2011-09-29
2011-09-03
2011-08-07
2011-08-02
2011-07-29
2011-07-10
2011-05-05
2011-05-04
2011-04-24
2011-04-13
2011-04-05
2011-03-26
2011-02-18
2011-02-15
2010-12-26
2010-12-07
2010-12-05
2010-11-23
2010-09-28
2010-09-23
2010-08-26
2010-08-22
2010-07-16
2010-01-17
2010-01-11
2009-10-04
2009-08-21
2009-08-13
2009-06-18
2009-06-01
2009-04-29
2009-02-16
2009-02-11
2009-02-03
2008-07-22
2008-07-21
2008-07-15
2008-07-14
2008-07-13
2008-07-12
2008-07-08
2008-07-05
2008-06-28
2008-06-17
2008-06-05
2008-06-02
2008-06-01
2008-05-29
2008-05-26
2008-05-21
2008-05-19
2008-05-18
2007-10-31
2007-10-27
2007-09-28
2007-09-23
2007-09-17
2007-09-16
2007-09-14
2007-09-11
2007-06-18
2007-04-15
2006-12-21
2006-11-30
2006-11-22
2006-08-17
2006-03-29
2006-03-28
2006-03-27

C/C++ DLL::Export/Import


C/C++ DLL エクスポート/インポート

※文中 msdn....(青い方のサイト) の MS サイトは4月で終了し、msdn2...(白い方)への移行に伴い、リンク切れ多発。他頁を含め直す気無いのでご了承ください。

C/C++ DLLの作成ページを目一杯書いたが、あまりにハードルが高い上、行数3倍書いても足りない気がしてきたのでページ分けしました。

具体的なエクスポート方法


C 言語の実行形式で使う C++ 関数のエクスポート

http://msdn.microsoft.com/library/ja/default.asp?u...

C++ で作成された DLL 関数の宣言(名前の装飾)に extern "C" を指定(C リンケージ)することで C言語で作成された物として、他の言語(C言語など)から関数呼出を可能とする。但し、C言語に無い機能は使用できなくなる。

// C++ で作成した DLL 関数を 他言語から呼出可とする
extern "C" __declspec( dllexport ) int functionCpp(int a);

※ソリューションのビルド時の注意点:dll project -> 構成プロパティ -> Linker -> Input -> Module Definition File : ****.def を設定しないと .def ファイルを使った function名のエクスポートを行わず、勿論 ****.lib の出力も行われないので注意。
※肝心なところが明記されておらず、command プロンプト実行時に /DEF オプションを選択するよう記載されているに留まっている。
※このページ自体もようやく見つけ出した。MSDN 白バージョンにメニューがあるのにリンク切れなのは何故?

memo:
/DEFEXPORTS E Ordina Hint FunctionEntry Point***.LIB
fn_a @1 NONAME - - - - -
(名前省略) - - - - -
fn_a @1 NONAME 0# 1(0x0001) N/A N/A 0x00011078
fn_a @1 C 1(0x0001) 0(0x0000)fn_1 0x00011078
fn_a @2 C 2(0x0002) 0(0x0000)fn_1 0x00011078
fn_a
fn_b
C
C
1(0x0001)
2(0x0002)
0(0x0000)
1(0x0001)
fn_a
fn_b
0x00011078
0x00011087
※一部確認省略有り※Entry Point は関数により都度変わる
※注:EXPORTS の 名前と関数名が一致しないとソリューションのビルドでエラーとなる。
※ツールに、Dependency Walker 2.2 を使用。(感謝!)

memo2:
※関数名については、.map file を見ることでも確認できるが、 .map も、 /MAP オプション指定が必要で、.def 同様 Linker -> Debugging -> Map Exports:Yes(/MAPINGO:EXPORTS) へ変更する必要あり。(訂正:同 Debugging -> Generate Map File:Yes(/MAP) とする?同じ結果となるようだが…)
.map file
〜
0002:00000360       ?fn_a@@YAHHH@Z             10011360 f   test.obj
0002:000003a0       ?fn_b@@YAHHH@Z             100113a0 f   test.obj
0002:000003e0       ?fn_c@@YAHHH@Z             100113e0 f   test.obj
0002:00000420       ?fn_d@@YAHHH@Z             10011420 f   test.obj
〜
※.def file を通す前の関数名が出てくる。
MSDN:VC++リンカオプション→/MAP (マップ ファイルの生成) 参照

▲上へ

DEF ファイルを使った DLL からのエクスポート

http://msdn.microsoft.com/library/ja/default.asp?u...

sample (.def)
;// dlldeftest.def
;// comment 行は、セミコロン、ダブルスラッシュどちらもエラー出ず。
;修正 def のコメントは ";"(セミコロン) である。
;"//", "/* 〜 */" 何れもエラー。意味無い行は無視されリンク可。

LIBRARY dlldeftest                   ;// 必須
VERSION 1.1                          ;// 任意
DESCRIPTION "モジュール定義"          ;// 任意

EXPORTS                ;// 必須
;//  function ordinal noname?
;// -------------------------
        fn_a      @1  NONAME
        fn_b      @2  NONAME
        fn_c      @3  NONAME
        fn_d      @4  NONAME
;// -------------------------
;// 関数名必須
;// 序数、NONAME は使い方に合わせ任意

sample (.cpp/.c)
// dlldeftest.cpp
// (DEFを使ったエクスポート例)
#include <windows.h>
#include <iostream>     // このソースなら無しで ok(仕様が c だからと思う)

// extern "C" に関連する記述のようである。詳細不明
// .cpp でビルドするが無くてもビルド可能である。
// 但し、無いと C++ 以外からのリンク不可可能性大
/*
BOOL APIENTRY DllMain(
                    HANDLE hdDLL,
                    DWORD  dwReason,
                    LPVOID lpReserved ) {
    return TRUE;
}
*/
// 又は・・・
/*
BOOL WINAPI DllMain(HINSTANCE hdDLL,
                    DWORD     dwReason,
                    LPVOID    lpReserved) {
    return TRUE;
}
*/
// 上記記述の有無に関わらず、以下 C言語準拠程度のソースでは、
// .cpp でも C と同様に利用可能な DLL ができる模様(動作未確認)
// ※Class など使用すると E が C++ となり絶対無理となると思われる。

int fn_a(int x,int y) {
    return (x+y);
}
int fn_b(int x,int y) {
    return (x-y);
}
int fn_c(int x,int y) {
    return (x*y);
}
int fn_d(int x,int y) {
    if (y==0) { return 0; }
    else      { return (x/y); }
}

▲上へ

__declspec(dllexport) を使った DLL からのエクスポート

http://msdn.microsoft.com/library/ja/default.asp?u...

 ・・・作成中・・・

▲上へ

エクスポートとは?


エクスポートとは、DLL 作成時、呼び出し側アプリケーションへどのように利用可能な関数名、変数名などを知らせるかを定義する手続き…のようなもの(…と思う…)。

具体的には、他言語で作成された DLL の関数名、変数名などは、全ての言語で共通利用出来る訳ではない。C++ で Class や namespace 、複雑な構造体とか… 同様の呼び出し名を、C や VB Java などでも利用出来無いと困るのである。

こうした問題を DLL 作成時に適切なエクスポート方法を選択し解決する必要がある。(…それ以外にも理由は有ると思うが…)

エクスポート方法を選択する


DLL ファイルをエクスポートする場合、.DEF file を使う方法__declspec(dllexport) を使う方法がある。

  • __declspec(dllexport)
    1. アプリケーションと一緒に管理可能な DLL を作成する。
    2. 必要に応じアプリケーションのリコンパイルが可能。
    3. .DEF file を使うのが面倒…など
  • .DEF file
    1. 利用アプリケーション(作成言語を含む)を限定せず、不特定多数へ公開される DLL 作成。
    2. 利用アプリケーションの管理不可能な場合。(DLL改版でも、何ら変更無く動作しないと困る場合)

  • 選択基準(2)
    • 呼出側プログラム言語
      • 同一言語のみ利用 … .DEF file / __declspec(dllexport)
      • 言語を問わず利用可能にしたい … .DEF file
    • 呼出側プログラムのリコンパイル可否
      • リコンパイル可能 … .DEF file / __declspec(dllexport)
      • リコンパイル不可能 … .DEF file
    • DLL 作成方法
      • 言語固有(C++ Class など)機能をつかう … .DEF file / __declspec(dllexport)
      • 従来同様 C言語仕様で記述する … .DEF file / __declspec(dllexport)
    • エクスポートの手間と DLL の汎用性
      • 簡単にエクスポートしたい … __declspec(dllexport)
      • 手間が掛かっても汎用性重視 … .DEF file

※など考慮する。「C++ エクスポート方式の使い分け」で、自ずと決定する。

▲上へ

C++ エクスポート方式の使い分け


 制限の低い DLL 作成では .DEF を使うのが基本と思われる。但し .DEF を使いこなすのは簡単ではない。
 .DEF を使わず簡単にエクスポートをする方策もある。但し、各種制限もある。

モジュール定義 (.def) ファイルを使う


1)柔軟な 共有DLL 作成が可能

 不特定多数のプログラムから利用されることを想定し、且つ、公開することを想定した DLL の作成に適する。

 .def file はエクスポート序数を制御可能。(※単に物を数える際の読み上げ数値が基数、物に番号を割振った数値を序数…と言う様である。言い回しが正しくない、又は、誤解釈の可能性もあるので注意)

 DLL に関数(エクスポート関数)を追加する場合、その関数に高い序数値を割当て可能である。これは呼出側アプリケーションを何ら変更することなく改版(関数追加)された DLL をそのまま利用可能に出来る。(新しい関数を含む新しいインポート ライブラリとリンクし直す必要がない。)(アプリケーション変更不要、新しい関数が使えないだけ・・・)

2)NONAME 属性を使って、関数をエクスポートできる

 NONAME 属性は、DLL のエクスポート テーブル内の序数のみを配置する。
 多数のエクスポート関数を含む DLL の場合、NONAME 属性を使うと、DLL file サイズを抑制できる。
 ※モジュール定義文の記述は、「モジュール定義ステートメントに関する規則」を参照。
 ※序数値によるエクスポートの詳細は、「名前ではなく序数値による DLL 関数のエクスポート」を参照。

※難しくて解からん!MSDN 再確認!

3)手続きが煩雑(面倒)である

 C++ ファイル内の関数をエクスポートする場合、コンパイラが関数名を装飾しないよう extern "C" を使って標準の C リンケージでエクスポート関数を定義するか、・・・.def ファイルに装飾名を記述する必要がある。

 .def file内に装飾名を配置する場合、装飾名を取得するには、DUMPBIN Tool や /MAP Linkar Option を使う。

▲上へ

関数の定義に __declspec(dllexport) キーワードを使用する


1)比較的簡単に利用できる

 __declspec(dllexport) は、.def file のメンテナンスやエクスポート関数の装飾名の取得など面倒な配慮が必要ないこと。

2)利用範囲が限定される

 内輪で利用する分には問題無いが、不特定多数へ配布する DLL 作成不可。利用プログラムの管理可能範囲に限定。(自分で制御するアプリケーションに使用できるよう DLL をデザインする場合などに適する。)

 DLL 改版に伴い、実行アプリケーションも同じくリビルドする必要が発生することがある。(新しいエクスポートで DLL をリビルドする場合、別Verのコンパイラを使い再コンパイルする際に、エクスポートされた C++ 関数の装飾名が変更される可能性があることから、アプリケーションもリビルドする必要がある可能性あり。)

※__declspec(dllexport) を使って DLL をリコンパイルし、呼出側プログラムが正常に動作しなくなった場合「プログラムもリコンパイルしなさい!」ってことと思われる。
※且つ、同一バージョンの VC++ 利用が推奨らしい。(…MS 拡張と思われる…)

▲上へ

リンク


内部リンク



外部リンク



▲上へ

独り言とかメモとか …


アプリケーションの実行


動作確認状況

  • 特定アプリケーションでの動作確認
    • … これから準備 …
      ※たぶんこの方法では出来ない気がする…

 *** 一時的メモ ********************************************

Script 定義
※呼出側 Script の追加ヘッダー
#import "inportFileName.***"          // ライブラリ名
double functionName(double a, int b); // 定義済み関数名

inportFileName.*** の内容
※DLL 本体に相当
double functionName(double x, int y) {
   double ret;
   ret = 〜 処理 〜
   return(ret);
}

 **********************************************************

※DLL 組込側の定義例を記載。同ソフトの Script ならこれで動く。
※これに置き換えて、今回作成した DLL から期待値を読み出せれば OK なのだが…
※あまりにも簡単すぎるような気がする…

※やはり、functionName が見つからないと出る。多分、extern "C" あたりがキーワードになると思われる。

 *** DLL 側変更? *****************************************

#define DllExport extern "C" __declspec(dllexport)
DllExport int __stdcall functionName(double a, int b)

また、テスト作成した DLL が Class のため ClassName::functionName(); となること。
さらに、namespace SampleDll {} などとなってるのも多分不味い気がする。

SampleDll::ClassName::functionName(double a, int b);

…でなければ関数名を呼び出せないのではないか?勿論これで関数呼び出しするとエラーとなる。

※それではと、呼び出し側の定義ごと SampleDll::ClassName::functionName() とやったら、さすがに "::" はコンパイルエラーの嵐となった。

※結局、呼び出し側の規則に合う形式で、DLL を作成する必要が当然のようにあるのであろう。

 **********************************************************

▲上へ
2008年05月18日(日) 19:49:43 Modified by cafeboy1




スマートフォン版で見る