「ライブラリの基礎 - DLLの作成(C/C++/MFC)」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
 
(同じ利用者による、間の6版が非表示)
8行目: 8行目:


== DLLの作成方法 ==
== DLLの作成方法 ==
==== defファイルを使用する ====
==== 呼び出し規約 ====
defファイルを作成する方法を記載する。<br>
[プロジェクト]メニューバー - [プロパティ]を選択して、[プロパティ]ダイアログを表示する。<br>
[プロパティ]ダイアログの[構成のプロパティ] - [C/C++] - [詳細設定]を選択する。<br>
[プロパティ]ダイアログの右ペインから、[呼び出し規約]プルダウンを<u>__cdecl (/Gd)</u>に変更する。 (デフォルト)<br>
<br>
==== モジュール定義ファイル (defファイル) を使用する場合 ====
モジュール定義 (.def拡張子) ファイルは、DLLがエクスポートする関数を記述したファイルであり、リンクするプログラムに関するエクスポート、属性、その他の情報をリンカに提供する。<br>
モジュール定義ファイルは、DLLをビルドする場合に最も役立つ。<br>
<br>
モジュール定義ステートメントの代わりに使用できるMSVCリンカオプションがあるため、モジュール定義ファイルが存在してくてもDLLを開発することができる。<br>
モジュール定義ファイルを使用しない場合は、エクスポートされる関数を指定する方法として、<code>__declspec(dllexport)</code>を使用する。<br>
<br>
<u>※注意</u><br>
<u>エクスポートを行わない実行ファイルを開発する場合、モジュール定義ファイルを使用すると、出力ファイルのサイズが大きくなり読み込みが遅くなることに注意する。</u><br>
<br>
<br>
defファイルとは、DLLがエクスポートする関数を記述したファイルのことである。<br>
[ソリューションエクスプローラ]を右クリックして、コンテキストメニューから[追加] - [新しい項目]を選択する。<br>
[ソリューションエクスプローラ]を右クリック - [追加] - [新しい項目]を選択して、[新しい項目の追加]ダイアログにて"<ファイル名>.def"を追加すると、defファイルが作成される。<br>
[新しい項目の追加]ダイアログが開くので、モジュール定義ファイル名 <u><ファイル名>.def</u> を入力する。<br>
[OK]ボタンを押下すると、モジュール定義ファイルが自動的に作成される。<br>
<br>
<br>
<span style="color:#C00000"><u>※ C++でDLLを作成する場合は、defファイルを作成することを推奨する。</u></span><br>
<span style="color:#C00000"><u>※ C++でDLLを作成する場合は、defファイルを作成することを推奨する。</u></span><br>
<br>
<br>
[プロジェクト]メニューバー - [プロパティ]を選択して、[プロパティ]ダイアログを表示する。<br>
[プロジェクト]メニューバー - [プロパティ]を選択して、[プロパティ]ダイアログを表示する。<br>
[プロパティ]ダイアログの[リンカー] - [入力] - [モジュール定義ファイル]項目に使用するdefファイル名を記述する。<br>
[プロパティ]ダイアログの[リンカー] - [入力] - [モジュール定義ファイル]項目に使用するモジュール定義ファイル名を入力する。<br>
[OK]ボタン、または、[適用]ボタンを押下して、変更内容を保存する。<br>
<br>
[[ファイル:MFC DLL 01.png|フレームなし|中央]]
[[ファイル:MFC DLL 01.png|フレームなし|中央]]
<br>
<br>
<u>※注意</u><br>
<u>※注意</u><br>
<u>C#にて作成したモジュール(EXEまたはDLL)からC++ DLLを呼び出す場合、C++ DLLではdefファイルを使用すること。</u><br>
<u>C#で開発したモジュール(EXEまたはDLL)からC++ DLLを呼び出す場合、C++ DLLではモジュール定義ファイルを使用すること。</u><br>
<br>
<br>
defファイルを作成して、以下のようにエクスポートする関数を記載する。<br>
モジュール定義ファイルを作成して、以下に示すようにエクスポートする関数を記述する。<br>
'''※但し、"@1"等の序数値は記載しなくてもよい'''。<br>
また、<u>@1</u>等の序数値の記載は任意である。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="ini">
  MainDLL.def
  ; MainDLL.def
  LIBRARY MainDLL
  LIBRARY MainDLL
   
   
34行目: 50行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
次に、"MainDLL.h"ファイルは以下のように記載する。<br>
次に、"MainDLL.h"ファイルを作成する。<br>
defファイルによるエクスポートを採用した場合、 エクスポート関数名にキーワードを付ける必要は無い。<br>
モジュール定義ファイルを使用する場合、エクスポートする関数名に<code>extern "C"</code>キーワードおよび<code>DECLSPEC __declspec(dllexport)</code>キーワードを付加する必要はない。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  MainDLL.h
  // MainDLL.h
   
   
  #pragma once
  #pragma once
   
   
  #ifndef  _USRDLL
  int   SampleFunc(int *lp1, int *lp2);
#define  DLL_EXPORT  extern "C" __declspec(dllimport)
  double TestFunc(double *lp1, double *lp2);
#else
#define  DLL_EXPORT
#endif
DLL_EXPORT int     __stdcall SampleFunc(int *lp1, int *lp2);
  DLL_EXPORT double   __stdcall TestFunc(double *lp1, double *lp2);
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
最後に、"MainDLL.cpp"ファイルには以下のように記載する。<br>
最後に、"MainDLL.cpp"ファイルには以下のように記載する。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  MainDLL.cpp
  // MainDLL.cpp
   
   
  #include "Stdafx.h"
  #include "Stdafx.h"
  #include "MainDLL.h"
  #include "MainDLL.h"
   
   
  int __stdcall SampleFunc(int *lp1, int *lp2)
  int SampleFunc(int *lp1, int *lp2)
  {
  {
     // 以下略
     // ...処理 1
  }
  }
   
   
  int __stdcall TestFunc(double *lp1, double *lp2)
  int TestFunc(double *lp1, double *lp2)
  {
  {
     // 以下略
     // ...処理 2
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
モジュール定義ファイルの詳細を知りたい場合は、[https://learn.microsoft.com/ja-jp/cpp/build/reference/module-definition-dot-def-files?view=msvc-170 Microsoftの公式ドキュメント]を参照すること。<br>
<br>
<br>


==== defファイルを使用しない ====
==== モジュール定義ファイル (defファイル) を使用しない場合 ====
defファイルを作成しない方法を記載する。<br>
モジュール定義ファイルを使用しない場合は、<code>extern "C"</code>キーワードおよび<code>__declspec(dllexport)</code>キーワードを付加する必要がある。<br>
<br>
<br>
Visual Studioの[プロジェクト]→[プロパティ]を選択する。<br>
C言語では同じ関数名を複数定義できないため、関数名の一意性があるが、C++では関数のオーバーロードができるため、同じ関数名を区別するためにDLLの出力時に関数名が自動的に変更される。<br>
[C++]→[プリプロセッサの定義]に"DLL"プリプロセッサを追加する。(“Stdafx.h”ファイルに”DLL”プリプロセッサを記載してもよい)<br>
エクスポートする関数名の一意に決定するため、<code>extern "C"</code>キーワードを付加することにより、DLLの出力時に特定の関数名を変更しないようにする。<br>
<br>
<br>
まず、"MainDLL.h"ファイルの先頭に以下のソースコードを追加する。<br>
Visual Studioの[プロジェクト] - [プロパティ]を選択する。<br>
[C++] - [プリプロセッサの定義]に"DLL"プリプロセッサを追加する。(“Stdafx.h”ファイルに”DLL”プリプロセッサを記載してもよい)<br>
<br>
まず、"MainDLL.h"ファイルを作成する。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  MainDLL.h // ファイルの先頭に以下を追加する。
  // MainDLL.h
   
   
  #ifndef __MAINDLL_H__
  #ifndef __MAINDLL_H__
89行目: 104行目:
  #endif
  #endif
   
   
  // 以下略
  // エクスポートする関数
#endif //__MAINDLL_H__
</syntaxhighlight>
<br>
次に、上記の"MainDLL.h"ファイルにエクスポートしたい関数を以下のように記載する。<br>
<syntaxhighlight lang="c++">
MainDLL.h
  #ifdef __cplusplus
  #ifdef __cplusplus
     extern "C"
     extern "C"
103行目: 110行目:
  #endif
  #endif
   
   
DLL_EXPORT int WINAPI SampleFunc(CString &p_rcStr, CWnd *p_pcWnd);
      DLL_EXPORT int SampleFunc(CString &p_rcStr, CWnd *p_pcWnd);
   
   
  #ifdef __cplusplus
  #ifdef __cplusplus
     }
     }
  #endif
  #endif
#endif //__MAINDLL_H__
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
"MainDLL.cpp"ファイルの先頭に以下を記載する。<br>
次に、"MainDLL.cpp"ファイルを作成する。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  MainDLL.cpp
  // MainDLL.cpp
   
   
  #include "StdAfx.h"
  #include "StdAfx.h"
  #include "MainDLL.h"
  #include "MainDLL.h"
</syntaxhighlight>
 
<br>
  extern "C" int SampleFunc(CString &p_rcStr, CWnd *p_pcWnd)
"MainDLL.cpp"ファイルにて関数を作成する時は、以下のように記載する。<br>
<syntaxhighlight lang="c++">
MainDLL.cpp
  extern "C" int WINAPI SampleFunc(CString &p_rcStr, CWnd *p_pcWnd)
  {
  {
     // 以下略
     // 以下略
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<code>extern "C"</code>キーワードを付加しない場合、他の実行ファイル等からDLLを使用すると、関数が見つからないとエラーが発生する。<br>
ネイティブの実行ファイルから呼び出す場合、コンパイル時にエラーが発生する場合が多い。<br>
ただし、マネージドの実行ファイルからC++ DLLを呼び出す場合、<u>実行時に</u>例外<code>System.EntryPointNotFoundException</code>が発生する。<br>
<br><br>
<br><br>


300行目: 308行目:
  int _tmain(int argc, _TCHAR* argv[])
  int _tmain(int argc, _TCHAR* argv[])
  {
  {
    char tmp[12 + 1];
    memset(tmp, 0, sizeof(tmp));
     // DLLを読み込む
     // DLLを読み込む
     HMODULE hModule = ::LoadLibrary(_T("Sample.dll"));
     HMODULE hModule = ::LoadLibrary(_T("Sample.dll"));
322行目: 327行目:
     }
     }
   
   
     // Hello関数を呼ぶ
     // Hello関数の実行
    char tmp[12 + 1];  // Hello関数の引数
    memset(tmp, 0, sizeof(tmp));
     int ret = (*lpFunc)(tmp);
     int ret = (*lpFunc)(tmp);
     if (ret != 0)
     if (ret != 0)

2024年2月10日 (土) 18:05時点における最新版

概要

MFC DLLには、以下の2つの種類がある。

  • 拡張DLL
    DLLを使用するEXEやDLLもMFCで作成する時にのみ使用する。
  • MFCの共有DLL(Regular DLL)
    内部的にMFCそのものを持っているため、DLLを使用するEXEやDLLをMFCで作成しない時でも使用できる。



DLLの作成方法

呼び出し規約

[プロジェクト]メニューバー - [プロパティ]を選択して、[プロパティ]ダイアログを表示する。
[プロパティ]ダイアログの[構成のプロパティ] - [C/C++] - [詳細設定]を選択する。
[プロパティ]ダイアログの右ペインから、[呼び出し規約]プルダウンを__cdecl (/Gd)に変更する。 (デフォルト)

モジュール定義ファイル (defファイル) を使用する場合

モジュール定義 (.def拡張子) ファイルは、DLLがエクスポートする関数を記述したファイルであり、リンクするプログラムに関するエクスポート、属性、その他の情報をリンカに提供する。
モジュール定義ファイルは、DLLをビルドする場合に最も役立つ。

モジュール定義ステートメントの代わりに使用できるMSVCリンカオプションがあるため、モジュール定義ファイルが存在してくてもDLLを開発することができる。
モジュール定義ファイルを使用しない場合は、エクスポートされる関数を指定する方法として、__declspec(dllexport)を使用する。

※注意
エクスポートを行わない実行ファイルを開発する場合、モジュール定義ファイルを使用すると、出力ファイルのサイズが大きくなり読み込みが遅くなることに注意する。

[ソリューションエクスプローラ]を右クリックして、コンテキストメニューから[追加] - [新しい項目]を選択する。
[新しい項目の追加]ダイアログが開くので、モジュール定義ファイル名 <ファイル名>.def を入力する。
[OK]ボタンを押下すると、モジュール定義ファイルが自動的に作成される。

※ C++でDLLを作成する場合は、defファイルを作成することを推奨する。

[プロジェクト]メニューバー - [プロパティ]を選択して、[プロパティ]ダイアログを表示する。
[プロパティ]ダイアログの[リンカー] - [入力] - [モジュール定義ファイル]項目に使用するモジュール定義ファイル名を入力する。
[OK]ボタン、または、[適用]ボタンを押下して、変更内容を保存する。

MFC DLL 01.png


※注意
C#で開発したモジュール(EXEまたはDLL)からC++ DLLを呼び出す場合、C++ DLLではモジュール定義ファイルを使用すること。

モジュール定義ファイルを作成して、以下に示すようにエクスポートする関数を記述する。
また、@1等の序数値の記載は任意である。

 ; MainDLL.def
 
 LIBRARY MainDLL
 
 EXPORTS
         SampleFunc   @1
         TestFunc     @2


次に、"MainDLL.h"ファイルを作成する。
モジュール定義ファイルを使用する場合、エクスポートする関数名にextern "C"キーワードおよびDECLSPEC __declspec(dllexport)キーワードを付加する必要はない。

 // MainDLL.h
 
 #pragma once
 
 int    SampleFunc(int *lp1, int *lp2);
 double TestFunc(double *lp1, double *lp2);


最後に、"MainDLL.cpp"ファイルには以下のように記載する。

 // MainDLL.cpp
 
 #include "Stdafx.h"
 #include "MainDLL.h"
 
 int SampleFunc(int *lp1, int *lp2)
 {
    // ...処理 1
 }
 
 int TestFunc(double *lp1, double *lp2)
 {
    // ...処理 2
 }


モジュール定義ファイルの詳細を知りたい場合は、Microsoftの公式ドキュメントを参照すること。

モジュール定義ファイル (defファイル) を使用しない場合

モジュール定義ファイルを使用しない場合は、extern "C"キーワードおよび__declspec(dllexport)キーワードを付加する必要がある。

C言語では同じ関数名を複数定義できないため、関数名の一意性があるが、C++では関数のオーバーロードができるため、同じ関数名を区別するためにDLLの出力時に関数名が自動的に変更される。
エクスポートする関数名の一意に決定するため、extern "C"キーワードを付加することにより、DLLの出力時に特定の関数名を変更しないようにする。

Visual Studioの[プロジェクト] - [プロパティ]を選択する。
[C++] - [プリプロセッサの定義]に"DLL"プリプロセッサを追加する。(“Stdafx.h”ファイルに”DLL”プリプロセッサを記載してもよい)

まず、"MainDLL.h"ファイルを作成する。

 // MainDLL.h
 
 #ifndef __MAINDLL_H__
 #define __MAINDLL_H__
 
 #ifdef DLL
    #define DLL_EXPORT	__declspec(dllexport)
 #else
    #define DLL_EXPORT	__declspec(dllimport)
 #endif
 
 // エクスポートする関数
 #ifdef __cplusplus
    extern "C"
    {
 #endif
 
      DLL_EXPORT int SampleFunc(CString &p_rcStr, CWnd *p_pcWnd);
 
 #ifdef __cplusplus
    }
 #endif
 
 #endif	//__MAINDLL_H__


次に、"MainDLL.cpp"ファイルを作成する。

 // MainDLL.cpp
 
 #include "StdAfx.h"
 #include "MainDLL.h"
  
 extern "C" int SampleFunc(CString &p_rcStr, CWnd *p_pcWnd)
 {
    // 以下略
 }


extern "C"キーワードを付加しない場合、他の実行ファイル等からDLLを使用すると、関数が見つからないとエラーが発生する。
ネイティブの実行ファイルから呼び出す場合、コンパイル時にエラーが発生する場合が多い。
ただし、マネージドの実行ファイルからC++ DLLを呼び出す場合、実行時に例外System.EntryPointNotFoundExceptionが発生する。


DLLファイルの確認

DLLファイルのエクスポートされた関数名は、dumpbinで確認することができる。

PowerShellまたはコマンドプロンプトを起動して、以下のコマンドを実行する。
この時、name項目に関数名が表示される。

dumpbin.exe /EXPORTS <DLLファイル名>

# 出力
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file <DLLファイル名>

File Type: DLL

Section contains the following exports for sample.dll

   00000000 characteristics
   49A74D91 time date stamp Fri Feb 27 01:18:57 2009
       0.00 version
          1 ordinal base
          1 number of functions
          1 number of names

   ordinal hint RVA      name

         1    0 00001034 FunctionName

 Summary

       1000 .data
       1000 .pdata
       1000 .rdata
       1000 .reloc
       1000 .text



DLLの使用

Visual StudioでDLLを作成している場合、プロジェクトから参照に追加することで使用できる。
他のIDE等でDLLを作成している場合、共有ライブラリとして使用するには、コンパイル時に以下の3つが必要となる。

  • ヘッダーファイル (.h)
  • インポートライブラリ (.lib)
  • DLL


また、外部から呼び出せる関数が存在しない場合、インポートライブラリ(.lib)は作成されない。


インポートライブラリの作成

インポートライブラリ(.lib)が提供されていない場合、DLLファイルから作成できる。

まず、dumpbinを実行して、エクスポートされた全ての定義をファイルに出力する。

dumpbin /exports target.dll > exports.txt


1行目にLIBRARY DLL名、2行目にEXPORTSを記述をしたDEFファイルを作成する。

echo LIBRARY <Dllファイル名> > target.def
echo EXPORTS >> target.def


DEFファイルに、最初に出力したファイルから関数の定義部分だけを追記する。

for /f "skip=19 tokens=4" %A in (exports.txt) do echo %A >> target.def


libコマンドを実行して、DEFファイルからインポートライブラリを作成する。

# 32bitを対象とする場合
lib /def:target.def /out:target.lib /machine:x86

# 64bitを対象とする場合
lib /def:target.def /out:target.lib /machine:x64


インポートライブラリを参照するには、リンカーのオプションにて、[追加の依存ファイル]で指定する。
これは、/DYNAMICBASEオプションを指定することと同じことである。
または、ソースコード内において、#pragmaディレクティブで指定する。


DLLの暗黙的リンクと明示的リンクの違い

暗黙的(静的)リンク 明示的(動的)リンク
関数の宣言 DLLの関数に__declspecl(dllimport)を付けて宣言する。 DLLの関数を宣言せず、typedefする。
リンカ リンカでライブラリファイルをリンクする必要がある。 リンカでのリンクは不要である。
DLLの読み込み EXEの実行の準備段階でDLLを読み込む。
DLLが見つからない場合、EXEは実行されない。
LoadLibrary関数でDLLを読み込む。
DLLが見つからない場合、NULLが返る。
DLL内の関数を実行するには、GetProcAddress関数で関数アドレスを取得する必要がある。
関数との紐付け ライブラリファイルで、DLL内の関数名(序数も含む)が保持されている。
この関数名(あるいは序数)が一致しないとNULLが返る。
GetProcAddress関数で、DLL内の関数名(あるいは序数)を指定する。
この関数名(または序数)が一致しないとNULLが返る。
暗黙的 / 明示的とは EXEの実行準備段階でDLLを自動で読み込むので、暗黙的という。 設計者がLoadLibrary関数を使用してDLLを呼び出すので、明示的という。
静的 / 動的とは リンカでリンクした時点で使用するDLLの種類や関数が決まるので、静的という。 LoadLibrary関数とGetProcAddress関数を使用してDLL内の関数を自由に使用できるので、動的という。



DLLの暗黙的リンク

EXEファイルのプロジェクトに、DLLファイルを暗黙的リンクする方法を記載する。

以下の例では、CppEXE.exeとCppDLL.dllが存在するものとして設定している。

  1. まず、CppEXE.exeのプロジェクトを起動する。
  2. [プロジェクト]メニュー - [CppEXEのプロパティ] - [構成プロパティ] - [C/C++] - [全般] - [追加のインクルードディレクトリ]項目に、
    CppDLL.dllのヘッダファイル(CppDLL.h)が存在するディレクトリを追加する。
  3. 次に、[構成プロパティ] - [リンカー] - [全般] - [追加のライブラリディレクトリ]項目に、
    DLLのライブラリファイル(CppDLL.lib)が存在するディレクトリを追加する。
  4. 最後に、[構成プロパティ] - [リンカー] - [入力] - [追加の依存ファイル]項目に、CppDLL.libと記述する。



DLLの明示的リンク

DLLの明示的リンクを行う場合、Windows APIのLoadLibrary関数を使用する。
DLLファイルが見つからない場合は、ハンドルがNULLで返るため、エラーハンドリングを行う。

以下の例では、Sample.dllファイルに定義されたHello関数を呼んでいる。

 // DLLファイルの読み込み
 HMODULE hModule = ::LoadLibrary(_T("Sample.dll"));
 
 if(hModule == NULL)
 {
    std::cerr << _T("DLLファイルの読み込みに失敗しました") << std::endl;
    return 0;
 }


次に、DLLファイルから呼ぶ関数のアドレスを取得する。
まず、DLLファイルに定義されたHello関数の呼び出すには、Hello関数の関数ポインタを定義する。

Hello関数のアドレスを取得するには、GetProcAddress関数を使用する。
Hello関数のアドレスの取得に失敗した場合は、必ずFreeLibrary関数を呼び、DLLファイルのハンドルを解放する。

 // C++03以前
 // typedef int (*FUNC)(char *);
 
 // C++11以降
 using FUNC = int (*)(char *);
 
 // 関数のアドレス取得
 FUNC lpFunc = (FUNC)::GetProcAddress(hModule, "Hello");
 if (lpFunc == NULL)
 {
    std::cerr << _T("関数のアドレス取得に失敗しました") << std::endl;
    ::FreeLibrary(hModule);
 
    return 0;
 }


最後に、GetProcAddress関数で取得したHello関数のアドレスに引数を渡す。

 // 関数の呼び出し
 int ret = (*lpFunc)(tmp);
 if(ret != 0)
 {
    std::cerr << _T("関数の呼び出しに失敗しました") << std::endl;
    ::FreeLibrary(hModule);
 
    return 0;
 }


以下に、サンプルコードの全体を示す。

 #include "stdafx.h"
 #include <Windows.h>
 #include <conio.h>
 
 // C++03以前
 // typedef int (*FUNC)(char *);
 
 // C++11以降
 using FUNC = int (*)(char *);
 
 int _tmain(int argc, _TCHAR* argv[])
 {
    // DLLを読み込む
    HMODULE hModule = ::LoadLibrary(_T("Sample.dll"));
    if (hModule == NULL)
    {
       std::cerr << _T("DLLファイルの読み込みに失敗しました") << std::endl;
 
       return 0;
    }
 
    // Hello関数のアドレスを取得
    FUNC lpFunc = (FUNC)::GetProcAddress(hModule, _T("Hello"));
    if (lpFunc == NULL)
    {
       std::cerr << _T("Hello関数のアドレス取得に失敗しました") << std::endl;
       ::FreeLibrary(hModule);
 
       return 0;
    }
 
    // Hello関数の実行
    char tmp[12 + 1];  // Hello関数の引数
    memset(tmp, 0, sizeof(tmp));
 
    int ret = (*lpFunc)(tmp);
    if (ret != 0)
    {
       std::cerr << _T("Hello関数の呼び出しに失敗しました") << std::endl;
       ::FreeLibrary(hModule);
 
       return 0;
    }
 
    // DLLの解放
    ::FreeLibrary(hModule);
 
    std::cerr << tmp << std::endl;
    _getch();
 
    return 0;
 }



デバッグ方法

C++DLLのデバッグ方法を、以下に記載する。

  1. [ソリューションエクスプローラー]において、C++DLLプロジェクトを右クリックして、[プロパティ]を選択する。
  2. [<Project>プロパティページ]画面が開くので、画面上部の[構成]プルダウンから[デバッグ]を選択する。
  3. 次に、画面左にある[構成プロパティ] - [デバッグ]を選択する。
  4. 画面右にある[起動するデバッガー]プルダウンから[ローカルWindowsデバッガー]または[リモートWindowsデバッガー]のいずれかを選択する。
  5. 画面右にある[コマンド]項目または[リモートコマンド]項目において、呼び出し元の実行ファイルのフルパスを入力する。
    コマンドライン引数が必要な場合、[コマンド引数]項目に任意の必要なコマンドライン引数を入力する。
  6. [OK]ボタンを押下する。