Invocar una DLL desde una herramienta de secuencia de comandos

Lo nuevo de la versión 2.5 de Python es el ctypes, una biblioteca de funciones externas. Este proporciona tipos de datos compatibles con C y permite invocar funciones de las DLL o bibliotecas compartidas. La utilización del módulo ctypes de Python permite que el código de ArcObjects escrito en C++ se utilice en una herramienta de secuencia de comandos de geoprocesamiento.

Utilizar ctypes de Python le permite cambiar fácilmente los parámetros y los tipos que espera la herramienta de secuencia de comandos sin tener que recompilar el código de C++. El módulo ctypes es compatible con cualquier función con tipos de datos básicos que se pueda invocar a través de C, tales como car, entero, flotante y doble, así como también estructuras y punteros. Para obtener más información acerca del módulo ctypes de Python 2.6.2, consulte16.15 ctypes—Una biblioteca de funciones externas para Python.

Invocar una DLL desde una secuencia de comandos de Python otorga muchos beneficios. Puede aprovechar las clases detalladas de ArcObjects en las tareas de geoprocesamiento, la propiedad intelectual está protegida y es mucho más fácil de implementar que al utilizar las interfaces de IGPFunction2 y IGPFunctionFactory. Crea el objeto en Python e invoca el método de ejecución, introduce los parámetros requeridos de la secuencia de comandos mediante el marco de geoprocesamiento.

Funcionamiento

Los pasos son los siguientes:

Cree un proyecto Win32 de C++ en Visual Studio 2008 que exporte una función simple con el prototipo:

int GpExecutetool(char* parameter1, char* parameter2)

Asegúrese de incluir el ArcGIS\com\directory en el proyecto y de importar los archivos .olb de ArcObjects.

Cree una herramienta de secuencia de comandos en una caja de herramientas personalizada que valide los dos parámetros y que los introduzca en la secuencia de comandos.

La secuencia de comandos de Python hace lo siguiente:

Los detalles

El proyecto de C++ (denominado GPToolAsSimpleDLL para este ejemplo) es un proyecto Win32 simple que agrega un campo AREA a la clase de entidad y calcula el valor.

El archivo de encabezado

#ifdef GPTOOLASSIMPLEDLL_EXPORTS #define GPTOOLASSIMPLEDLL_API extern "C"__declspec(dllexport) #else #define GPTOOLASSIMPLEDLL_API extern "C"__declspec(dllimport) #endif  GPTOOLASSIMPLEDLL_API int GPexecutetool(char*, char*);

El archivo de origen GPToolAsSimpleDLL abre la clase de entidad poligonal especificada y establece el archivo especificado en el área de cada entidad de polígono. Cada función de geoprocesamiento que escribió se puede implementar con un punto de entrada de función de C simple, en la misma DLL, junto con compañeros de la herramienta de secuencia de comandos, para exponer cada función en ArcToolbox.

GPTOOLASSIMPLEDLL_API int GPexecutetool(char* featureclassPath, char* fieldname) {     // Convert char*s to bstring     _bstr_t catalogPath;     catalogPath = featureclasspath;     _bstr_t newfieldname;     newfieldname = fieldname;      // Coinitialize GP utilities class     IGPUtilitiesPtr ipUtil(CLSID_GPUtilities);      // Feature class holder     IFeatureClassPtr ipFeatureclass(0);      HRESULT hr;      // Try to fetch feature class from catalog path     if (FAILED(hr = ipUtil->OpenFeatureClassFromString(catalogPath, &ipFeatureclass)))     {         return -1;     }      // Index position of the specified field    	long fieldIndex;    	ipFeatureclass->FindField(newfieldname, &fieldIndex);      // Set up query filter and feature cursor    	IQueryFilterPtr ipFilter(CLSID_QueryFilter);    	IFeatureCursorPtr ipCursor;    	IFeaturePtr ipRow;    	IGeometryPtr ipShape;      // Open search cursor on feature class    	ipFeatureclass->Search(ipFilter, VARIANT_FALSE, &ipCursor);      // Iterate     esriGeometryType gt;     for (ipCursor->NextFeature(&ipRow);        		ipRow != NULL;          ipCursor->NextFeature(&ipRow))     {          // Get row's associated geometry 		       ipRow->get_Shape(&ipShape);  		       // Ensure we've got a polygon 		       ipShape->get_GeometryType(&gt); 		       if (gt != esriGeometryPolygon) 			          return -2;  		       // Get area 		       IAreaPtr ipArea(ipShape);          double area; 		       ipArea->get_Area(&area);  		       // Pop double into a variant          VARIANT value; 		       value.vt = VT_R8; 		       value.dblVal = area;  		       // Set double variant onto target field 		       ipRow->put_Value(fieldIndex, value);  	       	// Save 	       	ipRow->Store();     }      return S_OK; }

La secuencia de comandos de Python actúa como mediador al aceptar los dos parámetros de la herramienta de secuencia de comandos como texto y enviarlos a la función de la DLL como cadenas de texto car* terminadas en cero. La secuencia de comandos también utiliza la herramienta de geoprocesamiento Añadir campo antes de que se invoque la función de la DLL. Esto puede hacer que el flujo de trabajo sea más sólido al implementar la funcionalidad propietaria de C++ y las tareas comunes de Python.

import arcpy import ctypes  # Get the parameters from the script tool dialog # shp = arcpy.GetParameterAsText(0) fieldName = arcpy.GetParameterAsText(1)  # See if the field already exists in the feature class. #   If not, add it. if len(arcpy.ListFields(shp, fieldName)) == 0:     arcpy.AddField_management(shp, fieldName, "DOUBLE")  # Import DLL into memory and get a pointer to the function #   Note: be sure the DLL is in your Python search path  # dll = ctypes.cdll.GPToolAsSimpleDLL perform_function = dll.GPExecutetool  # Tell ctypes the function accepts two char* arguments # perform_function.argtypes = [ctypes.c_char_p, ctypes.c_char_p]  # Tell ctypes the function return type # perform_function.restype = ctypes.c_int  # Call the function in the DLL # retval = perform_function(shp, fieldName)  # Check the return value.  If a 0 returned, success! # if retval == 0:     arcpy.AddMessage("Success") elif retval == 1:     arcpy.AddError("Unable to open " + shp) elif retval == 2:     arcpy.AddError("Not a polygon feature class")
9/11/2013