I have a little routine that I use to test ret vals of calls to Windows APIs:
TestRetVal proc ; this proc for calls to APIs that return zero for failure
test eax, eax ; TRV does not call ExitProcess, it just shows the error
jne @F
cmp MbTrvShow, eax ; eax is zero, so is MbTrvShow at prog start
jne @F
INT 3
nop
mov MbTrvShow, eax ; prevent multiple boxes
pushad
xor ebx, ebx ; NULL
mov esi, offset MbGpBuffer
invoke GetLastError
invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM,
ebx, ; GetItFromSystem
eax, ; ErrNum
ebx, ; Default language
esi, ; where to send the string from system
sizeof MbGpBuffer, ebx ; size, no arguments
invoke MessageBox, ebx, esi, ebx, MB_OKCANCEL
sub eax, IDOK
mov MbTrvShow, eax ; IDOK=keep showing
popad
nop
nop
@@:
ret
TestRetVal endp
It works fine, most of the time. But now I have a zero retval after a straightforward
invoke SendMessage, hSetWin, WM_SETTEXT, 0, edi
... and what happens is that the routine gets called, performs fine, the MessageBox shows but instead of continuing at sub eax, IDOK, the next instruction is the mov MbTrvShow, eax under INT 3.
On further investigation, it is (Win XP SP3) the call 7E3A757B here that misbehaves:
7E3A49B9 ³. 56 push esi ; ÚArg4
7E3A49BA ³. FF75 FC push dword ptr [ebp-4] ; ³Arg3
7E3A49BD ³. 57 push edi ; ³Arg2
7E3A49BE ³. 50 push eax ; ³Arg1
7E3A49BF ³. E8 B72B0000 call 7E3A757B ; ÀUSER32.7E3A757B
7E3A49C4 ³> 5F pop edi
7E3A49C5 ³. 5E pop esi
7E3A49C6 ³. 5B pop ebx
7E3A49C7 ³. C9 leave
7E3A49C8 À. C2 1800 retn 18
Most probably, that is by design ::) - does anybody have an idea why that can happen?
EDIT: I found the primary bug: A WM_TIMER message happening while the MsgBox was displayed. Which still does not explain why a WM_SETTEXT message returns zero with GetLastError = success. It happens only when the static control has the SS_ETCHEDFRAME style set.
You might find a clue here: The Secret Life of GetWindowText, Raymond Chen (http://blogs.msdn.com/b/oldnewthing/archive/2003/08/21/54675.aspx)
Quote from: baltoro on March 13, 2012, 07:23:33 PM
You might find a clue here: The Secret Life of GetWindowText, Raymond Chen (http://blogs.msdn.com/b/oldnewthing/archive/2003/08/21/54675.aspx)
Thanks, baltoro, the article is nice but doesn't give a clue why static controls don't like their own SS_ETCHEDFRAME style. Well, the simplest workaround is not to use that style :bg
What the article also doesn't say is that if you use WM_GETTEXT with SendMessageTimeout (MasmBasic technique for Let My$=Win$(handle), works fine even with children owned by other parents :bg) on apps that run under NTVDM.exe, the 16-bit app will spit into your face, merciless. Nasty, but I am close to having a nice workaround. Ever wondered how to find if a window belongs to 16-bit app? No API, no documentation, no help from Google.
Quote from: jj2007 on March 13, 2012, 08:02:24 PMEver wondered how to find if a window belongs to 16-bit app? No API, no documentation, no help from Google.
Maybe you can use VDMEnumProcessWOW (http://msdn.microsoft.com/en-us/library/bb963830(v=vs.85).aspx) to get all 16Bit host processes and then compare their IDs with the one returned by GetWindowThreadProcessId().
Quote from: qWord on March 13, 2012, 08:39:51 PM
Quote from: jj2007 on March 13, 2012, 08:02:24 PMEver wondered how to find if a window belongs to 16-bit app? No API, no documentation, no help from Google.
Maybe you can use VDMEnumProcessWOW (http://msdn.microsoft.com/en-us/library/bb963830(v=vs.85).aspx) to get all 16Bit host processes and then compare their IDs with the one returned by GetWindowThreadProcessId().
Wow, interesting, thanks :U (pun intented :bg)
It's a bit of an overkill. For practical purposes, GetWindowThreadProcessId does the job: If the ID equals the one of the hidden WOWExec window, it's a 16-bit Windows task, and no access to child windows allowed. The next edition of MB will feature a little macro:
.if App16(WinByTitle("All Unread Topics"))
Print "16-bit"
.else
Print "more than 16 bits"
.endif
App16 MACRO caption
ifdifi <caption>, <eax>
mov eax, caption
endif
push ecx ; MasmBasic ABI: preserve ecx ;-)
push eax ; original handle
push eax ; create a slot
invoke GetWindowThreadProcessId, eax, esp
push WinByTitle("WOWExec") ; get a handle and create a slot
invoke GetWindowThreadProcessId, eax, esp
pop edx ; ID Wow
pop ecx ; ID app
cmp ecx, edx
pop eax ; we surely need the handle
pop ecx ; restore a precious register
EXITM <Zero?>
ENDM
VDDRetrieveNtHandle ?
maybe not :P
NTVDM has several functions, though