Nine Posted Tuesday at 06:37 PM Posted Tuesday at 06:37 PM (edited) First I must thank @MattyD for showing me how to perform such a task in this thread. I felt I needed to play with it to fully understand the intrinsic. So I ended up making a small UDF that is accomplishing the creation of interface objects and the deletion of those made by the UDF. The example included in the zip file is largely inspired on the example made by the original author of the Media Engine topic. I believe the UDF is quite straightforward to use but, in any cases, post here your questions, I will be glad to answer in the scope of my knowledge. Version 2025-04-16 * Solved an issue with the tag transformation * Code optimization * Added tag validation ObjFromTag UDF.zip Edited Wednesday at 11:20 AM by Nine MattyD and mLipok 2 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
MattyD Posted Wednesday at 06:06 AM Posted Wednesday at 06:06 AM Hey mate - great work! just a suggestion - take or leave it This *should* add a placeholder for methods we don't care about, and don't want to wrap. (probably requires some more testing) expandcollapse popup#include <WinAPIConv.au3> #include <WinAPIConstants.au3> ; #ObjFromTag# ================================================================================================================= ; Name ..........: ObjFromTag UDF.au3 ; Description ...: Create COM interface object based on tag instead of CLSID ; Author ........: Nine ; Created .......: 2020-04-14 ; Modified ......: ; Remark ........: Inspired by MattyD, trancexx ; Links .........: https://www.autoitscript.com/forum/topic/212828-byo-com-object/ ; : https://www.autoitscript.com/forum/topic/153520-iuiautomation-ms-framework-automate-chrome-ff-ie/page/6/#findComment-1143566 ; Example .......: Yes ; =============================================================================================================================== ; #Functions# =================================================================================================================== ; ObjCreateFromTag($sPrefix, $tagInterface, ByRef $tInterface, $sIID = Default, $bIsUnknown = Default) ; _QueryInterface($pSelf, $pRIID, $pObj) ; _AddRef($pSelf) ; _Release($pSelf) ; ObjDeleteFromTag(ByRef $tInterface) ; =============================================================================================================================== Global Const $sIID_IUNKNOWN = "{00000000-0000-0000-C000-000000000046}" Global Const $tagIUNKNOWN = _ "QueryInterface hresult(ptr; ptr*);" & _ "AddRef ulong();" & _ "Release ulong();" Global Const $tagIHEADER = "align 4;ptr pObject;long iRefCnt;char sIID[" & StringLen($sIID_IUNKNOWN) + 1 & "];" Global Const $tagIINTERFACE = $tagIHEADER & "int iSize;ptr pVTable[%i];ptr pCallback[%i];" Global $hQueryInterface = DllCallbackRegister("_QueryInterface", "long", "ptr;ptr;ptr*") Global $hAddRef = DllCallbackRegister("_AddRef", "int", "ptr") Global $hRelease = DllCallbackRegister("_Release", "int", "ptr") Global $hNoMethod = DllCallbackRegister("_NoMthd", "int64", "ptr;int64;int64;int64;int64;int64;int64;int64;int64;int64;int64;int64;int64") Func ObjCreateFromTag($sPrefix, $tagInterface, ByRef $tInterface, $sIID = Default, $bIsUnknown = Default) If $sIID = Default Then $sIID = $sIID_IUNKNOWN If $bIsUnknown = Default Then $bIsUnknown = True Local $sInterface = ($bIsUnknown ? $tagIUNKNOWN : "") & $tagInterface Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($sInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3) Local $iUbound = UBound($aMethods), $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback $tInterface = DllStructCreate(StringFormat($tagIINTERFACE, $iUbound, $iUbound)) For $i = 0 To $iUbound - 1 $aSplit = StringSplit($aMethods[$i], "|", 2) If UBound($aSplit) <> 2 Then ReDim $aSplit[2] $sNamePart = $aSplit[0] $sTagPart = $aSplit[1] $sMethod = $sPrefix & $sNamePart $aTagPart = StringSplit($sTagPart, ";", 2) $sRet = $aTagPart[0] $sParams = StringStripWS("ptr" & StringReplace($sTagPart, $sRet, "", 1), $STR_STRIPALL) $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams) If @error Then ConsoleWrite( $sMethod & "/" & $sRet & "/" & $sParams & " = " & @error & @CRLF) $hCallback = $hNoMethod If $bIsUnknown Then Switch $i Case 0 $hCallback = $hQueryInterface Case 1 $hCallback = $hAddRef Case 2 $hCallback = $hRelease EndSwitch EndIf EndIf DllStructSetData($tInterface, "pVTable", DllCallbackGetPtr($hCallback), $i + 1) DllStructSetData($tInterface, "pCallback", $hCallback, $i + 1) Next $tInterface.iRefCnt = 1 ; start ref at 1 since creation is completed $tInterface.iSize = $iUbound $tInterface.pObject = DllStructGetPtr($tInterface, "pVTable") $tInterface.sIID = $sIID Return ObjCreateInterface(DllStructGetPtr($tInterface), $sIID, $tagInterface, $bIsUnknown) EndFunc ;==>ObjFromTag Func _QueryInterface($pSelf, $pRIID, $pObj) If Not $pObj Then Return $E_POINTER Local $sIID = _WinAPI_StringFromGUID($pRIID) Local $tInter = DllStructCreate($tagIHEADER, $pSelf) If $sIID = $tInter.sIID Or $sIID = $sIID_IUNKNOWN Then DllStructSetData(DllStructCreate("ptr", $pObj), 1, $pSelf) _AddRef($pSelf) Return $S_OK EndIf Return $E_NOINTERFACE EndFunc ;==>_QueryInterface Func _AddRef($pSelf) Local $tInter = DllStructCreate($tagIHEADER, $pSelf) $tInter.iRefCnt += 1 Return $tInter.iRefCnt EndFunc ;==>_AddRef Func _Release($pSelf) Local $tInter = DllStructCreate($tagIHEADER, $pSelf) $tInter.iRefCnt -= 1 Return $tInter.iRefCnt EndFunc ;==>_Release Func _NoMthd($pThis, $vP1, $vP2, $vP3, $vP4, $vP5, $vP6, $vP7, $vP8, $vP9, $vP10, $vP11, $vP12) EndFunc Nine 1
Nine Posted Wednesday at 11:24 AM Author Posted Wednesday at 11:24 AM (edited) @MattyD Thanks. Since we already need to provide a prefixed function for each of the method, we can left its content blank if we do not plan to use it. No reason to call another empty function. Also, if we have unused methods, we can leave their parameters blank, and simply use $pSelf in the callback function as a single parameter. Edited Wednesday at 11:26 AM by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
Solution Nine Posted Wednesday at 11:28 AM Author Solution Posted Wednesday at 11:28 AM New version available. MattyD 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
MattyD Posted Wednesday at 01:34 PM Posted Wednesday at 01:34 PM (edited) 2 hours ago, Nine said: Since we already need to provide a prefixed function for each of the method, Just wanted to clarify, the purpose was to remove the requirement. So if you don't define a function for a particular method, you (or something else) can still call it, but you'll actually be executing _NoMthd() so nothing will happen. But yeah, requiring funcs to be provided is an entirely reasonable position too! Edited Wednesday at 01:48 PM by MattyD
Nine Posted Wednesday at 02:56 PM Author Posted Wednesday at 02:56 PM (edited) Understand. I think I will leave it like that, feel it is less prone to bug if user misspelled by error the method-function. However, I could make it clearer to the user if a method-function does not exist. DllCallbackRegister will return an error but it is not obvious what is the reason. Edited Wednesday at 04:11 PM by Nine MattyD 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now