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
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);
	}
}

Open in new window

LVL 4
StefanKittelAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
Mechanic_KharkovConnect With a Mentor Commented:
Found the same thing. Many windows, but the only process. :-)
I even port it to Delphi to test.

program SizeFFWindow1;
{$APPTYPE Console}
 
uses
	SysUtils,
	Windows;
 
var m_Window: HWND;
 
function EnumWindowsProc(Wnd:HWND; lParam:LPARAM): boolean;
var processID: DWORD;
begin
	Result := true;
	processID := 1;
	GetWindowThreadProcessId(Wnd, @processID);
 
	writeln('PID = '+Inttohex(processID,8)+'  Wnd = '+Inttohex(Wnd,8)+
	'   Look for '+Inttohex(lParam,8));
 
	if processId = lParam then
		begin
			m_Window := Wnd;
			Result := false;
			writeln('------ Matched -----');
		end;
end;
 
var
				sProcessInfo: PROCESS_INFORMATION;
				sStartupInfo: STARTUPINFO;
				szCommandLine: PChar;
				dw: DWORD;
begin
			//start ff
				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;
				EnumWindows(@EnumWindowsProc, sProcessInfo.dwProcessId);
 
				if (m_Window <> 0) then
					MoveWindow(m_Window, 100, 100, 800, 600, TRUE);
 
				writeln('Press Enter');
				Readln;
 
end.

Open in new window

0
 
Mechanic_KharkovCommented:
Maybe here?

now
     m_Window = 0;
     EnumWindows(EnumWindowsProc, sProcessInfo.dwProcessId);

seems to be true
      m_Window = EnumWindows(EnumWindowsProc, sProcessInfo.dwProcessId);
 
;-)
0
 
Mechanic_KharkovCommented:
Sorry. It's global variable.
But it must be NOT null before GetWindowThreadProcessId call!
Try this:
    m_Window = 1;
    EnumWindows(EnumWindowsProc, 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.
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
Mechanic_KharkovCommented:
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;
}

Open in new window

0
 
StefanKittelAuthor Commented:
Hello Mechanic_Kharkov,

my code is working fine the way it is.
What MS says means this "::GetWindowThreadProcessId(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
0
 
Mechanic_KharkovCommented:
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?
0
 
StefanKittelAuthor Commented:
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
0
 
Mechanic_KharkovCommented:
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.
0
 
Mechanic_KharkovCommented:
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



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.

Open in new window

0
 
StefanKittelAuthor Commented:
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
0
 
Mechanic_KharkovCommented:
Such interesting problem.. and such simple solution.. :-(

:-) But works. So, let it be!
0
All Courses

From novice to tech pro — start learning today.