#pragma twice

KAB-studio > プログラミング > #pragma twice > 314 Version 15.14 自作 DLL を実行中リンクしてみる

#pragma twice 314 Version 15.14 自作 DLL を実行中リンクしてみる

前のページへ 表紙・目次へ 次のページへ

 Version 15.14
自作 DLL を実行中リンクしてみる

前回は DLL を実行中にリンクして、好きな関数を呼び出す、っていうの
をしてみました
あんなふうに使うと、リンクとか必要ないのねー
関数の呼び出しが特殊だからね。前回のプログラムをもう一度見てみよう


// Main.cpp
#include <Windows.h>

// MessageBox()関数ポインタの typedef 。
typedef int (WINAPI *type_pfnMessageBox)
    ( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // user32.dll に実行中リンクします。
    HINSTANCE hInstanceDll = LoadLibrary( "user32.dll" );
    if( hInstanceDll == NULL )
    {
        OutputDebugString( "DLLをロードできませんでした。" );
        return 0;
    }
    
    // user32.dll の MessageBoxA() 関数の関数ポインタを取得します。
    type_pfnMessageBox pfnMessageBox 
        = (type_pfnMessageBox)GetProcAddress
            ( hInstanceDll, "MessageBoxA" );
    if( pfnMessageBox == NULL )
    {
        OutputDebugString( "関数を取得できませんでした。" );
    }
    else
    {
        // ここで、 MessageBox() 関数を呼び出します。
        pfnMessageBox( NULL, "テスト", "テストダイアログ", MB_OK );
    }

    FreeLibrary( hInstanceDll );
    return 0;
}

関数を呼び出している

        pfnMessageBox( NULL, "テスト", "テストダイアログ", MB_OK );

が、関数ポインタを使って呼び出しているから、リンクの必要がない、と
いうかしようがないんです
こういう形なら、関数を呼び出してもリンクする必要がないわけね
この方法は【プラグイン】でよく使われます
プラグインって、絵を描くのとかでよく使われてるのだよね
そう、プラグインの場合、あとから好きな機能を追加できるようにする必
要があります。普通のプログラムの場合、それはリビルドしなきゃできない
でしょ
でも、この動的リンク使えば……
プラグインは DLL 形式にして、本体の Exe から呼び出す関数名と引数、
戻り値を決めておいて、特定のフォルダにその DLL を置くようにします。 
DLL のファイル名を LoadLibrary() で指定すれば
その DLL の関数が呼ばれるってわけねー
というわけで、これを自分で作った DLL で試してみます
! なんだか本格的!
使う DLL は、 Version 15.10 ( No.310 ) の段階での DLLTestEasy にし
ます
プログラムはそのまま?
今回はそのまま。 DLLTestEasy.cpp だけ載せるとこんな感じ

// DLLTestEasy.cpp : DLL アプリケーション用のエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "DLLTestEasy.h"

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}


// これはエクスポートされた変数の例です。
DLLTESTEASY_API int nDLLTestEasy=0;

// これはエクスポートされた関数の例です。
DLLTESTEASY_API int fnDLLTestEasy(void)
{
    OutputDebugString( "fnDLLTestEasy()\n" );
    return 42;
}

// これはエクスポートされたクラスのコンストラクタです。
// クラスの定義については DLLTestEasy.h を参照してください。
CDLLTestEasy::CDLLTestEasy()

    return; 
}

今回の例では fnDLLTestEasy() を呼び出します
うん、この前呼んだ関数ね
まず、これをビルドして作った DLL を BuildTest\Debug フォルダに
コピーしてください
つか前もコピーしてるからそのままでいいよね
うん、そのままでいいよ。次に、 BuildTest を以下のように修正しま


// Main.cpp
#include <Windows.h>

// fnDLLTestEasy()関数ポインタの typedef 。
typedef int (WINAPI *type_pfnDLLTestEasy)(void);

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // DLLTestEasy.dll に実行中リンクします。
    HINSTANCE hInstanceDll = LoadLibrary( "DLLTestEasy.dll" );
    if( hInstanceDll == NULL )
    {
        OutputDebugString( "DLLをロードできませんでした。" );
        return 0;
    }
    
    // DLLTestEasy.dll の fnDLLTestEasy() 関数の関数ポインタを取得します。
    type_pfnDLLTestEasy pfnDLLTestEasy 
        = (type_pfnDLLTestEasy)GetProcAddress
            ( hInstanceDll, "?fnDLLTestEasy@@YAHXZ" );
    if( pfnDLLTestEasy == NULL )
    {
        OutputDebugString( "関数を取得できませんでした。" );
    }
    else
    {
        // ここで、 fnDLLTestEasy() 関数を呼び出します。
        pfnDLLTestEasy();
    }

    FreeLibrary( hInstanceDll );
    return 0;
}

前回とほとんど同じね
違う所は、まず関数ポインタ

// fnDLLTestEasy()関数ポインタの typedef 。
typedef int (WINAPI *type_pfnDLLTestEasy)(void);

この辺は前回と同じ法則で作ってます
 MessageBox() よりも引数少ないから楽だね。引数なくても void は付け
るんだ。戻り値とか void ポインタにしか使わないと思ってたんだけど
本当は、関数に引数がないときは、引数に void って書くんです。ただ、
それは昔のルールで、今はほとんどしないかな
そうなんだ。で、次は DLL ね

    // DLLTestEasy.dll に実行中リンクします。
    HINSTANCE hInstanceDll = LoadLibrary( "DLLTestEasy.dll" );

 DLL のパスについて補足。 LoadLibrary() は、 DLL を次の順で探しま


1. Exe のあるフォルダ
2. カレントディレクトリ
3. System32 フォルダ
4. System フォルダ
5. ウィンドウズフォルダ
6. PATH 環境変数で設定されたフォルダ

まぁようするに、 Exe のあるフォルダと WinNT\System32 フォルダの
どっちかに置いとけばいいから。それにフルパスでも指定できるし
フルパスOKなんだ
プラグインの場合にはその方がいいかもね。では最後、関数ポインタの取


    // DLLTestEasy.dll の fnDLLTestEasy() 関数の関数ポインタを取得します。
    type_pfnDLLTestEasy pfnDLLTestEasy 
        = (type_pfnDLLTestEasy)GetProcAddress
            ( hInstanceDll, "?fnDLLTestEasy@@YAHXZ" );

……?????

?fnDLLTestEasy@@YAHXZ

って何!? なんで関数名がこんな変なの!? これバグってない?
バグってると思う?
……ビルドして実行……あ、〈fnDLLTestEasy()〉って出た
というわけで次回に続く!

/*
    Preview Next Story!
*/
何あの変な関数名!!
エクスポートするとああいう名前になるんです
ええーっ!? だって MessageBox() は普通だったじゃん!
それは、エクスポートの方法が違うから
方法……っていっぱいあるの?
というわけで次回
< Version 15.15 さまざまなエクスポート >
につづく!
この辺は MSDN にも載ってないから難しいよー?
ぐぐったら Codian ってとこに載ってたよ
あ、いや、それは……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。