何もしないプラグインを作る(おまけ)

注意:これはおまけのC言語版です。D言語版を元に書きましたが細かいところは手を抜いています。対象環境はMicrosoft Visual C++ ToolkitとPlatformSDKです。

では実際にプラグインを作っていきます。いきなり全ての機能を実装し、説明するのは困難なのでまずはRegnessemに認識できるだけの何もしないプラグインを作ります。これに機能を追加していって、最終的にお留守番プラグインを完成させましょう。

下準備

C:\Programs以下にaamという作業ディレクトリを用意します。実際のソースをここにおいてコンパイルします。ディレクトリ構造は以下のようになるはずです。


    C:\Programs       
     +-aam            ; An Answering Machine(留守番電話)から命名
        +-nsmplugin.h ; nsmsgsプラグインAPIヘッダ
        +-aam.c       ; プラグインのメインソース
        +-aam.def     ; 定義ファイル
  

それぞれのファイルやディレクトリは後述するので今はC:\Programs\aamディレクトリがあればOKです。

nsmplugin.h

nsmplugin.hにはAPIの定数、関数、型などが書かれています。Regnessem公式サイトの開発室にあるプラグインスケルトンの中に入っているのでコピーしておきます。

メインプログラム

C言語のソースファイルの拡張子にはわかりやすく.cと付けます。なのでメインプログラムのソースファイル名はaam.cとなります。以下にソースファイルの中身を書きます。


    #include <windows.h>
    #include "nsmplugin.h"
    
    const static char *PluginInfo[] = {
        NSM_API_VERSION,                     // API Version
        "AddIn/aam",                         // Module Name
        "An Answering Machine on Regnessem", // Plugin Title
        "An Answering Machine on Regnessem", // Description
        "Moon",                              // Author
        "Copyright (c) 2004 Moon",           // Copyright
        "0.0.1",                             // Version
    };
    
    BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
    {
        switch (ulReason) {
        case DLL_PROCESS_ATTACH:
            break;
        case DLL_PROCESS_DETACH:
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
            return FALSE;
        }
        return TRUE;
    }
    
    // DLL Export Functions
    
    int __stdcall GetPluginInfo(int nInfoNo, LPTSTR lpBuffer, int nSize)
    {
        if (nInfoNo < 0 || nInfoNo > sizeof(PluginInfo)/sizeof(PluginInfo[0])) {
            // Unknown Information Number
            return 0;
        } else {
            lstrcpyn(lpBuffer, PluginInfo[nInfoNo], nSize);
            return lstrlen(lpBuffer);
        }
    }
    
    int __stdcall Initialize(PNsmPluginInitInfo lpInitInfo)
    {
        return 0;
    }
    
    int __stdcall Terminate()
    {
        return 0;
    }
  

プラグイン情報


    const static char *PluginInfo[] = {
        NSM_API_VERSION,                     // API Version
        "AddIn/aam",                         // Module Name
        "An Answering Machine on Regnessem", // Plugin Title
        "An Answering Machine on Regnessem", // Description
        "Moon",                              // Author
        "Copyright (c) 2004 Moon",           // Copyright
        "0.0.1",                             // Version
    }
  

0番目(PluginInfo[0])の値NSM_API_VERSIONはnsmplugin.h内で"0.2.3"と定義されています。これは現在のRegnessemのAPIバージョンです。

1番目(PluginInfo[1])の値はモジュールの名前です。AddInプラグインのaamモジュールです。ここでいうモジュールはD言語のモジュールではなくRegnessemで使われるモジュールのことです。

2,3番目はプラグインの名前とプラグインの説明文です。任意に付けれるのでここでは"An Answering Machine on Regnessem"と付けています。

4,5番目はプラグインの作者名と著作権情報です。これらも任意に付けることが出来ます。

6番目はプラグインのバージョン文字列です。とりあえずここでは0.0.1としておきました。

DLLエントリポイント

DllMainはDLLのエントリポイントです。つまり通常のプログラムでいうmainWinMainと同じものです。

GetPluginInfo


    int __stdcall GetPluginInfo(int nInfoNo, LPTSTR lpBuffer, int nSize)
    {
        if (nInfoNo < 0 || nInfoNo > sizeof(PluginInfo)/sizeof(PluginInfo[0])) {
            // Unknown Information Number
            return 0;
        } else {
            lstrcpyn(lpBuffer, PluginInfo[nInfoNo], nSize);
            return lstrlen(lpBuffer);
        }
    }
  

GetPluginInfo関数はRegnessem本体がプラグインの情報を取得するために呼ばれます。nInfoNoに取得する情報番号、lpBufferに文字列を格納するためのバッファ、nSizeにバッファのサイズが入って呼び出されます。

API仕様書によると、バージョン0.2.3ではバージョン情報の番号は0~6と決まっています。そこでそれ以外の値がきた場合は無効なので0を返します。値を格納した場合はlpBufferに対して書き込んだ文字列を戻り値として返します。

lstrcpynはn文字をバッファにコピーするWindowsの関数で、ここで渡されたバッファに対して対応するプラグイン情報を書き込みます。そして戻り値としてlstrlen(文字列の長さを取得するWindows関数)で文字列の長さ(=書き込んだバイト数)を返しています。

Initialize


    int __stdcall Initialize(PNsmPluginInitInfo lpInitInfo)
    {
        return 0;
    }
  

Initialize関数は、Regnessem本体が一度だけプラグインを初期化するために呼び出します。ここでサービスを作ったり、イベントをフックしたりしますが、今回は何もしないプラグインなので当然何もしません。正常終了したことを示す0を返しているだけです。

Terminate


    int __stdcall Terminate()
    {
        return 0;
    }
  

Terminate関数はプラグインが破棄される前にRegnessem本体から呼び出されます。ここでフックしたイベントを解放したりしますが、Initialize関数で何もしていないのでここでも何もしません。正常終了したことを示す0を返しています。

モジュール定義ファイル

さて、上記のソースをそのままコンパイルしてもDLLはできあがりません。コンパイラに対してこのソース群がどのようなものかを定義した定義ファイルを作る必要があります。


    LIBRARY "aam.dll"
    EXPORTS
        GetPluginInfo
        Initialize
        Terminate
  

詳しい説明は省きますが、LIBRARYに作成するDLLの名前を、EXPORTSにDLLがexportする関数を記述します。基本的にRegnessemのプラグインの場合はGetPluginInfo,Initialize,Terminateの3つの関数をexportすればOKです。

コンパイル

これで全てのファイルが揃いました。早速コンパイルしてみましょう。


    C:\>cd \Programs\aam
    
    C:\Programs\aam>cl /LD aam.c aam.def
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
    Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
    
    aam.c
    Microsoft (R) Incremental Linker Version 7.10.3077
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /out:aam.dll
    /dll
    /implib:aam.lib
    /def:aam.def
    aam.obj
       Creating library aam.lib and object aam.exp
    
    C:\Programs\aam>
  

上記のようになれば成功です。成功すれば以下のようなファイル構成になっているはずです。


    C:\Programs
     +-aam
        +-nsmplugin.h
        +-aam.c
        +-aam.def
        +-aam.obj
        +-aam.exp
        +-aam.lib
        +-aam.dll
  

作成されたプラグインDLLをRegnessemのPluginsフォルダにコピーしてRegnessemを起動します。メインメニューのヘルプからバージョン情報を開くときちんと以下のようなプラグイン情報が表示されているはずです。


    "An Answering Machine on Regnessem" 0.0.1
    Copyright (c) 2004 Moon
  

Download

参考リンク

Copyright © 2004 Moon moon@users.sourceforge.jp