News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Mysteries of Windows

Started by jj2007, March 10, 2012, 09:17:51 PM

Previous topic - Next topic

jj2007

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.

baltoro

Baltoro

jj2007

Quote from: baltoro on March 13, 2012, 07:23:33 PM
You might find a clue here: The Secret Life of GetWindowText, Raymond Chen

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.

qWord

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 to get all 16Bit host processes and then compare their IDs with the one returned by GetWindowThreadProcessId().
FPU in a trice: SmplMath
It's that simple!

jj2007

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 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

dedndave

VDDRetrieveNtHandle ?
maybe not   :P
NTVDM has several functions, though