6 votos

Python, comtypes y ArcObjects: Error al crear el objeto AppROT

Estoy experimentando con comtypes y ArcObjects bajo Python 2.6.5 y ArcGIS 10 SP1. Estoy usando el método de Python puro para envolver los OLBs de ArcObjects descritos en esta respuesta pero se produce un error en el comtypes.CoCreateInstance método.

Este es el código que estoy ejecutando:

def WrapModules():
    #force wrapping of all ArcObjects libraries (OLBs)
    import os
    import comtypes.client
    # change com_dir to whatever it is for you
    com_dir = r'C:\Program Files\ArcGIS\Desktop10.0\com'
    coms = [os.path.join(com_dir, x) for x in os.listdir(com_dir) if os.path.splitext(x)[1].upper() == '.OLB']
    map(comtypes.client.GetModule, coms)

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
            if pApp.Name == 'ArcMap':
                print "ArcMap found"
                return pApp
        print 'No ArcMap session is running at this time.'
    print "No AppROT found"
    return None

def NewObj(MyClass, MyInterface):
    """Creates a new comtypes POINTER object where\n\
    MyClass is the class to be instantiated,\n\
    MyInterface is the interface to be assigned"""
    from comtypes.client import CreateObject
    import traceback
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        print traceback.format_exc()
        return None

if __name__ == "__main__":
    WrapModules()
    pApp = GetApp()
    if pApp is not None:
        print "HWND: %d" % pApp.hWnd
    else:
        print "No ArcGIS application found!"

Y aquí está la salida del script:

Traceback (most recent call last):
  File "C:\\temp\\ComHelpers.py", line 35, in NewObj
    ptr = CreateObject(MyClass, interface=MyInterface)
  File "C:\\Python26\\ArcGIS10.0\\lib\\site-packages\\comtypes\\client\\\_\_init\_\_.py", line 235, in CreateObject
    obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface)
  File "C:\\Python26\\ArcGIS10.0\\lib\\site-packages\\comtypes\\\_\_init\_\_.py", line 1145, in CoCreateInstance
    \_ole32.CoCreateInstance(byref(clsid), punkouter, clsctx, byref(iid), byref(p))
  File "\_ctypes/callproc.c", line 925, in GetResult
WindowsError: \[Error -2147221231\] ClassFactory cannot supply requested class

No AppROT found
No ArcGIS application found!

Gracias por cualquier idea que pueda tener.

9voto

auramo Puntos 161

Esto es en parte en respuesta a la discusión en los comentarios con respecto a envolver un solo módulo sólo si es necesario, y también sólo para compartir mi versión del módulo de ayuda. Esto combina la importación y la envoltura de las bibliotecas de tipos en un solo paso, por ejemplo:

esriFramework = GetESRIModule("esriFramework")

Esto comprobará si el esriFramework (wrapper) ya existe, envuélvelo si no, e impórtalo como la variable llamada esriFramework .

Aquí está el código de mi módulo de ayuda. Puedes importarlo siempre que esté en tu sys.path . También puede ejecutarlo de forma autónoma para comprobar que encuentra adecuadamente la aplicación ArcMap e imprime su mango de ventana.

def GetESRIModule(module):
    """Returns the named ESRI module from comtypes.gen,
    creating the wrapper for it if necessary"""
    import sys
    mod = 'comtypes.gen.%s' % module
    try:
        __import__(mod, globals(), locals(), [module], -1)
    except ImportError:
        WrapModule(module)
        __import__(mod, globals(), locals(), [module], -1)
    return sys.modules[mod]

def GetLibPath():
    """Returns the location of the directory containing the ArcGIS object
    library (.olb) files"""
    import _winreg, os.path
    with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,r"SOFTWARE\ESRI") as esrikey:
        # Lets first look for ArcGIS 10.0+ installations, e.g. HKLM\SOFTWARE\ESRI\Desktop10.0\InstallDir
        try:
            i = 0
            while True:
                subkeyname = _winreg.EnumKey(esrikey, i)
                if subkeyname.startswith("Desktop") or subkeyname.startswith("Engine"):
                    # Take the first one we find
                    with _winreg.OpenKey(esrikey, subkeyname) as subkey:
                        return os.path.join(_winreg.QueryValueEx(subkey, "InstallDir")[0], "com")
                i += 1
        except WindowsError:
            pass
        # Try the pre-10.0 key, e.g. HKLM\SOFTWARE\ESRI\ArcGIS\InstallDir
        try:
            with _winreg.OpenKey(esrikey, "ArcGIS") as subkey:
                return os.path.join(_winreg.QueryValueEx(subkey, "InstallDir")[0], "com")
        except WindowsError:
            pass
    raise WindowsError("ArcGIS InstallDir key not found!")

def WrapModules():
    """Force wrapping of all ArcObjects libraries (OLBs)"""
    import os.path
    import comtypes.client
    from glob import iglob
    comdir = GetLibPath()
    for olb in iglob(os.path.join(comdir, "*.olb")):
        comtypes.client.GetModule(olb)

def WrapModule(module):
    """Wrap a single ArcObjects library (OLB)"""
    import os
    import comtypes.client
    comdir = GetLibPath()
    olb = os.path.join(comdir, module + ".olb")
    comtypes.client.GetModule(olb)

def GetCurrentApp():
    """Returns the Application if the script is being run from
    within the application boundary of an ArcGIS application"""
    esriFramework = GetESRIModule("esriFramework")
    return NewObj(esriFramework.AppRef, esriFramework.IApplication)

def GetApp(app="ArcMap"):
    """Returns the Application if the script is being run from
    outside the application boundary of an ArcGIS application.
    "app" must be 'ArcMap' (default) or 'ArcCatalog'"""
    if not app in ("ArcMap", "ArcCatalog"):
        raise ValueError("app must be 'ArcMap' or 'ArcCatalog'")
    esriFramework = GetESRIModule("esriFramework")
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    if pAppROT:
        pApp = None
        appcount = pAppROT.Count
        if appcount > 0:
            for i in range(appcount):
                pApp = pAppROT.Item(i)
                if pApp.Name == app:
                    break
        return pApp
    else:
        raise RuntimeError("AppROT object could not be created!")

def NewObj(MyClass, MyInterface):
    """Creates a new comtypes POINTER object where
    MyClass is the class to be instantiated,
    MyInterface is the interface to be assigned"""
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None

def CType(obj, interface):
    """Casts obj to interface and returns comtypes POINTER or None"""
    try:
        newobj = obj.QueryInterface(interface)
        return newobj
    except:
        return None

def CLSID(MyClass):
    """Return CLSID of MyClass as string"""
    return str(MyClass._reg_clsid_)

if __name__ == "__main__":
    import arcpy # Required to initialize ArcObjects (for ArcGIS 10)
    ##import arcgisscripting # Required to initialize ArcObjects (for either ArcGIS 10 or 9)
    pApp = GetCurrentApp() # try to get IApplication from AppRef first, in case we are in-process
    if not pApp:
        print "AppRef not available (script is not running from within an ArcGIS application), attempting AppROT..."
        pApp = GetApp() # defaults to look for ArcMap
    if pApp:
        print "%s HWND: %x" % (pApp.Name, pApp.hWnd)
    else:
        print "No ArcGIS application found!"

5voto

Paul Puntos 555

Importa arcpy primero, no estás haciendo ninguna comprobación de la licencia ni configurando el tiempo de ejecución de ArcObjects 10.0 tal cual, por lo que no encontrará la CoClass.

1voto

Craig Puntos 1013

Bueno, no veo que haya mucha diferencia con lo que publiqué en la respuesta a la que te refieres. Pones el procedimiento de envoltura en una función que luego llamas desde el bucle principal. Yo ejecuto la envoltura en primer lugar en el nivel superior del módulo principal. Podrías intentar mover el código de envoltura al nivel superior. No es obvio por qué poner la envoltura en una función causaría un problema, pero Python puede ser bastante enrevesado cuando se trata del ámbito de los espacios de nombres. Dicho esto, dudo que este sea el problema. Tus funciones GetApp() y NewObj() son esencialmente idénticas a las que he publicado, y me funcionan bien. Por lo tanto, mi suposición es que al menos uno de los módulos .pyc generados en el directorio comtypes/gen está mal, y mi sospecha es el módulo esriFramework

Ir a la C:\Python26\ArcGIS10.0\Lib\site -paquetes \comtypes\gen busque el archivo esriFramework.py y ábralo en un editor de texto. En la primera línea habrá una cadena larga a continuación de la declaración from-import, que probablemente comience con un guión bajo. Este es el nombre de archivo del módulo compilado en bytes (.pyc) que realmente contiene todo el código envuelto. Busque este archivo en el mismo directorio. Ábrelo en un editor de texto y mira si está vacío o tiene muy poco contenido. He visto estos módulos .pyc corromperse de esta manera antes. Usted puede escribir un montón de código quisquilloso como lo hice en un momento para ir a través de todos los archivos de envoltura pyc en el directorio en busca de los corruptos y luego volver a envolver sólo los OLBs, sin embargo, por todo ese esfuerzo que realmente no ahorra mucho tiempo de procesamiento y no es realmente vale la pena. Así que, yo recomendaría simplemente borrar todo en el directorio comtypes/gen y volver a ejecutar su script. Yo he tenido que hacer eso un par de veces. Los archivos py y pyc se reconstruyen cuando se ejecuta el script. Si esto no funciona, entonces intentaría desinstalar y volver a instalar comtypes. Conozco a otra persona que tenía problemas de no reconocimiento de objetos y reinstaló comtypes. A partir de entonces todo fue bien.

Oh, otra cosa que he pensado. No es en absoluto la intención de ser insultante, me gustaría advertir que usted asegúrese de que tiene una sesión de ArcMap en ejecución antes de ejecutar el script. Obvio, lo sé, pero admitiré que me he quedado perplejo con esto más de una vez.

Eso es lo que puedo ofrecer en este momento. Por favor, manténganos informados sobre cómo van las cosas. Mucha suerte.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X