各ドキュメントが新しいプロセスで開かれるマルチプロセス アプリに取り組んでいます。Google Chrome のように動作します。
これを除いて、すべてが正常に機能しています。
埋め込みアプリのいずれかのコントロールがアクティブな場合、メイン ウィンドウ (埋め込みウィンドウを含む) はキーストローク (Ctrl + N など) を受け取りません。埋め込まれたウィンドウが別のプロセスで実行されるという事実を理解しています。これが機能しない理由です。
私は何をする必要がありますか:
- メイン ウィンドウは、埋め込みウィンドウで押されたキーストロークを検出する必要があります
- メイン ウィンドウにキーストロークに何かが割り当てられている場合、メイン ウィンドウは埋め込みフォームではなくキーボード ショートカットを受け取る必要があります。
いくつかの重要な詳細:
- 私は両方のプロセスのソースコードを制御しています(動作が異なる同じexeです)
- キーストロークにアクションを使用しています
- 更新: IPC に WM_COPYDATA を使用します (レコードの送信)
- 更新:UIプロセスは1つだけです(別名メインウィンドウ)
埋め込みコード:
このコードは、他のプロセスのウィンドウをメイン UI ウィンドウに埋め込みます。受け取った値に基づいて、WM_COPYDATA ハンドラによって直接呼び出されます。
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;
これは、子プロセスがメイン ウィンドウに通知する方法です。
/// 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);
私はこれまでに何を持っていますか?
IPC には WM_COPYDATA を使用します。
ホットキーのリストを埋め込みフォームに送信し、そこにアクションとして登録するコードはまだありません。アイデアだけです。アクションが埋め込みフォームで実行されると、キーストロークがメイン フォームに送信されます。
このアイデアはエレガントな解決策ではありません。より良い解決策があれば知りたいです。もしあれば、それは何でしょうか。