TypeLib2AHK - Convert COM Type libraries to AHK code

Post your working scripts, libraries and tools for AHK v1.1 and older
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

08 Oct 2017, 10:12

Was there any particular reason for shifting the function parameters and inserting pInterface? I noticed it creates big problems with byref parameters and removed it. Seems to have no ill effect...
Yes, this was because pInterface was not actually the interface, it was the 2nd argument (because it's an object method, the first, hidden parameter is assigned to this. Therefore "this" is actually pInterface in all cases.
For some reason your original code and my adaptation of your example only seems to receive a single event and then nothing more. Do you have any idea why that could be?
If you've removed the shifting, that's probably why. The 2nd post I made had a much simpler way to get the job done.

If you're only receiving one event, is it possible that you're not holding a reference to the sub-class? That would cause the class to self-delete, possibly clear the vtable. The program might or might-not crash but the events wouldn't come through properly.
Elgin
Posts: 124
Joined: 30 Sep 2013, 09:19

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

08 Oct 2017, 10:56

If you've removed the shifting, that's probably why. The 2nd post I made had a much simpler way to get the job done.
Nope, it's not. I only get one event from your first code and simplified code with the shifting, as well as from mine without shifting.

In any case there needs to be a solution without the parameter shifting.
Stuff like this:

Code: Select all

	_GetPatternProvider(patternId, byref pRetVal)
will simply fail when you shift the parameters as the byref gets garbled up.
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

08 Oct 2017, 11:15

Isn't ByRef similar/same to ppRetVal?

Actually, in this particular case, no parameter forwarding would be necessary really, it's just that this == pInterface, so it could be like this (I think):

Code: Select all

_GetPatternProvider(patternId, byRef pRetVal) {
	if (!IsObject(this))
		return ComObjImpl.ObjMap[this]._GetPatternProvider(patternId, pRetVal)

	NumPut(pImplementor, pRetVal+0)
	return 0x00 ; S_OK
}
But in other situations, where parameter shifting is necessary, wouldn't this work just as well?

Code: Select all

_GetPatternProvider(patternId, ppRetVal) {
	if (!IsObject(this))
		return ComObjImpl.ObjMap[this]._GetPatternProvider(patternId, ppRetVal)

	; Would need to treat ppRetVal as a pointer-pointer
	NumPut(pImplementor, (*pRetVal))
	return 0x00 ; S_OK
}
No expert, but I think that would be right...
Elgin wrote: I gave your code a quick test and it only seems to run in 64bit but not in 32. Any idea what might cause this? I'd like to support both if possible.
On this topic, did you get it working with 32 bit? I tried everything I could think of but could not get it to work, by the end I was just trying random things but I think it has to do w/ UPtr/UInt in 32 bit code with all the various calls, etc.
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

08 Oct 2017, 11:17

cpriest wrote:
Elgin wrote: I gave your code a quick test and it only seems to run in 64bit but not in 32. Any idea what might cause this? I'd like to support both if possible.
On this topic, did you get it working with 32 bit? I tried everything I could think of but could not get it to work, by the end I was just trying random things but I think it has to do w/ UPtr/UInt in 32-bit code with all the various calls, etc.
Come to think of it, if we had debugging symbols for AutoHotKey it might help to be able to trace with Visual Studio what/where it's going wrong.
Elgin
Posts: 124
Joined: 30 Sep 2013, 09:19

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

13 Oct 2017, 05:13

I've done a good bit of reading... the byref is only really necessary in very few cases, e.g. when integers are passed as FIN/FOUT parameters, as the most commonly used types are handled as byref by AHK anyway. So I removed most byrefs and also removed the implementation code for interfaces that extend IDispatch as those are also handled natively by AHK. I still need to decide if I'll just add a warning for the byref or make the parameters before those also byref for good measure...

I've updated the test branch accordingly with the parameter shifting back in place.

But: I still only get a single event back from the test code and had no luck with 32bit.
Do the events work for you now?
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

14 Oct 2017, 09:46

Yeah, they're working for me. Can you post the code you're using? (I haven't tried it yet with the new export, but maybe I can spot where the problem is)
Elgin
Posts: 124
Joined: 30 Sep 2013, 09:19

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

15 Oct 2017, 05:23

The test code is in the test branch on Github (uiaeventhandlertest.ahk).
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

15 Oct 2017, 08:29

So currently I get the created events every time, the destroyed events are not consistent but I have gotten them. Here's a trace of whats happening with my version. Still looking through your code, but thought this might help:

Note that in this log for every 'notepad' I created I also closed (but no destroyed event), but I'm getting destroyed events for the alt-tab window
Spoiler
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

15 Oct 2017, 09:06

Looking at the code I noticed this isn't right:

https://github.com/Elgin1/TypeLib2AHK/b ... e.ahk#L177

It should be:
NumPut(0, ppvObject+0, "Ptr")

I think that may be the problem.
Elgin
Posts: 124
Joined: 30 Sep 2013, 09:19

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

15 Oct 2017, 14:18

That made it better, but it still crashes after a few (2-4) events, so there must be something else...

Could you please post your working code? Then I can compare it and hopefully work out the kinks.
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

15 Oct 2017, 20:18

Yes, though mine uses some things from my own library that may not be available, most notably OutputDebug() function, which is mostly a wrapper for OutputDebug % Format...

Code: Select all

; #Include <uia>

#Include TL2A\UIAutomationClient-v1_0-x86_64.ahk
#Include UIAutomationEventHandler.ahk

; #include UIA_Testing_FromForum.ahk

global UIA := CUIAutomation()

global DesktopElem := UIA.GetRootElement()
; global EvtHandle := IUIAutomationEventHandler_new()
; OutputDebug("AddAutomationEventHandler, DesktopElem={:X}, EvtHandle={:X}", DesktopElem, EvtHandle )
; OutputDebug("AddAutomationEventHandler, DesktopElem={}, OnCreated.pInterface={:X}", DesktopElem.CurrentName(), OnCreated.pInterface )

; MsgBox % Format("{} {}", UIAutomationClientTLConst.UIA_Window_WindowOpenedEventId, UIAutomationClientTLConst.TreeScope_Children)

hr := UIA.AddAutomationEventHandler( UIAutomationClientTLConst.UIA_Window_WindowOpenedEventId
	, DesktopElem
	, UIAutomationClientTLConst.TreeScope_Children
	, 0
 	, OnCreated.pInterface )

; hr := UIA.AddAutomationEventHandler( UIAutomationClientTLConst.UIA_Window_WindowClosedEventId
; 	, DesktopElem
; 	, UIAutomationClientTLConst.TreeScope_Children
; 	, 0
;  	, OnDestroyed.pInterface )

; UIA.RemoveAllEventHandlers()





; ------------------------------------------
; 	Using #Include <uia>
; ------------------------------------------

; global UIA := new IUIAutomation
; UIA.Element := new IUIAutomationElement
; UIA.Condition := new IUIAutomationCondition
; UIA.CacheRequest := new IUIAutomationCacheRequest
; UIA.TreeWalker := new IUIAutomationTreeWalker


; global DesktopElem := UIA.GetRootElement()
; ; global EvtHandle := IUIAutomationEventHandler_new()
; ; OutputDebug("AddAutomationEventHandler, DesktopElem={:X}, EvtHandle={:X}", DesktopElem, EvtHandle )
; OutputDebug("AddAutomationEventHandler, DesktopElem={:X}, OnCreated.pInterface={:X}", DesktopElem, OnCreated.pInterface )

; hr := UIA.AddAutomationEventHandler( UIA_Event("Window_WindowOpened")
; 	, DesktopElem
; 	, UIA_Enum("TreeScope_Children")
; 	, 0
;  	, OnCreated.pInterface )
; 	; , EvtHandle )

; ; UIA.RemoveAllEventHandlers()

; ------------------------------------------
; 	End of Using #Include <uia>
; ------------------------------------------


; OutputDebug("After AddAutomationEventHandler, HRESULT={:X}", hr)

UIA_Exit() {
	OutputDebug(A_ThisFunc "()")
	; Remove our exit function from the list
	OnExit(A_ThisFunc, 0)

	if (IsObject(UIA)) {
		UIA.RemoveAllEventHandlers()
		UIA := ""
	}

	if (DesktopElem) {
		ObjRelease(DesktopElem)
		DesktopElem := 0
	}

	if(OnCreated)
		OnCreated :=
	if(OnDestroyed)
		OnDestroyed :=

	return 0
}

OnExit("UIA_Exit")

Code: Select all

; *************************************************************************
; IUIAutomationEventHandler
; GUID: {146C3C17-F12E-4E22-8C27-F894B9B79C69}
; *************************************************************************

; class IUIAutomationEventHandler {
; 	; Generic definitions

; 	static __IID := "{146C3C17-F12E-4E22-8C27-F894B9B79C69}"

; 	__New(p="", flag=1) {
; 		this.__Type:="IUIAutomationEventHandler"
; 		this.__Value:=p
; 		this.__Flag:=flag
; 	}

; 	__Delete() {
; 		this.__Flag? ObjRelease(this.__Value):0
; 	}

; 	__Vt(n) {
; 		return NumGet(NumGet(this.__Value, "Ptr")+n*A_PtrSize,"Ptr")
; 	}

; 	; Interface functions

; 	; VTable Positon 3: INVOKE_FUNC Vt_Hresult HandleAutomationEvent([FIN] IUIAutomationElement*: sender, [FIN] Int: eventId)
; 	HandleAutomationEvent(sender, eventId) {
; 		If (IsObject(sender) and (ComObjType(sender)=""))
; 			refsender:=sender.__Value
; 		else
; 			refsender:=sender
; 		res:=DllCall(this.__Vt(3), "Ptr", this.__Value, "Ptr", refsender, "Int", eventId, "Int")
; 		return res
; 	}
; }


class Heap {
	ProcessHeap {
		get {
			static heap := DllCall("GetProcessHeap", "Ptr")
			return heap
		}
	}
	Allocate(bytes) {
		static HEAP_GENERATE_EXCEPTIONS := 0x00000004, HEAP_ZERO_MEMORY := 0x00000008

		; return DllCall("HeapAlloc", "Ptr", Heap.ProcessHeap, "UInt", HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY, "UInt", bytes, "UPtr")
		p := DllCall("HeapAlloc", "Ptr", Heap.ProcessHeap, "UInt", HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY, "UInt", bytes, "Ptr")
		; OutputDebug("Heap Allocated: {:X}", p)
		return p
	}
	GetSize(buffer) {
		return DllCall("HeapSize", "Ptr", Heap.ProcessHeap, "UInt", 0, "Ptr", buffer, "Ptr" )
	}
	Release(buffer) {
		; OutputDebug("Heap Released: {:X}", buffer)
		return DllCall("HeapFree", "Ptr", Heap.ProcessHeap, "UInt", 0, "Ptr", buffer, "Int")
	}
}

StringFromCLSID(riid) {
	res := DllCall("ole32\StringFromCLSID", "Ptr", riid, "PtrP", pStrCLSID := 0)
	sCLSID := StrGet(pStrCLSID, "UTF-16")
	DllCall("ole32\CoTaskMemFree", "Ptr", pStrCLSID)
	return sCLSID
}

global 	VT 		:= 0
	   ,REFS 	:= 1


global boundFunc :=

/**
 *	Base implementation for all Com Objects
 *		- Handles creation of static vTable
 *		- Registers new class instance with vtoMap for efficient memory management of vTable use
 *		- Creates global pObject pointer for use with COM
 *
 *	 NOTE - Tested that:
 *		- this.vTable and this.vtoMap accesses the static declaration in the top level class declaration
 */
class ComObjImpl {

	; Pointers to vTables by this.IID
	static vTables := { }
	; Map of Interface Pointers to Object by this.IID
	static ObjMap := { }

	; Array of string GUID Com Interfaces that this object implements
	ImplementsInterfaces := []

	; Array of Com Functions that are implemented in the class hierarchy
	ComFunctions := []

	__New() {
		; OutputDebug("{:-30.30s} ({})", A_ThisFunc "()", this.__Class)

		; Using the last Interface in the implementation array, this *should* be the highest IID in the chain
		this.IID := this.ImplementsInterfaces[this.ImplementsInterfaces.Length()]

		this.PopulateVirtualMethodTable()

		this.pInterface := Heap.Allocate(A_PtrSize + 4)
		ComObjImpl.ObjMap[this.pInterface] := this
		ObjRelease(&this)	; Release the reference just created, this reference will be free'd when __Delete is actually called

		NumPut(ComObjImpl.vTables[this.IID][VT], this.pInterface, 0, "Ptr")
		ComObjImpl.vTables[this.IID][REFS] += 1

		Refs := this._AddRef(this.pInterface)	; Adding our own reference, on delete should be 0

		OutputDebug("    this.pInterface={:X}, ComObj.vT={:X}, Refs={}", this.pInterface, ComObjImpl.vTables[this.IID][VT], Refs)

		; this.DumpObjectMap()
	}

	/**
	 *	Populates the static this.vTable with the callback points
	 *		NOTE: vTable is being passed in ByRef because it would seem using this.vTable with
	 *		VarSetCapacity/NumPut does not function correctly, using them on a ByRef of it works
	 *		just fine.
	 */
	PopulateVirtualMethodTable() {
		; OutputDebug("{:-30.30s}", A_ThisFunc)

		; this.DumpMethodTable("I")
		if (!ComObjImpl.vTables[this.IID]) {
			; Allocate a Ptr record for each method in ComFunctions
			ComObjImpl.vTables[this.IID, VT] := Heap.Allocate(this.ComFunctions.Length() * A_PtrSize)
			ComObjImpl.vTables[this.IID, REFS] := 0

			for i, func in this.ComFunctions {
; 				OutputDebug("*  ComObjImpl.vTables[this.IID][VT]={:X} - {:s} = {:p} - {}@{} name={} cName={}", ComObjImpl.vTables[this.IID][VT], func, callback, this[_func].Name, this[_func].MaxParams, name, cName)
; 				NumPut(callback, ComObjImpl.vTables[this.IID][VT], (i-1) * A_PtrSize)

				; boundFunc := this[_func].Bind(this)
				; ; boundFunc := ObjBindMethod(this, _func)
				; callback := RegisterCallback(boundFunc)
				; OutputDebug("    &callback={:X}, IsObject(boundFunc={}) - a={} b={}", &callback, IsObject(boundFunc), IsFunc(this[_func]), boundFunc)
				; if(func == "AddRef") {
				; 	OutputDebug("      Calling boundFunc.Call() where boundFunc is {}", func)
				; 	boundFunc.Call(this.pInterface, 45, 55)
				; }

				callback := RegisterCallback(this["_" func].Name)

				NumPut(callback, ComObjImpl.vTables[this.IID][VT], (i-1) * A_PtrSize)
				OutputDebug("*  ComObjImpl.vTables[this.IID][VT]={:X} - {:s} = {:p} - {}@{} name={} cName={}", ComObjImpl.vTables[this.IID][VT], func, callback, this["_" func].Name, this["_" func].MaxParams)
				; OutputDebug("    vTable={:X} = callback={:X} - &callback={:X}", ComObjImpl.vTables[this.IID][VT], callback, &callback)
			}
		}
		; this.DumpMethodTable("O")
	}
	DumpObjectMap() {
		for key, val in ComObjImpl.ObjMap {
			OutputDebug("{:X} - {} - {}", key, val.IID, val.__Class)
		}
	}
	DumpMethodTable(Prefix=" ") {
		for i, func in this.ComFunctions {
			OutputDebug(Prefix "  ComObjImpl.vTables[{}]={:X} - {:s} = {:p}", this.IID, ComObjImpl.vTables[this.IID][VT], func, NumGet(ComObjImpl.vTables[this.IID][VT], (i-1) * A_PtrSize) )
		}
	}

	__Delete() {
		ComObjImpl.ObjMap[this.pInterface] :=
		ComObjImpl.vTables[this.IID][REFS] -= 1
		; OutputDebug("{} - VT Refs={}", A_ThisFunc "()", ComObjImpl.vTables[this.IID][REFS])
		Heap.Release(this.pInterface)

		if (ComObjImpl.vTables[this.IID][REFS] == 0) {
			; OutputDebug("Freeing vTable for {}, RefCount=0", this.IID)
			Heap.Release(ComObjImpl.vTables[this.IID][VT])
			ComObjImpl.vTables[this.IID] :=
		}
	}
}

class UnknownImpl extends ComObjImpl {
	; Declare the functions our class is implementing (expected to be over-ridden by sub-classes)
	; This array should be complete for the interface and in the correct vTable order per the Type Library
	ComFunctions := ["QueryInterface", "AddRef", "Release"]

	__New() {
		; Add the GUID of the interface this class is implementing
		this.ImplementsInterfaces.InsertAt(1, "{00000000-0000-0000-C000-000000000046}")		; IUnknown
		base.__New()
	}
	/**
	 *	Implementation of IUnknown::QueryInterface
	 *		Each class level that implements some part of the final vTable should have its interface GUID
	 *		declared in this.ImplementsInterface array
	 */
	_QueryInterface(pInterface, riid, ppvObject) {
		if (!IsObject(this))
			return ComObjImpl.ObjMap[this]._QueryInterface(this, pInterface, riid)

		OutputDebug("{:-30.30s} pInt={:X}, riid={:X} ppvObject={:X}, (Class={})", A_ThisFunc "()", pInterface, riid, ppvObject, this.__Class)

		sCLSID := StringFromCLSID(riid)

		for i, sIID in this.ImplementsInterfaces {
			if (sCLSID == sIID) {
				NumPut(pInterface, ppvObject+0, "Ptr")
				OutputDebug("   Matched {} - ppvObject={:X}", sIID, ppvObject)
				this._AddRef(pInterface)
				return 0 ; S_OK
			}
		}
		; OutputDebug("   {} Interface Requested - Denied", sCLSID)
		NumPut(0, ppvObject+0, "Ptr")
		return 0x80004002 ; E_NOINTERFACE
	}

	; Implementation of IUnknown::AddRef
	_AddRef(pInterface) {
		if (!IsObject(this))
			return ComObjImpl.ObjMap[this]._AddRef(this)

		NumPut((RefCount := NumGet(pInterface+0, A_PtrSize, "UInt") + 1), pInterface+0, A_PtrSize, "UInt")
		OutputDebug("{:-30.30s} pInt={:x}, RefCount={} ({})", A_ThisFunc "()", pInterface, RefCount, this.__Class)
		return RefCount
	}

	; Implementation of IUnknown::Release
	_Release(pInterface) {
		if (!IsObject(this))
			return ComObjImpl.ObjMap[this]._Release(this)

		if ((RefCount := this.GetRefs()) > 0) {
			RefCount -= 1
			NumPut(RefCount, pInterface+0, A_PtrSize, "UInt")
		}
		OutputDebug("{:-30.30s} pInt={:x}, RefCount={} ({})", A_ThisFunc "()", pInterface, RefCount, this.__Class)
		return RefCount
	}

	GetRefs() {
		return NumGet(this.pInterface+0, A_PtrSize, "UInt")
	}

	__Delete() {
		if ( (RefCount := this.GetRefs()) != 1)
			OutputDebug("WARNING: RefCount={} in {}, should be 1 (our own reference)", RefCount, A_ThisFunc "()")
		; OutputDebug("{} - RefCount={}", A_ThisFunc "()", RefCount)
		base.__Delete()
	}
}

/**
 *	UIAutomationEventHandlerImpl
 *		- Top Level Interface Implementation
 *		- Should have vTable and vtoMap declare as static
 *		- Sub-classes are user-level implementations and should just override
 *			HandleAutomationEvent verbatim.
 */
class UIAutomationEventHandlerImpl extends UnknownImpl {

	; Declare the functions our class is implementing, this should not be over-ridden by userland classes
	; 	This array should be complete for the interface and in the correct vTable order per the Type Library
	ComFunctions := ["QueryInterface", "AddRef", "Release", "HandleAutomationEvent"]

	__New() {
		; Add the GUID of the interface this class is implementing
		this.ImplementsInterfaces.InsertAt(1, "{146C3C17-F12E-4E22-8C27-F894B9B79C69}")		; IUIAutomationEventHandler
		base.__New()
	}

	;
	; 	Handles a Microsoft UI Automation event.
	;		@see: https://msdn.microsoft.com/en-us/library/windows/desktop/ee696045(v=vs.85).aspx
	;
	;	IUIAutomationEventHandler 	pInterface	Pointer to our interface address
	;	IUIAutomationElement		pSender		Pointer to Element for which Event happened
	;	EVENTID 					EventID 	The event identifier.
	;		@see: https://msdn.microsoft.com/en-us/library/windows/desktop/ee671223(v=vs.85).aspx
	;
	_HandleAutomationEvent(pInterface, pSender, EventID) {
		if (!IsObject(this))
			return ComObjImpl.ObjMap[this]._HandleAutomationEvent(this, pInterface, pSender)

		OutputDebug("{:-30.30s} pInt={:X}, pSender={:X} EventID={}, (Class={})", A_ThisFunc "()", pInterface, pSender, EventID, this.__Class)
		this.HandleAutomationEvent(pInterface, pSender, EventID)
	}
}

class UIA_SnoopWindowsDestroyed extends UIAutomationEventHandlerImpl {
	;
	; 	Handles a Microsoft UI Automation event, called by the parent class which received the
	;		event call.
	;	@see: https://msdn.microsoft.com/en-us/library/windows/desktop/ee696045(v=vs.85).aspx
	;
	;	IUIAutomationEventHandler 	pInterface	Pointer to our interface address
	;	IUIAutomationElement		pSender		Pointer to Element for which Event happened
	;	EVENTID 					EventID 	The event identifier.
	;		@see: https://msdn.microsoft.com/en-us/library/windows/desktop/ee671223(v=vs.85).aspx
	;
	HandleAutomationEvent(pInterface, pSender, EventID) {
		OutputDebug(A_ThisFunc)
		Sender := new IUIAutomationElement(pSender)
		hWnd := Sender.CurrentNativeWindowHandle
		WinGet, sProcess, ProcessName, ahk_id %hWnd%
		OutputDebug("Window Destroyed - hwnd={:X}, CurrentName={:20.20s}, Class={:20.20s}, Process={:s}", hWnd, Sender.CurrentName, Sender.CurrentClassName, sProcess)
	}
}

class UIA_SnoopWindowsCreated extends UIAutomationEventHandlerImpl {
	;
	; 	Handles a Microsoft UI Automation event, called by the parent class which received the
	;		event call.
	;	@see: https://msdn.microsoft.com/en-us/library/windows/desktop/ee696045(v=vs.85).aspx
	;
	;	IUIAutomationEventHandler 	pInterface	Pointer to our interface address
	;	IUIAutomationElement		pSender		Pointer to Element for which Event happened
	;	EVENTID 					EventID 	The event identifier.
	;		@see: https://msdn.microsoft.com/en-us/library/windows/desktop/ee671223(v=vs.85).aspx
	;
	HandleAutomationEvent(pInterface, pSender, EventID) {
		Sender := new IUIAutomationElement(pSender)
		hWnd := Sender.CurrentNativeWindowHandle
		WinGet, sProcess, ProcessName, ahk_id %hWnd%
		OutputDebug("Window Created - hwnd={:X}, CurrentName={:20.20s}, Class={:20.20s}, Process={:s}", hWnd, Sender.CurrentName, Sender.CurrentClassName, sProcess)
	}
}

global OnDestroyed := ; new UIA_SnoopWindowsDestroyed()
; OutputDebug("-----------------------------------------------------------------------------------")
global OnCreated := new UIA_SnoopWindowsCreated()
; OutputDebug("-----------------------------------------------------------------------------------")
For the most part, you can ignore commented out code, it is/was something I am/was playing with.
User avatar
king-of-hearts
Posts: 30
Joined: 01 Oct 2017, 06:29

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

21 Oct 2017, 07:19

Fantastic!! Great work!
https://autohotkey.com/boards/viewtopic.php?f=6&t=38707 - MS Access Manager - SQL Query: Incredible tool for MS Access/SQL Queries on the fly!!
cpriest
Posts: 20
Joined: 17 Sep 2017, 08:06

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

01 Nov 2017, 20:23

@elgin, sorry been super busy the last couple of weeks, probably for a while going forward but will circle back to this when I can. Have you found any other gotchas I missed?
Elgin
Posts: 124
Joined: 30 Sep 2013, 09:19

Re: TypeLib2AHK - Convert COM Type libraries to AHK code

03 Nov 2017, 09:34

@cpriest: haven't had time to really look into it. It's very busy here. Your full code works for me at least with multiple events but a quick text compare between your and my code showed no clear differences... It'll be at least another one or two weeks until I have time to try things out further.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: comvox, gwarble, TOTAL and 130 guests