News:

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

String & String Buffer + Error

Started by Crashish, March 23, 2007, 03:23:57 AM

Previous topic - Next topic

Crashish

Hello,
Having problems with the following code.
I'm simply trying to cycle through the child windows of the desktop and find the one who's window text matches that of the one
I've specified. I needed to have a function that compares 2 strings of a variable length, like the function 'strncmp' in C.
I didn't see any string functions like this in masm. szCmp & szCmpi do not do what I need.

The problem has to do with the second parameter of StrnCmp (ADDR szBuffer ) inside the EnumChildProc. It seems as if it encounters a
zero in the buffer at anytime it craps out and crashes.

If I compare to strings like this below it works fine:

.data
string1 db "New Text Document",0
string2 db "New Text Document",0


...but not:

.data
string1 db "New Text Document",0
szBuffer db 255 dup (0)

nor

.data
string1 db "New Text Document",0
.data?
szBuffer db 255 dup (?)




.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
StrnCmp proto :DWORD,:DWORD,:DWORD          ;// Protos
EnumChildProc proto :DWORD,:DWORD           ;// ...

.data
hTargetWnd dd 0                             ;// Target window handle
ClassName db "SimpleWinClass",0
AppName  db "Our First Window",0

szWindowText db "New Text Document",0       ;// Text of window to find
szBuffer db 255 dup (0)                     ;// Buffer for GetWindowText
                 
szText db "We have a match!",0              ;// Success
szCaption db "TRUE",0                       ;// ...

szText2 db "Window handle not found!",0     ;// Failure
szCaption2 db "FALSE",0                     ;// ...


.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?

.code
start:
invoke GetModuleHandle, NULL
mov    hInstance,eax
invoke GetCommandLine
mov    CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov   wc.cbSize,SIZEOF WNDCLASSEX
mov   wc.style, CS_HREDRAW or CS_VREDRAW
mov   wc.lpfnWndProc, OFFSET WndProc
mov   wc.cbClsExtra,NULL
mov   wc.cbWndExtra,NULL
push  hInstance
pop   wc.hInstance
mov   wc.hbrBackground,COLOR_WINDOW+1
mov   wc.lpszMenuName,NULL
mov   wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov   wc.hIcon,eax
mov   wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov   wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
mov   hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov     eax,msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL

      .ELSEIF uMsg==WM_CREATE
            invoke GetDesktopWindow
            invoke EnumChildWindows, eax, ADDR EnumChildProc, 0
            mov eax, hTargetWnd     
            .if eax != 0            ;// Success
                invoke MessageBox, hWnd, ADDR szText, ADDR szCaption, MB_ICONINFORMATION
            .elseif eax == 0        ;// Failure
                invoke MessageBox, hWnd, ADDR szText2, ADDR szCaption2, MB_ICONINFORMATION
            .endif

             ret       
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp

StrnCmp proc str1:DWORD, str2:DWORD, count:DWORD

   mov esi, str1
   mov edi, str2
   mov ecx, count
   repz cmpsb
   jne strings_not_equal
   strings_are_equal:
   mov eax, -1
   jmp @F
   strings_not_equal:
   mov eax, 0
@@:
   ret

StrnCmp endp

EnumChildProc proc hwnd:DWORD, lParam:DWORD
   
    invoke GetWindowText, hwnd, ADDR szBuffer, 18     ;// length+zero
    invoke StrnCmp, ADDR szWindowText, ADDR szBuffer, 17
.IF eax == -1                ;// If they match
mov eax, hwnd
mov hTargetWnd, eax
mov eax, 0           ;// Stop enumeration
ret
.ELSE
mov eax, 1           ;// Cont enumeration
ret
.ENDIF

EnumChildProc endp

end start



Could someone point out the problem with this.

sinsi

In your StrnCmp procedure you are using ESI and EDI - since the procedure is being called from a callback procedure, Windows
will expect those registers to be the same after the callback. It is usual to preserve EBX,ESI,EDI and EBP if you use them - this also
means that you can be sure these registers will be preserved by Windows in an API call, so you can use them within your procedure
without any push/pop either side of the call. EAX,ECX and EDX will, however, usually be trashed by an API call.
Light travels faster than sound, that's why some people seem bright until you hear them.

Crashish

*Hugs sinsi*

Thanks sinsi, wow it was just staring me in the face. I have another question for you if I may.
Which is better:


StrnCmp proc USES esi edi str1:DWORD, str2:DWORD, count:DWORD

or

StrnCmp proc str1:DWORD, str2:DWORD, count:DWORD
  push esi
  push edi
  ...
  ...
  pop edi
  pop esi
  ret



sinsi

If you use USES, you only need it once - less typing  :bdg
It's personal preference I guess...
Light travels faster than sound, that's why some people seem bright until you hear them.