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
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
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.
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.
thanks for the tips, guys :U
i am not too sure about the C code - i can probably figure it out
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.
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
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
What are you trying to filter ?
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
DAVE !!!
Here is the MSDN documentation for the C Runtime function, _tcsicmp: _stricmp, _wcsicmp, _mbsicmp, _stricmp_l, _wcsicmp_l, _mbsicmp_l (http://msdn.microsoft.com/en-us/library/k59z8dwe(v=vs.80).aspx)
: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.
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
i was just going to use REPZ CMPSB :P
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.
: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
:bg
You will be seeing TCHAR real soon[tm]. :bdg
yes, sadly, i think i have to become more familiar with unicode
it will be interesting to see how it is implemented in the upcoming masm32 version
it will also be interesting to see how WINVER and _WIN32_WINNT are handled :P
...So,...DAVE !!!
...Did you get it to work ???
...And, HUTCH,...
Quote from: HUTCH...You will be seeing TCHAR real soon,...
THANK GOD !!!
well - i have that part written - not tested yet
i was just noticing how much variation there can be in what the GetCommandLine function returns - lol
there are a number of ways to open a process...
;typing at command prompt
;batch file (with/without quotes on command and/or tail)
;shortcut (with/without quotes on command and/or tail)
;explorer double-click
;desktop double-click
;CreateProcess - extending the process string
;CreateProcess - command line tail parameter
;let's not forget - right-click - Open With
there are others - but those are the ones i am primarily concerned with (registry entries, ShellExecute)
you get different tail strings for different methods
most noticably, some methods give you the EXE filename - some do not :'(
sometimes the EXE is a fully qualifed path - sometimes not
seems like MS could have been a little more consistent
i want to pass the command line tail to the browser
Note: I have provided a suggestion in LARGE FONT, for enhanced readability
I ran into this cool blog entry over at Raymond Chen's, The Old New Thing: How Can I Get Notified When Some Other Window Is Destroyed ? (http://blogs.msdn.com/b/oldnewthing/archive/2011/10/26/10230020.aspx).
...And, here,...are a listing of: Event Constants, MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066(v=vs.85).aspx)
This might help you conceptually.
...But, remember,...I'm usually WRONG about stuff like this,... :eek
got it working - very cool
i wrote the EnumWindowsProc callback to be dual-mode
in one mode, it creates a list of matching handles
in the other mode, it looks for a new handle (that is not in already in the list)
so, i call it in the first mode
create the browser process
every 100 ms, i call it to see if a new matching handle appears
if it does, i have my window handle
i time out if it doesn't find it in 8 seconds (too bad - lol)
now, to play with GetCommandLine to see what the "rules" are
it is not at all documented on MSDN
surprisingly, no community content on the subject, either
i guess most of those guys write in C and use the arg() functions
EDIT: nice, baltoro, i can read that no prob
oh no! :eek
thought i had a virus
playing with my program - i ran it - it opened firefox - which opened 2 webpages automatically
www.and.com and www.settings.com
i thought i had one of those re-direction viruses
then, i noticed more closely the names of the sites
little bug in my program
as it turned out, the command line for opening firefox was....
(http://www.masm32.com/board/index.php?action=dlattach;topic=17615.0;id=9889)
oops
(http://www.quickersoft.com/pictures/crackmeup.gif)
having a small problem with CreateProcess
namely, setting the STARTUPINFO.dwFlags STARTF_FORCEOFFFEEDBACK bit does not turn off the hour-glass
has anyone else seen this problem before ?