News:

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

Get Window Handle of Created Process

Started by dedndave, October 26, 2011, 05:26:22 AM

Previous topic - Next topic

dedndave

i found this code on the CodeGuru forum, written by Ovidiu Cucu
it appears that he has a good handle on the subject   :bdg

however, i get a little lost in translating it from C
i was hoping someone in here could help me out.....

HWND StartApplication(LPTSTR pszExeName, LPCTSTR pszWndClass)
{
   HWND hWndMain = NULL;
   STARTUPINFO startupInfo = {0};
   PROCESS_INFORMATION processInfo = {0};

   if(::CreateProcess(NULL, pszExeName,
                      NULL, NULL, FALSE, 0, NULL, NULL,
                      &startupInfo, &processInfo))
   {
      // wait for process initialization
      ::WaitForInputIdle(processInfo.hProcess, 10000);

      // find the main window
      DWORD dwProcessId = 0;
      HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
      while(NULL != hWnd)
      {
         DWORD dwThreadId =
               ::GetWindowThreadProcessId(hWnd, &dwProcessId);
         if((dwThreadId == processInfo.dwThreadId) &&
            (dwProcessId == processInfo.dwProcessId))
         {
            const int nMaxCount = 256;
            TCHAR pszClassName[nMaxCount];
            ::GetClassName(hWnd, pszClassName, nMaxCount);
            if(!_tcsicmp(pszClassName, pszWndClass))
            {
              hWndMain = hWnd;
               break;
            }
         }
         hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
      }
   }


my goal is to get the main window handle for a recently created process
i get the part about WaitForInputIdle   :bg

where i lose it is all the dang braces   :red

this part is particularly confusing
            if(!_tcsicmp(pszClassName, pszWndClass))
            {
              hWndMain = hWnd;
               break;
            }

it appears as though he is comparing the pszClassName string against pszWndClass
pszWndClass is a parameter to the function
where does he come up with that ????   :red

dedndave

well - this function may not work in my specific case, anyways
i am trying to open IE or firefox
the problem is - both of these programs seem to create new windows as you attempt to open new instances
that is, they do not necessarily create new processes (at least, not lasting ones)
older versions of firefox weren't that way

at any rate, what i may have to do is enumerate desktop windows before and after the CreateProcess call
then, pick out the new one   ::)

the problem i am having is that, when i create a new instance of a browser, it does not always come to the foreground
if i can get the window handle, i think BringWindowToTop will do the job
if not, i can always use SetWindowPos, which always seems to work

ToutEnMasm

It is just a code who try to reuse any executable file.
You run it(createprocess),then you get the handles of interest.
Best method to do this , is to create a special hook sending a message when he is ready to work.
I have made a source code (don't read the french comment) on this.
http://www.asmfr.com/codes/REUTILISER-IMPORTE-QUEL-PROGRAMME-EX-WORDPAD_52647.aspx
The technique is very sure and give better results than the one you posted.



qWord

Quote from: dedndave on October 26, 2011, 06:23:19 AMthe problem i am having is that, when i create a new instance of a browser, it does not always come to the foreground
if i can get the window handle, i think BringWindowToTop will do the job
if not, i can always use SetWindowPos, which always seems to work
Well, you can enumerate all top level windows and compare their class name with 'IEFrame' or 'MozillaWindowClass' - this is what the above Cpp-code can do.
However, to be sure, compare also the class style with WS_OVERALAPEDWINDOW.
FPU in a trice: SmplMath
It's that simple!

dedndave

thanks for the tips, guys   :U

i am not too sure about the C code - i can probably figure it out

ToutEnMasm


Quote
I am not too sure about the C code - i can probably figure it out
I agree with that.The Bad method is WaitForInputIdle.To have study the problem,this method work only for the notepad.
The workpad failed because of a synchronisation problem and the enumerate loop find nothing.

dedndave

yah - that won't work for IE or FF anyways
you may create a new instance of the program, but....
it probably disappears quickly as the original instance takes over, creates a new thread, and closes the process you created
the process handle and ID you get from the PROCESS_INFORMATION structure are useless

i am going to play with EnumWindows   :U

dedndave

inside the EnumWindowsProc, i use this code at the beginning (based on qWord's suggestion)...
        INVOKE  GetWindowLong,hWnd,GWL_STYLE
        and     eax,WS_OVERLAPPEDWINDOW or WS_VISIBLE or WS_POPUP or WS_CHILD or WS_MINIMIZE or WS_DISABLED
        cmp     eax,WS_OVERLAPPEDWINDOW or WS_VISIBLE
        jnz     skip_this_one


the window must have all the WS_OVERLAPPEDWINDOW bits set and be visible
the window must not have WS_POPUP, WS_CHILD, WS_MINIMIZE, or WS_DISABLED bits set

that really gets rid of a lot of windows   :P
in some cases, the WS_MINIMIZE bit might be allowed

ToutEnMasm


dedndave

well - my program opens a browser, either IE or FF
both of those programs do some "strange" things
that is, the process you start may or may not run the actual window that opens
so - i want to find the newly created window handle

at any rate - that code can be used for many things
if you enumerate all top level windows and display them, you get all kinds of stuff   :P
by filtering out all the non-overlapped windows, the list is down to the ones you see on the desktop

baltoro

DAVE !!!

Here is the MSDN documentation for the C Runtime function, _tcsicmp: _stricmp, _wcsicmp, _mbsicmp, _stricmp_l, _wcsicmp_l, _mbsicmp_l
:bg The C language people and Microsoft do this to drive assembly programmers crazy,...it's a conspiracy. A common Windows type in the C and C++ language, is the TCHAR. The _tcsicmp function is a simple string comparison function, written to compare TCHARs. The TCHAR is quite simply a single byte ASCII character, unless UNICODE is defined somewhere in the source code, in which case, the TCHAR type is a two-byte Unicode character.
...And the code segment,...
            if(!_tcsicmp(pszClassName, pszWndClass))
            {
              hWndMain = hWnd;
               break;
            }

...Means,...that if the function, _tcsicmp returns FALSE (or, zero), it means that the two strings are equal,...and the following block (enclosed in the curly braces) is executed. The "if" just indicates that the _tcsicmp function is executed conditionally. So, if the two strings are equal, the Window handle, hWnd, value is copied to hWndMain. The Window Handle, hWndMain. is defined as:
   HWND hWndMain = NULL;

The break operator merely terminates the loop that the code is executing within.
That would be, this code block:   
      while(NULL != hWnd)
      {
         DWORD dwThreadId =
               ::GetWindowThreadProcessId(hWnd, &dwProcessId);
         if((dwThreadId == processInfo.dwThreadId) &&
            (dwProcessId == processInfo.dwProcessId))
         {
            const int nMaxCount = 256;
            TCHAR pszClassName[nMaxCount];
            ::GetClassName(hWnd, pszClassName, nMaxCount);
            if(!_tcsicmp(pszClassName, pszWndClass))
            {
              hWndMain = hWnd;
               break;
            }
         }


...In C or C++. the curly braces are used just to enclose a code block. You can use them legally almost anywhere,...but, if you use them in a conditional or comparison statement, the braces indicate the code block to execute,...and, at the closing curly brace, the code execution exits the block to the code immediately following. In assembly language, the equivalent syntax woul be to use an .IF and .ENDIF block.
Baltoro

qWord

include \masm32\include\masm32rt.inc
.code

PHWND typedef ptr HWND
ENUM_INFO struct
    pszCalssName    PCHAR   ?
    phWnd           PHWND   ?
    nWnd            DWORD   ?
ENUM_INFO ends

EnumProc proc uses ebx esi edi hWnd:DWORD,pEnumInfo: ptr ENUM_INFO
LOCAL sz[1024]:CHAR
    .if rv(GetClassName,hWnd,ADDR sz,LENGTHOF sz)
        mov ebx,pEnumInfo
        .if !rv(Cmpi,[ebx].ENUM_INFO.pszCalssName,ADDR sz)
            mov esi,[ebx].ENUM_INFO.nWnd
            mov edi,[ebx].ENUM_INFO.phWnd
            .if !esi
                mov edi,alloc(SIZEOF HWND)
            .else
                mov edi,rv(GlobalReAlloc,edi,ADDR [esi*4+4],GMEM_ZEROINIT or GMEM_MOVEABLE)
            .endif
            m2m HWND ptr [edi+esi*4],hWnd
            lea esi,[esi+1]
            mov [ebx].ENUM_INFO.nWnd,esi
            mov [ebx].ENUM_INFO.phWnd,edi           
        .endif
    .endif
    mov eax,1
    ret
   
EnumProc endp

main proc
LOCAL EnumInfo1:ENUM_INFO
LOCAL sz[1024]:CHAR

   
    mov EnumInfo1.pszCalssName,chr$("IEFrame")
    mov EnumInfo1.phWnd,0
    mov EnumInfo1.nWnd,0
   
    invoke EnumWindows,ADDR EnumProc,ADDR EnumInfo1
   
    mov esi,EnumInfo1.phWnd
    xor edi,edi
    .while edi < EnumInfo1.nWnd
        .if rv(GetClassName,HWND ptr [esi+edi*4],ADDR sz,LENGTHOF sz)
            print "CalssName: "
            print ADDR sz,13,10
            print "Titel: "
            invoke GetWindowText,HWND ptr [esi+edi*4],ADDR sz,LENGTHOF sz
            print ADDR sz,13,10
        .endif
        lea edi,[edi+1]
    .endw
   
    .if EnumInfo1.phWnd
        free EnumInfo1.phWnd
    .endif
   
    inkey
    exit

main endp
end main
FPU in a trice: SmplMath
It's that simple!

dedndave

i was just going to use REPZ CMPSB   :P

baltoro

Actually, the way the C author has written the code is kinda funky.
This is one of those cases where the necessary functionality can be much more reliably done in assembly language.
Baltoro

dedndave

 :bg
qWord's code is much prettier than the C guy's
but, i am inclined not to rely so much on macros
i like to stick my own code in there   :P
and - i have a hard time reading indented code

i am an old-timer - lol
it was hard for me just to break away from using all upper case letters   :lol