2014年11月25日 星期二

[軟體/Debug]於win7環境下提示視窗帶至前景的功能(SetForegroundWindow)偶發失敗

最近前台電腦環境轉換至win7,平常在winXP運作正常將提示視窗帶到前景的功能,會偶發失敗(壓視窗)的情況發生。對於醫師來說,這非常影響門診看診的"順暢性"。所以,非常認真的找了一下資料,不然電話那頭都會傳來關切的聲音(好累喔!)...
最後參考了CodeProject的這篇文章"How to bring window to top with SetForegroundWindow()",並將相關程式碼轉換成C#的語法來使用。因為仍有電腦環境的問題要考慮,所以並沒有整合到目前的程式碼,不過還是記錄一下好了!

[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();

[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

[DllImport("user32.dll")]
public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

public const uint SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
public const uint SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
public const uint SPIF_SENDWININICHANGE = 0x02;
public const uint SPIF_UPDATEINIFILE = 0x01;
[DllImport("user32.dll")]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni);

public const int ASFW_ANY = -1;
[DllImport("user32.dll")]
public static extern bool AllowSetForegroundWindow(int dwProcessId);

[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

/// <summary>
/// How to bring window to top with SetForegroundWindow()
/// http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo
/// </summary>
/// <param name="hWnd"></param>
private void SetForegroundWindowInternal(IntPtr hWnd)
{
 if(!IsWindow(hWnd)) return;

 //relation time of SetForegroundWindow lock
 uint lockTimeOut = 0;
 IntPtr hCurrWnd = GetForegroundWindow();
 uint dwThisTID = GetCurrentThreadId();
 uint dwCurrTID = GetWindowThreadProcessId(hCurrWnd, IntPtr.Zero);

 //we need to bypass some limitations from Microsoft :)
 if (dwThisTID != dwCurrTID)
 {
  AttachThreadInput(dwThisTID, dwCurrTID, true);

  SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref lockTimeOut, 0);
  SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref lockTimeOut, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);

  AllowSetForegroundWindow(ASFW_ANY);
 }

 SetForegroundWindow(hWnd);

 if (dwThisTID != dwCurrTID)
 {
  SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,ref lockTimeOut, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
  AttachThreadInput(dwThisTID, dwCurrTID, false);
 }
}

參考資料
[1] 把視窗移到最前面
[2] How to bring window to top with SetForegroundWindow()
[3] Control in Focus in Other Processes
[4] PInvoke.net

沒有留言:

張貼留言