5

I've developed Add-in tools (with Windows dialog GUIs) for ArcMap which work fine, but I would also like to be able to call these directly (passing in parameters so I won't need to display the dialog) from either a Model Workflow or a Python Script.

Is this possible ?

As a workaround I've tried using inter-process coms (via a named pipe) with a worker task / thread and this works right up to the point where I attempt to store changes - when ArcMap itself goes legs-up (I'm guessing maybe a lock issue?).

AndreJ
  • 76,698
  • 5
  • 86
  • 162
Scott Quinn
  • 181
  • 5
  • More likely a thread issue causing ArcMap to go legs-up.. ArcMap is a single thread process and its objects are not thread safe. Calling from python is discussed https://gis.stackexchange.com/questions/129456/guidelines-for-using-arcobjects-from-python/150711#150711 you should be able to call a public Execute method within your code with ICommandItem.Execute. – Michael Stimson Aug 23 '17 at 01:02
  • Okay - that makes sense (threads).How am I getting the ICommandItem for the addin when it's on a custom toolbar ? – Scott Quinn Aug 23 '17 at 03:00
  • ICommandBars.Find('ID_of_your_Code',False,True) http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/index.html#//002300000068000000 make sure your code has a public function to locate or it will not be found. – Michael Stimson Aug 23 '17 at 03:02
  • Or it might be simpler to create an interface as a GP tool (example https://desktop.arcgis.com/en/arcobjects/latest/java/ac36e770-bb76-4231-b833-7510c27a6215.htm) which references your addin dll and call that from python. There is an older example in .net http://resources.esri.com/help/9.3/ArcGISEngine/dotnet/e7d06ae9-a6d1-4248-a7a3-9d5f375f088c.htm – Michael Stimson Aug 23 '17 at 03:21
  • Thanks @MichaelStimson. RE: Comment 1: So that should work although I'd rather a method that doesn't tie me to a specific command toolbar (users have a way of messing with bars and moving buttons). RE Comment 2 - Hmmm ... interesting ... it's certainly going to be a fun afternoon of reading to get my head around all that - one thing, that's for VS 2005 and ArcMap 9.3, is that still valid with 10.x ? I'm surprised this isn't easier and more common esp. considering the limitations and problems with Python ?! – Scott Quinn Aug 23 '17 at 04:23
  • ICommandBars.Find will find the tool whether it's on a toolbar or not, as long as the tool is registered with EsriRegAsm for desktop it can be found. There is an idiom switch between 9.x and 10.0 with the advent of Esriaddin tools though the older style of implementing interfaces as dll files still builds and works within ArcGIS; I can't find any newer example of creating a custom geoprocessing tool to reference so I don't know if it's changed or dropped, but there must still be a way of creating custom geoprocessing tools - google returns so many results it's hard to find gold in the dross. – Michael Stimson Aug 23 '17 at 04:31
  • Found it http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#/Building_a_custom_geoprocessing_function_tool/00010000049w000000/ you need to implement IGPFunction2 https://desktop.arcgis.com/en/arcobjects/latest/net/webframe.htm#IGPFunction2.htm and IGPFunctionFactory http://help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/index.html#/d/002n00000287000000.htm then override the Execute method. – Michael Stimson Aug 23 '17 at 04:50
  • So @MichaelStimson the command bars option will work well I think - is there a standard for passing data between apps / addins in ESRI ? I just want to pass a string (XML converted to a string) .. was thinking Named Pipes or a Mail Slot but these seem like an overkill ... surely three's an easier way ? – Scott Quinn Aug 24 '17 at 02:08
  • No standard that I know of. I don't know much about pipes etc.. no argument is passed to the command item on execute so I guess how the parameters get there is up to you. – Michael Stimson Aug 24 '17 at 02:19
  • Thanks a heap @MichaelStimson - I'll pass the parameters via the "tag". One more question though, how do I find the command from python ?? I can't see where one can access the CommandBars from python ... – Scott Quinn Aug 24 '17 at 06:24
  • Have a read of the post https://gis.stackexchange.com/questions/129456/guidelines-for-using-arcobjects-from-python/150711#150711 and https://gis.stackexchange.com/questions/80/accessing-arcobjects-from-python/110#110 about using comtypes to leverage ArcObjects from python. You can access ICommandBars from IDocument.CommandBars http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/index.html#//0023000000q3000000 see example http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/index.html#//0049000000n0000000 – Michael Stimson Aug 24 '17 at 20:45

1 Answers1

3

So yes this is possible (many thanks to Michael Stimson for his help - the solution is basically in his comments, I'm just putting it all together here).

On the Python Side:

You'll need imports for the usual suspects (sys, os, and arcpy).

Get the COM functions you'll need from the "comtypes" library for Python (Google it) ... and import the framework while you're at it.

from comtypes.client import GetModule, CreateObject
import comtypes.gen.esriFramework

Load the framework COM module

modFramework = GetModule(<Your ArcGis Path> + r"com\esriFramework.olb") 

Create the app

pApp = CreateObject(modFramework.AppROT, interface=modFramework.IAppROT)

From it get a pointer to the document (NB: You want the Doc not the MXDoc)

pDoc = pApp.Item(0).Document.QueryInterface(modFramework.IDocument)  

Form there I got the Command Bars (could probably have skipped this).

pCmdBars = pDoc.CommandBars.QueryInterface(modFramework.ICommandBars)

Use the CommandBars "Find" to get a pointer to your Addin

pAddIn = pCmdBars.Find(<Your Addin Name>)

I used the "Tag" field to pass some params to the addin (optional)

pAddIn.Tag = <Some data (e.g. parameters) you want to pass to the addin>

Then execute (start) the addin

pAddIn.Execute()

If your addin is a "Button" that will call "OnClick".

On the C# side:

You don't need to do much if anything here. All I did was get the command bar and extract the Tag text (which I'd packed params into).

ICommandBars commandBars = ArcMap.Application.Document.CommandBars;
ICommandItem item = commandBars.Find(<Your Addin Name>);
item.Tag *<-- text is here* 

It's convoluted, but that's one way to do it (there may be others).

Cheers,

Scott

Scott Quinn
  • 181
  • 5