- 追加された行はこの色です。
- 削除された行はこの色です。
[[Open棟梁Project>http://opentouryo.osscons.jp/]] - [[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]
「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。
-[[戻る>DLL]]
* 目次 [#aa6384d6]
#contents
*概要 [#m5af277b]
-https://github.com/OpenTouryoProject/SampleProgram
--VC++ DLL:「\InteropWithUnmanage\VC\VC_DLL」
--VC++ 呼出元:「\InteropWithUnmanage\VC\VC_Client\VC_Client1」
--C# 呼出元:「\InteropWithUnmanage\DNET\DNET_Client」
*手順 [#k159e01b]
**プロジェクトの作成 [#l75830cc]
-新規作成→Win32プロジェクトを選択
-ウィザードで、DLLを選択。
-プロジェクトが作成される。
--dllmain.cppはDLLのエントリポイント。
--(プロジェクト名).cppにエクスポート関数を定義する。
**エクスポート関数の実装 [#t9300a13]
以下、2つのメソッドをエクスポートしている。
-Test_MYLIBAPI
-TestArrayMethod
***明示的ロードが不要だが、関数のエクスポートが手間な方式 [#cc6a9e66]
-ヘッダ・ファイル
-ソース・ファイル
-モジュール定義ファイル
を作成して関数をエクスポートする方式
-ヘッダ・ファイル(MYLIBAPI.h)~
プロジェクトに、ヘッダ・ファイルを追加する。
// エクスポートとインポートの切り替え
#ifdef MYLIBAPI // VC_DLL_EXPORTS でもいいかも
// DLLのPJではソース・ファイル(MYLIBAPI.cpp)を使用して関数をエクスポート。
#else
// EXEの(DLLを利用する)PJではヘッダ・ファイル(MYLIBAPI.h)を使用して関数をインポート。
// extern "C" は、他の言語から呼ぶ場合に必要。
#define MYLIBAPI extern "C" __declspec(dllimport)
#endif
// 以下、エクスポート関数のプロトタイプ宣言
// 通常、__stdcallを適用する(__stdcall = WINAPI)。
MYLIBAPI void __stdcall Test_MYLIBAPI(LPCWSTR lpText, LPCWSTR lpCaption);
// この方式だと、C4603、C4273の警告が出るが、問題はない。
// ・C4603:'<identifier>': マクロが定義されていないか、
// プリコンパイル済みヘッダーが使用している定義とは異なります。
// ・C4273:dll リンクが一貫していません。
-ソース・ファイル(MYLIBAPI.cpp)~
プロジェクトに、ソース・ファイルを追加する。
// このソースコードの関数と変数をエクスポート
#define MYLIBAPI extern "C" __declspec(dllexport)
#include <stdafx.h>
#include <windows.h>
#include <stdio.h>
// エクスポート関数の宣言
#include "MYLIBAPI.h"
// 以下、エクスポート関数の実装
// 通常、__stdcallを適用する(__stdcall = WINAPI)。
void __stdcall Test_MYLIBAPI(LPCWSTR lpText, LPCWSTR lpCaption)
{
// MessageBoxを呼び出すだけ。
MessageBox(NULL, lpText, lpCaption, MB_OK);
}
-モジュール定義ファイル(Exports.def)~
プロジェクトに、モジュール定義ファイルを追加する。
;MS系以外のツールから呼ぶときは、
;DefファイルのEXPORTSを使用してExportする。
LIBRARY "VC_DLL"
EXPORTS
Test_MYLIBAPI
TestArrayMethod
***明示的ロードが必要だが、関数のエクスポートが簡単な方式 [#p97c5784]
簡単な方式では明示的ロードでVC、DOTNETから使用するので、~
ヘッダ・ファイル、モジュール定義ファイルなどのモジュールが不要。
-ソース・ファイル(Simple.cpp)~
プロジェクトに、ソース・ファイルを追加する。
// 簡単な方式(明示的ロードが必要)
// Simple.cpp : DLL アプリケーション用にエクスポートされる関数を定義します。
#include "stdafx.h"
#include <stdio.h>
// 以下は、
// The try, catch, and throw Statements
// http://msdn.microsoft.com/en-us/library/6dekhbbc(VS.80).aspx
// から引用
class CTest {
public:
CTest() {};
~CTest() {};
const char *ShowReason() const {
return "Exception in CTest class.";
}
};
extern "C"{
typedef struct _A{
int m1;
char m2_in[12]; // 11文字まで (MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)
char m3_out[48]; // 47文字まで (MarshalAs(UnmanagedType.ByValTStr, SizeConst=48)
} A;
// 明示的ロードでVC、DOTNETから使用するのでヘッダーファイルは不要
// なお、__cdeclでもDOTNETから正しく呼び出せることを確認している。
// 通常、__stdcallを適用する(__stdcall = WINAPI)。
__declspec(dllexport) int __stdcall TestArrayMethod(A a, A *pa, int len, A aa[]);
int __stdcall TestArrayMethod(A a, A *pa, int len, A aa[]){
// 配列の長さが0未満はありえないので
// 例外を発行する(C++の例外を発行してみる)
if(len < 0){
throw CTest();
} // extern "c" で警告が表示される(__cdeclでも__stdcallでも)。
// 値渡しの構造体 a
char *p_inputmessage = a.m2_in;
int counter = a.m1;
// 参照渡しの構造体 *pa(構造体 a からコピー)
pa->m1 = ++counter; // 先に ++ してから代入
sprintf_s(pa->m3_out, 47, "%s by pa->", p_inputmessage);
// 参照渡しの構造体配列 aa[](構造体 a からコピー)
int i;
for (i = 0; i < len; i++){
aa[i].m1 = ++counter; // 先に ++ してから代入
sprintf_s(aa[i].m3_out, 47, "%s by aa[%d].", p_inputmessage, i);
}
return counter;
}
}
*DLLの呼び出し方法 [#i3b400f4]
-参考:Advanced Windows
--第 4 部 DLL
---第 19 章 DLL の基礎
---第 20 章 DLL の高度なテクニック
**暗黙のうちにリンク [#y6d6bb39]
∗.libファイルを使用する。~
リンカが*.libファイルを使ってインポートされている関数/変数の参照を解決しながら*.objモジュールを結合し、~
∗.exeファイル(必要なDLLとインポートされているシンボルのリストであるインポートテーブルを格納している)を生成する。~
**明示的にリンク [#w266ec25]
明示的なリンクでは、*.libファイルを使用せず~
(従って、*.exeファイルはインポートテーブルを持たない)、~
Win32APIのLoadLibraryを使用してDLLをロードする。
*DLL呼び出し側コード例 [#z837f076]
**VC++ [#ufc73858]
-VC++からのDLL呼び出しでは、∗.libファイルを使用した暗黙のリンクを使用している。
-∗.libファイルを参照する場合は、以下の手順に従う。
--リンカ入力としての .lib ファイル~
http://msdn.microsoft.com/ja-jp/library/ba1z7822.aspx
+++プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。
+++[リンカ] フォルダをクリックします。
+++[入力] プロパティ ページをクリックします。
+++[追加の依存ファイル] プロパティを変更します。
// VC_Client1.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#include <windows.h>
#include "../../VC_DLL/MYLIBAPI.h"
int _tmain(int argc, _TCHAR* argv[])
{
// 通常のLibを使用したDLL関数の呼び出し方法。
Test_MYLIBAPI(L"text", L"caption");
return 0;
}
**C# [#a947e0a4]
.NETからのDLL呼び出し(P/Invoke)では、
明示的なリンクを使用している。
/// <summary>VC_DLL.TestArrayMethod</summary>
[DllImport("VC_DLL.dll")]
private extern static int TestArrayMethod(A a, ref A pa, int len, [In, Out] A[] aa);
// 第4引数(構造体配列)を、結果受け取り用で宣言する場合は
// "ref" では不可、"[Out]" 属性を設定する必要がある
/// <summary>DLL呼び出し</summary>
private void Button1_Click(object sender, RoutedEventArgs e)
{
try
{
A a1 = new A();
A a2 = new A();
A[] a3 = new A[3];
a1.m1 = 8;
a1.m2_in = "{入力値側}";
// 正常系: 第3引数(配列サイズ)を正しく指定
int ret1 = TestArrayMethod(a1, ref a2, a3.Length, a3);
}
catch (SEHException ex)
{
//MessageBox
MessageBox.Show(
"Err.Number:" + ex.ErrorCode + "\r\n" +
"Err.Description:" + ex.Message,
"例外", MessageBoxButton.OK);
}
}
*補足 [#oa4f829d]
-MYLIBAPI
--上記コード中で定義されるマクロです。
--当該(DLLの)プロジェクトではエクスポートを実行
--(DLLの)利用側プロジェクトではインポートを実行
-extern "C"~
関数がC言語形式 になっていることを示す。
-__stdcall = WINAPI
--Web-DB プログラミング徹底解説
---Hello, world の解説 ~ WINAPI とは何か? __stdcall の説明~
http://keicode.com/winprimer/wp07.php
---関数を呼び出すということ~
http://keicode.com/winprimer/wp07b.php
-__declspec(dllexport)
--DLL からのエクスポート~
http://msdn.microsoft.com/ja-jp/library/z4zxe9k8.aspx
---__declspec(dllexport) を使った DLL からのエクスポート~
http://msdn.microsoft.com/ja-jp/library/a90k134d.aspx
-__declspec(dllimport)
--アプリケーションへのインポート~
http://msdn.microsoft.com/ja-jp/library/kh1zw7z7.aspx
---__declspec(dllimport) を使った関数呼び出しのインポート~
http://msdn.microsoft.com/ja-jp/library/zw3za17w.aspx
-モジュール定義ファイル、LIBRARY、EXPORTS~
--DEF ファイルを使った DLL からのエクスポート~
http://msdn.microsoft.com/ja-jp/library/d91k01sh.aspx
*参考 [#r819416c]
**DLLの作成 [#z0f83354]
-Codian(DLL・フック)~
http://www.kab-studio.biz/Programing/Codian/#DLL_Hook_SClass
--DLLを使おう!!~
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/01.html
--DLLの実行中リンク~
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/02.html
--DLLを作ろう!(関数編)~
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/03.html
--「自作」DLLを使おう!!~
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/04.html
--DLLを作ろう!(クラス編)~
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/05.html
-Win32API(C言語)編 トップページ
--Win32API(C言語)編 第57章 ダイナミックリンクライラリ(DLL)~
http://www.geocities.jp/ky_webid/win32c/057.html
--Win32API(C言語)編 第58章 LoadLibrary()によるDLLロード~
http://www.geocities.jp/ky_webid/win32c/058.html
--Win32API(C言語)編 第59章 .DEFファイルによるDLLエクスポート~
http://www.geocities.jp/ky_webid/win32c/059.html
-ダイナミック リンク ライブラリ(DLL)の基礎知識~
http://exlight.net/devel/windows/dll/windll.html
-VC++DLL作成補足(Hishidama's VC++Memo DLL)~
http://www.ne.jp/asahi/hishidama/home/tech/vcpp/dllusage.html
-C++で作成したDLLを他の言語で利用できるようにする » 二流プログラマの三流な日常~
http://blogs.konuma.org/blog/2007/04/c_b43e/
**P/Invoke [#t9cf3ae5]
-P-Invoke - Wikipedia~
http://ja.wikipedia.org/wiki/P/Invoke
-pinvoke.net the interop wiki!~
http://www.pinvoke.net/