【问题标题】:Non-focusable child window不可聚焦的子窗口
【发布时间】:2015-11-25 09:12:17
【问题描述】:

我有一个简单的 VCL 表单,这个表单位于注入的 dll 中。 DLL 注入以使用窗口进行处理。我需要使我的表单不可聚焦,并且始终位于父窗口(注入进程的主窗口)之前。

表单创建:

procedure CreateForm;
var
  hWindow: THandle;
  Rect: TRect;
begin
  if GetProcessWindowHandle(GetCurrentProcessId, hWindow) then begin
    FormButtons := TFormButtons.Create(nil);
    GetWindowRect(hWindow, Rect);
    FormButtons.Left := Rect.Left + 50;
    FormButtons.Top  := Rect.Top;
    FormButtons.ShowModal;
    FormButtons.Free;
  end;
end;

procedure DLLEntryPoint(dwReason: DWORD);
begin
  case dwReason of
    DLL_PROCESS_ATTACH: begin
                          CreateForm;
                        end;
    DLL_PROCESS_DETACH: begin
                        end;
  end;
end;

begin
  DLLProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.

为表单创建参数:

procedure TFormButtons.CreateParams(var Params: TCreateParams);
var
  hWindow: THandle;
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_NOACTIVATE;
  if GetProcessWindowHandle(GetCurrentProcessId, hWindow) then
    Params.WndParent := hWindow;
end;

我有什么:

  1. 使用WS_EX_NOACTIVATE 和不使用Params.WndParent := hWindow,我的窗口(TFormButtons)是不可聚焦的,但这不是主窗口的子窗口,当激活主窗口时,我的窗口会停留在主窗口下。留在顶部是个坏主意,我的窗口应该只在主窗口之前。

  2. 使用WS_EX_NOACTIVATE 和机智Params.WndParent := hWindow 我的子 VCL 窗口具有良好的 z 顺序,这始终位于主窗口之前,但激活我的窗口时主窗口总是失去焦点

    李>
  3. 还有一个问题:如何在没有ShowModal 而使用Show 的情况下显示我的VCL 窗口。没有ShowModal,这是不可见的

【问题讨论】:

    标签: delphi dll-injection


    【解决方案1】:

    可能使用类助手处理表单的 WM_NCHITTEST 消息。

    procedure TFormButtonsHelper.WMNCHitTest(var Msg: TWMNCHitTest);
    begin
        if (Msg.Result <> HTHSCROLL) and (Msg.Result <> HTVSCROLL) then
            Msg.Result := HTCLIENT;
    end;
    

    【讨论】:

    • 这无济于事。即使在单击客户区域后表单也获得焦点
    【解决方案2】:

    终于找到了解决办法。我的表单从未获得焦点,每次都放在主表单上并随主表单移动:

    注入的dll:

    var
      hWndHook: HHOOK = 0;
      hWndMain: THandle = 0;
      ProcessId: DWORD = 0;
      ThreadId: DWORD = 0;
    
    function CallWndProc(Code: Integer; wParam: WPARAM; CWPStruct: PCWPStruct): LRESULT; stdcall;
    var
      Rect: TRect;
    begin
      Result := CallNextHookEx(hWndHook, Code, wParam, LPARAM(CWPStruct));
      if (Code = HC_ACTION) then begin
        case CWPStruct.message of
          WM_MOVE: if hWndMain > 0 then begin
            if Assigned(FormButtons) then begin
              GetWindowRect(hWndMain, Rect);
              SetWindowPos(FormButtons.Handle, HWND_TOPMOST, Rect.Left, Rect.Top - 10, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE);
              SetWindowPos(FormButtons.Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
            end;
          end;
          WM_ACTIVATE: if (hWndMain > 0) then begin
            if Assigned(FormButtons) then begin
              SetWindowPos(FormButtons.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
              SetWindowPos(FormButtons.Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
            end;
          end;
          WM_CLOSE: if (hWndMain > 0) and (hWndMain = CWPStruct.hwnd) then begin
            try
                UnhookWindowsHookEx(hWndHook);
                hWndMain := 0;
            except
              MessageBox(0, 'Error: WM_CLOSE', '', MB_OK);
            end;
          end;
        end;
      end;
    end;
    
    function ThreadProc(Params: Pointer): Integer;
    begin
      Result := 0;
      try
        ProcessId := GetCurrentProcessId;
        if GetProcessWindowHandle(ProcessId, hWndMain) then
          ThreadId := GetWindowThreadProcessId(hWndMain);
    
        if hWndHook = 0 then
          hWndHook := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance, ThreadId);
    //    MessageBox(0, PChar('Hook installed!' + sLineBreak +
    //                        'Process Id: ' + IntToStr(ProcessId) + sLineBreak +
    //                        'Thread Id: ' + IntToStr(ThreadId) + sLineBreak +
    //                        'hWndMain: ' + IntToStr(hWndMain) + sLineBreak +
    //                        'hWndHook: ' + IntToStr(hWndHook)), '', MB_OK);
    
        FormButtons := TFormButtons.Create(nil);
        FormButtons.ShowModal;
    
        Result := 0;
      except
    //    Result := ERROR_GEN_FAILURE;
      end;
    end;
    
    procedure DLLEntryPoint(dwReason: DWORD);
    var
      hThread: THandle;
      ThreadId: UInt32;
    begin
      case dwReason of
        DLL_PROCESS_DETACH: begin
    //                          MessageBox(0, PChar('DLL_PROCESS_DETACH: ' + IntToStr(ProcessId)), '', MB_OK);
                            end;
        DLL_PROCESS_ATTACH: begin
                              hThread := BeginThread(nil, 0, ThreadProc, nil, 0, ThreadId);
                              if hThread <> 0 then
                                CloseHandle(hThread);
    //                          MessageBox(0, PChar('DLL_PROCESS_ATTACH: ' + IntToStr(GetCurrentProcessId)), '', MB_OK);
                            end;
      end;
    end;
    
    begin
      DLLProc := @DLLEntryPoint;
      DLLEntryPoint(DLL_PROCESS_ATTACH);
    end.
    

    为表单创建参数:

    procedure TFormButtons.CreateParams(var Params: TCreateParams);
    var
      hWindow: THandle;
    begin
      inherited CreateParams(Params);
      Params.ExStyle := Params.ExStyle or WS_EX_NOACTIVATE;
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-05
      • 2018-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多