應用程序擴展
在很多場合,我們需要在已有軟件程序上增加一些新的功能,幾乎所有原因是因為原有軟件功能不能滿足我們的需要,我們平時做的插件就屬於這種情況,最常見的是VS IDE的插件開發,網上老外寫的一篇關於插件開發的文章,很詳細(網址)。如果我們要給一個已有軟件擴展新的功能,一般我們必須知道原有軟件提供給二次開發人員的接口,也就是說,如果原有軟件在設計的時候,壓根兒就沒有考慮到后續可能存在的二次開發,也不提供任何接口,那么通常情況下,是很難在它的基礎上擴展出新功能的(除非是原有軟件開發者)。
還有一種可以擴展已有程序功能的方式,網址,利用windows消息、windows hook技術,理論上可以給任何一個桌面應用程序擴展出新功能,而不需要任何接口,但是,這種方式很有局限性,擴展出來的功能幾乎停留在操作系統級別上,比如UI外觀樣式等,並不能真正的去與已有軟件程序進行交互。老外這篇文章其實重點是在講Windows hooks和Windows Message。
這篇文章不是講怎么去開發VS插件,更不是談哪個具體軟件比如CAD、PROE的二次開發,我只是想將看似復雜的東西簡單化地解釋一下,看看“給已有軟件擴展新功能”到底是怎么回事。以插件為例:
首先,宿主程序和插件之間一定要有交互的,不然的話,插件是不會知道什么時候該干什么事情;其次,宿主程序一定會傳遞某些數據信息給插件,否則你叫插件拿什么原材料干活?最后,宿主程序一定是要有所准備的,什么叫有所准備?也就是說,在開發宿主程序的時候,一定要為以后的功能擴展留有接口,所有插件必須遵守這個接口給出的規范,知道應該在什么時候跟插件通訊,了解插件的任何一個行為將會導致什么樣的結果,並且作出相應的反應。綜上所述,給已有程序擴展新功能,關鍵還是在這個“已有程序”身上,如果一個程序出生的時候就沒想着將來別人要給自己增加功能,那你不用再想着去給它擴展功能了。也就是我文章剛開始說到的,並不是你可以在任何一個程序基礎上擴展新功能。
圖1
如上圖所示,宿主程序與插件之間通過某一協議進行通信,這個跟上一篇最后講到的“框架和客戶端代碼之間的關系”很相似,你可以把宿主程序看做是框架,而插件則是客戶端代碼(參見上一篇文章圖6)。
圖2
如上圖,在宿主程序中應該提前設計好該在什么時候與插件通信,以及給它傳遞對應數據信息,接着返回交互結果。宿主程序應該考慮所有與插件交互的地方和時間,然而插件不一定處處都會有所反應,也就是說,一個宿主程序設計好100個與插件交互的地方(插件最多可以在這100個地方大做文章),但是你開發一個插件時,根據具體需要,完全可以只響應其中的某幾個。
圖3
文章后面我附上一個簡單的畫圖Demo,實現簡單的畫板、保存(默認可以保存JPG圖片格式和PIC可編輯格式)等功能,然后自己又做了一個插件,插件主要新增了以下功能:
1)增加一個“關於”菜單,點擊彈出關於對話框;
2)已有畫板程序只能繪制圓形和正方形,增加了一個三角形圖形;
3)將畫圖保存成JPG格式時,在圖片上添加水印;
4)增加一種全新的文件格式(newpic格式),可以將畫圖保存為newpic格式的文件,這個有點類似photoshop的ico插件,安裝后,PS可以將圖片保存為ico格式。
整個項目源碼分為以下三個部分:
- PluginDemo:宿主程序,在它的基礎上擴展新的功能;
- PluginHelper:擴展功能時必須遵守的規范(接口),隨宿主程序一起開發,通常就是我們常說的“二次開發包”,理論上應該還有二次開發說明文檔之類的東西;
- Plugin:我自己開發的一個插件。
正常情況下,1和2由已有軟件開發商提供,3由二次開發人員開發。
下面主要說明一下PluginHelper中的兩個接口,其余的源碼諸位可以自己下下來看看。
IPlugin接口:

1 /// <summary> 2 /// 插件接口 所有插件必須實現該接口 3 /// </summary> 4 public interface IPlugin 5 { 6 void ApplicationLoaded(PluginApplication pluginApplication); //應用加載后 7 void FileSavingAsJPG(Bitmap bitmap,string filepath); //文件保存為JPG 8 void FileSavingAsPIC(PluginApplication pluginApplication); //文件保存為PIC 9 void BeforeSave(Dictionary<string,SaveFileHandler> extensions); //保存文件之前 10 void BeforeOpen(Dictionary<string,OpenFileHandler> extensions); //打開文件之前 11 void ApplicationExiting(); //應用退出時 12 }
如接口代碼所示,在固定時候固定地方,宿主程序都會調用對應方法與插件通信。
IObject接口:

1 /// <summary> 2 /// 圖形接口 所有的圖形都必須實現該接口 3 /// </summary> 4 public interface IObject 5 { 6 int X 7 { 8 get; 9 set; 10 } 11 int Y 12 { 13 get; 14 set; 15 } 16 void Draw(Graphics g); 17 }
所有新擴展圖形都必須實現該接口。
如果想要開發自己的插件,只需要知道二次開發包(PluginHelper.dll),定義一個類實現IPlugin接口就行。
圖4
最后上幾張效果圖,沒插件之前的宿主程序:
圖5
安裝插件后的宿主程序:
圖6
如上圖所示,安裝插件后,菜單多了“關於”菜單項,工具欄多了“三角形”按鈕,可以保存另外一種“newpic”格式的文件,另外,在保存為JPG格式圖片時,已有軟件保存圖片為:
圖7
安裝插件后,保存為JPG格式文件如下:
圖8
如上圖,安裝插件后,保存的JPG圖有水印。
下載源碼:http://files.cnblogs.com/xiaozhi_5638/PluginDemo.rar
將開發的插件放在宿主程序的plugins目錄下,重啟宿主程序就可以。希望對各位有幫助!