GetActiveObjects Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
RNDLDVL
Posts: 15
Joined: 04 Oct 2015, 10:48

GetActiveObjects

Post by RNDLDVL » 19 Aug 2020, 03:28

Not sure if this is the right section. Anyone happen to have the v2 version of this function? I've tried porting it basing on the v2 documentation but I'm not sure how the DllCalls work themselves so I'm not sure what I am doing wrong or perhaps an alternative to fetching all active specific COM objects of a certain type in v2.

v1 Original:

Code: Select all

GetActiveObjects(Prefix:="",CaseSensitive:=false) {
	objects := {}
	DllCall("ole32\CoGetMalloc", "uint", 1, "ptr*", malloc) ; malloc: IMalloc
	DllCall("ole32\CreateBindCtx", "uint", 0, "ptr*", bindCtx) ; bindCtx: IBindCtx
	DllCall(NumGet(NumGet(bindCtx+0)+8*A_PtrSize), "ptr", bindCtx, "ptr*", rot) ; rot: IRunningObjectTable
	DllCall(NumGet(NumGet(rot+0)+9*A_PtrSize), "ptr", rot, "ptr*", enum) ; enum: IEnumMoniker
	while DllCall(NumGet(NumGet(enum+0)+3*A_PtrSize), "ptr", enum, "uint", 1, "ptr*", mon, "ptr", 0) = 0 ; mon: IMoniker
	{
		DllCall(NumGet(NumGet(mon+0)+20*A_PtrSize), "ptr", mon, "ptr", bindCtx, "ptr", 0, "ptr*", pname) ; GetDisplayName
		name := StrGet(pname, "UTF-16")
		DllCall(NumGet(NumGet(malloc+0)+5*A_PtrSize), "ptr", malloc, "ptr", pname) ; Free
		if InStr(name, Prefix, CaseSensitive) = 1 {
			DllCall(NumGet(NumGet(rot+0)+6*A_PtrSize), "ptr", rot, "ptr", mon, "ptr*", punk) ; GetObject
	; Wrap the pointer as IDispatch if available, otherwise as IUnknown.
			if (pdsp := ComObjQuery(punk, "{00020400-0000-0000-C000-000000000046}"))
				obj := ComObject(9, pdsp, 1), ObjRelease(punk)
			else
				obj := ComObject(13, punk, 1)
	; Store it in the return array by suffix.
			objects[SubStr(name, StrLen(Prefix) + 1)] := obj
		}
		ObjRelease(mon)
	}
	ObjRelease(enum)
	ObjRelease(rot)
	ObjRelease(bindCtx)
	ObjRelease(malloc)
	return objects
}
v2 Attempt:

Code: Select all

GetActiveObjects(Prefix:="",CaseSensitive:=false) {
        objects := {}
        malloc := DllCall("ole32\CoGetMalloc", "uint", 1, "Cdecl ptr*") ; malloc: IMalloc
        bindCtx := DllCall("ole32\CreateBindCtx", "uint", 0, "Cdecl ptr*", ) ; bindCtx: IBindCtx
        rot := DllCall(NumGet(NumGet(bindCtx+0, "UPtr")+8*A_PtrSize, "UPtr"), "ptr", bindCtx, "Cdecl ptr*") ; rot: IRunningObjectTable
        enum := DllCall(NumGet(NumGet(rot+0, "UPtr")+9*A_PtrSize, "UPtr"), "ptr", rot, "Cdecl ptr*") ; enum: IEnumMoniker
		mon := DllCall(NumGet(NumGet(enum+0, "UPtr")+3*A_PtrSize, "UPtr"), "ptr", enum, "uint", 1, "ptr*", mon, "ptr", 0)
        While mon = 0 ; mon: IMoniker
        {
            pname := DllCall(NumGet(NumGet(mon+0, "UPtr")+20*A_PtrSize, "UPtr"), "ptr", mon, "ptr", bindCtx, "ptr", 0, "Cdecl ptr*") ; GetDisplayName
            name := StrGet(pname, "UTF-16")
            DllCall(NumGet(NumGet(malloc+0, "UPtr")+5*A_PtrSize, "UPtr"), "ptr", malloc, "ptr", pname) ; Free
            If InStr(name, Prefix, CaseSensitive) = 1 {
                punk := DllCall(NumGet(NumGet(rot+0, "UPtr")+6*A_PtrSize, "UPtr"), "ptr", rot, "ptr", mon, "Cdecl ptr*") ; GetObject
                ; Wrap the pointer as IDispatch If available, otherwise as IUnknown.
                If (pdsp := ComObjQuery(punk, "{00020400-0000-0000-C000-000000000046}"))
                    obj := ComObject(9, pdsp, 1), ObjRelease(punk)
                Else
                    obj := ComObject(13, punk, 1)
                ; Store it in the Return array by suffix.
                objects[SubStr(name, StrLen(Prefix) + 1)] := obj
            }
            ObjRelease(mon)
        }
        ObjRelease(enum)
        ObjRelease(rot)
        ObjRelease(bindCtx)
        ObjRelease(malloc)
        Return objects
    }
Last edited by BoBo on 19 Aug 2020, 07:43, edited 1 time in total.
Reason: Moved to 'Ask for Help v2'.

User avatar
aseiot
Posts: 79
Joined: 05 Mar 2017, 04:25

Re: GetActiveObjects  Topic is solved

Post by aseiot » 19 Aug 2020, 05:10

Try this:

Code: Select all

GetActiveObjects(Prefix:="", CaseSensitive:=false) {
    objects := Map()
   ,DllCall("ole32\CoGetMalloc", "uint", 1, "ptr*", malloc:=0) ; malloc: IMalloc
   ,DllCall("ole32\CreateBindCtx", "uint", 0, "ptr*", bindCtx:=0) ; bindCtx: IBindCtx
   ,ComCall(8, bindCtx, "ptr*", rot:=0) ; rot: IRunningObjectTable
   ,ComCall(9, rot, "ptr*", enum:=0) ; enum: IEnumMoniker
    while ComCall(3, enum, "uint", 1, "ptr*", mon:=0, "ptr", 0) = 0 ; mon: IMoniker
    {
        ComCall(20, mon, "ptr", bindCtx, "ptr", 0, "ptr*", pname:=0) ; GetDisplayName
      , name := StrGet(pname, "UTF-16")
      , ComCall(5, malloc, "ptr", pname) ; Free
        if InStr(name, Prefix, CaseSensitive) = 1 {
            ComCall(6, rot, "ptr", mon, "ptr*", punk:=0) ; GetObject
            ; Wrap the pointer as IDispatch if available, otherwise as IUnknown.
            if (pdsp := ComObjQuery(punk, "{00020400-0000-0000-C000-000000000046}"))
                ObjAddRef(pdsp.ptr),obj := ComObject(9, pdsp.ptr, 1),ObjRelease(punk)
            else
                obj := ComObject(13, punk, 1)
            ; Store it in the return array by suffix.
            objects[SubStr(name,StrLen(Prefix) + 1)] := obj
        }
        ObjRelease(mon)
    }
    ObjRelease(enum)
   ,ObjRelease(rot)
   ,ObjRelease(bindCtx)
   ,ObjRelease(malloc)
    return objects
}

RNDLDVL
Posts: 15
Joined: 04 Oct 2015, 10:48

Re: GetActiveObjects

Post by RNDLDVL » 19 Aug 2020, 07:41

Code: Select all

        if InStr(name, Prefix, CaseSensitive) = 1 {
I think something about the changes regarding string variables gives me an invalid parameter #2 in this line, which is the Prefix variable. I've tested both v1 and v2, v1 proceeds inside the the if block despite Prefix having a null value which kinda doesn't make sense when you look at it now.

v1:
v2:

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: GetActiveObjects

Post by swagfag » 19 Aug 2020, 07:52

read InStr's remarks about blank needles

RNDLDVL
Posts: 15
Joined: 04 Oct 2015, 10:48

Re: GetActiveObjects

Post by RNDLDVL » 19 Aug 2020, 08:07

swagfag wrote:
19 Aug 2020, 07:52
read InStr's remarks about blank needles
Oh god, I'm stupid. I overlooked that part. Thanks mate, it works fine now.

Here's the code for people interested in COM specifically excel, might be of use.

Code: Select all

GetActiveObjects(Prefix:="", CaseSensitive:=false) {
        objects := Map()
        ,DllCall("ole32\CoGetMalloc", "uint", 1, "ptr*", malloc:=0) ; malloc: IMalloc
        ,DllCall("ole32\CreateBindCtx", "uint", 0, "ptr*", bindCtx:=0) ; bindCtx: IBindCtx
        ,ComCall(8, bindCtx, "ptr*", rot:=0) ; rot: IRunningObjectTable
        ,ComCall(9, rot, "ptr*", enum:=0) ; enum: IEnumMoniker
        while ComCall(3, enum, "uint", 1, "ptr*", mon:=0, "ptr", 0) = 0 ; mon: IMoniker
        {
            ComCall(20, mon, "ptr", bindCtx, "ptr", 0, "ptr*", pname:=0) ; GetDisplayName
            , name := StrGet(pname, "UTF-16")
            , ComCall(5, malloc, "ptr", pname) ; Free
            if (Prefix == "" || InStr(name, Prefix, CaseSensitive) = 1) {
                ComCall(6, rot, "ptr", mon, "ptr*", punk:=0) ; GetObject
                ; Wrap the pointer as IDispatch if available, otherwise as IUnknown.
                if (pdsp := ComObjQuery(punk, "{00020400-0000-0000-C000-000000000046}"))
                    ObjAddRef(pdsp.ptr),obj := ComObject(9, pdsp.ptr, 1),ObjRelease(punk)
                else
                    obj := ComObject(13, punk, 1)
                ; Store it in the return array by suffix.
                objects[SubStr(name,StrLen(Prefix) + 1)] := obj
            }
            ObjRelease(mon)
        }
        ObjRelease(enum)
        ,ObjRelease(rot)
        ,ObjRelease(bindCtx)
        ,ObjRelease(malloc)
        return objects
    }

fatodubs
Posts: 29
Joined: 20 Sep 2017, 18:53

Re: GetActiveObjects

Post by fatodubs » 24 May 2023, 17:34

I'm trying to use this for the 2.0.2 and running into errors. Here's what I have working, but I don't know enough about COM Interfaces to know if it's wholly accurate.

Code: Select all

GetActiveObjects(Prefix:="",CaseSensitive:="Off") {
	objects:=Map()
		,DllCall("ole32\CoGetMalloc", "uint", 1, "ptr*", &malloc:=0) ; malloc: IMalloc
		,DllCall("ole32\CreateBindCtx", "uint", 0, "ptr*", &bindCtx:=0) ; bindCtx: IBindCtx
		,ComCall(8, bindCtx, "ptr*",&rot:=0) ; rot: IRunningObjectTable
		,ComCall(9, rot, "ptr*", &enum:=0) ; enum: IEnumMoniker
	while (ComCall(3, enum, "uint", 1, "ptr*", &mon:=0, "ptr", 0)=0) ; mon: IMoniker
	{
		ComCall(20, mon, "ptr", bindCtx, "ptr", 0, "ptr*", &pname:=0) ; GetDisplayName
			,name:=StrGet(pname, "UTF-16")
			,ComCall(5,malloc,"ptr",pname) ; Free
		if ((Prefix="") OR (InStr(name,Prefix,CaseSensitive)=1)) {
			ComCall(6, rot, "ptr", mon, "ptr*", &punk:=0) ; GetObject
			; Wrap the pointer as IDispatch if available, otherwise as IUnknown.
			obj:=ComObjFromPtr(punk)
			objects[name]:=obj
		}
		ObjRelease(mon)
	}
	ObjRelease(enum)
		,ObjRelease(rot)
		,ObjRelease(bindCtx)
		,ObjRelease(malloc)
	return objects
}
Is there a way from this to identify the type of object? In v1, most of the returned objects included a DispatchType property.

Thanks!

Spitzi
Posts: 313
Joined: 24 Feb 2022, 03:45

Re: GetActiveObjects

Post by Spitzi » 01 Jun 2023, 14:49

Hi @fatodubs.

Thanks for your code, it works as a AHKV2 replacement for @lexikos GetActiveObjects-Function written in AHKV1, originally posted here: http://ahkscript.org/boards/viewtopic.php?f=6&t=6494.

Since i heavily relied on function in my V1 script, I am happy to now have a AHKV2 counterpart. Maybe lexikos finds a minute to check wether it is wholly accurate...

Thanks to both of you for this function - my scripts would not be possible without it.

Spitzi
Posts: 313
Joined: 24 Feb 2022, 03:45

Re: GetActiveObjects

Post by Spitzi » 13 Jul 2023, 16:41

Hi there.

Lately I had users reporting errors in my skript, one of them stemming from the GetActiveObjects-function by @fatodubs that I use. I think it has do do with com objects becoming unavailable (because the user closes an app) while the function is running. I added a try clause to ignore the causing com object:

Code: Select all

	
	; for AHK V1 by lexikos http://ahkscript.org/boards/viewtopic.php?f=6&t=6494
	; for AHK V2 by fatodubs https://www.autohotkey.com/boards/viewtopic.php?f=82&t=80074&hilit=GetActiveObjects
	; gets all active comObjects that are available on the system
	GetActiveObjects(Prefix:="",CaseSensitive:="Off") {
		objects:=Map()
		DllCall("ole32\CoGetMalloc", "uint", 1, "ptr*", &malloc:=0) ; malloc: IMalloc
		DllCall("ole32\CreateBindCtx", "uint", 0, "ptr*", &bindCtx:=0) ; bindCtx: IBindCtx
		ComCall(8, bindCtx, "ptr*",&rot:=0) ; rot: IRunningObjectTable
		ComCall(9, rot, "ptr*", &enum:=0) ; enum: IEnumMoniker
		while (ComCall(3, enum, "uint", 1, "ptr*", &mon:=0, "ptr", 0)=0) ; mon: IMoniker
		{
			ComCall(20, mon, "ptr", bindCtx, "ptr", 0, "ptr*", &pname:=0) ; GetDisplayName
			name:=StrGet(pname, "UTF-16")
			ComCall(5,malloc,"ptr",pname) ; Free
			if ((Prefix="") OR (InStr(name,Prefix,CaseSensitive)=1)) {
				try {
					ComCall(6, rot, "ptr", mon, "ptr*", &punk:=0) ; GetObject											; can throw an Error: (0x800401FB) Object is not registered - probably when an app is closed and is suddenly unavailable
					; Wrap the pointer as IDispatch if available, otherwise as IUnknown.
					obj:=ComObjFromPtr(punk)
					objects[name]:=obj
				}
			}
			ObjRelease(mon)
		}
		ObjRelease(enum)
		ObjRelease(rot)
		ObjRelease(bindCtx)
		ObjRelease(malloc)
		return objects
	}
Maybe comes in hady for someone.

Post Reply

Return to “Ask for Help (v2)”