闪烁 window
Flashing a window
我在我的 c# 应用程序中使用 flashwindowex winapi 在图标托盘中刷新 IE window。当我在代码中添加断点并在调试中添加 运行 时,代码 运行 很好。但是删除断点后,相同的代码将无法运行。
这是一个控制台应用程序,我使用很少 windows api 通过名称查找已创建 IE 进程的句柄。进程句柄进一步传递给 FlashWindowEX
WINAPI 以刷新进程。
public static System.IntPtr hnd = IntPtr.Zero;
public delegate bool CallBackPtr(IntPtr hwnd, int lParam);
public static CallBackPtr callBackPtr;
public const UInt32 FLASH_T = 3;
public const UInt32 FLASH_S = 12;
static void Main(string[] args)
{
try
{
OrigCode();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
public static void OrigCode()
{
string strPzszPath = string.Empty;
string strCommandLine = string.Empty;
string strpath1 = "http://localhost/Till/Default.aspx";
strPzszPath = string.Concat(strPzszPath, strpath1);
strPzszPath = string.Concat(strPzszPath, "?TSCashierID=JILL&TSBalPeriod=2&TSBalDate=2015-06-02");
strCommandLine = strPzszPath;
Process procRequested = new Process();
////Create the process in minimised mode by default
procRequested.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
procRequested.StartInfo.UseShellExecute = false;
////Get the file name in which process is required to be started
procRequested.StartInfo.FileName = @"C:\Program Files\Internet Explorer\IExplore.exe";
procRequested.StartInfo.Arguments = strCommandLine;
////Start the process, process should be created in minimised mode
procRequested.Start();
callBackPtr = new CallBackPtr(SetFocusEnum);
int intResult = EnumWindows(callBackPtr, 0);
FLASHWINFO fi = new FLASHWINFO();
fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
fi.hwnd = hnd;
fi.dwFlags = FLASH_T | FLASH_S;
fi.ucount = UInt32.MaxValue;
fi.dwTimeout = 0;
FlashWindowEx(ref fi);
}
private static bool SetFocusEnum(IntPtr hWnd, int intLParam)
{
int intSize = GetWindowTextLength(hWnd);
try
{
if (intLParam == 0) //Process created so check by name
{
if (intSize++ > 0)
{
//Capture the running window name
StringBuilder sbWindowName = new StringBuilder(intSize);
GetWindowText(hWnd, sbWindowName, intSize);
//Capture the running process with the window name
if (sbWindowName.ToString().Contains("My Web Application Title"))
{
//Capture the handle which will be used to set the focus
hnd = hWnd;
}
}
}
}
catch (Exception ex)
{
}
finally
{
}
return true;
}
以下是我使用的 winapi 函数:
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int EnumWindows(CallBackPtr callPtr, int intProc);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowTextLength(IntPtr intptrHwnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowText(IntPtr intptrHwnd, StringBuilder strText, int intMaxCount);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[StructLayout(LayoutKind.Sequential)]
private struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 ucount;
public UInt32 dwTimeout;
}
就像我在评论中所说的那样,这里的问题是加载页面需要太长时间才能在执行 EnumWindows()
函数时更改 window 的文本.您使用的代码几乎立即执行,而打开进程和加载页面需要几百毫秒到几秒。添加延迟是解决您问题的最简单的解决方法。
这是我所做的:
procRequested.Start();
procRequested.WaitForInputIdle();
System.Threading.Thread.Sleep(750); //Wait for approximately 750 ms.
通常建议不要使用 Thread.Sleep()
,但由于您在控制台应用程序中,除了在运行的短时间内阻止用户输入外,它没有太大区别。
您可能还注意到我添加了对 Process.WaitForInputIdle()
的调用,这是为了让您的应用程序等待,直到进程完成其启动过程(例如加载资源,或其他 Windows在应用程序实际启动之前处理一个进程)以便我们知道什么时候可以预期 window 实际显示。
如果您有时觉得或体验到 750 毫秒的延迟不够,请尝试将其提高到 1250 或类似值。
编辑:
因为(如您所说)聚焦的 window 不会闪烁,您可以存储一个 window 句柄到先前聚焦的 window,并使用它来聚焦 window 在让 FlashWindowEx
代码执行之前再次出现。
为此,您将需要两次 WinAPI 调用:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
GetForegroundWindow()
获取当前焦点 window 的 window 句柄。
SetForegroundWindow()
通过指定 window 句柄设置当前焦点 window。
那你就用这两个函数吧:
IntPtr focusedhWnd = GetForegroundWindow(); //Get the window handle to the currently focused window.
procRequested.Start();
procRequested.WaitForInputIdle();
System.Threading.Thread.Sleep(750); //Wait for approximately 750 ms.
callBackPtr = new CallBackPtr(SetFocusEnum);
int intResult = EnumWindows(callBackPtr, 0);
SetForegroundWindow(focusedhWnd); //Focus the previously focused window again.
FLASHWINFO fi = new FLASHWINFO();
fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
fi.hwnd = hnd;
fi.dwFlags = FLASH_T | FLASH_S;
fi.ucount = UInt32.MaxValue;
fi.dwTimeout = 0;
FlashWindowEx(ref fi);
我在我的 c# 应用程序中使用 flashwindowex winapi 在图标托盘中刷新 IE window。当我在代码中添加断点并在调试中添加 运行 时,代码 运行 很好。但是删除断点后,相同的代码将无法运行。
这是一个控制台应用程序,我使用很少 windows api 通过名称查找已创建 IE 进程的句柄。进程句柄进一步传递给 FlashWindowEX
WINAPI 以刷新进程。
public static System.IntPtr hnd = IntPtr.Zero;
public delegate bool CallBackPtr(IntPtr hwnd, int lParam);
public static CallBackPtr callBackPtr;
public const UInt32 FLASH_T = 3;
public const UInt32 FLASH_S = 12;
static void Main(string[] args)
{
try
{
OrigCode();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
public static void OrigCode()
{
string strPzszPath = string.Empty;
string strCommandLine = string.Empty;
string strpath1 = "http://localhost/Till/Default.aspx";
strPzszPath = string.Concat(strPzszPath, strpath1);
strPzszPath = string.Concat(strPzszPath, "?TSCashierID=JILL&TSBalPeriod=2&TSBalDate=2015-06-02");
strCommandLine = strPzszPath;
Process procRequested = new Process();
////Create the process in minimised mode by default
procRequested.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
procRequested.StartInfo.UseShellExecute = false;
////Get the file name in which process is required to be started
procRequested.StartInfo.FileName = @"C:\Program Files\Internet Explorer\IExplore.exe";
procRequested.StartInfo.Arguments = strCommandLine;
////Start the process, process should be created in minimised mode
procRequested.Start();
callBackPtr = new CallBackPtr(SetFocusEnum);
int intResult = EnumWindows(callBackPtr, 0);
FLASHWINFO fi = new FLASHWINFO();
fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
fi.hwnd = hnd;
fi.dwFlags = FLASH_T | FLASH_S;
fi.ucount = UInt32.MaxValue;
fi.dwTimeout = 0;
FlashWindowEx(ref fi);
}
private static bool SetFocusEnum(IntPtr hWnd, int intLParam)
{
int intSize = GetWindowTextLength(hWnd);
try
{
if (intLParam == 0) //Process created so check by name
{
if (intSize++ > 0)
{
//Capture the running window name
StringBuilder sbWindowName = new StringBuilder(intSize);
GetWindowText(hWnd, sbWindowName, intSize);
//Capture the running process with the window name
if (sbWindowName.ToString().Contains("My Web Application Title"))
{
//Capture the handle which will be used to set the focus
hnd = hWnd;
}
}
}
}
catch (Exception ex)
{
}
finally
{
}
return true;
}
以下是我使用的 winapi 函数:
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int EnumWindows(CallBackPtr callPtr, int intProc);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowTextLength(IntPtr intptrHwnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowText(IntPtr intptrHwnd, StringBuilder strText, int intMaxCount);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[StructLayout(LayoutKind.Sequential)]
private struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 ucount;
public UInt32 dwTimeout;
}
就像我在评论中所说的那样,这里的问题是加载页面需要太长时间才能在执行 EnumWindows()
函数时更改 window 的文本.您使用的代码几乎立即执行,而打开进程和加载页面需要几百毫秒到几秒。添加延迟是解决您问题的最简单的解决方法。
这是我所做的:
procRequested.Start();
procRequested.WaitForInputIdle();
System.Threading.Thread.Sleep(750); //Wait for approximately 750 ms.
通常建议不要使用 Thread.Sleep()
,但由于您在控制台应用程序中,除了在运行的短时间内阻止用户输入外,它没有太大区别。
您可能还注意到我添加了对 Process.WaitForInputIdle()
的调用,这是为了让您的应用程序等待,直到进程完成其启动过程(例如加载资源,或其他 Windows在应用程序实际启动之前处理一个进程)以便我们知道什么时候可以预期 window 实际显示。
如果您有时觉得或体验到 750 毫秒的延迟不够,请尝试将其提高到 1250 或类似值。
编辑:
因为(如您所说)聚焦的 window 不会闪烁,您可以存储一个 window 句柄到先前聚焦的 window,并使用它来聚焦 window 在让 FlashWindowEx
代码执行之前再次出现。
为此,您将需要两次 WinAPI 调用:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
GetForegroundWindow()
获取当前焦点 window 的 window 句柄。SetForegroundWindow()
通过指定 window 句柄设置当前焦点 window。
那你就用这两个函数吧:
IntPtr focusedhWnd = GetForegroundWindow(); //Get the window handle to the currently focused window.
procRequested.Start();
procRequested.WaitForInputIdle();
System.Threading.Thread.Sleep(750); //Wait for approximately 750 ms.
callBackPtr = new CallBackPtr(SetFocusEnum);
int intResult = EnumWindows(callBackPtr, 0);
SetForegroundWindow(focusedhWnd); //Focus the previously focused window again.
FLASHWINFO fi = new FLASHWINFO();
fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
fi.hwnd = hnd;
fi.dwFlags = FLASH_T | FLASH_S;
fi.ucount = UInt32.MaxValue;
fi.dwTimeout = 0;
FlashWindowEx(ref fi);