ダイナミック リンク ライブラリ(DLL)の基礎知識

1. DLLの作り方(VC++編)

関数subをDLLにしたい場合,次のようにソースプログラムを作成する. 外部プログラムから呼び出したい関数(この場合sub)の前に __declspec(dllexport)という おまじないをつけておく(このおまじないがついていない関数はDLL外部からは見えないので安心).

sub.c
#include <stdio.h>

__declspec(dllexport) int sub(int arg)
{
    printf("sub %d\n", arg);
    return arg + 1;
}
sub.cをダウンロード

通常の静的にリンクして利用する関数を作る場合(*.objまたは静的リンク ライブラリ*.libを作ってリンクする場合)との違いは, DLLの外に公開したい関数の定義の前に__declspec(dllexport)というキーワードがつけることだけになっている. [さらに*.defファイルを作成してコンパイル時にコンパイラにわたすようにすれば, __declspec(dllexport)も書かなくてよくなり, ソースは*.objや静的リンク ライブラリ*.libを作る場合とまったく同じにできる.] [注:静的リンク ライブラリはマイクロソフト用語では“標準ライブラリ”と呼ばれているようだ. しかし,ここではDLL(ダイナミック リンク ライブラリ=動的リンク ライブラリ)の対になる語としてわかりやすい静的リンク ライブラリという語を使うことにする.]

コンパイル時にはオプション/LDを指定する.

> cl /LD sub.c

これで,sub.dllsub.objsub.libの3つのファイルができたと思う. コンパイラのバージョンによってはsub.libはできていないかもしれないが, 絶対必要なファイルはsub.dllだけなので気にしなくてもよい(というか特に必要でなければsub.dll以外は削除してもよい). [注:このDLLを作るときに副産物として生成されるsub.libのことをインポート ライブラリと呼んでいる. ファイル名は静的リンク ライブラリ(標準ライブラリ)とまったく同じ*.libだが,内容はまったく違うもので, 後で説明する暗黙リンクによるDLLの使用方法を採用した場合に必要になる. したがって,インポート ライブラリの作り方については後節にて説明する.]

2. DLLの使い方

DLLの使い方には次の2種類の方法がある.

通常の実用的なアプリケーションでは明示的なリンクによる方法を使うことになると思われるが, まずはソースプロうグラムが簡単に書ける暗黙的なリンクによる方法を説明する.

2.1. DLLの使い方:暗黙的なリンクによる方法

ポイントは次の2点である.

暗黙リンクでDLLを使用するプログラムは以下のように書けばよい.

main_static.c
#include <stdio.h>

__declspec(dllimport) int sub(int);

int main(void)
{
    printf("main %d\n", sub(1));
    return 0;
}
main_static.cをダウンロード

ここでは一覧性がよいように関数subのプロトタイプ宣言(__declspec(dllimport) int sub(int);の部分)を メインプログラム内に書いているけど,普通はこのプロトタイプはsub.hというヘッダファイルに書いてあって メインプログラムはsub.hをインクルードするだけになっているだろうから, この方法ではメインプログラムはDLLを使う場合でも静的リンクする場合 (*.objや静的リンク ライブラリ*.libを使う場合)でも変更する必要はないということになる.

コンパイル時にはDLL作成時に同時に生成されたインポート ライブラリsub.libも いっしょにわたしておく.

> cl main_static.c sub.lib

これで実行可能ファイルmain_static.exeができあがる.

ちゃんとDLL内のsubが使われていることを確かめたい場合は,sub.dllを削除してから実行してみればよい. ダイアログボックスが現れてsub.dllが見つからないというエラーメッセージを表示するはずだ. [注:もしsub.dllを削除してからmain_static.exeを実行してもエラーにならずに正しく実行できてしまったという場合は sub.libがインポート ライブラリではなく静的リンク ライブラリ(標準ライブラリ)になってしまっていると思われる. “付録A. インポート ライブラリの作り方”を参照してインポート ライブラリを作り直してから再度main_static.cをコンパイルしなおしてほしい.]

2.2. DLLの使い方:明示的リンクによる方法

明示的リンクでDLLを利用するプログラムは, LoadLibraryGetProcAddressFreeLibrary の3手からなる.

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

int main(void)
{
    HINSTANCE hDLL;
    int (*func)(int);
    if ((hDLL = LoadLibrary("sub.dll")) == NULL)
        printf("LoadLibrary is failed.\n");
    else {
        if ((func = (int (*)(int))GetProcAddress(hDLL, "sub")) == NULL)
            printf("GetProcAddress is failed.\n");
        else
            printf("main %d\n", func(1));
        FreeLibrary(hDLL);
    }
    return 0;
}
main_dynamic.cをダウンロード

コンパイル方法は特に工夫はいらない.普通にコンパイルすればよい.

> cl main_dynamic.c

2.3. 暗黙的リンク・明示的リンク,どちらを使うべき?

暗黙的リンクによる方法の利点は簡単・簡潔なところだが, 実際のアプリケーションでは諸般の事情から明示的リンクを使うことが多い. 諸般の事情とは だいたい以下のような感じのものだ.

ほかにも いろいろな理由があると思うのだけども,これらを見ただけでも, 不特定多数の人が使う実用的なアプリケーションの場合は普通 明示的リンクを選択するしかないのかな,と理解してもらえると思う.

付録A. インポート ライブラリの作り方

(※この節は)

少し古いバージョンのVisual C++を利用している場合, cl /LD sub.cとするだけではインポート ライブラリsub.libができないかもしれない (sub.dllsub.objの2つだけが生成される). その場合,次のコマンドを試してみてほしい. [注:現時点の最新版であるVisual C++ 2005(Visual Studio 2005)を使っている場合は“1. DLLの作り方”に示している方法で生成されるため,このオプションは不要. いつごろから不要になったのかは定かではない.]

> cl /LD sub.c /link /IMPLIB:sub.lib

/link /IMPLIB:sub.libはリンカにインポート ライブラリを作成するように指示するオプションである. リンカ オプションなので,sub.objを使ってlink /IMPLIB:sub.lib sub.objとしてもよいが, 紛らわしいので,上記のようにDLLと一緒に作ってしまうほうがいいかもしれない(そうでもないか…).

なお,インポート ライブラリは静的リンク ライブラリ(標準ライブラリ)とまったく同じ名前になるので, うっかり静的リンク ライブラリを作ってしまって それをリンクしてテスト&配布してしまうというミスをおかさないように十分に注意しないといけない. 必ずDLLを削除してみてDLLが見つからないというエラーになるかという確認を行うようにしよう.

付録B. 実験用プログラム等まとめてダウンロード


はたいたかし
2006-08-04
トップ > 開発ツール > Windows > DLL