ioa747 Posted September 3, 2025 Posted September 3, 2025 The problem I am facing is I'm running the example 'C:\Program Files (x86)\AutoIt3\Examples\Helpfile\GUICtrlCreateTab.au3' as the target application, and with the main script I'm trying to read the tab names the issue is that the main script runs on X64 and the target on X32 up to Local $hParentWnd = _WinAPI_GetParent($hCtrl) everything goes well, but if I try with _GUICtrlTab_GetItemText($hCtrl, $x) , then the target crashes I took a look in #include <GuiTab.au3> and I realized that it has something to do with the SendMessage and the architectural incompatibility main script #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <GuiTab.au3> If Not WinExists("My GUI Tab") Then Exit Local $hWnd = WinWait("My GUI Tab", "", 1) ConsoleWrite("$hWnd=" & $hWnd & @CRLF) Local $hCtrl = ControlGetHandle($hWnd, "", "SysTabControl321") ConsoleWrite("$hCtrl=" & $hCtrl & @CRLF) Local $hParentWnd = _WinAPI_GetParent($hCtrl) ConsoleWrite("$hParentWnd=" & $hParentWnd & @CRLF) ; Show number of tabs Local $iTabCnt = _GUICtrlTab_GetItemCount($hCtrl) ConsoleWrite("Number of tabs: " & $iTabCnt & @CRLF & @CRLF) Local $sItemText ; With this part the target crashes ;~ For $x = 0 To $iTabCnt - 1 ;~ $sItemText = _GUICtrlTab_GetItemText($hCtrl, $x) ;~ ConsoleWrite($x & ") " & $sItemText & @CRLF) ;~ Next the easy solution I thought of is to make a helper script like a bridge But if there is a way to avoid this, I would like to know Thanks a lot I know that I know nothing
Solution pixelsearch Posted September 3, 2025 Solution Posted September 3, 2025 @ioa747 Hi When you call _GUICtrlTab_GetItemText, then _GUICtrlTab_GetItem is called And _GuiCtrlTab_GetItem had issues as seen on Trac Ticket 3903 and in this post. In the post, @Danyfirex worked on this x86-x64 issue and maybe he could give an advice here if he got time ? Also I notice code in _GUICtrlTab_GetItem has been updated in new release 3.3.17.1 (beta) . Did you check your script with 3.3.17.1 , maybe it's solved with the new release ? Fingers crossed & good luck ioa747, Danyfirex and SOLVE-SMART 2 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
ioa747 Posted September 4, 2025 Author Posted September 4, 2025 (edited) pixelsearch, analytical and comprehensive as always, thank you very much The solution proposed by Danyfirex 🏆, in this particular post is completely functional expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <GuiTab.au3> ;>> Target: C:\Program Files (x86)\AutoIt3\Examples\Helpfile\GUICtrlCreateTab.au3 If Not WinExists("My GUI Tab") Then Exit Local $hWnd = WinWait("My GUI Tab", "", 1) ConsoleWrite("$hWnd=" & $hWnd & @CRLF) Local $hCtrl = ControlGetHandle($hWnd, "", "SysTabControl321") ConsoleWrite("$hCtrl=" & $hCtrl & @CRLF) Local $hParentWnd = _WinAPI_GetParent($hCtrl) ConsoleWrite("$hParentWnd=" & $hParentWnd & @CRLF) ; Show number of tabs Local $iTabCnt = _GUICtrlTab_GetItemCount($hCtrl) ConsoleWrite("Number of tabs: " & $iTabCnt & @CRLF & @CRLF) Local $sItemText, $aItem ; Now is working !! For $x = 0 To $iTabCnt - 1 $aItem = _GUICtrlTab_GetItemEx($hCtrl, $x) $sItemText = $aItem[1] ConsoleWrite("$sItemText=" & $sItemText & @CRLF) Next Func _GUICtrlTab_GetItemEx($hWnd, $iIndex) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) Local $tagTCITEMEx = $tagTCITEM & ";ptr Filler" ; strange the Filler is erased by TCM_GETITEM : MS Bug!!! If Not _WinAPI_InProcess($hWnd, $__g_hGUICtrl_LastWnd) Then ;x86 read remote x64 If (Not @AutoItX64) And (Not _WinAPI_IsWow64Process(DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)[2])) Then $tagTCITEMEx = StringReplace($tagTCITEMEx, "ptr", "INT64") EndIf ;x64 read remote x86 If (@AutoItX64) And (_WinAPI_IsWow64Process(DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)[2])) Then $tagTCITEMEx = StringReplace($tagTCITEMEx, "ptr", "ULONG") EndIf EndIf Local $tItem = DllStructCreate($tagTCITEMEx) DllStructSetData($tItem, "Mask", $TCIF_ALLDATA) DllStructSetData($tItem, "StateMask", BitOR($TCIS_HIGHLIGHTED, $TCIS_BUTTONPRESSED)) Local $tBuffer, $iMsg If _GUICtrlTab_GetUnicodeFormat($hWnd) Then $tBuffer = $__g_tTabBuffer $iMsg = $TCM_GETITEMW Else $tBuffer = $__g_tTabBufferANSI $iMsg = $TCM_GETITEMA EndIf Local $iRet = __GUICtrl_SendMsg($hWnd, $iMsg, $iIndex, $tItem, $tBuffer, True, 4, True) Local $aItem[4] $aItem[0] = DllStructGetData($tItem, "State") $aItem[1] = DllStructGetData($tBuffer, "Text") $aItem[2] = DllStructGetData($tItem, "Image") $aItem[3] = DllStructGetData($tItem, "Param") Return SetError($iRet = 0, 0, $aItem) EndFunc ;==>_GUICtrlTab_GetItem This way, I avoid having to make a helper script like a bridge, I just add the function. Mission accomplished. Thank you very much Edited September 4, 2025 by ioa747 argumentum, pixelsearch and Danyfirex 3 I know that I know nothing
ioa747 Posted Wednesday at 10:34 AM Author Posted Wednesday at 10:34 AM I'm getting back on topic. because I encountered a problem with _GUICtrlTab_GetItemText again this time only in the case x64 Caller -> x64 Target I encountered the problem in scite_overlaytab project and it was about whether scite runs on x64 architecture and my script also on x64, sometimes (not always) my script crashes with AutoIt3 ended. rc:-1073740940 Looking to find what's wrong, I came across _GUICtrlTab_GetItem which internally calls __GUICtrl_TagOutProcess expandcollapse popup; AutoIt Version : 3.3.18.0 ; GuiTab.au3 Func _GUICtrlTab_GetItem($hWnd, $iIndex) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) Local $tagTCITEMEx = $tagTCITEM If IsHWnd($hWnd) And DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)[2] <> @AutoItPID Then ; Not _WinAPI_InProcess __GUICtrl_TagOutProcess($hWnd, $tagTCITEMEx) EndIf Local $tItem = DllStructCreate($tagTCITEMEx) DllStructSetData($tItem, "Mask", $TCIF_ALLDATA) DllStructSetData($tItem, "StateMask", BitOR($TCIS_HIGHLIGHTED, $TCIS_BUTTONPRESSED)) Local $tBuffer, $iMsg If _GUICtrlTab_GetUnicodeFormat($hWnd) Then $tBuffer = $__g_tTabBuffer $iMsg = $TCM_GETITEMW Else $tBuffer = $__g_tTabBufferANSI $iMsg = $TCM_GETITEMA EndIf Local $iRet = __GUICtrl_SendMsg($hWnd, $iMsg, $iIndex, $tItem, $tBuffer, True, 4, True) ; will set "TextMax" Local $aItem[4] $aItem[0] = DllStructGetData($tItem, "State") $aItem[1] = DllStructGetData($tBuffer, "Text") $aItem[2] = DllStructGetData($tItem, "Image") $aItem[3] = DllStructGetData($tItem, "Param") Return SetError($iRet = 0, 0, $aItem) EndFunc ;==>_GUICtrlTab_GetItem ; GuiCtrlInternals.au3 Func __GUICtrl_TagOutProcess($hWnd, ByRef $sTag) Local $bIsWow64 = __GUICtrl_IsWow64Process($hWnd) ;x86 read remote x64 If Not (@AutoItX64 Or $bIsWow64) Then $sTag = StringRegExpReplace($sTag, "(dword_ptr)|(uint_ptr)|(int_ptr)|(ptr)|(lparam)|(wparam)|(hwnd)|(handle)", "UINT64") EndIf ;x64 read remote x86 If @AutoItX64 And $bIsWow64 Then $sTag = StringRegExpReplace($sTag, "(dword_ptr)|(uint_ptr)|(int_ptr)|(ptr)|(lparam)|(wparam)|(hwnd)|(handle)", "UINT") EndIf EndFunc ;==>__GUICtrl_TagOutProcess While the function correctly scales pointers to UINT64 for x64 targets, it completely ignores Structure Alignment/Padding requirements. In case 64-bit script -> 64-bit target, the function does nothing. It leaves $tagTCITEM as is. When an x86 process (or even an x64 process) queries an x64 external control (like SciTE's TabControl) using a structure like TCITEM, the pointer field (pszText) is expected at Offset 16, not Offset 12. In x64 architecture, a 64-bit pointer must be aligned to an 8-byte boundary. Current Logic: uint Mask (4); uint State (4); uint StateMask (4); ptr pszText (8) -> Puts pszText at Offset 12. Windows x64 Requirement: Requires 4 bytes of padding after StateMask to align pszText at Offset 16. Result: _GUICtrlTab_GetItem returns an empty string or garbage because it reads from the wrong memory offset. If I understood what I read correctly, then the __GUICtrl_TagOutProcess should be something like this Func __GUICtrl_TagOutProcess($hWnd, ByRef $sTag) Local $bTargetIsWow64 = __GUICtrl_IsWow64Process($hWnd) Local $bCurrentIs64 = @AutoItX64 ; x64 Caller -> x64 Target (Critical Fix for Padding) If $bCurrentIs64 And (Not $bTargetIsWow64) Then ; If structure starts with 12 bytes of UINTS (TCITEM layout), ; we must inject 4 bytes of padding to align the next pointer to offset 16. If StringInStr($sTag, "uint Mask;uint State;uint StateMask") Then $sTag = StringReplace($sTag, "StateMask;", "StateMask;uint AlignmentPadding;") EndIf EndIf ; x86 Caller -> x64 Target If (Not $bCurrentIs64) And (Not $bTargetIsWow64) Then ; Scale pointers to 64-bit integers $sTag = StringRegExpReplace($sTag, "(?i)(dword_ptr|uint_ptr|int_ptr|ptr|lparam|wparam|hwnd|handle)", "UINT64") ; Apply x64 padding for the 64-bit target process If StringInStr($sTag, "uint Mask;uint State;uint StateMask") Then $sTag = StringReplace($sTag, "StateMask;", "StateMask;uint AlignmentPadding;") EndIf EndIf ; x64 Caller -> x86 Target (WOW64) If $bCurrentIs64 And $bTargetIsWow64 Then ; Scale pointers down to 32-bit integers $sTag = StringRegExpReplace($sTag, "(?i)(dword_ptr|uint_ptr|int_ptr|ptr|lparam|wparam|hwnd|handle)", "UINT") EndIf EndFunc ;==>__GUICtrl_TagOutProcess but since it is beyond the limits of my knowledge I leave it to the experts, I am simply mentioning it in case anyone sees it. I know that I know nothing
Nine Posted Wednesday at 04:54 PM Posted Wednesday at 04:54 PM @ioa747 It doesn't appear to be the structure fault. It is automatically padded for right alignment. I tried digging to find what could cause the crash, but without success. It happens (most of the time) on return from __GUICtrl_SendMsg. My take is a memory allocation issue. Although all informations are correctly gathered within the function, it crashes on return, like memory has been corrupted somewhere. Need to investigate. ps. even padding manually it still get crash. The strange thing is sometimes the script finishes all the way, but crashes on Exit. Really seems to be a memory corruption. ioa747 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
Nine Posted Wednesday at 07:34 PM Posted Wednesday at 07:34 PM Ok, I think I found the bug. It is effectively a memory corruption within __GUICtrl_SendMsg. Need to test it some more, but now I have dinner over friends and I am already late....Tomorrow. ioa747 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
Nine Posted 20 hours ago Posted 20 hours ago (edited) Alright. Tested all four possible architecture combinations and it works correctly now. The elusive bug is that it was writing a few more bytes beyond the end of the $tItem structure causing memory corruption. You need to replace the line in __GUICtrl_SendMsg : If $bRetItem Then _MemRead($tMemMap, $pMemory, $tItem, $iItem) with If $bRetItem Then _MemRead($tMemMap, $pMemory, $tItem, DllStructGetSize($tItem)) Still a bit strange that only x64 vs x64 shows the issue. Ticket. Edited 19 hours ago by Nine WildByDesign and ioa747 1 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