0

I am working on a multiprocess app, where each document is opened in a new process. It behaves like Google Chrome.

Everything is working fine, except this:

When any control in the embedded app is active, the main window (which contains the embedded windows) doesn't receive keystrokes (Such as Ctrl + N, and the like). I understand the fact, that the embedded window runs in a different process, and this is why it doesn't work.

What i need to do:

  • Main window should detect keystrokes pressed in the embedded window
  • If main window has something assigned to the keystroke, the main window should receive the keyboard shortcut instead of the embedded form.

Some important details:

  • I have control over the source code of both processes (It's the same exe, with different behaviors)
  • I'm using actions for keystrokes
  • Update: I use WM_COPYDATA for IPC (Sending a record through)
  • Update: There is only one UI process (aka main window)

The embed code :

This code embeds the other processes' windows into the main UI window. It is called directly by the WM_COPYDATA handler, based on the received values.

procedure TWTextAppFrame.adoptChild(WindowHandle: Cardinal; Container: TWinControl);
var
  WindowStyle : Integer;
  FAppThreadID: Cardinal;
  ts          : TTabSheet;
begin

  /// Set running app window styles.

  WindowStyle := GetWindowLong(WindowHandle, GWL_STYLE);
  WindowStyle := (WindowStyle and not WS_POPUP) or WS_CHILD;

  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

  /// The window will be embedded on a tabsheet
  ts := TTabSheet.Create(Self);
  ts.TabVisible := false;
  ts.PageControl := WindowPages;
  ts.Tag := WindowHandle;

  Winapi.Windows.SetParent(WindowHandle,ts.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
  );

  /// This creates a small object which holds some info about the embedded window
  /// (Document dirty status, embedded window handle, file name, etc. )
  /// The main window uses this to identify an embedded window, and also for tracking the processes
  AddHandleToControlList(WindowHandle,PChar('win'+IntToStr(WindowHandle)), 0, 0, 0, 0, alClient,ts);

  /// Page control holding all the tabsheet
  WindowPages.ActivePage := ts;

  /// activate the embedded window
  SetForegroundWindow(WindowHandle);
end;

This is how the child processes are notifying the main window:

/// Record sent through

TSendData = Packed Record
  sender: Cardinal; /// The handle of the sender window
  s  : WideString;  /// String data
  i  : Integer;  /// Integer data, usually and identifier for a function (defined with constants)
  i2 : Integer; /// Status, or other integer data
  b  : boolean; /// boolean information 
End;

var WData: TSendData;

///...

WData.sender := Self.Handle;
WData.i := WE_SETPARENT;

/// SendCommand is a wrapper function around the WM_COPYDATA sending code
SendCommand(Self.Handle, MainWindow, WData);

What i have so far?

I use WM_COPYDATA for IPC.

No code yet, only an idea, of transmitting a list of the hotkeys to the embedded form, and register them as actions there. When the action is executed in the embedded form, the keystroke would be sent to the main form.

This idea isn't an elegant solution, i would like to know, if there is a better one, and if there is, what would that be.

beerwin
  • 9,813
  • 6
  • 42
  • 57
  • You haven't given any real indication of how all the bits fit together. Yes you have multiple processes. Presumably you have a single UI process. And IPC to the other processes to do the work. – David Heffernan Jan 28 '14 at 22:47
  • @DavidHeffernan: I have updated the question with more relevant information. Please let me know, if anything else is still needed. – beerwin Jan 28 '14 at 23:29
  • You cannot expect good things of SetParent. Find a different solution. – David Heffernan Jan 28 '14 at 23:41
  • http://blogs.msdn.com/b/oldnewthing/archive/2013/04/12/10410454.aspx – David Heffernan Jan 29 '14 at 00:02
  • Well, this only tells that SetParent is problematic in this case. However it offers no alternative solution. A suggestion to where to start and what to look for would be helpful enough for me. I'm wasting time. – beerwin Jan 29 '14 at 00:21

0 Answers0