ArcGis Classic COM Add-Ins外掛開發的一般流程 C#
COM add-ins是我對這種開發方式的稱呼,Esri的官方文件裡稱其為“Extending ArcObject”或者“Classic COM extensibility”,其所稱的addins是指esriAddin載入項。esriAddin的安裝包是副檔名為“.esriAddin”的壓縮檔案,而本文所講述的Com add-ins的安裝檔案只是一個dll,可以選擇是否生成.tlb(Type Library)檔案,可以通過在ArcGis的桌面程式中載入.tlb檔案實現外掛的載入,不過這種載入方式有時會存在問題,具體的會在後續的“安裝與解除安裝”博文中作出說明。
COM add-ins是一種不同於esriAddin的開發方式,該種開發方式較後者對com元件的操作更直接,而且更全面,後者只能建立官方已經封裝到模板列表的擴充套件項,有侷限。參考
add-ins應該稱為“載入項”才對,plug in翻譯成“外掛”,混起來都叫“外掛”。
本例說明
開發目的:在ArcMap新增一個工具條ToolBar,上新增一個按鈕Command,點選按鈕,彈窗 say hello。
ArcGis版本:10.1
VisualStudio版本:2010
開發環境(IDE)的搭建
開發使用的Visual Studio版本最好與安裝的ArcGis版本一致,避免不必要的麻煩(VS可以多版本並存的),本例項開發ArcMap 10.1的工具條外掛,適配VS2010版本。先安裝VS2010,再安裝與ArcGis同版本的ArcObjects SDK for .NET,然後就可以開始在VS開發外掛了。
Let's code
一、建立一個解決方案
1、名為ArcGis Classic COM extensibility demo
2、模板選擇ArcGis——Extending ArcObject——Class Library(ArcMap)
3、可以選擇新增引用,也可以直接“Finish”,在建立解決方案之後新增。
4、建立“解決方案”後
在名稱上右鍵——屬性——生成,勾選“為COM互操作註冊”,這樣就可以在生成的時候自動註冊到com component category的登錄檔位置並且生成.tlb檔案用以載入外掛到ArcGis。
在屬性——除錯——啟動外部程式,新增ArcGis的路徑。
一般在利用模板建立解決方案的時候以上已經自動設定。
5、建立解決方案後,預設工程裡會生成一個class1.cs,可以直接刪掉。後面用到的時候再新增“類庫”。
二、新增一個Toolbar
1、在專案名上右鍵——新增——新建項,如下圖,選擇模板Base Toolbar,嚮導程式型別當然是ArcMap。
2、看一下模板裡都自動添加了啥。
①這個類繼承了BaseToolbar,以實現其方法、屬性;
②自動生成了GUID以標識該類,ProgId也用於標識該類,不過前者具有唯一性,一般使用前者即可,COM元件註冊時將GUID寫入登錄檔。
[Guid("deb23831-5b2e-453c-b900-f12462b000fb")] [ClassInterface(ClassInterfaceType.None)] [ProgId("ArcGis_Classic_COM_extensibility_demo.ArcGISToolbar1")]
③從模板建立toolbar類時還建立了一個建構函式,重寫了兩個方法(屬性)。
在建構函式中,
使用基類提供的AddItem方法將Command、Menu Command等新增到工具條(Toolbar),該方法提供了6個過載,可以根據需要選用,一般使用AddItem("ProgId")即可;
使用基類提供的BeginGroup方法建立一個分隔器,其在工具條上表現為分隔開不同類別功能(自己定義)的豎線。
在重寫的兩個方法中,
Caption返回string型別的標題,用以顯示Toolbar的標題,這裡我們命為"My First Toolbar",Name則是程式內部的標識。
public ArcGISToolbar1() { //建構函式,新增Command、Menu Command等至此,載入到工具條(Toolbar) //AddItem("esriArcMapUI.ZoomInTool"); //BeginGroup(); //Separator //AddItem("{FBF8C3FB-0480-11D2-8D21-080009EE4E51}", 1); //AddItem(new Guid("FBF8C3FB-0480-11D2-8D21-080009EE4E51"), 2); } public override string Caption { get { // bar caption return "My First Toolbar"; } } public override string Name { get { // bar ID return "ArcGISToolbar1"; } }
④最後看一下COM元件註冊函式,沒興趣可以跳過。
ArcGISCategoryRegistration與ArcGISCategoryUnregistration兩個方法在COM元件註冊時分別會被RegisterFunction、UnregisterFunction兩個方法呼叫。
#region COM Registration Function(s)
[ComRegisterFunction()]
[ComVisible(false)]
static void RegisterFunction(Type registerType) { ArcGISCategoryRegistration(registerType); } [ComUnregisterFunction()] [ComVisible(false)] static void UnregisterFunction(Type registerType) { ArcGISCategoryUnregistration(registerType); } #region ArcGIS Component Category Registrar generated code private static void ArcGISCategoryRegistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); MxCommandBars.Register(regKey); } private static void ArcGISCategoryUnregistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); MxCommandBars.Unregister(regKey); } #endregion #endregion
RegisterFunction、UnregisterFunction兩個方法是COM註冊與反註冊方法,執行COM元件註冊時呼叫。
ArcGISCategoryRegistration與ArcGISCategoryUnregistration兩個方法分別呼叫MxCommandBars類提供的Register與Unregister方法實現註冊與反註冊。
而MxCommandBars等的元件註冊的類由ESRI.ArcGIS.ADF.CATIDs這個名稱空間提供,該名稱空間在ESRI.ArcGIS.ADF.dll中,可以在C:\Program Files (x86)\ArcGIS\DeveloperKit10.1\DotNet\ESRI.ArcGIS.ADF.dll找到該dll,具體路徑可能因ArcObjects SDK for .NET安裝位置與系統位數而異。
反編譯一下dll,跟蹤一下就可以看看註冊的時候發生啥了?
看看登錄檔你會驚奇地發現外掛註冊時並沒有按照ESRI.ArcGIS.ADF.CATIDs.CatReg的方法幹活兒。自10.0開始ESri改變了以往的把COM元件類別部分註冊資訊寫進登錄檔的註冊方法,採用了自家的ESRIRegAsm.exe對dll進行註冊,將部分資訊寫入登錄檔,搭配一個xml文件儲存註冊資訊。
對登錄檔寫入的內容與位置可以通過外掛註冊前後的登錄檔快照分析得出;
XML配置文件的被包裹在一個.ecfg格式的文件中,而這個.ecfg文件實質是一個“匿名的”壓縮檔案,嗯,又是“壓縮檔案”,看來Esri的大神喜歡把東西塞進壓縮檔案以創造新格式……
至於ESRIRegAsm.exe對dll進行註冊時幹了什麼樣神奇的操作,不得而知,因為俺沒有找到相關支援材料。
using System;
namespace ESRI.ArcGIS.ADF.CATIDs
{
/// <summary>Registers or unregisters a class to the MxCommandBars component category.</summary> public class MxCommandBars : CatReg { /// <summary>Registers a class to the MxCommandBars component category.</summary> /// <param name="CLSID">The CLSID of the class to be registered.</param> public static void Register(string CLSID) { CatReg.Reg(CLSID, "{B56A7C4A-83D4-11D2-A2E9-080009B6F22B}"); } /// <summary>Unregisters a class from the MxCommandBars component category.</summary> /// <param name="CLSID">The CLSID of the class to be unregistered.</param> public static void Unregister(string CLSID) { CatReg.Unreg(CLSID, "{B56A7C4A-83D4-11D2-A2E9-080009B6F22B}"); } } }
三、新增一個Command
同樣是新增“新建項”,這次模板選BaseCommand,嚮導程式型別ArcMap。
1、看一按下建構函式
上邊是一堆按鈕的屬性設定程式碼,一般地可以只設置m_caption與m_toolTip,後者提供滑鼠懸浮於按鈕之上顯示的提示文字。
try……catch……語句塊裡是對按鈕圖示的定義,如果註釋掉,按鈕顯示m_caption的內容。
可以替換自動生成的圖片為自己需要的圖片,注意格式;另外,俺提供一種更為簡單的方法,在資原始檔中新增圖示,直接使用下面method2的方式使用即可。
public Command1() { base.m_category = ""; //localizable text base.m_caption = "SayHello"; //localizable text base.m_message = ""; //localizable text base.m_toolTip = "show a messagebox"; //localizable text base.m_name = ""; //unique id, non-localizable (e.g. "MyCategory_ArcMapCommand") try { //method1: string bitmapResourceName = GetType().Name + ".bmp"; base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); //method2:把圖示塞進資原始檔,然後直接使用 // base.m_bitmap = Properties.Resources.cmd_ExportExcel; } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap"); } }
2、建立一個WinFrom
為了貼近實際程式設計需求,這裡創造難度,在點選按鈕時彈出WinFrom,WinFrom上加一個button按鈕,點選在ArcMap的Statusbar上留一行文字。
引入兩個名稱空間
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Framework
在窗體初始化時傳入hookHeper,在點選button時獲取當前宿主application,在Statusbar上寫字
using System; using System.Windows.Forms; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.Framework; namespace ArcGis_Classic_COM_extensibility_demo { public partial class Form1 : Form { IHookHelper m_hookHelper; IApplication m_application; public Form1(IHookHelper hookHeper) { InitializeComponent(); m_hookHelper = new HookHelperClass(); m_hookHelper = hookHeper; } private void button1_Click(object sender, EventArgs e) { m_application= m_hookHelper.Hook as IApplication; m_application.StatusBar.set_Message(0,"I am good,I am great,I am wonderful."); } } }
3、回到Command1
重寫OnCreate方法,在command按鈕初始化的時候例項化IHookHelper型別。
重寫OnClick方法,在點選的時候例項化Form1,並彈窗。
IHookHelper m_hookHelper; public override void OnCreate(object hook) { if (hook == null) return; m_hookHelper = new HookHelperClass(); m_hookHelper.Hook = hook; } public override void OnClick() { //Form例項化時傳入IHookHelper 引數 Form1 f = new Form1(m_hookHelper); f.Show(); }
④ 去ToolBar1新增按鈕ProgID
AddItem("ArcGis_Classic_COM_extensibility_demo.Command1");
四、生成一下
在ArcMap就可以看到效果了。
外掛咋載入到ArcMap的,還有什麼其他方法載入,怎麼解除安裝?欲知詳情,且等下回分解。