Jump to content

confused by WinGetTitle


636C65616E
 Share

Recommended Posts

Heyo,

I noticed something a bit weird.

I was playing with Kernel32 and User32, after creating a window and loging the mesages received, I noticed that WinGetTitle (native AutoIt) was sending a (2 !!) WM_NULL msg instead of WM_GETTEXT.

Quote

$hwnd = 0x04680908
call: U32_SetWindowTextA($hwnd,"foo")
[WndProc] hwnd:0x04680908 msg:0x000C
call: WinGetTitle($hwnd)
[WndProc] hwnd:0x04680908 msg:0x0000
[WndProc] hwnd:0x04680908 msg:0x0000
WinGetTitle > title = ""
call: U32_GetWindowTextA($hwnd,$ptr,256)
[WndProc] hwnd:0x04680908 msg:0x000D
GetWindowTextA > title = "foo"

I can provide the code ...

Edited by 636C65616E
Link to comment
Share on other sites

local const $K32_HANDLE = DllOpen('kernel32.dll')
local const $NT_HANDLE  = DllOpen('ntdll.dll')
local const $U32_HANDLE = DllOpen('user32.dll')

func debug($msg)
    ConsoleWrite($msg & @CRLF)
endfunc
func WrapString($str, $wchar = FALSE)
    local $struct, $len = StringLen($str)
    if ($wchar) then
        $struct = DllStructCreate('WCHAR[' & ($len + 1) & ']')
    else
        $struct = DllStructCreate('CHAR[' & ($len + 1) & ']')
    endif
    DllStructSetData($struct, 1, $str)
    return $struct
endfunc


local const $STRUCTSTR_SYSTEM_INFO = ''  & _
    'DWORD dwOemId;'                     & _
    'DWORD dwPageSize;'                  & _
    'PTR   lpMinimumApplicationAddress;' & _
    'PTR   lpMaximumApplicationAddress;' & _
    'DWORD dwActiveProcessorMask;'       & _
    'DWORD dwNumberOfProcessors;'        & _
    'DWORD dwProcessorType;'             & _
    'DWORD dwAllocationGranularity;'     & _
    'WORD  wProcessorLevel;'             & _
    'WORD  wProcessorRevision;'

local const $STRUCTSTR_MSG = '' & _
    'HWND   hwnd;'    & _
    'UINT   message;' & _
    'WPARAM wParam;'  & _
    'LPARAM lParam;'  & _
    'DWORD  time;'    & _
    'LONG   pt_x;'    & _ ;'STRUCT;LONG x;LONG y;ENDSTRUCT pt;' & _
    'LONG   pt_y;'    & _
    'DWORD  lPrivate;'

local const $STRUCTSTR_WNDCLASSEXA = '' & _
    'UINT   cbSize;'        & _
    'UINT   style;'         & _
    'PTR    lpfnWndProc;'   & _
    'INT    cbClsExtra;'    & _
    'INT    cbWndExtra;'    & _
    'HANDLE hInstance;'     & _
    'HANDLE hIcon;'         & _
    'HANDLE hCursor;'       & _
    'HANDLE hbrBackground;' & _
    'PTR    lpszMenuName;'  & _
    'PTR    lpszClassName;' & _
    'HANDLE hIconSm;'

func CheckError($name, $prefix = 'DLLCALL', $error = @ERROR)
    if ($error <> 0) then
        debug('[ERROR:' & $prefix & '] ' & $name & ': ' & $error)
    endif
    SetError($error) ; to maintain the error flag after this call
endfunc

func K32_SetLastError($error)
    DllCall($K32_HANDLE, 'NONE', 'SetLastError', 'DWORD', $error)
    CheckError('K32_SetLastError')
endfunc
func K32_GetLastError()
    local $ret = DllCall($K32_HANDLE, 'DWORD', 'GetLastError')
    CheckError('K32_GetLastError')
    return $ret[0]
endfunc
func K32_OpenProcess($dwDesiredAccess,$bInheritHandle,$dwProcessId)
    K32_SetLastError(0)
    local $ret = DllCall($K32_HANDLE, 'HANDLE', 'OpenProcess', _
        'DWORD', $dwDesiredAccess, _
        'BOOL' , $bInheritHandle, _
        'DWORD', $dwProcessId)
    CheckError('K32_OpenProcess')
    return $ret[0]
endfunc
func K32_CloseHandle($hObject)
    K32_SetLastError(0)
    local $ret = DllCall($K32_HANDLE, 'BOOL', 'CloseHandle', 'HANDLE', $hObject)
    CheckError('K32_CloseHandle')
    return $ret[0]
endfunc

;HWND CreateWindowExA
;  DWORD     dwExStyle,
;  LPCSTR    lpClassName,
;  LPCSTR    lpWindowName,
;  DWORD     dwStyle,
;  int       X,
;  int       Y,
;  int       nWidth,
;  int       nHeight,
;  HWND      hWndParent,
;  HMENU     hMenu,
;  HINSTANCE hInstance,
;  LPVOID    lpParam
func U32_CreateWindowExA($dwExStyle,$lpClassName,$lpWindowName,$dwStyle,$X,$Y,$nWidth,$nHeight,$hWndParent,$hMenu,$hInstance,$lpParam)
    K32_SetLastError(0)
    local $ret = DllCall($U32_HANDLE, 'HWND', 'CreateWindowExA', _
        'DWORD', $dwExStyle, _
        'STR', $lpClassName, _
        'STR', $lpWindowName, _
        'DWORD', $dwStyle, _
        'INT', $X, _
        'INT', $Y, _
        'INT', $nWidth, _
        'INT', $nHeight, _
        'HWND', $hWndParent, _
        'HANDLE', $hMenu, _
        'HANDLE', $hInstance, _
        'PTR', $lpParam)
    CheckError('U32_CreateWindowExA')
    return $ret[0]
endfunc
func U32_DestroyWindow($hWnd)
    K32_SetLastError(0)
    local $ret = DllCall($U32_HANDLE, 'BOOL', 'DestroyWindow', 'HWND', $hWnd)
    CheckError('U32_DestroyWindow')
    return $ret[0]
endfunc
func U32_RegisterClassExA($arg)
    K32_SetLastError(0)
    local $ret = DllCall($U32_HANDLE, 'WORD', 'RegisterClassExA', 'PTR', $arg)
    CheckError('U32_RegisterClassExA')
    return $ret[0]
endfunc
;LRESULT LRESULT DefWindowProcA
;   HWND   hWnd,
;   UINT   Msg,
;   WPARAM wParam,
;   LPARAM lParam
func U32_DefWindowProcA($hWnd,$Msg,$wParam,$lParam)
    local $ret = DllCall($U32_HANDLE, 'LONG_PTR', 'DefWindowProcA', _
        'HWND', $hWnd, _
        'UINT', $Msg, _
        'WPARAM', $wParam, _
        'LPARAM', $lParam)
    CheckError('U32_DefWindowProcA')
    return $ret[0]
endfunc
;int GetWindowTextA
;   HWND  hWnd,
;   LPSTR lpString,
;   int   nMaxCount
func U32_GetWindowTextA($hWnd,$lpString,$nMaxCount)
    K32_SetLastError(0)
    local $ret = DllCall($U32_HANDLE, 'INT', 'GetWindowTextA', _
        'HWND', $hWnd, _
        'PTR', $lpString, _
        'INT', $nMaxCount)
    CheckError('U32_GetWindowTextA')
    return $ret[0]
endfunc
;BOOL SetWindowTextA
;   HWND   hWnd,
;   LPCSTR lpString
func U32_SetWindowTextA($hWnd,$lpString)
    K32_SetLastError(0)
    local $ret = DllCall($U32_HANDLE, 'BOOL', 'SetWindowTextA', _
        'HWND', $hWnd, _
        'STR', $lpString)
    CheckError('U32_SetWindowTextA')
    return $ret[0]
endfunc

global const $INVALID_HANDLE_VALUE = (-1)
global const $NULLPTR = ptr(0)
global const $PROCESS_ALL_ACCESS = 0x1FFFFF
global const $CW_USEDEFAULT = 0x80000000
global const $HWND_MESSAGE = ptr(-3)

; ---------------------------------------------------

;LRESULT CALLBACK WindowProc(
;   _In_ HWND   hwnd,
;   _In_ UINT   uMsg,
;   _In_ WPARAM wParam,
;   _In_ LPARAM lParam
func WndProcFunc($hwnd, $uMsg, $wParam, $lParam)
    debug('[WndProc] hwnd:' & ptr($hwnd) & ' msg:0x' & hex($uMsg,4))
    return U32_DefWindowProcA($hWnd,$uMsg,$wParam,$lParam)
endfunc
local $WndProc = DllCallbackRegister(WndProcFunc, 'LONG_PTR', 'HWND;UINT;WPARAM;LPARAM;')

local $className = 'MyWndMsg'
local $wrappedClassName = WrapString($className)

local $class_struct = DllStructCreate($STRUCTSTR_WNDCLASSEXA)
    $class_struct.cbSize = DllStructGetSize($class_struct)
    $class_struct.style = 0
    $class_struct.lpfnWndProc = DllCallbackGetPtr($WndProc)
    $class_struct.cbClsExtra = 0
    $class_struct.cbWndExtra = 0
    $class_struct.hInstance = null ; $proc
    $class_struct.hIcon = null
    $class_struct.hCursor = null
    $class_struct.hbrBackground = null
    $class_struct.lpszMenuName = null
    $class_struct.lpszClassName = DllStructGetPtr($wrappedClassName)
    $class_struct.hIconSm = null

local $res = U32_RegisterClassExA(DllStructGetPtr($class_struct))
if ($res = 0) then
    debug('U32_RegisterClassExA failed')
    local $err = K32_GetLastError()
    debug('LastError = ' & $err)
endif

debug('call: U32_CreateWindowExA(....)')
local $hwnd = U32_CreateWindowExA(0x0, $className, null, 0x0, $CW_USEDEFAULT, $CW_USEDEFAULT, 0, 0, 0, null, null, null)
if ($hwnd = $NULLPTR) then
    debug('U32_CreateWindowExA failed')
    local $err = K32_GetLastError()
    debug('LastError = ' & $err)
endif
debug('$hwnd = ' & $hwnd)

debug('call: U32_SetWindowTextA($hwnd,"foo")')
local $res = U32_SetWindowTextA($hwnd,'foo')
if ($res = 0) then
    debug('U32_SetWindowTextA failed')
    local $err = K32_GetLastError()
    debug('LastError = ' & $err)
endif

debug('call: WinGetTitle($hwnd)')
local $title = WinGetTitle($hwnd)
debug('WinGetTitle > title = "' & $title & '"')

local $title_struct = DllStructCreate('CHAR[256]')
debug('call: U32_GetWindowTextA($hwnd,$ptr,256)')
local $res = U32_GetWindowTextA($hwnd, DllStructGetPtr($title_struct), 256)
if ($res = 0) then
    debug('U32_GetWindowTextA failed')
    local $err = K32_GetLastError()
    debug('LastError = ' & $err)
endif
local $title = DllStructGetData($title_struct, 1)
debug('GetWindowTextA > title = "' & $title & '"')

here it is :)

Link to comment
Share on other sites

13 minutes ago, argumentum said:

hmmm, changing this local $className = 'AutoIt v3' ; 'MyWndMsg' make it work :huh2:

yep, it works ... tryed with random stuff with spaces and other combinations, and still doesn't work ... im not a Microsoft expert so guess I miss something haha

edit: by changing the class name, you use the autoit class WndProc by overwriting the custom class (as this class already exists), but the DefWindowProc should handle the stuff (and it does for pure MS functions ...)

Edited by 636C65616E
Link to comment
Share on other sites

Works for me on Win7 (without changing any of your code) but fails on Win10.

On Win7 there is that double WM_NULL also, but there is additional messages (WM_GETTEXTLENGTH + WM_GETTEXT).

Whereas in Win10 there are no additional messages...

Link to comment
Share on other sites

... tested _WinAPI_RegisterClassEx() and is basically what you'd like to do. Compare notes between the _WinAPI_RegisterClassEx() example and yours.
( since I'm clueless of all this DLL calling, I may be missing the point. In that case ... let me know )

Yes, WinGetTitle() fails. :(

debug( '! WinGetTitleByList > "' & WinGetTitleByList($hwnd) & '"')
Func WinGetTitleByList($hwnd)
    Local $aWinList = WinList()
    For $n = 1 To UBound($aWinList) -1
        If $hwnd = $aWinList[$n][1] Then
            Return SetError(0, UBound($aWinList) -1, $aWinList[$n][0])
            ConsoleWrite($n & @TAB & $aWinList[$n][1] & @TAB & $aWinList[$n][0] & @CRLF)
        EndIf
    Next
    Return SetError(1, UBound($aWinList) -1, "")
EndFunc

this WinGetTitleByList() works, so, there should be a ticket opened. What say you @Nine

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

I believe there is bug with WinGetTitle under Win10 using parameter $hWnd.  If you replace $hWnd with "foo", it works.  If you use "[CLASS:MyWndMsg]", it works.  If you do a WinList(), it will appear in the list.  I don't see how it cannot be a bug...

Edit : tested on beta still same bug.

Edited by Nine
Link to comment
Share on other sites

Link to comment
Share on other sites

  • 1 month later...

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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...