Recently, due to the need of the project, some data display pages of the system are developed using web pages. The web page needs to be displayed like a dialog box. When it pops up, it can be placed on top of the first window on the desktop. You can customize each The size of the window. The browser uses the firefox browser packaged by a third-party company, which blocks the address bar and favorites bar, so it looks exactly the same as the dialog box. I happened to be watching the core programming of windows, and I took advantage of this project to practice my hands and become familiar with the windows API.
Use the following interface when creating a firefox process:
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
In the LPPROCESS_INFORMATION structure, there is information about the process being created, but there is no HWND of the window handle. Only through the window handle can the window size, display position and other information be set, and the following functions can be called:
BOOL WINAPI SetWindowPos( _In_ HWND hWnd, _In_opt_ HWND hWndInsertAfter, _In_ int X, _In_ int Y, _In_ int cx, _In_ int cy, _In_ UINT uFlags );
Where uFlags is set to HWND_TOPMOST to ensure that the window is at the front of the Z-Order.
There is processId in the LPPROCESS_INFORMATION structure information. We can use enumwindows to traverse all windows to obtain the window handle HWND by judging whether the two process IDs are equal.
BOOL WINAPI EnumWindows(
_In_ WNDENUMPROC lpEnumFunc,
_In_ LPARAM lParam
);
However, the firefox browser is a single process after the process is created. Even if the subsequent tab page is created using the createprocess method (with its own processId and threadId), it always only displays one in the task manager. Therefore, the above method cannot obtain the handle of the tab page (or new window) created later. But since windows has drawn this page, it must have a handle, so now we need to find a way to get this HWND.
The above enumwindows method is still used here, but the lpEnumFunc method needs to be modified, because the interface is created by me, so I know what the title of each window is. When traversing all windows, use getwindowtext to get the current traversed Title of HWND
int WINAPI GetWindowText( _In_ HWND hWnd, _Out_ LPTSTR lpString, _In_ int nMaxCount );
Use GetWindowThreadProcessId to get the process ID of hwnd:
DWORD WINAPI GetWindowThreadProcessId(
_In_ HWND hWnd,
_Out_opt_ LPDWORD lpdwProcessId
);
Compare whether its title and process number are consistent with firefox's process number and whether the browser title parameter we passed in is consistent, so that the HWND of the corresponding window can be obtained.
Another problem occurred during on-site deployment. There is another manufacturer on site. They also use firefox browser for data display. Of course, it is not our customized version, because we also use the npapi plug-in, so if someone else opens it first Their browser, and then open my browser through my interface, my window interface will indeed open, but it is created by someone else's browser executable, even if I explicitly write myself when using the createprocess method The executable path and configuration file path. The parameters of lpCommandLine are as follows:
-no -profile %profile path -new -tab
I Googled here for a long time, and I concluded that how to enable firefox multi-instance operation. The final conclusion is that this can be done. The parameters of lpCommandLine are as follows:
-no-remote -profile %profile path -new -tab
It is possible to open a new instance of firefox according to the set executable path, but the problem is that when you need to open another page, an error will be reported, because using the "-no-remote" parameter will lock the current configuration file, and my The plugin is in the profile, which means that I need to re-specify a profile path every time I open a new page, and the size of each profile is about 70m.
I can't think of a good solution for now.
to be continued.