Jump to content
Sign in to follow this  
Iczer

GUICtrlTreeView UDF - 64bit script on x86 control

Recommended Posts

Iczer

I have troubles with moving script to 64bit - functions "_GUICtrlTreeView_GetImageIndex()" and "_GUICtrlTreeView_GetText()" stop working without any errors

treeView control belong some x86 application - and x86 script work with it .

What i can do about it? Is it bug in UDF?

#AutoIt3Wrapper_UseX64=Y
#include <GuiTreeView.au3>

Func SubFunction_GetState($hWnd)
    Local $TVShandle, $TVSSelHandle, $TVSCount, $TVSParentHandle, $TVSS, $i, $TVSItemHandle, $TVSItemIcon
    AutoItSetOption("WinTitleMatchMode", 2)
    WinWaitActive($hWnd)
    $TVShandle = ControlGetHandle($hWnd, "", "[NAME:_treeView]")
    $TVSSelHandle = _GUICtrlTreeView_GetSelection($TVShandle)
    ConsoleWrite(@crlf&"$TVSSelHandle = "&$TVSSelHandle&@crlf&"@Error = "&@error&@crlf)

    $TVSCount = _GUICtrlTreeView_GetSiblingCount($TVShandle, $TVSSelHandle)
    ConsoleWrite(@crlf&"$TVSCount = "&$TVSCount&@crlf&"@Error = "&@error&@crlf)

    $TVSParentHandle = _GUICtrlTreeView_GetParentHandle($TVShandle)
    ConsoleWrite(@crlf&"$TVSParentHandle = "&$TVSParentHandle&@crlf&"@Error = "&@error&@crlf)

    Local $TVSS[1] = [0]
    For $i = 0 To $TVSCount-1
        $TVSItemHandle = _GUICtrlTreeView_GetItemByIndex($TVShandle, $TVSParentHandle, $i)
        ConsoleWrite(@crlf&"$TVSItemHandle = "&$TVSItemHandle&@crlf&"@Error = "&@error&@crlf)

        $TVSItemIcon = _GUICtrlTreeView_GetImageIndex($TVShandle, $TVSItemHandle)
        ConsoleWrite("$TVSItemIcon = "&$TVSItemIcon&@crlf&"@Error = "&@error&@crlf)
        ConsoleWrite("_GUICtrlTreeView_GetText = "&_GUICtrlTreeView_GetText($TVShandle, $TVSItemHandle)&@crlf&"@Error = "&@error&@crlf)

        If $TVSItemIcon = 7 Then
            ReDim $TVSS[UBound($TVSS)+1]
            $TVSS[0] += 1
            $TVSS[$TVSS[0]] = $TVSItemHandle
            ConsoleWrite("_GUICtrlTreeView_GetText = !!!"&@crlf)
        EndIf
    Next

EndFunc

x86 script output:

$TVSSelHandle = 0x066F3FD0
@Error = 0

$TVSCount = 40
@Error = 0

$TVSParentHandle = 0x003CBFB8
@Error = 0

$TVSItemHandle = 0x066F3930
@Error = 0
$TVSItemIcon = 5
@Error = 0
_GUICtrlTreeView_GetText = Item01
@Error = 0

x64 script output:

$TVSSelHandle = 0x00000000066F3FD0
@Error = 0

$TVSCount = 40
@Error = 0

$TVSParentHandle = 0x00000000003CBFB8
@Error = 0

$TVSItemHandle = 0x00000000066F3930
@Error = 0
$TVSItemIcon = 0
@Error = 0
_GUICtrlTreeView_GetText = 
@Error = 0

 

Share this post


Link to post
Share on other sites
Iczer

tried to search bug tracker for something similar - found #1816 and #2694

If change in $tagLVITEM "ptr Text" to "uint Text" (i.e. make it 32bit) _GUICtrlListView_GetItemText solve the problem (but not solves the bug).

 but it didn't help...

Also bug #1479 seems relevant

 

Edited by Iczer
addition

Share this post


Link to post
Share on other sites
LarsJ

This is not a bug. You must use a 32 bit AutoIt script to automate a 32 bit application. And you must use a 64 bit AutoIt script to automate a 64 bit application.

If you look at _GUICtrlTreeView_GetText it uses a TVITEMEX structure. On 64 bit this is a 80 byte structure. On 32 bit this is a 60 byte structure.

If your AutoIt script is running 64 bit a 80 byte structure is created. The communication between your script and the application takes place when the _SendMessage command (succeeding "If $fUnicode Then") is executed. $pMemory is a pointer to the structure. But the application running 32 bit expects a 60 byte structure. This means that the _SendMessage command fails and returns False (0).

Perhaps one can say that it is a mistake not to check the return value of the _SendMessage command and set @error in case of an error.

Func _GUICtrlTreeView_GetText($hWnd, $hItem = 0)
  If Not IsHWnd($hItem) Then $hItem = _GUICtrlTreeView_GetItemHandle($hWnd, $hItem)
  If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)

  If $hItem = 0x00000000 Then Return SetError(1, 1, "")

  Local $tTVITEM = DllStructCreate($tagTVITEMEX)
  Local $tText
  Local $fUnicode = _GUICtrlTreeView_GetUnicodeFormat($hWnd)
  If $fUnicode Then
    $tText = DllStructCreate("wchar Buffer[4096]"); create a text 'area' for receiving the text
  Else
    $tText = DllStructCreate("char Buffer[4096]"); create a text 'area' for receiving the text
  EndIf

  DllStructSetData($tTVITEM, "Mask", $TVIF_TEXT)
  DllStructSetData($tTVITEM, "hItem", $hItem)
  DllStructSetData($tTVITEM, "TextMax", 4096)

  If _WinAPI_InProcess($hWnd, $__ghTVLastWnd) Then
    DllStructSetData($tTVITEM, "Text", DllStructGetPtr($tText))
    _SendMessage($hWnd, $TVM_GETITEMW, 0, $tTVITEM, 0, "wparam", "struct*")
  Else
    Local $iItem = DllStructGetSize($tTVITEM)
    Local $tMemMap
    Local $pMemory = _MemInit($hWnd, $iItem + 4096, $tMemMap)
    Local $pText = $pMemory + $iItem
    DllStructSetData($tTVITEM, "Text", $pText)
    _MemWrite($tMemMap, $tTVITEM, $pMemory, $iItem)
    If $fUnicode Then
      _SendMessage($hWnd, $TVM_GETITEMW, 0, $pMemory, 0, "wparam", "ptr")
    Else
      _SendMessage($hWnd, $TVM_GETITEMA, 0, $pMemory, 0, "wparam", "ptr")
    EndIf
    _MemRead($tMemMap, $pText, $tText, 4096)
    _MemFree($tMemMap)
  EndIf

  Return DllStructGetData($tText, "Buffer")
EndFunc   ;==>_GUICtrlTreeView_GetText

 

Edited by LarsJ

Share this post


Link to post
Share on other sites
Iczer

hmm... so, if i change this structure to be 60 byte in both x64 and x86 cases, it should work in Autoit64 for control over x86 applications?

Share this post


Link to post
Share on other sites
LarsJ

How will you do it? On x64 a pointer is 8 byte. On x86 it's 4 byte. How will you store an 8 byte pointer in a 4 byte structure field? This is not just a problem for pointers. This is also a problem for the following data types: hwnd, handle, int_ptr, long_ptr, lresult, lparam, uint_ptr, ulong_ptr, dword_ptr, wparam and struct. You have to add a lot of additional code to handle this. All the additional code will make your script run slow.

When you have implemented all that code, your script will not work if the target application is running 64 bit. The 64 bit application still expects a 80 byte structure.

Have you considered how many functions you need to change in that way? You have to change _GUICtrlTreeView_GetImageIndex, too. How many more functions in the GuiTreeView UDF do you have to change? How many more functions in the other GUI UDFs do you have to change? How many functions in the WinApi and other UDFs do you have to change?

Believe me. It's a bad idea. Instead of messing around with the code in the standard UDFs, it's a much better idea to make sure that your own scripts can run as both 32 and 64 bit programs. And they probably can this by default. If you need to automate a 32 bit target application, run the script as a 32 bit program. If the target application is running 64 bit, run the script as a 64 bit program.

Share this post


Link to post
Share on other sites
Iczer

problem is - i need to automate a 32 bit target application, but my script in peak memory consumption hitting upper limit for x86 and crush - it seems (?) it about 1400...1500 Mb. I wanted to counter that and get some speed by moving to 64 bit. If i have to divide script to 32 and 64bit parts... can i instead call functions from autoit_x86.dll from 64bit script? :sweating:

Share this post


Link to post
Share on other sites
LarsJ

Why does your script use so much memory? There seems to be something wrong. Does the target application also use that much memory? To try to solve the problems by porting your script to 64 bit will just make things worse. You should focus on why your script uses so many resources.

Share this post


Link to post
Share on other sites
Iczer

It's big input files and then fileread uses up to 6x times of filesize and then up to 8...10x times uses regexp, and in the end sqlite give finishing blow to script...

64bit do not have this limit. all i need is 2-3Gb of memory. any way i cannot reduce memory consumption of filesize and regexp...

i'm working on sqlite for now

Share this post


Link to post
Share on other sites
LarsJ

If you run this version of _GUICtrlTreeView_GetText on a 64 bit system, you can get the text of a treeview item in a 32 bit application.

Func _GUICtrlTreeView_GetText32($hWnd, $hItem = 0)
  If Not IsHWnd($hItem) Then $hItem = _GUICtrlTreeView_GetItemHandle($hWnd, $hItem)
  If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)

  If $hItem = 0x00000000 Then Return SetError(1, 1, "")

  ; All 8 byte data types for a 64 bit system changed to 4 byte uint's for a 32 bit system
  Local $tagTVITEMEX32 = "struct; uint Mask;struct; uint hItem;uint State;uint StateMask;uint Text;int TextMax;int Image;int SelectedImage;int Children;uint Param; endstruct;" & _
  "int Integral;uint uStateEx;uint hwnd;int iExpandedImage;int iReserved; endstruct"

  Local $tTVITEM = DllStructCreate($tagTVITEMEX32)
  Local $tText
  Local $fUnicode = _GUICtrlTreeView_GetUnicodeFormat($hWnd)
  If $fUnicode Then
    $tText = DllStructCreate("wchar Buffer[4096]"); create a text 'area' for receiving the text
  Else
    $tText = DllStructCreate("char Buffer[4096]"); create a text 'area' for receiving the text
  EndIf

  DllStructSetData($tTVITEM, "Mask", $TVIF_TEXT)
  DllStructSetData($tTVITEM, "hItem", BitShift( $hItem, -32 )) ; 8 byte value --> 4 byte value
  DllStructSetData($tTVITEM, "TextMax", 4096)

  If _WinAPI_InProcess($hWnd, $__ghTVLastWnd) Then
    DllStructSetData($tTVITEM, "Text", DllStructGetPtr($tText))
    _SendMessage($hWnd, $TVM_GETITEMW, 0, $tTVITEM, 0, "wparam", "struct*")
  Else
    Local $iItem = DllStructGetSize($tTVITEM)
    Local $tMemMap
    Local $pMemory = _MemInit($hWnd, $iItem + 4096, $tMemMap)
    Local $pText = $pMemory + $iItem
    DllStructSetData($tTVITEM, "Text", BitShift( $pText, -32 )) ; 8 byte value --> 4 byte value
    _MemWrite($tMemMap, $tTVITEM, $pMemory, $iItem)
    If $fUnicode Then
      _SendMessage($hWnd, $TVM_GETITEMW, 0, BitShift( $pMemory, -32 ), 0, "wparam", "ptr") ; 8 byte value --> 4 byte value
    Else
      _SendMessage($hWnd, $TVM_GETITEMA, 0, $pMemory, 0, "wparam", "ptr")
    EndIf
    _MemRead($tMemMap, $pText, $tText, 4096)
    _MemFree($tMemMap)
  EndIf

  Return DllStructGetData($tText, "Buffer")
EndFunc

 

Share this post


Link to post
Share on other sites
Iczer

Thanks - 64bit is reachable now :)

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • Tjalve
      By Tjalve
      Hello fellow coders.
      Im currently making a GUI for a webapp. Im using a REST API to get information and display this in a Tree view. Its basically a scheduler of "tasks" and these tasks are great to display in a tree view.
      The problem im having is that on some servers the tree can get rather large. So my GUI is reziable in ordet to be able to fit all the tasks in the view. I have then used GUICtrlSetResizing with diffrent options to get the GUI to look alright even when i resize it. It works fine an all GUI elements, except for the Tree-view. And if i remember correctly, the treeview item is another type of object and you cannot use regular GUI functions on it. Therefor im wondering of there are any alternatives?
       
      #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <GuiTreeView.au3> #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 208, 220, 192, 124,$WS_SIZEBOX) $idTV = _GUICtrlTreeView_Create($Form1, 4, 25, 200, 140) GUICtrlSetResizing(-1,$GUI_DOCKMENUBAR) $Button1 = GUICtrlCreateButton("Button1", 8, 168, 75, 25) GUICtrlSetResizing(-1,$GUI_DOCKSTATEBAR) $Text = GUICtrlCreateLabel("Text", 8, 8, 25, 17) GUICtrlSetResizing(-1,$GUI_DOCKMENUBAR) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd This code is an example of my problem (run it and try to resize the window). If anyone has any ideas i would appreciate it  
×