StefanKittel
asked on
How to set the position and size for firefox using CreateProcess and MoveWindow (Visual Studio 2008, MFC)
Hello,
I want to start firefox and set the size of the window to a specific value. Say 800x600 for tesing a homepage.
I wrote a small sample that works find with notepad.exe but not firefox.exe.
I used FindWindow the compare processID and it does not match.
Does anyone have an idea?
Stefan
I want to start firefox and set the size of the window to a specific value. Say 800x600 for tesing a homepage.
I wrote a small sample that works find with notepad.exe but not firefox.exe.
I used FindWindow the compare processID and it does not match.
Does anyone have an idea?
Stefan
HWND m_Window;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD processID;
::GetWindowThreadProcessId(hwnd, &processID);
if (processID == lParam)
{
m_Window = hwnd;
return FALSE;
}
return TRUE;
}
void CRunResDlg::OnBnClickedButtonfirefox()
{
PROCESS_INFORMATION sProcessInfo;
STARTUPINFO sStartupInfo;
ZeroMemory(&sStartupInfo,sizeof(STARTUPINFO));
ZeroMemory(&sProcessInfo,sizeof(PROCESS_INFORMATION));
sStartupInfo.cb = sizeof( STARTUPINFO);
// char szCommandLine[260] = {"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"};
char szCommandLine[260] = {"C:\\windows\\notepad.exe"};
CreateProcess(NULL, szCommandLine, 0, 0, 0, CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS, 0, 0, &sStartupInfo, &sProcessInfo);
DWORD dw = WaitForInputIdle((HANDLE)sProcessInfo.hProcess, 10000);
Sleep(2000);
m_Window = 0;
EnumWindows(EnumWindowsProc, sProcessInfo.dwProcessId);
if (m_Window != 0)
{
::MoveWindow(m_Window, 100, 100, 800, 600, TRUE);
}
}
Sorry. It's global variable.
But it must be NOT null before GetWindowThreadProcessId call!
Try this:
m_Window = 1;
EnumWindows(EnumWindowsPro c, sProcessInfo.dwProcessId);
MSDN says:
Syntax
DWORD GetWindowThreadProcessId(
HWND hWnd,
LPDWORD lpdwProcessId
);
Parameters
hWnd [in] Handle to the window.
lpdwProcessId [out] Pointer to a variable that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not.
But it must be NOT null before GetWindowThreadProcessId call!
Try this:
m_Window = 1;
EnumWindows(EnumWindowsPro
MSDN says:
Syntax
DWORD GetWindowThreadProcessId(
HWND hWnd,
LPDWORD lpdwProcessId
);
Parameters
hWnd [in] Handle to the window.
lpdwProcessId [out] Pointer to a variable that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not.
Oops. Not m_Window, but processID :-[
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD processID;
processID = 1; //Here not null
::GetWindowThreadProcessId(hwnd, &processID);
if (processID == lParam)
{
m_Window = hwnd;
return FALSE;
}
return TRUE;
}
ASKER
Hello Mechanic_Kharkov,
my code is working fine the way it is.
What MS says means this "::GetWindowThreadProcessI d(hwnd, NULL)"
My code works fine with notepad.exe but not with firefox.exe. It seems like the main process from ff is not connected to the window. So I need to find the other processes startet by the main process and then search for the window.
Stefan
my code is working fine the way it is.
What MS says means this "::GetWindowThreadProcessI
My code works fine with notepad.exe but not with firefox.exe. It seems like the main process from ff is not connected to the window. So I need to find the other processes startet by the main process and then search for the window.
Stefan
I checked this version. You are wrong in this. FF really works with correct PID attached to it's main window. I used "Spy & Capture utility" to determine this condition is true.
And MS says that
lpdwProcessId [out] Pointer to a variable that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not.
Are they wrong?
Look into Your code, and You will see that Your lpdwProcessId is NOT DEFINED before call to this function. And why it works with notepad - it's possible if data in this variable is not null. We can not guarantee anything, if we don't initialize variable. Just try to set it not null before call, and try again. Is it so hard to implement?
And MS says that
lpdwProcessId [out] Pointer to a variable that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not.
Are they wrong?
Look into Your code, and You will see that Your lpdwProcessId is NOT DEFINED before call to this function. And why it works with notepad - it's possible if data in this variable is not null. We can not guarantee anything, if we don't initialize variable. Just try to set it not null before call, and try again. Is it so hard to implement?
ASKER
Hello,
I found out. During tesing a had a window with ff open to google.
When starting ff a second time, it attaches the new window to the first process. So I could not find it.
Thats the trick.
But I'm not sure how to deal with it.
Stefan
I found out. During tesing a had a window with ff open to google.
When starting ff a second time, it attaches the new window to the first process. So I could not find it.
Thats the trick.
But I'm not sure how to deal with it.
Stefan
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
If the bug located, it's just a time question to solve, nothing mysterious..
E.g. we can enumerate working processes and match executable name.
E.g. we can enumerate working processes and match executable name.
Ready to see some terrible solution? ;-)
It works, finding PID within filename of exe, and then looks for window not just with this PID, but also checks window class name. :-) But we still do not know that we find the last opened window.. Here we can store existing windows list, or hook CreateWindowEx, or..
Too many ways to go. :-) Interested problem, but I need to sleep right now. Sorry.
You can download working exe here.
ftp://mechanic.is-a-geek.com/pub/Garbage/!2kill/SizeFFWindow.zip
It works, finding PID within filename of exe, and then looks for window not just with this PID, but also checks window class name. :-) But we still do not know that we find the last opened window.. Here we can store existing windows list, or hook CreateWindowEx, or..
Too many ways to go. :-) Interested problem, but I need to sleep right now. Sorry.
You can download working exe here.
ftp://mechanic.is-a-geek.com/pub/Garbage/!2kill/SizeFFWindow.zip
program SizeFFWindow1;
{$APPTYPE Console}
uses Windows, Classes, Sysutils, Psapi, tlhelp32;
const FF_WndClass = 'MozillaUIWindowClass';
var m_Window: HWND;
lpclass: PChar;
function EnumWindowsProc(Wnd:HWND; lParam:LPARAM): boolean; stdcall;
var processID: DWORD;
begin
Result := true;
GetWindowThreadProcessId(Wnd, @processID);
writeln('PID = '+Inttohex(processID,8)+' Wnd = '+Inttohex(Wnd,8)+
' Look for PID '+Inttohex(lParam,8));
if processId = lParam then
begin
GetClassName(Wnd,lpclass,Length(FF_WndClass)+1);
writeln('Class *'+lpclass+'*');
if lpclass = FF_WndClass then
begin
m_Window := Wnd;
Result := false;
writeln('------ Matched -----');
end;
end;
end;
procedure CreateWin9xProcessList(List: TstringList);
var
hSnapShot: THandle;
ProcInfo: TProcessEntry32;
begin
if List = nil then Exit;
hSnapShot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapShot <> THandle(-1)) then
begin
ProcInfo.dwSize := SizeOf(ProcInfo);
if (Process32First(hSnapshot, ProcInfo)) then
begin
//List.Add(ProcInfo.szExeFile);
List.AddObject(ProcInfo.szExeFile,TObject(ProcInfo.th32ProcessID));
while (Process32Next(hSnapShot, ProcInfo)) do
//List.Add(ProcInfo.szExeFile);
List.AddObject(ProcInfo.szExeFile,TObject(ProcInfo.th32ProcessID));
end;
CloseHandle(hSnapShot);
end;
end;
procedure CreateWinNTProcessList(List: TstringList);
var
PIDArray: array [0..MAX_PATH - 1] of DWORD;
cb: DWORD;
I: Integer;
ProcCount: Integer;
hMod: HMODULE;
hProcess: THandle;
ModuleName: array [0..300] of Char;
begin
if List = nil then Exit;
EnumProcesses(@PIDArray, SizeOf(PIDArray), cb);
ProcCount := cb div SizeOf(DWORD);
for I := 0 to ProcCount - 1 do
begin
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or
PROCESS_VM_READ,
False,
PIDArray[I]);
if (hProcess <> 0) then
begin
EnumProcessModules(hProcess, @hMod, SizeOf(hMod), cb);
GetModuleFilenameEx(hProcess, hMod, ModuleName, SizeOf(ModuleName));
//List.Add(ModuleName);
List.AddObject(ModuleName,TObject(PIDArray[I]));
CloseHandle(hProcess);
end;
end;
end;
procedure GetProcessList(var List: TstringList);
var
ovi: TOSVersionInfo;
begin
if List = nil then Exit;
ovi.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
GetVersionEx(ovi);
case ovi.dwPlatformId of
VER_PLATFORM_WIN32_WINDOWS: CreateWin9xProcessList(List);
VER_PLATFORM_WIN32_NT: CreateWinNTProcessList(List);
end
end;
function EXE_Running(FileName: string; bFullpath: Boolean; var aPID: integer): Boolean;
var
i: Integer;
MyProcList: TstringList;
begin
MyProcList := TStringList.Create;
try
GetProcessList(MyProcList);
Result := False;
if MyProcList = nil then Exit;
for i := 0 to MyProcList.Count - 1 do
begin
if not bFullpath then
begin
if CompareText(ExtractFileName(MyProcList.Strings[i]), FileName) = 0 then
begin Result := True; aPID := integer(MyProcList.Objects[i]); end
end
else if CompareText(MyProcList.strings[i], FileName) = 0 then
begin Result := True; aPID := integer(MyProcList.Objects[i]); end;
if Result then Break;
end;
finally
MyProcList.Free;
end;
end;
function GetExePID(const FileName: string): integer;
begin
EXE_Running(FileName, FileName<>ExtractFileName(FileName), Result);
end;
var
sProcessInfo: PROCESS_INFORMATION;
sStartupInfo: STARTUPINFO;
szCommandLine: PChar;
dw: DWORD;
sProcessId: DWORD;
begin
//init structures
lpclass := StrAlloc(Length(FF_WndClass)+1);
ZeroMemory(@sStartupInfo,sizeof(STARTUPINFO));
ZeroMemory(@sProcessInfo,sizeof(PROCESS_INFORMATION));
sStartupInfo.cb := sizeof( STARTUPINFO);
szCommandLine := PChar('H:\Program Files\Mozilla Firefox\firefox.exe');
//char szCommandLine[260] = {"C:\\windows\\notepad.exe"};
CreateProcess(nil, szCommandLine, nil, nil, false, CREATE_NO_WINDOW or
NORMAL_PRIORITY_CLASS, 0, 0, sStartupInfo, sProcessInfo);
dw := WaitForInputIdle(sProcessInfo.hProcess, 10000);
Sleep(2000);
m_Window := 0;
sProcessId := 0;
sProcessId := GetExePID(szCommandLine);
if sProcessId <> 0 then
begin
EnumWindows(@EnumWindowsProc, sProcessId);
if (m_Window <> 0) then
MoveWindow(m_Window, 100, 100, 800, 600, TRUE);
end;
StrDispose(lpclass);
writeln('Press Enter');
Readln;
end.
ASKER
Hello,
because this is a special ff-feature/bug I close this question.
I let the use choose it select process-ID (which works for most programs safe) or current top window (for ff).
Thanks
Stefan
because this is a special ff-feature/bug I close this question.
I let the use choose it select process-ID (which works for most programs safe) or current top window (for ff).
Thanks
Stefan
Such interesting problem.. and such simple solution.. :-(
:-) But works. So, let it be!
:-) But works. So, let it be!
now
m_Window = 0;
EnumWindows(EnumWindowsPro
seems to be true
m_Window = EnumWindows(EnumWindowsPro
;-)