#ifndef _i_hello_h_ #define _i_hello_h_ // 提供者が作成し、ユーザに公開する、Chello の interface // <<interface>> class Ihello{ public: virtual void Delete(void) = 0 ; virtual void greet(void) = 0 ; } ; // typedef Ihello* (*PnewHello)(void) ; #endif /* _i_hello_h_ */
#ifndef _c_hello_h_ #define _c_hello_h_ // 提供者が作成する、ユーザには非公開の、Chello の specification #include <i_hello.h> // <<imprementation>> <<specification>> class Chello : public Ihello { public: void Delete(void) ; void greet(void) ; } ; #endif /* _c_hello_h_ */
// 提供者が作成する、Chello の body と interface の実装 #include <stdio.h> #include "c_hello.h" // <<imprementation>> <<body>> void Chello::Delete(void){ delete this ; } void Chello::greet(void){ printf("Hello, World!\n") ; } // 操作 : 実体 // このDLLからエクスポートしているのは NewHello() だけ extern "C" __declspec(dllexport) Ihello* NewHello(void){ return new Chello ; }
(VC++ の ウィザードが生成したコードのままなので、DllMain() 等は略。)
// ユーザが作成する、Chello のメンバを直接使用していないファイル。 #include <i_hello.h> static Ihello* NewHello(void) ; int main(void) { Ihello* hello = NewHello() ; if (hello) { hello->greet() ; hello->Delete() ; } return 0 ; } // ここから Windows依存部 #include <windows.h> // # FreeLibrary() のタイミングを考えるのが面倒だったので作ったクラス。 // # 話の本筋とはあまり関係無し。 class CdllMng { HINSTANCE m_hDll ; public: CdllMng(){ m_hDll = 0 ; } ~CdllMng(){ if (m_hDll) { FreeLibrary(m_hDll) ; } } FARPROC GetProcAddress(char* dll, char* proc){ if (!m_hDll) { m_hDll = LoadLibrary(__TEXT(dll)) ; } return m_hDll ? ::GetProcAddress(m_hDll, proc) : 0 ; } } ; static CdllMng aDll ; // DLL のロードを実行時に行うことで、 // ユーザはインポートライブラリのリンクを不要にできる。 // つまり、提供者が DLLの実装を変更しても、そのインターフェイスが不変なら // ユーザの実行形式はそのまま使用できる。 // 逆に、インターフェースさえ同じなら、DLLの実装は複数あっても良く、 // 実行時にユーザが自由に選択することも可能である。 static Ihello* NewHello(void){ static PnewHello newHello = 0 ; if (!newHello) { newHello = (PnewHello)aDll.GetProcAddress("if_03_dll.dll", "NewHello") ; } return newHello ? newHello() : 0 ; }