Jump to content
Sign in to follow this  
Sheri

Get Delphi app's statusbar text?

Recommended Posts

Sheri

I'm new to scripting in AutoIt. I'm not a programmer but am not a complete newbie to script writing.

I'd like to get the text in part 3 of a Delphi app's. The Class Name for a standard Delphi statusbar is TStatusBar. I have the handle to one as $statusbar. I know that if you can be in the same process space it would respond to normal windows statusbar messages.

This doesn't work:

$sbtext = StatusbarGetText ( $statusbar , "", 3 )

It looked like maybe this would work:

$sbtext = _GuiCtrlStatusBar_GetText ($statusbar, 3)

but it generated the following error. Btw, when I look at the referenced file and function, it looks like it DOES have an EndFunc. I have not attempted to figure out how or why this got called, but I assume I would need to do something to allow access to the app's process before _GuiCtrlStatusBar_GetText ($statusbar, 3) would work?

Line 59 (File "C:\Program Files\AutoIt3\Include\Security.au3"):

Func _Security_AdjustTokenPrivileges($hToken, $DisableAll, $pNewState, $BufferLen, $pPrevState = 0, $pRequired = 0)

Error: "Func" statement has no matching "EndFunc".

Thanks,

Sheri

Share this post


Link to post
Share on other sites
Sheri

I did solve this btw, but I did it using process, memory, and dllstruct functions to get around the other process issue. After that just needed a simple SB_GetText SendMessage to the TStatusBar control.

I thought AutoIt would have a simple function for this but apparently the StatusbarGetText function is restricted to a specific class name of msctls_statusbar32 for a statusbar. Autoit's function could probably be enhanced to remove the restriction and let you give the handle to the statusbar whose text you want.

Edited by Sheri

Share this post


Link to post
Share on other sites
Zedna

I did solve this btw, but I did it using process, memory, and dllstruct functions to get around the other process issue. After that just needed a simple SB_GetText SendMessage to the TStatusBar control.

Can you post this script? I'm interested in this solution.

Share this post


Link to post
Share on other sites
Sheri

Can you post this script? I'm interested in this solution.

OK, it took awhile for me to adapt it for more general purpose than what I had done and since I'm new to AutoIt I was fighting syntax errors (which I still don't understand what was causing them ). Plus I don't want to mislead, I got a lot of the "how" from what others did with other scripting tools.

:) This is GeneralStatusBarText.au3:

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.2.12.0
 Author:         Sheri Pierce

 Script Function:
    General Function to get status bar text
    $mainhwnd is handle to the main application window
    $statusbarhwnd is handle to the statusbar control
    $panel is the zero-based part of the status bar whose text is wanted

#ce ----------------------------------------------------------------------------

#Include <Memory.au3>

Func _GetStandardStatusBarText($mainhwnd, $statusbarhwnd, $panel)

    $WM_USER = 0x0400
    $SB_GETTEXTLENGTH = $WM_USER + 3
    $SB_GETTEXT = $WM_USER + 2
    $PROCESS_ALL_ACCESS = 0x1F0FFF
    Local $len = _SendMessage ($statusbarhwnd, $SB_GETTEXTLENGTH, $panel, 0)
    Local $draw = _WinAPI_HiWord($len)
    if ($draw <> 0) Then
        $statusbartext = ""
    Else
        Local $processid = WinGetProcess ( $mainhwnd )
        Local $phan = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, 0, $processid)
        Local $mem = _MemVirtualAllocEx($phan, 0, $len, $MEM_COMMIT, $PAGE_READWRITE)
        Local $retrievemem=DllStructCreate("char buffer[" & $len & "]")
        Local $retrieveptr=DllStructGetPtr ( $retrievemem )
        _SendMessage($statusbarhwnd, $SB_GETTEXT, $panel, $mem)
        Local $iRead
        _WinAPI_ReadProcessMemory ($phan, $mem, $retrieveptr, $len, $iRead)
        _MemVirtualFreeEx ($phan, $mem, $len, $MEM_RELEASE)
        _WinAPI_CloseHandle ($phan)
        Local $sbtext = DllStructGetData ($retrievemem, "buffer" )
        Local $statusbartext = DllStructGetData ($retrievemem, "buffer" )
        $retrievemem = 0
        Return $statusbartext
    EndIf

EndFunc

Here is a sample script to use it. You will press Ctrl+W to see the status bar panel texts of the active window. Strangely some windows have multiple instances of status bar controls. The sample script looks at the first instance only.

#Include "GeneralStatusBarText.au3"

HotKeySet ("^w", "CC")

While 1
    Sleep(100)
WEnd

Func CC()
    Local $WM_USER = 0x0400
    Local $SB_GETPARTS = $WM_USER + 6
    Local $mainhwnd = WinGetHandle("Active")
    Local $statusbarhwnd = ControlGetHandle ($mainhwnd, "", "[REGEXPCLASS:(?i).*StatusBar.*; INSTANCE:1]")
    Local $panelcount = _SendMessage($statusbarhwnd, $SB_GETPARTS, 0, 0)
    Local $statusbartext
    Local $panel
    For $panel = 0 to $panelcount-1
        $statusbartext = $statusbartext & @CRLF & $panel & ": " & _
        _GetStandardStatusBarText($mainhwnd, $statusbarhwnd, $panel)
        Next
    MsgBox("0", "GeneralStatusBarText Demo", WingetTitle($mainhwnd) & @CRLF & $statusbartext)
    Return
EndFunc

Share this post


Link to post
Share on other sites
Zedna

@Sheri

Many thanks for posting your stuff. It works GREAT!!

I just corrected code to work also on WIN9x systems.

As you can see in _MemInit() UDF there are different _MemVirtualAlloc() / _MemVirtualFree() functions on WINXP/ WIN9x systems.

Here is your chaanged UDF:

Func _GetStandardStatusBarText($mainhwnd, $statusbarhwnd, $panel)

;~     $WM_USER = 0x0400
;~     $PROCESS_ALL_ACCESS = 0x1F0FFF
    $SB_GETTEXTLENGTH = $WM_USER + 3
    $SB_GETTEXT = $WM_USER + 2
    Local $len = _SendMessage ($statusbarhwnd, $SB_GETTEXTLENGTH, $panel, 0)
    Local $draw = _WinAPI_HiWord($len)
    if ($draw <> 0) Then
        $statusbartext = ""
    Else
        Local $processid = WinGetProcess ( $mainhwnd )
        Local $phan = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, 0, $processid)
        If @OSTYPE = "WIN32_WINDOWS"  Then
            Local $mem = _MemVirtualAlloc(0, $len, BitOR($MEM_RESERVE, $MEM_COMMIT, $MEM_SHARED), $PAGE_READWRITE)
        Else
            Local $mem = _MemVirtualAllocEx($phan, 0, $len, $MEM_COMMIT, $PAGE_READWRITE)
        EndIf
        Local $retrievemem=DllStructCreate("char buffer[" & $len & "]")
        Local $retrieveptr=DllStructGetPtr ( $retrievemem )
        _SendMessage($statusbarhwnd, $SB_GETTEXT, $panel, $mem)
        Local $iRead
        _WinAPI_ReadProcessMemory ($phan, $mem, $retrieveptr, $len, $iRead)
        If @OSTYPE = "WIN32_WINDOWS"  Then
            _MemVirtualFree ($mem, $len, $MEM_RELEASE)
        Else
            _MemVirtualFreeEx ($phan, $mem, $len, $MEM_RELEASE)
        EndIf
        _WinAPI_CloseHandle ($phan)
        Local $sbtext = DllStructGetData ($retrievemem, "buffer" )
        Local $statusbartext = DllStructGetData ($retrievemem, "buffer" )
        $retrievemem = 0
        Return $statusbartext
    EndIf
EndFunc

Share this post


Link to post
Share on other sites
Siao

I don't think it's any different from what _GuiCtrlStatusBar_GetText does.


"be smart, drink your wine"

Share this post


Link to post
Share on other sites
Zedna

I don't think it's any different from what _GuiCtrlStatusBar_GetText does.

Yeah you are right. He accidentally reinvented the wheel.

I'm courious about that because AutoIt's internal StatusbarGetText() doesn't work in this case but _GUICtrlStatusBar_GetText() works!

Share this post


Link to post
Share on other sites
Sheri

I don't think it's any different from what _GuiCtrlStatusBar_GetText does.

The status bar text I get with that function is truncated/incomplete. Are you sure it is working for you?

Share this post


Link to post
Share on other sites
Zedna

The status bar text I get with that function is truncated/incomplete. Are you sure it is working for you?

It works fine for me (no truncation).

#include <GUIStatusBar.au3>

MsgBox(0,'StatusBar_GetText_All',StatusBar_GetText_All(ControlGetHandle('My title','','TStatusBar1')))

Func StatusBar_GetText_All($statusbarhwnd)
    Local $statusbartext 
    Local $panelcount = _SendMessage($statusbarhwnd, $SB_GETPARTS, 0, 0)
    For $panel = 0 to $panelcount-1
        $statusbartext &= $panel & ": " & _GUICtrlStatusBar_GetText($statusbarhwnd, $panel) & @CRLF
    Next
    Return $statusbartext
EndFunc

Share this post


Link to post
Share on other sites
Sheri

It works fine for me (no truncation).

#include <GUIStatusBar.au3>

MsgBox(0,'StatusBar_GetText_All',StatusBar_GetText_All(ControlGetHandle('My title','','TStatusBar1')))

Func StatusBar_GetText_All($statusbarhwnd)
    Local $statusbartext 
    Local $panelcount = _SendMessage($statusbarhwnd, $SB_GETPARTS, 0, 0)
    For $panel = 0 to $panelcount-1
        $statusbartext &= $panel & ": " & _GUICtrlStatusBar_GetText($statusbarhwnd, $panel) & @CRLF
    Next
    Return $statusbartext
EndFunc

(sorry, reposting cos just learning to use the forum software)

Totally every panel is truncated for me.

Example output of your (Zedna's) scriptlet accessing PSPad:

---------------------------

StatusBar_GetText_All

---------------------------

0: 16 : 28 (

1:

2:

3:

4:

5: T 8

6: Powe

7: D

8: Code page: AN

---------------------------

OK

---------------------------

Share this post


Link to post
Share on other sites
Zedna

I tested it on my WIN98SE with AutoIt 3.2.10.

You probably use Unicode.

Try to run it on AutoIt 3.2.11.xx beta or 3.2.12 where are corrected UDFs also for Unicode.

Func _GUICtrlStatusBar_GetText($hWnd, $iPart)
    If $Debug_SB Then _GUICtrlStatusBar_ValidateClassName($hWnd)
    Local $iBuffer, $pBuffer, $tBuffer, $pMemory, $tMemMap

    $iBuffer = _GUICtrlStatusBar_GetTextLength($hWnd, $iPart)
    If $iBuffer = 0 Then Return ""

    If @AutoItUnicode Then
        $tBuffer = DllStructCreate("wchar Text[" & $iBuffer & "]")
    Else
        $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]")
    EndIf
    $pBuffer = DllStructGetPtr($tBuffer)
    If _WinAPI_InProcess($hWnd, $__ghSBLastWnd) Then
        If @AutoItUnicode Then
            _SendMessage($hWnd, $SB_GETTEXTW, $iPart, $pBuffer, 0, "wparam", "ptr")
        Else
            _SendMessage($hWnd, $SB_GETTEXT, $iPart, $pBuffer, 0, "wparam", "ptr")
        EndIf
    Else
        $pMemory = _MemInit($hWnd, $iBuffer, $tMemMap)
        If @AutoItUnicode Then
            _SendMessage($hWnd, $SB_GETTEXTW, $iPart, $pMemory, 0, "wparam", "ptr")
        Else
            _SendMessage($hWnd, $SB_GETTEXT, $iPart, $pMemory, 0, "wparam", "ptr")
        EndIf
        _MemRead($tMemMap, $pMemory, $pBuffer, $iBuffer)
        _MemFree($tMemMap)
    EndIf
    Return DllStructGetData($tBuffer, "Text")
EndFunc   ;==>_GUICtrlStatusBar_GetText
Edited by Zedna

Share this post


Link to post
Share on other sites
Sheri

I tested it on my WIN98SE.

You probably use Unicode.

Try to run it on AutoIt 3.2.11.xx beta or 3.2.12 where are corrected UDFs also for Unicode.

I'm using AutoIt Release 3.2.12.0 (only version I have).

I get the same truncation even on apps where use of Ansi sendmessage works in an altered version of my function. (so I don't see how it could be a unicode issue.)

I'm on XP SP3.

Share this post


Link to post
Share on other sites
Siao

The status bar text I get with that function is truncated/incomplete. Are you sure it is working for you?

I'm not using it. I just said it does pretty much the same what you did, and is supposed to work. If it doesn't work, then it could be a bug, so write a short example to reproduce the problem and report it to Bug Tracker. The point is not that I think these official UDF packages are the best thing ever and you've just wasted your time rewriting some of it on your own, it's the opposite. They are not perfect, but if the powers that be think that they must be included in standard package, then the only thing left is to improve them.

Now I took a glance at it and do see a problem in current _GUICtrlStatusBar_GetText() which could cause truncation running on Unicode version of AutoIt (because count of chars sized memory buffer is allocated, instead of count*2 for wchar buffer). To fix it, open GuiStatusBar.au3, and in function _GUICtrlStatusBar_GetText, make this change:

If @AutoItUnicode Then
        $tBuffer = DllStructCreate("wchar Text[" & $iBuffer & "]")
        $iBuffer *= 2;adjust buffer size for _MemInit()
    Else
        $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]")
    EndIf
Edited by Siao

"be smart, drink your wine"

Share this post


Link to post
Share on other sites
Zedna

I'm using AutoIt Release 3.2.12.0 (only version I have).

I get the same truncation even on apps where use of Ansi sendmessage works in an altered version of my function. (so I don't see how it could be a unicode issue.)

I'm on XP SP3.

Then try to observe what part of UDF's sources give wrong values.

Func _GUICtrlStatusBar_GetTextFlags($hWnd, $iPart)
    If $Debug_SB Then _GUICtrlStatusBar_ValidateClassName($hWnd)
    If @AutoItUnicode Then
        Return _SendMessage($hWnd, $SB_GETTEXTLENGTHW, $iPart)
    Else
        Return _SendMessage($hWnd, $SB_GETTEXTLENGTH, $iPart)
    EndIf
EndFunc   ;==>_GUICtrlStatusBar_GetTextFlags

Func _GUICtrlStatusBar_GetTextLength($hWnd, $iPart)
    Return _WinAPI_LoWord(_GUICtrlStatusBar_GetTextFlags($hWnd, $iPart))
EndFunc   ;==>_GUICtrlStatusBar_GetTextLength

If _GUICtrlStatusBar_GetTextLength() gives wrong or good values.

Share this post


Link to post
Share on other sites
Zedna

Now I took a glance at it and do see a problem in current _GUICtrlStatusBar_GetText() which could cause truncation running on Unicode version of AutoIt (because count of chars sized memory buffer is allocated, instead of count*2 for wchar buffer). To fix it, open GuiStatusBar.au3, and in function _GUICtrlStatusBar_GetText, make this change:

If @AutoItUnicode Then
        $tBuffer = DllStructCreate("wchar Text[" & $iBuffer & "]")
        $iBuffer *= 2
    Else
        $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]")
    EndIf
Look at my post #12.

This bug (in 3.2.10) was corrected in 3.2.11.xx beta already. He uses 3.2.12 version.

Share this post


Link to post
Share on other sites
Siao

Look at my post #12.

This bug (in 3.2.10) was corrected in 3.2.11.xx beta already. He uses 3.2.12 version.

I don't need to look at your posts.

I use 3.2.12.0 myself, I just tested to see if it's an issue, saw that it is, and offered a fix.


"be smart, drink your wine"

Share this post


Link to post
Share on other sites
Zedna

I don't need to look at your posts.

I use 3.2.12.0 myself, I just tested to see if it's an issue, saw that it is, and offered a fix.

Oh sorry. Now I see the point from your fix code suggestion.

I saw some unicode correction in this UDF in 3.2.11.xx beta but there is still bug as you said.

EDIT: Will you create BUG track ticket for this bug?

Edited by Zedna

Share this post


Link to post
Share on other sites
Sheri

I'm not using it. I just said it does pretty much the same what you did, and is supposed to work. If it doesn't work, then it could be a bug, so write a short example to reproduce the problem and report it to Bug Tracker. The point is not that I think these official UDF packages are the best thing ever and you've just wasted your time rewriting some of it on your own, it's the opposite. They are not perfect, but if the powers that be think that they must be included in standard package, then the only thing left is to improve them.

I didn't rewrite anything that was there. I started from scratch and managed to get results and learn some things on my own. Then Zedna wanted to see how I solved it which is the only reason I formulated it into a function and posted it. I was subsequently surprised to see truncated rather than no result from the _GuiCtrlStatusBar_GetText function. Possibly I was not using a zero-based panel number when I first tried to use that function.

This thread is in the General Help and Support Topic. If you read from the beginning you would know that I'm new and that I found and tried to use the provided functions. I would certainly have been much happier if the provided functions worked out of the box or if someone like yourself had kept me from needing to "waste time".

Now I took a glance at it and do see a problem in current _GUICtrlStatusBar_GetText() which could cause truncation running on Unicode version of AutoIt (because count of chars sized memory buffer is allocated, instead of count*2 for wchar buffer). To fix it, open GuiStatusBar.au3, and in function _GUICtrlStatusBar_GetText, make this change:

If @AutoItUnicode Then
        $tBuffer = DllStructCreate("wchar Text[" & $iBuffer & "]")
        $iBuffer *= 2;adjust buffer size for _MemInit()
    Else
        $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]")
    EndIf
Yes, with that change, _GUICtrlStatusBar_GetText now works for me. If its true that the _Gui functions are intended for use only with Guis made with AutoIt, it would be helpful if StatusbarGetText() also worked.

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  

×