如何将我的申请放在首位?

Posted

技术标签:

【中文标题】如何将我的申请放在首位?【英文标题】:How to bring my application to the front? 【发布时间】:2012-10-08 09:49:33 【问题描述】:

我知道为什么这是一个坏主意的所有原因。如果应用程序窃取输入焦点,我不喜欢它,但这纯粹是为了个人使用,我希望它发生;它不会打扰任何事情。

(好奇:我在 NetBeans 中运行单元测试,它会生成一个日志文件。当我的后台应用程序看到日志文件的时间戳更改时,我希望它解析日志文件并来到前面显示结果) .

This question 没有帮助,谷歌搜索也没有帮助。 BringToFront() 似乎已经很久没有工作了,我找不到任何替代方案。

有什么想法吗?

【问题讨论】:

你不能这样做。 Windows XP 有一个允许它的解决方法。此后的版本禁止它。 +1 @ken 如果您 100% 确定,请发布答案,我将奖励。我希望有一些不起眼的技巧,比如缩小到系统托盘然后恢复,或者隐藏然后再次显示...... @Mawg 你测试我的解决方案了吗? @Mawg - 出于好奇,你有没有测试过我帖子中的解决方案? @Mawg - 这不是关于接受(如果是的话,我不会发布对已经回答的问题的答案),而是关于反馈 - 只是“是的,它有效”或“不,这不不行”。上面的评论/问题不是第一个,它的前任在那里呆了几天,然后我把它删除了,当我确定你在线时问另一个(这个也呆了五天多)。 【参考方案1】:

这里有一些简单但似乎可行的方法,已使用多个由 XP、Server2003、Vista、Server2008、W7 组成的机器进行了测试。测试应用程序使用标准(或管理员)帐户运行,在前台写入时从记事本中窃取了输入焦点。

var
  Input: TInput;
begin
  ZeroMemory(@Input, SizeOf(Input));
  SendInput(1, Input, SizeOf(Input)); // don't send anyting actually to another app..
  SetForegroundWindow(Handle);

您可以进一步调整它 f.i.用于最小化的应用程序等(如果需要)。

【讨论】:

谢谢!也适用于 Windows 8.1。 当窗口被隐藏但不能恢复已最小化到任务栏的窗口时效果很好。【参考方案2】:

你不能可靠地做到这一点。 Windows XP 有一个允许它的解决方法,但从那时起的版本大部分都禁止它(参见下面的注释)。这在 SetForegroundWindow 上的 MSDN 文档的备注部分中有明确说明:

系统限制哪些进程可以设置前台窗口。只有满足以下条件之一,进程才能设置前台窗口:

该进程是前台进程。 进程由前台进程启动。 进程收到最后一个输入事件。 没有前台进程。 正在调试前台进程。 前景未锁定(请参阅 LockSetForegroundWindow)。 前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。 没有处于活动状态的菜单。

当用户正在使用另一个窗口时,应用程序不能将一个窗口强制置于前台。相反,Windows 会闪烁窗口的任务栏按钮以通知用户。

注意引用文档的最后一段,尤其是第一句。

问题

这纯粹是为了个人使用,我希望它发生;它不会打扰任何事情。

是任何应用程序都可以尝试做同样的事情。 “纯粹个人使用”如何告诉您是您个人而不是任何应用程序? :-)

注意:当我单击帮助工具按钮时,我已经尝试了所有我能想到的让 IDE 的文档显示在前台的方法,但我能得到的只是闪烁的任务栏按钮(我作为用户想要它)这样做)。

【讨论】:

+1(以及您在上面的评论 ;-) 显然,我会活在希望中,并在颁奖前将其开放几个小时。正如我所说,我希望有一些不起眼的技巧,比如缩小到系统托盘然后恢复,或者隐藏然后再次显示 - 但我尝试过的任何东西都不起作用:-(这是很多工作,只是为了避免 Alt-Tab (嗯,也许如果我有一个“启动器”应用程序,然后启动一个“进程”应用程序。新应用程序会在前台启动吗?) 你可以使用 AlwaysOnTop 风格,不是说它对其他应用程序友好,但它会引起用户的注意。虽然也许像 Growl/Snarl 这样的特殊警报服务更适合它。【参考方案3】:

我在我的一个应用程序中做类似的事情,这个功能对我有用 在 xp/vista/w7 中:

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
      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);
        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;

另一种解决方案是不窃取焦点,只是将窗口TOPMOST放在z缓冲区中:

procedure ForceForegroundNoActivate(hWnd : THandle);

begin
 if IsIconic(Application.Handle) then
  ShowWindow(Application.Handle, SW_SHOWNOACTIVATE);
 SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE);
 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE);
end;

【讨论】:

这在以非管理员身份运行的 Win7 上不起作用,在 Win2008 域上运行的机器上也无法正常工作,因此它不总是工作,这就是为什么我给出了我所做的答案。 :-) 当然,我(以及操作系统本身的制造商)知道什么? @KenWhite,此功能用于最终用户应用程序,他们混合使用 XP 和 W7 (UAC ON),我在受限环境中没有遇到任何问题 这里有一件事让我很头疼:SystemParametersInfo(SPI_SET...。设置系统范围的参数是个好主意吗?这甚至适用于 UAC 环境中的标准用户吗? 附带说明,SystemParametersInfo() 的第三个参数是Pointer,因此代码应该使用nil 而不是TObject(0) 我赞成这个答案,除非其他人可以证明这个代码不起作用(我自己没有测试过这个)。 @Ken,您实际上是否在以非管理员身份运行 Win7 时测试了此代码?【参考方案4】:

假设没有其他 StayOnTop 应用程序在运行,您可以暂时将表单 FormStyle 设置为 fsStayOnTop,然后执行 Application Restore 和 BringToFront,然后将表单样式改回原来的样子。

tmpFormStyle := Application.MainForm.FormStyle;
Application.MainForm.FormStyle := fsStayOnTop;
Application.Restore; // optional
Application.BringToFront;
Application.MainForm.FormStyle := tmpFormStyle;

同样,这仅在没有其他留在顶部的应用程序时才有效。

【讨论】:

【参考方案5】:

即使在 Windows7+8 操作系统中也应该可以工作。唯一的要求是应用程序本身可以调用函数。使用外部应用程序设置另一个进程的窗口前端比较棘手。

Application.Restore; // unminimize window, makes no harm always call it
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE);
SetWindowPos(self.Handle, HWND_TOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE);
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE);

编辑好的,我发现了一个问题。应用程序被放在前面,但焦点保留在原始应用程序中。使用这个答案来解决问题,它的方法非常复杂,但复制粘贴可以解决问题。在调用 ForceForegroundWindow(wnd) 之前,您可能必须调用 Application.Restore 来取消最小化窗口。 https://***.com/a/5885318/185565

【讨论】:

【参考方案6】:

您可以编写一个可执行文件来解决该限制。以一个简单的(非可视的)应用程序为例(基本上是一个控制台应用程序,但没有 $APPTYPE CONSOLE),其唯一目的是将您想要的窗口放在前面。

您的监控后台应用程序通过命令行调用(例如 ShellExecute)调用帮助应用程序,无论何时需要您的 bringtofront 操作。由于此应用程序正在成为前台进程,因此它能够将其他窗口置于前面(SetForeGroundWindow)。您可以使用 FindWindow 来获取目标窗口的句柄或在启动帮助应用程序时传递适当的参数。

【讨论】:

【参考方案7】:
function WinActivate(const AWinTitle: string): boolean;
var
  _WindowHandle: HWND;
begin
  Result := false;
  _WindowHandle := FindWindow(nil, PWideChar(AWinTitle));
  if _WindowHandle <> 0 then
  begin
    if IsIconic(_WindowHandle) then
      Result := ShowWindow(_WindowHandle, SW_RESTORE)
    else
      Result := SetForegroundWindow(_WindowHandle);
  end;
end;

if WinActivate(self.Caption) then
  ShowMessage('This works for me in Windows 10');

【讨论】:

【参考方案8】:

Form.bringtofront; ?

应该可以。 如果你把它放在一个计时器中,它会留在前面。

【讨论】:

以上是关于如何将我的申请放在首位?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 邓白氏编码申请流程

如何开通H5微信支付

QQ互联申请及配置

如果我的申请获得批准并准备发布,但误以为我的应用证书被吊销,我的应用会被发布吗?

如何将我的应用程序限制为仅适用于 iPhone [重复]

每天更新一次申请徽章