当外部工具(通过api)调用我的应用程序时,它需要获得焦点,我知道默认设置是,它应该只在任务栏中闪烁,但在这种情况下,这绝对不是我想要的行为。在这种情况下,我试图通过“this.activate()”(c)获得焦点。
这就是前场锁定超时的作用。
但是,我在理解systemparameterinfo spi_setForegroundLockTimeout时遇到了一个小问题。
我知道它是用来设置ForegroundLockTimeout的,它定义了你的应用在获得它所请求的焦点之前需要等待多长时间。
(更多信息,变量“val”是设置为0的intptr)
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,val,SPIF_SENDWININICHANGE + SPIF_UPDATEINIFILE);
此项将更改处理超时的注册表项(hkey_current_user\control panel\desktop\foregroundlocktimout)
因为这将改变所有应用程序的行为,所以这确实是最后一种使用方法。
现在我想如果我不更新注册表项怎么办。所以我试了一下:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, val, 0);
但是它不会以任何方式改变我的应用程序的行为,但是
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,val,SPIF_SENDWININICHANGE);
做.
我不明白的是,为什么这只适用于我的应用程序,这绝对是我想要的,但我不明白。为什么我必须广播一个更改,这只适用于我的应用程序,当没有对任何注册表项或其他做任何更改,为什么这只适用于我的应用程序。
注意:如果要测试此行为,请在Visual Studio未运行时对其进行测试,而在它运行时(即使未加载此解决方案),它会在任何情况下将应用程序的行为更改为获取焦点。
最佳答案
这不是每个应用程序的设置,而是全局系统设置。无法仅为应用程序设置它,因此当您使用0调用最后一个参数SystemParametersInfo
时,不会发生任何事情。
另一方面,当您使用SPIF_SENDWININICHANGE
时,新设置将以WM_SETTINGCHANGE
消息的形式广播。(这就是为什么手动编辑注册表是错误的;总是调用文档化的api。)
除此之外,这个代码是错误的:
SPIF_SENDWININICHANGE + SPIF_UPDATEINIFILE
要连接两个标志,必须使用布尔或运算符(
|
),而不是加法运算符(+
)。在这种特殊情况下,因为0x1 + 0x2
和0x1 | 0x2
都等于3,所以它似乎起作用,但那只是一个意外。这个问题的真正解决方案不需要操纵全局设置(因为您肯定不想在客户端计算机上这样做,即使您自己也可以这样做)。你需要与系统合作,而不是试图与之对抗。在系统模型中,当前具有焦点的进程是具有设置/更改焦点权限的进程。所以基本上有三种选择:
只需调用外部工具
SetForegroundWindow
本身并将应用程序的窗口作为参数传递。这完全避免了你的应用程序必须激活自己。使用
AllowSetForegroundWindow
函数将外部工具的前台窗口设置权限委托给应用程序。它应该调用此函数,并将应用程序进程的ID作为参数传递。这样,当你的应用程序调用SetForegroundWindow
时,它将按预期工作。根据工具和应用程序的设计方式,您可以让外部工具启动应用程序。就像the documentation所说的,如果进程是由前台进程启动的,则允许设置前台窗口。