Delphi - Win7 窗口焦点问题

发布于 2024-11-05 02:19:40 字数 148 浏览 0 评论 0原文

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

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

I execute exe file by CreateProcess() and set foreground process by SetForegroundWindow().
but it doesn't work in Win7 so I have to click icon in taskbar.

How can I implement the behaviour I want (which is to Launch and BringToForeground)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

星光不落少年眉 2024-11-12 02:19:40

你甚至不应该尝试这样做。 SetForegroundWindow 中的更改是有意为之 - 它阻止了应用程序会窃取用户想要获得焦点的焦点。请参阅上面链接的备注部分。

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

您应该只使用 FlashWindow 来获取正如微软建议的那样,引起用户的注意。任何坚持窃取我选择执行的操作焦点的应用程序都将被立即卸载。

You shouldn't even try to do this. The change in SetForegroundWindow was intentional - it prevents applications from stealing the focus from what the user wants to have focus. See the Remarks section of the link above.

Win7 probably won't let non-administrative users change the needed registry setting, much less do it without a restart of the system.

You should just use FlashWindow instead to get the user's attention, as Microsoft recommends. Any application that insists on stealing focus away from what I choose to do will be uninstalled immediately.

过去的过去 2024-11-12 02:19:40

我打算在一段代码中发布一个链接(在评论中),我曾经必须应用该代码来解决我自己的问题。现在该链接已损坏,因此我在这里发布代码以了解其价值(它已在 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.

除了一个小注释“bingo”之外,我没有在函数中添加任何内容,它标记了实际带来所需效果的行。

为了让你们不要认为我在利用这个功能滥用用户体验,这里有一些解释。

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

现在,我们应用程序的某些部分必须作为单独的小应用程序来实现,并且它们被设计为保留在所有其他窗口之上,直到关闭为止,就像模态窗口一样。有时它们会丢失 Z 顺序并隐藏在主应用程序的主窗口下,这对用户来说是一场彻底的灾难。在那里使用“最顶层”属性不是一个选择,因此我们必须找到一种方法来维持它们的 Z 顺序位置。所以我们使用了这个函数。

I was going to post a link (in a comment) to a piece of code that I once had to apply to solve a problem of my own. The link has turned out to be broken now, so I'm posting the code here for what it's worth (it has been tested in Windows XP Pro SP2 and Windows Server 2003, but not in 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.

I didn't add anything to the function apart from a small comment 'bingo', which marks the line which actually brought about the desired effect.

Just so you guys didn't think I was abusing users' experience with this function, here's some explanation.

This function was used in an application that was called remotely with the help of Citrix software set up on users' Tablet PCs, and the application ran in full screen. A typical working session almost entirely consisted of that application (other parts were just system components which user never interacted with).

Now some parts of our application had to be implemented as separate small applications, and they were designed to stay on top of all other windows until closed, just like modal windows. Once in a while they used to lose their Z order and hide under the main application's main window, and that was a total disaster for users. Using the 'top-most' property wasn't an option there, so we had to find a way to sustain their Z-order positions. And so we used this function.

恋竹姑娘 2024-11-12 02:19:40

ForceForegroundWindow 在 Win10 中为我工作。但是,它不会激活外部程序。它只会使其可见并位于顶部。该程序也仅在调用自身时执行相同的操作。我假设如果它被激活,它也会为用户适当地设置焦点。

Rick

我找到了激活和设置焦点的解决方案...在“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;

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

ForceForegroundWindow worked for me in Win10. However, it does not activate the external program. It only makes it visible and on top. The program also only does the same when calling itself. I am assuming that if it activated it would also setfocus appropriately for the user.

Rick

I found a resolution for activating and setting focus... In the "SetAppRestore" procedure I initiated it with "MainFrm.visible:= false". Then it goes to SwitchApp, and it calls ForceForegroundWindow. After it returns to "SetAppRestore", I inserted "MainFrm.visible:= true". This triggered the app to become active and have focus on defined component: DataPge.SetFocus.

I apologize for not placing the code in a code block. I couldn't understand the instructions. So I put it all between 2 ===== bars.

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

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;

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文