2019年7月10日水曜日

キャプチャソフト開発 その3 DLLを作ってみる

DLLってそもそも何?なんか難しそう...
と思ったが、全然そんなことはなかった。

主に参考にしたサイト

これらを参考に実装していきます。
本ページの目的を以下に示します。
  • DLLを明示的に呼び出す
  • DLLからHello Worldする

メインソースファイル
#include <stdio.h>

#include <windows.h>

#include "./util.h"



int main(int argc, char* argv[]) {

  (void)argc;

  (void)argv;



  // Load DLL.

  HINSTANCE hDLL = LoadLibrary(L"util.dll");

  if (hDLL == NULL) {

    fwprintf(stderr, L"Failed to load DLL\n");

    return 1;

  }



  // Load DLL function.

  void (*func)() = NULL;

  func = (void (*)())GetProcAddress(hDLL, "HelloWorld");

  if (func == NULL) {

    fwprintf(stderr, L"Failed to get function\n");

  } else {

    func();

  }



  // Release DLL.

  FreeLibrary(hDLL);



  return 0;

}






  • hDLL
    今回作成したDLLへのインスタンスハンドルです。
  • LoadLibraryFreeLibrary
    それぞれ、DLLのロードと解放を行う関数です。
  • GetProcAddress
    DLLから関数のアドレスを取得します。


DLLのソースファイル
#define DLLAPI extern "C" __declspec(dllexport)



#include "./util.h"

#include <stdio.h>



DLLAPI void HelloWorld() { wprintf(L"Hello World!\n"); }





DLLのヘッダファイル
#ifndef _UTIL_H_

#define _UTIL_H_



#include <stdio.h>



#ifndef DLLAPI

#define DLLAPI extern "C" __declspec(dllimport)

#endif



DLLAPI void HelloWorld();



#endif  // _UTIL_H_







  • #define DLLAPI extern "C" __declspec(dllexport)
    DLLAPIマクロを、DLLのソースファイルではこのように定義しておきます。
    ヘッダファイルをインクルードする前に定義するのがポイントです。
  • #define DLLAPI extern "C" __declspec(dllimport)
    DLLAPIマクロを、DLLのヘッダファイルではこのように定義しておきます。
  • HelloWorld
    DLLに実装する、ハローワールドする関数です。
  • DLLMainは?
    今回のケースは簡単なので、書かなくても大丈夫です。
    作りたいプログラムによっては、あると便利な場合もあるのでしょう。
DLLAPIマクロのからくりについては、参考サイトの方で詳しく解説されています。

メイクファイル
TARGET = main.exe

PDB = main.pdb

MAP = main.map

RES =

SRC = main.cc util.cc

OBJ = $(OBJDIR)\main.obj

DLL = util.dll

OBJDIR = build



CC = "$(VCINSTALLDIR)\cl.exe"

LINK = "$(VCINSTALLDIR)\link.exe"

CPPFLAGS = /nologo /W4 /Zi /O2 /MT /EHsc /Fd"$(TMPDIR)/" /DUNICODE /D_UNICODE \

      /DDEBUG

LFLAGS = "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" \

     "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" \

     "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "libcmt.lib" \

     /NOLOGO /SUBSYSTEM:CONSOLE /DEBUG



ALL: $(TARGET)



$(TARGET): $(OBJ) $(DLL) $(RES)

 $(LINK) $(LFLAGS) /OUT:$(TARGET) /PDB:"$(PDB)" /MAP:"$(MAP)" \

 $(OBJ) $(RES)



.cc{$(OBJDIR)}.obj:

 @[ -d $(OBJDIR) ] || mkdir $(OBJDIR)

 $(CC) $(CPPFLAGS) /Fo"$(OBJDIR)\\" /c $<



.cc.dll:

 $(CC) $(CPPFLAGS) /LD $<



clean:

 rm $(OBJ) $(TARGET) *.map *.pdb *.ilk *.obj *.lib *.dll *.exp






  • SUBSYSTEM:CONSOLE
    コンソールアプリケーションとしてビルドすることを、リンカオプションで設定します。
  • .cc.dll
    CCファイルからDLLファイルを作るルールを指定します。
    clコンパイラでは、LDオプションを付けることでDLLを作れます。
DLLを含むプロジェクトのためのMakefileは初出ですが、.cc.dllのルールが加わったこと以外、あまり変わりませんね。

備考

意外とあっさりしていて驚いた。
DLLを扱ったことで、Windowsに対する理解が深まった気がする。

プロジェクト一式については、GitHubにも上げておきます

0 件のコメント:

コメントを投稿

コメント表示は承認制に設定しています