Accessing COM applications from the Running Object Table

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Dulus
Posts: 10
Joined: 09 Oct 2014, 06:43

Accessing COM applications from the Running Object Table

22 Oct 2014, 12:41

Having gotten AHK working with my COM API, I now find that I need to distinguish between multiple instances running simultaneously. ComObjActive can only get the first instance per Prog ID because of limitations of the MS API. I think the work-around is to access the Running Object Table (ROT). Below is a naive attempt at translating this C# program into AHK. Can anyone help me get this working?
http://adndevblog.typepad.com/autocad/2 ... table.html

Code: Select all

#NoEnv
#SingleInstance Force
SetBatchLines, -1
Ptr := A_PtrSize ? "Ptr" : "UInt"
UPtr := A_PtrSize ? "UPtr" : "UInt"

TestROT()


Return



CreateBindCtx() {
	DllCall("ole32.dll\CreateBindCtx", UInt, reserved, UPtr, prot)
	Return prot
}
GetRunningObjectTable() {
	DllCall("ole32.dll\GetRunningObjectTable", UInt, reserved, UPtr, prot)
	Return prot
}

; Get all running instance by querying ROT
GetRunningInstances(progIds)
{
	static Type := ComObjCreate( "System.Runtime.InteropServices").ComTypes
	static clsIds := {}
	
	; get the app clsid
	for progId in progIds
	{
		type := Type.GetTypeFromProgID(progId)
	
		if(type != "")
			clsIds.Insert(type.GUID)
	}
	
	; get Running Object Table ...
	Rot := GetRunningObjectTable()
	if (Rot = "")
		return ""
	
	; get enumerator for ROT entries
	monikerEnumerator := Rot.EnumRunning._NewEnum()
	
	instances := {}
	
	; go through all entries and identifies app instances
	while (monikerEnumerator.Next(1, monikers, pNumFetched) = 0)
	{
		bindCtx := CreateBindCtx()
		if (bindCtx = "")
			continue
		
		monikers[0].GetDisplayName(bindCtx, "", displayName)
		
		for clsId in clsIds
		{
			if (displayName.IndexOf(clsId) > 0)
			{
				ComObject := Object()
				Rot.GetObject(monikers[0], ComObject)
				
				if (ComObject = "")
					continue
				
				instances.Insert(ComObject)
				break
			}
		}
	}
	return instances
}

TestROT()
{
	; Look for acad 2009 & 2010 & 2014
	progIds := ["AutoCAD.Application.17.2","AutoCAD.Application.18","AutoCAD.Application.19.1"]
	
	instances = GetRunningInstances(progIds)
	
	for acadObj in instances
	{
		try
		{
			; do some stuff ... 	
		}
		catch
		{
		  	
		}
	}
}
Dulus
Posts: 10
Joined: 09 Oct 2014, 06:43

Re: Accessing COM applications from the Running Object Table

23 Oct 2014, 14:58

Or, instead of translating C#, how about translating MSDN?
pprot [out]
The address of an IRunningObjectTable* pointer variable that receives the interface pointer to the local ROT. When the function is successful, the caller is responsible for calling Release on the interface pointer. If an error occurs, *pprot is undefined.
The address of a variable of a pointer to a pointer to an object? Here's my best shot:

Code: Select all

VarSetCapacity(prot, A_PtrSize)
DllCall("ole32.dll\GetRunningObjectTable", UInt, 0, UPtrP, prot)
ROT:=numget(prot+0)
ROT2:=Object(ROT) ; to much to expect for this to work
ObjRelease(ROT)
At least ROT gives the same integer each time.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Accessing COM applications from the Running Object Table

22 Feb 2015, 00:39

I came across a need to do this with multiple instances of Visual Studio, so wrote GetActiveObjects(). It probably does what you want.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: peter_ahk and 348 guests