COM add-ins是我对这种开发方式的称呼,Esri的官方文档里称其为“Extending ArcObject”或者“Classic COM extensibility”,Esri所称的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组件并且生成.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的大神喜欢把东西塞进压缩文件以创造新格式……

.ecfg文档在~:\Program Files\Common Files\ArcGIS\Desktop10.0\Configuration\CATID路径下

至于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(,"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的,还有什么其他方法加载,怎么卸载?戳 ArcGis Classic COM Add-Ins插件dll的安装与卸载

ArcGis Classic COM Add-Ins插件开发的一般流程 C#的更多相关文章

  1. ArcGis Classic COM Add-Ins插件dll的安装与卸载

    本文是去年<ArcGis Classic COM Add-Ins插件开发的一般流程 C#>一文(以下称“开发流程”)的后续.“开发流程”中写到会有“安装与卸载”系列的文章,今天把它补上. ...

  2. 在Revit中如何显示附件模块(Add Ins) 这个命令页?zz

      分类: 概念说明 Revit Revit界面编程 Revit 二次开发入门2013-08-22 13:58 1395人阅读 评论(9) 收藏 举报 在windows 7 32-bit OS 上装了 ...

  3. arcgis python arcpy add data script添加数据脚本

    arcgis python arcpy add data script添加数据脚本mxd = arcpy.mapping.MapDocument("CURRENT")... df ...

  4. ArcGIS ArcMap “ Add Data” 打开后,一直卡死,无内容

    打开ArcMap能打开,Add Data 或打开mxd就出Runtime Error对话框.打开ArcCatlog或者ArcGlobe出现Runtime Error对话框Runtime Error!P ...

  5. ArcGIS for Android_离在线一体化核心技术基本流程

    核心思想: a.数据首先存储于ArcSDE中,要素添加GlobleID,图层数据启用数据归档或开启版本化.b.然后将ArcSDE数据库托管于ArcGIS for Server作为数据存储.c.在Arc ...

  6. Add In 简介(主要翻译于ESRI官方文档)

    为ArcGIS桌面端建立Add In插件 平时以工作为主,有空时翻译一些文档,顺便练习英文,这个是因为用Add In来学习一下. 主要包括: 关于Add In 什么时候使用Add In Python ...

  7. Portal for ArcGIS 资源承载数据类型

    在Portal中数据主要分为两大类:Web内容与桌面内容.对于Web内容与桌面内容中的每个项目(item)又被具体分为maps,layers, styles, tools,applications,和 ...

  8. IntelliJ IDEA/Android Studio插件开发指南

    前言 目前在为安卓手机QQ做自动化的相关工作,包括UI自动化,逻辑层自动化等.使用到的uiautomator等框架,需要在Android Studio进行编码工作. 其中很多工作如果做到插件化的话,可 ...

  9. ArcGIS 10.5新功能预览

    ArcGIS for Server产品线被重命名为ArcGIS Enterprise. 带来更多丰富的时空GIS功能. 分析地理大数据 捕捉和分析实时传感器数据 快速地理影像分析 ArcGIS Ent ...

随机推荐

  1. 软件设计之Deep Module(深模块)

    类是不是越小越好?最近在读John Ousterhout的<A Philosophy of Software Design>,感到作者文笔流畅,书中内容具有启发性.这里摘要一部分内容,以供 ...

  2. Python开发【第一篇】基础题目二

    1 列表题 l1 = [11, 22, 33] l2 = [22, 33, 44] # a. 获取l1 中有,l2中没有的元素 for i in l1: if i not in l2: # b. 获取 ...

  3. addq

    <template> <el-row id="AddRoom"> <el-col :xs="0" :sm="2" ...

  4. JS中的闭包(closure)

    JS中的闭包(closure) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面就是我的学习笔记,对于Javascript初学者应该是很有用 ...

  5. kafka实战kerberos

    more /etc/krb5.conf [logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log a ...

  6. AI Conditional GAN

    Conditional GAN 参考链接: https://arxiv.org/pdf/1611.07004v1.pdf

  7. 1-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(来看一下怎么样监听网络数据,监听电脑上位机软件的数据)

    首先安装网络监听软件 运行这个软件 这个软件安装到电脑上,默认是监听咱电脑上的网络通信 咱们先监听电脑的软件的网络通信数据,然后再说怎么监听Wi-Fi和APP的软件的网络通信数据 咱就监听咱基础篇的 ...

  8. webpack4配置详解之新手上路初探

    前言 经常会有群友问起webpack.react.redux.甚至create-react-app配置等等方面的问题,有些是我也不懂的,慢慢从大家的相互交流中,也学到了不少. ​ 今天就尝试着一起来聊 ...

  9. Day4 Numerical simulation of optical wave propagation之数字傅里叶变换

    标量衍射理论是波动光学模拟的物理基础.这一理论基础的结果是将电磁波在真空中的传播作为线性系统进行处理. 对于单色波,系统观察平面的电场矢量是源平面电场矢量和自由空间脉冲响应的卷积. 因此,线性系统理论 ...

  10. Qt中的QWebView

    一.Webkit了解   Webkit是一个开源的浏览器引擎,chrome也使用了作为核心.Qt中对Webkit做了封装,主要有以下几个类: QWebView :最常用的类,作为一个窗体控件 QWeb ...