最近在研究KeePass的源代碼,老外的大牛果然不同凡響,令人恐怖的宏到處都是。令我等菜鳥心服口服。不用我說,這個源代碼確實有許多值得學習的地方,首先這是一個基於插件機制的程序。也就是隻要按照它定義的規範就可以根據自己的需要爲KeePass編寫插件。這是不是很炫啊。記得我剛接觸到vs studio開發環境時,裝了源代碼管理器插件。然後就可以直接在vs studio中使用源代碼管理,這個功能讓我感到非常的神奇,後來才知道vs studio是基於插件的。O(∩_∩)O而且KeePass界面也是很強大。
KeePass插件機制是基於COM規範的,而且是綠色的。也就是所用的插件不用向系統註冊,直接放到KeePass程序目錄裏就可以使用了。那這個插件機制是怎麼實現的呢。如果不瞭解COM規範,可以參考msdn上關於COM規範的資料。
首先,敘述下,KeePass是如何實現插件機制的?
當KeePass啓動時,首先在程序目錄下查找所有的dll,並且對這些dll進行驗證,如何驗證呢。KeePass是通過dll文件的版本信息來識別的,也就是說如果dll的版本信息的Product是 KeePass Pulgin,則認爲這個dll是KeePass的插件。否則的話就是不加載。根據KeePass的規範,凡是KeePass的dll插件,都要導出三個函數:KpCreateInstance(創建插件的函數)、KpInitializeLibrary(初始化插件的函數)、KpReleaseLibrary(釋放插件函數)。
KeePass首先通過API函數GetProcAddr獲取KpInitializeLibrary的函數對插件進行初始化,然後在獲取KpCreateInstance函數創建插件。如果沒有失敗,則加入KeePass的插件列表中m_plugins.插件加載完了之後,KeePass調用BuildPluginMenu爲插件建立用戶接口。也就是在菜單Tools裏建立插件的子菜單。首先插件要實現兩個規範:GetMenuItems是獲取插件裏菜單資源,返回類型是KP_MENU_ITEM型指針,這個結構體是這樣定義的:
typedef struct
{
DWORD dwFlags; // 菜單標識
DWORD dwState; // 菜單狀態
DWORD dwIcon; //圖標
LPTSTR lpCommandString; ///菜單文本
DWORD dwCommandID; ///菜單ID標識,注意這個是由KeePass使用的
DWORD_PTR dwReserved; ///< Reserved for future use, must be 0.
} KP_MENU_ITEM;
KeePass根據KP_MENU_ITEM型指針建立插件的用戶接口(菜單項),並且爲每個菜單項分配一個CommandId。KeePass不知道插件到底有什麼用戶接口,那如何響應菜單項的命令消息呢。這就要根據CommandId來區分了。首先映射消息:
ON_COMMAND_RANGE(WM_PLUGINS_FIRST, WM_PLUGINS_LAST, OnPluginMessage)
也就是說把消息id在WM_PLUGINS_FIRST和WM_PLUGINS_LAST之間的消息都映射到函數OnPluginMessage,然後根據CommandId來區分每個消息的所對應的commandId找到對應的插件,並且通過接口OnMessage映射到插件的OnMessage進行處理。
好了,我們看到要實現插件機制,關鍵在於定義一組接口,通過這組接口建立起插件和主程序之間的交互。