Delphi - Win7窗口焦点问题

时间:2011-05-04 00:51:32

标签: delphi windows-7 focus

我通过CreateProcess()执行exe文件,并通过SetForegroundWindow()设置前台进程。 但它在Win7中不起作用,所以我必须单击任务栏中的图标。

如何实现我想要的行为(即Launch和BringToForeground)?

3 个答案:

答案 0 :(得分:8)

你甚至不应该尝试这样做。 SetForegroundWindow中的更改是故意的 - 它可以防止应用程序从用户想要关注的内容中窃取焦点。请参阅上面链接的备注部分。

Win7可能不会让非管理用户更改所需的注册表设置,更不用说重新启动系统了。

您应该使用FlashWindow来引起用户的注意,正如Microsoft建议的那样。任何坚持将注意力从我选择的东西上移开的应用程序都将立即卸载。

答案 1 :(得分:3)

我打算在一段代码中发布一个链接(在评论中),我曾经不得不申请解决我自己的问题。这个链接现在已经破了,所以我在这里发布了它的代码值(它已在Windows XP Pro SP2和Windows Server 2003中测试过,但不在Windows 7中) :

function ForceForegroundWindow(hwnd: THandle): boolean;
{
found here:
http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=borland.public.delphi.rtl.win32&messageid=501_3f8aac4b@newsgroups.borland.com
}
const
  SPI_GETFOREGROUNDLOCKTIMEOUT = $2000;
  SPI_SETFOREGROUNDLOCKTIMEOUT = $2001;
var
  ForegroundThreadID: DWORD;
  ThisThreadID: DWORD;
  timeout: DWORD;
begin
  if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE);
  if GetForegroundWindow = hwnd then Result := true
  else begin
    // Windows 98/2000 doesn't want to foreground a window when some other
    // window has keyboard focus

    if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4)) or
       ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and ((Win32MajorVersion > 4) or
                                                          ((Win32MajorVersion = 4) and (Win32MinorVersion > 0)))) then begin
      // Code from Karl E. Peterson, www.mvps.org/vb/sample.htm
      // Converted to Delphi by Ray Lischner
      // Published in The Delphi Magazine 55, page 16

      Result := false;
      ForegroundThreadID := GetWindowThreadProcessID(GetForegroundWindow,nil);
      ThisThreadID := GetWindowThreadPRocessId(hwnd,nil);
      if AttachThreadInput(ThisThreadID, ForegroundThreadID, true) then
      begin
        BringWindowToTop(hwnd); // IE 5.5 related hack
        SetForegroundWindow(hwnd);
        AttachThreadInput(ThisThreadID, ForegroundThreadID, false);  // bingo
        Result := (GetForegroundWindow = hwnd);
      end;
      if not Result then begin
        // Code by Daniel P. Stasinski

        SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @timeout, 0);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0), SPIF_SENDCHANGE);
        BringWindowToTop(hwnd); // IE 5.5 related hack
        SetForegroundWindow(hWnd);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(timeout), SPIF_SENDCHANGE);
      end;
    end
    else begin
      BringWindowToTop(hwnd); // IE 5.5 related hack
      SetForegroundWindow(hwnd);
    end;

    Result := (GetForegroundWindow = hwnd);
  end;
end; { ForceForegroundWindow }

end.

除了一个小小的评论“宾果游戏”之外,我没有添加任何功能,这标志着实际产生预期效果的线条。

所以你们不认为我滥用了这个功能的用户体验,这里有一些解释。

此功能用于在用户平板电脑上设置的Citrix软件远程调用的应用程序,并且应用程序全屏运行。典型的工作会话几乎完全由该应用程序组成(其他部分只是用户从未与之交互过的系统组件)。

现在我们的应用程序的某些部分必须作为单独的小应用程序实现,并且它们被设计为在关闭之前保持在所有其他窗口之上,就像模态窗口一样。有一段时间他们曾经失去他们的Z顺序并隐藏在主应用程序的主窗口下,这对用户来说是一场灾难。使用“最顶层”属性不是一个选项,所以我们必须找到一种方法来维持他们的Z阶位置。所以我们使用了这个功能。

答案 2 :(得分:0)

ForceForegroundWindow在Win10中为我工作。但是,它不会激活外部程序。它只会让它显而易见。该程序在调用自身时也只是这样做。我假设如果它被激活它也会适当地为用户设置焦点。

瑞克

我找到了激活和设置焦点的解决方案......在“SetAppRestore”过程中,我使用“MainFrm.visible:= false”启动它。然后它转到SwitchApp,它调用ForceForegroundWindow。在它返回“SetAppRestore”后,我插入了“MainFrm.visible:= true”。这会触发应用程序变为活动状态并专注于已定义的组件:DataPge.SetFocus。

我很抱歉没有将代码放在代码块中。我无法理解说明。所以我把它全部放在2 =====条之间。

// ==========================

function TMainFrm.FindWindowExtd(partialTitle: string): HWND;  // get with wildcard
var                                   // by Dorin Duminica, September 10, 2009
  hWndTemp: hWnd;
  iLenText: Integer;
  cTitletemp: array [0..254] of Char;
  sTitleTemp: string;
begin
  hWndTemp := FindWindow(nil, nil);
  while hWndTemp <> 0 do
    begin
    iLenText := GetWindowText(hWndTemp, cTitletemp, 255);
    sTitleTemp := cTitletemp;
    sTitleTemp := UpperCase(copy( sTitleTemp, 1, iLenText));
    partialTitle := UpperCase(partialTitle);
    if pos(partialTitle, sTitleTemp) <> 0 then Break;
    hWndTemp := GetWindow(hWndTemp, GW_HWNDNEXT);
    end;
  result := hWndTemp;
end;

function ForceForegroundWindow(hwnd: THandle): boolean;
const
  SPI_GETFOREGROUNDLOCKTIMEOUT = $2000;
  SPI_SETFOREGROUNDLOCKTIMEOUT = $2001;
var
  ForegroundThreadID: DWORD;
  ThisThreadID: DWORD;
  timeout: DWORD;
begin
  if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE);
  if GetForegroundWindow = hwnd
     then Result:= true
     else begin
          // Windows 98/2000 doesn't want to foreground a window when some other
          // window has keyboard focus
          if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4)) or
             ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and ((Win32MajorVersion > 4) or
             ((Win32MajorVersion = 4) and (Win32MinorVersion > 0)))) then
               begin
               // Code from Karl E. Peterson, www.mvps.org/vb/sample.htm
               // Converted to Delphi by Ray Lischner
               // Published in The Delphi Magazine 55, page 16
               Result:= false;
               ForegroundThreadID:= GetWindowThreadProcessID(GetForegroundWindow,nil);
               ThisThreadID:= GetWindowThreadPRocessId(hwnd,nil);
               if AttachThreadInput(ThisThreadID, ForegroundThreadID, true) then
                  begin
                  BringWindowToTop(hwnd); // IE 5.5 related hack
                  SetForegroundWindow(hwnd);
                  AttachThreadInput(ThisThreadID, ForegroundThreadID, false);  // bingo
                  Result:= (GetForegroundWindow = hwnd);
                  //showmessage('case 1');
                  end;
               if not Result then
                  begin
                  // Code by Daniel P. Stasinski
                  SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @timeout, 0);
                  SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0), SPIF_SENDCHANGE);
                  BringWindowToTop(hwnd); // IE 5.5 related hack
                  SetForegroundWindow(hWnd);
                  SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(timeout), SPIF_SENDCHANGE);
                  //showmessage('case 2');
                  end;
               end
               else begin
                    BringWindowToTop(hwnd); // IE 5.5 related hack
                    SetForegroundWindow(hwnd);
                    //showmessage('case 3');
                    end;
          Result:= (GetForegroundWindow = hwnd);
          end;
end; { ForceForegroundWindow }

procedure TMainFrm.SwitchApp(AppCaption:string); // application.restore;
          begin
          //TmpAppHandle:= FindWindow(nil, PChar(AppCaption)); // uses Windows unit - must be entire caption
          TmpAppHandle:= FindWindowExtd(AppCaption);   //  finds 'notepad' as partial of 'Document - Notepad'
          if (TmpAppHandle<>0)
             then begin
                  //SetForegroundWindow(TmpAppHandle); // worked by itself for WinXP and Win7
                  ForceForegroundWindow(TmpAppHandle);
                  end
             else ShowAlert(AppCaption+' *not found*');
          end;

// application.restore can't restore from MainForm.windowstate:=wsMinimized
// SetAppMinimize and SetAppRestore fix that issue and manual minimizations
procedure TMainFrm.SetAppMinimize; // application.minimize
          begin
          if not(MainFrm.WindowState=wsMinimized) then
             begin
             MainFrm.WindowState:= wsMinimized;
             end;
          SwitchApp(ServerName); // autocad or bricscad
          end;

procedure TMainFrm.SetAppRestore; // application.restore
          begin
          MainFrm.visible:= false;  // ** to reinsate and focus in win10 **
          if (MainFrm.WindowState=wsMinimized) then
             begin
             MainFrm.WindowState:= wsNormal;
             end;
          SwitchApp('CmdData');  // partial string for app title
          MainFrm.visible:= true;   // ** to reinsate and focus in win10 **
          FormatGrid; // added for activex crash
          DataPge.SetFocus;
          Update;
          end;

// ==========================