Attaching a window to another process

I read a few posts here on StackOverflow, but no one worked for me. Here is the code that I use to display the standard calculator window in my form:

procedure TForm1.Button1Click(Sender: TObject); var Tmp: Cardinal; R: TRect; begin CalcWindow := FindWindow(nil, 'Calculator'); if (CalcWindow <> 0) then begin GetWindowThreadProcessID(CalcWindow, CalcProcessID); Tmp := GetWindowLong(CalcWindow, GWL_STYLE); Tmp := (Tmp and not WS_POPUP) or WS_CHILD; SetWindowLong(CalcWindow, GWL_STYLE, Tmp); GetWindowRect(CalcWindow, R); SetForegroundWindow(CalcWindow); Windows.SetParent(CalcWindow, Panel1.Handle); SetWindowPos(CalcWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_FRAMECHANGED); AttachThreadInput(GetCurrentThreadID(), CalcWindow, True); end; end; 

It displays a window in my form, but the glass border is lost and sometimes (especially when I move my form), it is difficult to restore focus to the built-in window (I need to click several times).

What could be the reason for this? Also, do you see any potential problems that I may encounter when using this method?

Thank you for your time.

+4
source share
2 answers

Try this code. I took it from one of my old sources. You will lose the glass frame, but the main menu is visible, and I did not notice any problems when setting the focus back to the built-in application. You must do this using the SetForegroundWindow () API function. Whenever you move your container form, your embedded application loses focus, so you need to call SetForegroundWindow again to restore focus:

 procedure ShowAppEmbedded(WindowHandle: THandle; Container: TWinControl); var WindowStyle : Integer; FAppThreadID: Cardinal; begin /// Set running app window styles. WindowStyle := GetWindowLong(WindowHandle, GWL_STYLE); WindowStyle := WindowStyle - WS_CAPTION - WS_BORDER - WS_OVERLAPPED - WS_THICKFRAME; SetWindowLong(WindowHandle,GWL_STYLE,WindowStyle); /// Attach container app input thread to the running app input thread, so that /// the running app receives user input. FAppThreadID := GetWindowThreadProcessId(WindowHandle, nil); AttachThreadInput(GetCurrentThreadId, FAppThreadID, True); /// Changing parent of the running app to our provided container control Windows.SetParent(WindowHandle,Container.Handle); SendMessage(Container.Handle, WM_UPDATEUISTATE, UIS_INITIALIZE, 0); UpdateWindow(WindowHandle); /// This prevents the parent control to redraw on the area of its child windows (the running app) SetWindowLong(Container.Handle, GWL_STYLE, GetWindowLong(Container.Handle,GWL_STYLE) or WS_CLIPCHILDREN); /// Make the running app to fill all the client area of the container SetWindowPos(WindowHandle,0,0,0,Container.ClientWidth,Container.ClientHeight,SWP_NOZORDER); SetForegroundWindow(WindowHandle); end; 

You can call it like this:

  ShowAppEmbedded(FindWindow(nil, 'Calculator'), Panel1); 
+6
source

For the sake of your sanity and the sanity of the users of your program, I think you better abandon this idea:

I tried to do just that with my own software (a window from a 32-bit application embedded in a 64-bit shell), and it never worked 100%, even using tricks from other answers that you got here.

  • It is very difficult to make it work reliably, there are small minor issues that you will never achieve. If you mess with windows of other applications that are not aware of your manipulations, you usually ask for problems.

  • You are changing the way users expect Windows to behave. This will be confusing and unexpected for them.

+2
source

All Articles