[GIS] Add layer to open mxd using ArcObjects from outside the map document crashes ArcMap

arcgis-10.0arcobjectsms accesspython

I have an Access database (MS Access 2010) that allows users to enter a variety of land treatment information including associated points, lines, or polygons which users can select and the database would then load as part of the project, to a master geodatabase, and allow the user to view the features in an ArcMap. In Arc 9.3 this was all accomplished with VBA and worked well. Because of the upgrade to Arc 10, VBA is no longer an option and I have been learning how to program in python and call the commands through Access using the Shell feature. I have nearly completed everything except for the ability to allow users to add their feature to the current ArcMap document. Here are the steps that should occur.

1) User clicks a button in the Access program which identifes the feature(s) of interest.

2) Access determines if the correct mxd is open and if not opens it (the document is usually open so this step is often uneccessary)

3) The Python script opens using the Python shell command, identifes the correct and open mxd, and adds feature to the open ArcMap document

I have tried both arcpy and ArcObjects. I can run arcpy within the open map but opening a Python file via VBA in MS Access does not manipulate the open mxd. The ESRI forum suggested that I work with ArcObjects. I have found and used code to identify and manipulate layer already loaded in the ArcMap document of interest but am completely stuck on how to identify and add a new layer. Here is the code so far, I think it will work if I can correctly identify the layer file in the last section of code. At least it all runs without the pMap.AddLayer(FC) near the bottom of the code, but I am an ecologist and not a programmer by training so there may be something else I am missing. Any help would be appreciated.

Update: I am now very close. I can identify the feature in the geodatabase but now ArcMap crashes when attempting to add the data to the map and I generate the error: COMError: (-2147467259, 'Unspecified error', (None, None, None, 0, None)). However, my output appear to identify the correct feature. I am unsure as to why ArcMap is crashing. Please help, I am so close.

import arcpy
from arcpy import env
import os
import sys
import comtypes.gen.esriArcMapUI as esriArcMapUI
import comtypes.gen.esriCarto as esriCarto
import comtypes.gen.esriGeoDatabase as esriGeoDatabase
import comtypes.gen.esriFramework as esriFramework
import comtypes.gen.esriSystem as esriSystem
import comtypes.gen.esriDataSourcesFile as DataSourcesFile

#Eventaully these will be the arguments that call the feature
#test = sys.argv[0]
#Name = sys.argv[1]
#Alias = sys.argv[2]

def NewObj(MyClass, MyInterface):
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None

def CType(obj, interface):
    try:
        newobj = obj.QueryInterface(interface)
        return newobj
    except:
        return None

def GetApp():
    """Get a hook into the current session of ArcMap""" 
    #from comtypes.gen import esriFramework
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    if pAppROT is not None:
        iCount = pAppROT.Count 
        if iCount == 0: 
            print 'No ArcGIS application currently running.  Terminating ...' 
            return None 
        for i in range(iCount): 
            pApp = pAppROT.Item(i)  #returns IApplication on AppRef
            print pApp.Name
            if pApp.Name == 'ArcMap': 
                print "ArcMap found"
                pDoc = pApp.Document
                print pDoc.Title
                if pDoc.Title == "CreateShapefile10x.mxd" or pDoc.Title == "CreateShapefile10x":
                    return pApp 
    print 'No ArcMap session is running at this time.' 
print "No AppROT found"
print "Failed"
return None

pApp = GetApp()

try:
    pDoc = pApp.Document
    pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)
    pMap = pMxDoc.FocusMap
    if pMap.Name == "LTDL Layers":

        ###New Code###

        sPath = r"Y:\LTDL_Data\LTDL_Files\Abate_Seeding_1965\Abate_Seeding_1965.gdb"
        sPath1 = r"Abate_Seeding_1965"
        pWSF = NewObj(esriDataSourcesGDB.FileGDBWorkspaceFactory, esriGeoDatabase.IWorkspaceFactory)
        print pWSF
        pWS = pWSF.OpenFromFile(sPath, 0)
        pDS = CType(pWS, esriGeoDatabase.IDataset)

        print "Workspace name: " + pDS.BrowseName
        print "Workspace category: " + pDS.Category

        FWSS = CType(pWS, esriGeoDatabase.IFeatureWorkspace)
        FL = NewObj(esriCarto.FeatureLayer, esriCarto.IFeatureLayer)
        FL.FeatureClass = FWSS.OpenFeatureClass(sPath1)
        print FL
        print FL.FeatureClass.AliasName
        LAN = CType(FL, esriCarto.ILayer)
        LAN.Name = FL.FeatureClass.AliasName + ": Project Boundary"
        print LAN.Name

        ###New Code###

        pMap.AddLayer(FC)
        pLayout = pMxDoc.PageLayout
        pActiveView = CType(pLayout, esriCarto.IActiveView)
        pActiveView.Refresh()
        pMxDoc.UpdateContents
    print "Done"
except:
    print "Failed"

Best Answer

You're adding a layer "FC" to your map which should be "FL" or "LAN". Either the feature layer or the layer should work.

Be aware that the map may be in data view instead of layout view in which case pMxDoc.PageLayout is incorrect... I can't tell what pLayout is as it's not defined in the code block.

It would be safer to use IMXDocument.FocusMap as this could be either of type layout or data view.

assuming pApp is IApplication:

IMxDocument pDoc = (IMxDocument) pApp.Document;
IMap pMap = pDoc.FocusMap;
pMap.AddLayer(LAN);

OR

(pApp.Document as IMxDocument).FocusMap.AddLayer(LAN);

I usually do it on the three lines so it's not so confusing for the reader.

  • oops! that was C#, my bad! The VB isn't too hard to work out from here as you're already up to the pMap = pMxDoc.FocusMap.

p.s. I personally prefer to dim my objects, it makes it easier to work out what's happening:

dim pMxDoc as IMxDocument = ctype(pApp.Document, IMxDocument)
dim pMap as IMap = pMxDoc.FocusMap

That way the reader knows for a certainty what each object is.