Page 1 of 1

GetActiveObjects

Posted: 19 Aug 2020, 03:28
by RNDLDVL
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
    }

Re: GetActiveObjects  Topic is solved

Posted: 19 Aug 2020, 05:10
by aseiot
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
}

Re: GetActiveObjects

Posted: 19 Aug 2020, 07:41
by RNDLDVL

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:

Re: GetActiveObjects

Posted: 19 Aug 2020, 07:52
by swagfag
read InStr's remarks about blank needles

Re: GetActiveObjects

Posted: 19 Aug 2020, 08:07
by RNDLDVL
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
    }

Re: GetActiveObjects

Posted: 24 May 2023, 17:34
by fatodubs
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!

Re: GetActiveObjects

Posted: 01 Jun 2023, 14:49
by Spitzi
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.

Re: GetActiveObjects

Posted: 13 Jul 2023, 16:41
by Spitzi
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.