编写DLL扩展ArcMap功能

Posted by 蒋波涛 10 September,2006 Views (23)Comment

ArcGIS不仅仅是一个可直接使用的GIS程序集,也是一套完整的功能框架,它提供了多种方式可以让用户扩展功能,我们知道,这种扩展方式有三种,VBA,DLL和控件开发,前两者与框架是紧密相关的。对于VBA,许多书中已经介绍的非常清楚,而使用MapControl控件,也是我的书的重点内容。使用DLL来扩展功能,则是见于一些零散的文档中。

作为一个应用程序框架,以ArcMap为例,它必然提供了许多接口让用户可以实现,从而达到扩展的功能。以产生一个浮动窗口为例,即DockableWindow,我们知道,如果要产生这样一个对象,必须使用IDockableWindowDef接口;产生这样一个窗体后,我们希望是使用一个按钮的方式来打开这个窗口,这又必须使用ICommand接口才行,而这个按钮,还需要与已经存在的按钮在格调上一致。

下面是整个过程:

  1. 启动VB6,然后点击ActiveX dll选项,在工程中会出现一个class1.cls的类模块(我更喜欢使用VB6来写DLL,因为它对DLL的UID设置和Outbound Interface的实现都比较方便)
  2. 将工程名改为DockableWindow,它将来将作为一个类库名出现。
  3. 引入必须的类库,如ArcMapUI、FrameWork、System、SystemUI和Carto
  4. 引入资源文件,点选菜单“Add -Ins”下的“Add -in Manager”,在弹出的对话框的列表框中选择“VB Resource (RES) Editor”,单击“OK“后退出对话框。这样在“Tools”菜单栏中就有一项“Resource Editor”了。打开这个工具然后导入一个已经存在的位图文件,这个文件被加入后的编号为101,我们将在ICommand中使用它。
  5. 添加一个窗体,改名为frmDockWin,在窗体上添加一个listbox控件,改名为lstSelCount
  6. 将class1改名为cmdDockWin,然后键入如下代码:
  7. Implements ICommand '必须实现该接口才能成为一个按钮

    Private m_pApp As IApplication
    Private m_pDockWinMgr As IDockableWindowManager
    Private m_pDockWin As IDockableWindow
    Private m_pBitmap As IPictureDisp

    Private Sub Class_Initialize()
    '使用我们刚才新建的资源文件,0为位图类型
    Set m_pBitmap = LoadResPicture(101, 0)
    End Sub

    Private Property Get ICommand_Bitmap() As esriSystem.OLE_HANDLE
    '按钮的图标为m_pBitmap对象,即我们引入的那张位图
    ICommand_Bitmap = m_pBitmap
    End Property

    Private Property Get ICommand_Caption() As String
    ICommand_Caption = "SelCount Dockable Window"
    End Property

    Private Property Get ICommand_Category() As String
    '该按钮会出现的目录是在Developer Samples,当我们打开Customize时,在Commands中会看到两栏,左边就是目录,右边是目录中可用的命令
    ICommand_Category = "Developer Samples"
    End Property

    Private Property Get ICommand_Checked() As Boolean
    ICommand_Checked = m_pDockWin.IsVisible
    End Property

    Private Property Get ICommand_Enabled() As Boolean
    ICommand_Enabled = True
    End Property

    Private Property Get ICommand_HelpContextID() As Long

    End Property

    Private Property Get ICommand_HelpFile() As String

    End Property

    Private Property Get ICommand_Message() As String
    ICommand_Message = "Display the selection count dockable window"
    End Property

    Private Property Get ICommand_Name() As String
    ICommand_Name = "DeveloperSamples_SelCountDockableWindow"
    End Property

    Private Sub ICommand_OnClick()
    m_pDockWin.Show Not m_pDockWin.IsVisible
    End Sub

    Private Sub ICommand_OnCreate(ByVal hook As Object)
    '按钮初始化,从hook中引入Application对象,新建浮动窗体对象m_pDockWin
    Set m_pApp = hook
    Set m_pDockWinMgr = hook 'QI for IDockableWindowManager
    ' Get a reference to the selection count dockable window
    Dim u As New UID
    u.Value = "DockableWindow.DockWin"
    Set m_pDockWin = m_pDockWinMgr.GetDockableWindow(u)
    End Sub

    Private Property Get ICommand_Tooltip() As String
    ICommand_Tooltip = "Selection Count"
    End Property

  8. 添加一个类模块,改名为DockWin,键入如下代码
  9. Implements IDockableWindowDef

    Private m_pApp As IApplication
    Private m_pMXDoc As IMxDocument
    Private WithEvents m_pDocEvent As MxDocument ' Listen for the MxDocument events
    Private WithEvents m_pMapEvent As Map ' Listen for the Map events
    Private WithEvents m_pLayoutEvent As PageLayout ' Listen for the PageLayout events

    Private Property Get IDockableWindowDef_Caption() As String
    IDockableWindowDef_Caption = "Selected Features Count"
    End Property

    Private Property Get IDockableWindowDef_ChildHWND() As esriSystem.OLE_HANDLE
    '它需要使用到frmdockwin窗体的listbox控件来显示数据
    IDockableWindowDef_ChildHWND = frmDockWin.lstSelCount.hWnd
    End Property

    Private Property Get IDockableWindowDef_Name() As String
    IDockableWindowDef_Name = "Selection Count"
    End Property

    Private Sub IDockableWindowDef_OnCreate(ByVal hook As Object)
    Set m_pApp = hook
    'Start listening to the MxDocument events
    If Not m_pDocEvent Is m_pApp.Document Then
    Set m_pDocEvent = m_pApp.Document
    End If
    Set m_pMXDoc = m_pApp.Document
    If Not m_pMapEvent Is m_pMXDoc.FocusMap Then
    Set m_pMapEvent = m_pMXDoc.FocusMap
    End If
    If Not m_pLayoutEvent Is m_pMXDoc.PageLayout Then
    Set m_pLayoutEvent = m_pMXDoc.PageLayout
    End If
    End Sub

    Private Sub IDockableWindowDef_OnDestroy()
    Set m_pMapEvent = Nothing
    Set m_pLayoutEvent = Nothing
    Set m_pMXDoc = Nothing
    Set m_pApp = Nothing
    End Sub

    Private Property Get IDockableWindowDef_UserData() As Variant

    End Property

    Private Function m_pDocEvent_MapsChanged() As Boolean
    ' Clear the list box and reset the reference to the map when a new dataframe
    ' is added to the document.

    frmDockWin.lstSelCount.Clear
    If Not m_pMapEvent Is m_pMXDoc.FocusMap Then
    Set m_pMapEvent = m_pMXDoc.FocusMap
    End If
    End Function

    Private Function m_pDocEvent_NewDocument() As Boolean
    ' Clear the list box and reset the reference to the map and pagelayout when
    ' a new document is created.

    frmDockWin.lstSelCount.Clear
    If Not m_pMapEvent Is m_pMXDoc.FocusMap Then
    Set m_pMapEvent = m_pMXDoc.FocusMap
    End If
    If Not m_pLayoutEvent Is m_pMXDoc.PageLayout Then
    Set m_pLayoutEvent = m_pMXDoc.PageLayout
    End If
    End Function

    Private Function m_pDocEvent_OpenDocument() As Boolean
    ' Clear the list box and reset the reference to the map and pagelayout when
    ' another document is opened.

    frmDockWin.lstSelCount.Clear
    If Not m_pMapEvent Is m_pMXDoc.FocusMap Then
    Set m_pMapEvent = m_pMXDoc.FocusMap
    End If
    If Not m_pLayoutEvent Is m_pMXDoc.PageLayout Then
    Set m_pLayoutEvent = m_pMXDoc.PageLayout
    End If
    End Function

    Private Sub m_pLayoutEvent_FocusMapChanged()
    ' Clear the list box and reset the reference to the map when
    ' a different map (dataframe) is made active.

    frmDockWin.lstSelCount.Clear
    If Not m_pMapEvent Is m_pMXDoc.FocusMap Then
    Set m_pMapEvent = m_pMXDoc.FocusMap
    End If
    End Sub

    Private Sub m_pMapEvent_SelectionChanged()
    ' When the selection changes is the map, update the contents of the listbox
    Dim pMap As IMap
    Dim i As Integer
    Dim pFLayer As IFeatureLayer
    Dim pSel As IFeatureSelection
    Set pMap = m_pMapEvent

    frmDockWin.lstSelCount.Clear

    'Loop through the layers in the map and add the layer's name and
    'selection count to the list box
    For i = 0 To pMap.LayerCount - 1
    If TypeOf pMap.Layer(i) Is IFeatureSelection Then
    Set pFLayer = pMap.Layer(i)
    Set pSel = pFLayer
    frmDockWin.lstSelCount.AddItem pFLayer.Name & ": " & pSel.SelectionSet.Count
    End If
    Next
    End Sub

  10. 代码编写完毕,点击文件——生成DockableWindow.dll按钮,生成一个DLL文件(如果开始没有保存,此时将要求保存)
  11. 打开工程——DockableWindow属性——部件,将“版本兼容”设置为“二进制兼容”,保存工程。
  12. 打开ArcGIS的Component Category Manager,分别将dll中的两个类导入不同的组件目录,cmdDockWin导入ESRI Mx Comands目录,DockWin导入ESRI Mx Dockable Windows目录
  13. 打开ArcGIS程序,在Customize中查看是否存在“Developer Samples”目录,将目录中的命令拖到任何一个命令栏上,点击后,即可出现一个浮动窗体。

Related Items

Categories : ArcObjects Tags : ArcGIS  ArcObjects  
Comments
2006-9-16 13:00:13

嗯,在看你的书,写的很好。是学习AO的好帮手。谢谢你为大家提供了这么好的东西~~
我最近遇到一个问题,自己解决不了,想问问你和各位大佬。也是关于dll方式扩展ArcMap功能的。在你的书里的第二章最后讲述了一个使用dll为ArcMap做扩展的例子。我安装例子完成后也注册完成了。使用ArcGis的Component Category Manager看到在Mx Extension中也确实存在了我自己的扩展了,但是实现不了预期的想像工作。即打开文档和新建文档时都有提供框出现。请问可能是什么原因呢?需要怎么解决呢?

Posted by laurel Gravatar Icon

2006-9-16 16:39:13

1.检查你的代码是否写的真是和书上一样
2.是否引入了messagebox类的类库

Posted by 蒋波涛 Gravatar Icon

2006-9-20 9:46:42

呵呵,还是不行,你说的问题我都检查了,代码是一样的,至于messagebox,你在书中特意强调要引入system.windows.forms,我注意到了。检查之后还是不行。我也不知道什么原因~~郁闷呀~~
最近又遇到新的问题了(我笨笨的),在map中加入新的元素这点我实现不了,不知道怎么办呵呵。我的问题真多~~

Posted by Laurel Gravatar Icon

2007-3-29 16:39:57

斑竹你好
你的网站不错。很高兴看到你的文章。若你想宣传你的网站,让更多的人访问你的网站,我建议你学习一些网站优化排名的知识。我推荐你到网站优化排名服务和搜索引擎优化排名的网站去看看。那里有上千篇有关网站优化排名的文章,一定对你有所帮助。

Posted by 道可道 Gravatar Icon

2007-3-29 18:03:02

大哥你好!
小弟有个问题。。。。
我是用vc7.0+Ao做开发 ,现在正做一个点击地图查询属性的功能。
在vb中有 Dim pMxApplication As IMxApplication
Dim pMxDocument As IMxDocument
set pMxApplication = Application
set pMxDocument=Application.Document
set pMap=pMxDocument.FocusMap
.............
请问在vc中如何上面的语句,关键是第一个set语句。
我定义了IMxApplicationPtr pMxApplication;
后面如何让pMxApplication获得Application,实现vb中
set pMxApplication = Application 相同的操作呢!
有时间请帮助指点一下迷津。。。。。


KissedKissedKissedKissed

Posted by gisbooy Gravatar Icon

2007-3-29 20:52:45

除非是使用基于ArcMap的vba编程或dll编程,否则Application这个对象都是不可用的。你使用的AO+vc,肯定用了控件,是没有Application这个对象的。因此第一个set不能实现。
建议你看看我的书中写的东西。

Posted by chiangbt Gravatar Icon

2007-7-22 15:45:32

是不是控件开发,IMxApplication和IMxDocument都用不了

Posted by bkgr Gravatar Icon

2007-7-22 17:11:25

对,这个原因在我的书中写的非常清楚。

Posted by 蒋波涛 Gravatar Icon

2007-8-17 14:16:29

我已经购买了arcobjcets开发与技巧,请问如何用c#编写的dll/tlb引用到令一台机器arcmap里,在本机加载没有问题,但到了令一台机器就不行了,请问采用什么措施才能完成。

Posted by 请教 Gravatar Icon

2007-8-18 16:42:02

请说的更清楚一点。

Posted by 蒋波涛 Gravatar Icon

2007-8-18 19:36:04

呵呵,您的blog写的真是好啊,对ao开放者来说简直是个宝
我最近也在做ao开发,刚开始弄
有个问题请教 "引入资源文件,点选菜单“Add -Ins”.."我在中文版的vb环境下怎么找不着啊
先谢了

Posted by liddy Gravatar Icon

2007-8-19 9:53:04

我用c#2005写的程序编译后生成dll和tlb,把tlb加到本机器的arcmap里正常运行(可以加载进去),但我把这个dll和tlb文件拷贝到令一台机器上,就加载不上去,是不是在本机器编译时候注册了什么,所以导致直接拷贝的tlb在令一台机器上加不进去,请问如何解决?谢谢

Posted by 请教 Gravatar Icon

2007-8-20 10:34:43

在VB中是使用Project--Reference来引入ESRI的AO库的。
写DLL,还是用VB或VC比较好,.NET写DLL出的问题很多,我也是深受其难的。

Posted by 蒋波涛 Gravatar Icon

2007-9-26 8:55:13

找不到“Developer Samples”目录啊,能指导一下么?

Posted by 初学者 Gravatar Icon

2007-9-26 23:00:47

在ArcGIS安装目录\DeveloperKit\samples中

Posted by 蒋波涛 Gravatar Icon

2007-11-14 20:45:11

该按钮会出现的目录是在Developer Samples,当我们打开Customize时,在Commands中会看到两栏,我中Customize根本找不到“Developer Samples”目录啊,能指导一下么?

Posted by paoichang Gravatar Icon

2008-6-12 12:35:27

你好,为什么在打开另一个mxd文件后,菜单栏上的按钮会消失呢?

Posted by nbpig Gravatar Icon

2009-3-1 11:14:58

我用c#2005写的程序编译后生成dll和tlb,把tlb加到本机器的arcmap里正常运行(可以加载进去),但我把这个dll和tlb文件拷贝到令一台机器上,就加载不上去,是不是在本机器编译时候注册了什么,所以导致直接拷贝的tlb在令一台机器上加不进去,请问如何解决?谢谢
这个问题有解决方法吗??

Posted by 若朴 Gravatar Icon

2009-3-27 11:27:01

看了您的文章受益非浅,不过还是有一个问题想咨询一下,VBA写的程序与相同功能的vbDLL在速度上有多少优势,我现在写了一个VBA,需要处理24小时才能算完一个结果,我不知道改成DLL后会不会快一些,

Posted by GIsFans Gravatar Icon

2009-3-27 13:46:07

会快一点,但不会高出一个数量级那么恐怖

Posted by 蒋波涛 Gravatar Icon

2009-7-9 10:31:15

你好,我按照您的做法在VB6 中文版里面进行了开发,前面几步骤都很顺利,但是到第10步的时候,提示“Can't Load Library”,非常奇怪。
代码都是从你的Blog上拷贝过去的,应该不会有问题。

Posted by balling Gravatar Icon

2009-7-9 10:32:56

补充一下,使用的环境是 VB 6 中文版,ArcGIS 9.2 安装了SDK for VB 。

SDK for .NET 装不上。

Posted by balling Gravatar Icon

2009-7-9 20:18:01

可能是版本不同,导致了库的不同,你可能没有引入相关库

Posted by 蒋波涛 Gravatar Icon

Leave a comment

Or, take a look at Archives and Categories

目录

存档