2018年10月26日 星期五

插件成了 header only 的罩門

什麼是 header only? 可以先看此文了解一下 http://zevoid.blogspot.com/2012/04/c11-extern-template.html

簡單的說,header only 是把一個 class 的程式碼就包含在這個 class 中,而這個 class 就放在引入檔(.h)中供大家使用。有別於引入檔只放 class 介面,程式碼則放在 .cpp 中。

header only 的好處是執行快,因一大部份的函數可以用 inline 的方式呼叫,另外也不用再加 .cpp 或是還要連結程式庫(lib 或 dll)。

但有一個不得不面對的問題,class 的程式碼因不放在特定的 .cpp 中,那麼使用它的模組(exe、lib、dll)都得編譯出各別的執行碼,一般來說除了程式會比較胖之外,也沒有其它不好的影響。但是遇到插件就出問題了。

插件是一個 dll 檔,特點是要用的時候才載入,不用的時候可以卸載,但若某一個 class 產生的物件,其執行碼在那個被卸載的 dll 中,就會出大問題了,以下範例程式就是在演示這種情況。

/* 
** test.h : header only 形式的引入檔 
*/
class Test
{
  const char Str[20]{ "I am Test" };
public:
  Test()
  {
  }
  ~Test() {};
  // inline
  const char *GetStr1() const
  {
    return Str;
  }
  // 迫使使用端一定得使用服務端提供的實作碼
  virtual const char *GetStr2() const
  {
    return Str;
  }
};
/* 
** dllmain.cpp : 定義 DLL 應用程式的進入點。
*/
#include "test.h"
extern "C" __declspec(dllexport)
Test *__cdecl GetTest()
{
  return new Test;
}
/*
** customer.cpp: 定義主控台應用程式的進入點。
*/
#include <Windows.h>
#include <test.h>
#include <iostream>
using namespace std;
HINSTANCE DLLInst;
Test*(__cdecl *GetTest)();
int main()
{
  DLLInst = LoadLibraryW(L"Server.dll");
  GetTest = (decltype(GetTest))GetProcAddress(DLLInst, "GetTest");
  Test *pTest = GetTest();  
  const char *Str1;
  const char *Str2;
  Str1 = pTest->GetStr1();
  cout << "Str1: " << Str1 << endl;
  Str2 = pTest->GetStr2();
  cout << "Str2: " << Str2 << endl;
  FreeLibrary(DLLInst);
  Str1 = pTest->GetStr1();
  cout << "Str1: " << Str1 << endl;
  Str2 = pTest->GetStr2();
  cout << "Str2: " << Str2 << endl;
  return 0;
}





沒有留言:

張貼留言