[C#]程式幫您按按鈕(SendKey & SendMessage)

十二月 6, 2008

前言

專案中有個程式負責透過 ACDSee 列印(ProcessStartInfo.Verb=”Print”)各種圖檔。但 ACDSee 在列印時會出現讓使用者設定格式、頁首頁尾、印表機選項的視窗出現,要按下「列印(P)」之後才會真的開始列印,所以程式必須在開始工作時偵測 ACDSee 的狀態並且按下列印鈕。

方法如下:

  1. hWnd = FindWindow(null,”ACDSee – 列印”); // 尋找 ACDSee 的列印視窗
  2. SetForegroundWindow(hWnd); // 將視窗帶到前景
  3. SendKeys.SendWait(“{ENTER}”); // 送出 ENTER 鍵按列印鈕

事前測試都OK,但安裝到客戶的機器上卻經常發生沒有自動按列印鈕而卡住的問題。原以為是被其它程式干擾{ENTER}的發送,但奇怪的是同事在現場怎麼測試都無法重現問題,一離開不久客戶就反應問題又發生了。

最後,細心的同事發現是因為機器一段時間沒人操作就會被鎖住(lock),流程卡住的問題就開始了!

推測:當系統 lock 時,畫面看不到 ACDSee 的視窗(但 FindWindow 可以找到)所以 SendKey 無法送到正確的視窗。


解法

SendMessage 發送 WM_COMMAND

程式(C版)

    HWND hWnd = ::FindWindow(NULL, "ACDSee - Print");
    if(NULL != hWnd)
    {
        HWND hButton = ::FindWindowEx(hWnd, NULL, "BUTTON", "&Print");
        if(NULL != hButton)
        {
            ::PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(::GetDlgCtrlID(hButton), BN_CLICKED),(LPARAM)hButton);
        }
        else
        {
            AfxMessageBox("Can not find [Print]");
        }
    }
    else
    {
        AfxMessageBox("Can not find [ACDSee - Print]");
    }

 

程式(C#版)

IntPtr hWnd = FindWindow(null, "ACDSee - 列印");
if ( !hWnd.Equals(IntPtrZero) )
{
	IntPtr hButton = FindWindowEx(hWnd, 0, "BUTTON", "列印(&P)");
	if ( !hButton.Equals(IntPtrZero) )
	{
		SendMessage(hWnd, WM_COMMAND, GetDlgCtrlID(hButton) , hButton);
	} // if
} // if

/* API 定義*/
[DllImport("User32.dll",EntryPoint="FindWindow")]
private static extern IntPtr FindWindow(string lpClassName,string lpWindowName); 

[DllImport("User32.dll")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, int hwndChildAfter, string lpszClass, string lpszWindow); 

[DllImport("user32.dll")]
public static extern int GetDlgCtrlID(IntPtr hWnd);

[DllImport("user32.dll", EntryPoint = "SendMessageA")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);

private const int WM_COMMAND = 0x111;
private const int BN_CLICKED = 0;

相關文章

3,574 views

 

Leave a Reply