PCB CAM自動化基於Incam 打造,在測試時經常遇到調試障礙,每次自行對功能測試時,生成了exe腳本后,再到Incam里面運行,發現問題,再回來修改代碼,非常不爽, 參考Genesis調試運行模式的方式,為了工程組寫腳本調試時用着爽,那就讓大家爽一下,,擴展了一下InCAM 調試功能(即可以在Visual Studio 中可以加斷點邊調邊執行COM指令), 先采用類似Genesis一樣查找JOB內存地址,結果碰壁了, 得尋找另外一種方式,發現InCAM每個窗品標題欄都含有JOB與STEP信息,以這個為出發點就很好解決了.

一.獲取JOB名的方法(同時兼容,內掛,外掛,區分Genesis,InCAM)
寫好一個腳本,可以外掛運行,也可以內掛運行
/// <summary> /// 獲取JOB名 /// </summary> /// <param name="JOB_Address"> 如是外掛使用時:填寫JOB基址</param> /// <returns></returns> public static string getJOB(int JOB_Address = _JOB_Address, int pid = 0) // 97b2 0x2FE623C 99b 0x0307BF84 { if (pid > 0) //pid 大於0為外掛啟用 { if (JOB_Address == 0) { JOB_Address = _JOB_Address; } g.JOB = API.ReadMemorystring(JOB_Address, pid); } else { if (gPID > 0) { if (g.isInCam()) { string incamTitel = getWindowAllTiltel(); //獲取incam標題 調用下方的函數了 不能像Genesis一樣通過基址找到JOB地址呢 if (!string.IsNullOrEmpty(incamTitel)) { incamTitel = incamTitel.Replace(" ", " "); var arrList = incamTitel.Split(' '); g.JOB = arrList[8]; g.STEP = arrList[10]; } } else { g.JOB = API.ReadMemorystring(JOB_Address, gPID); } } else { if (JOB_Address == 0) { JOB_Address = _JOB_Address; } g.JOB = System.Environment.GetEnvironmentVariable("JOB"); } } return (g.JOB); } /// <summary> /// 模糊查找標題 incam標題獲得JOB STEP名 /// </summary> /// <param name="TitlelName">InCAM v4</param> /// <returns></returns> public static string getWindowAllTiltel(string TitlelName = "InCAM v4") { string result = ""; StringBuilder sb = new StringBuilder(256); IntPtr desktopPtr = API.GetDesktopWindow(); IntPtr winPtr = API.GetWindow(desktopPtr, GetWindowCmd.GW_CHILD); while (winPtr != IntPtr.Zero) { winPtr = API.GetWindow(winPtr, GetWindowCmd.GW_HWNDNEXT); API.GetWindowTextW(winPtr, sb, sb.Capacity); if (sb.ToString().IndexOf(TitlelName) > -1) { result = sb.ToString(); winPtr = IntPtr.Zero; } } return result; }
二.用於查找InCAM標題WindowsAPI
/// <summary> /// 獲取窗口Text /// </summary> /// <param name="hWnd"></param> /// <param name="lpString"></param> /// <param name="nMaxCount"></param> /// <returns></returns> [DllImport("user32.dll")] public static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount); /// <summary> /// 該函數返回桌面窗口的句柄。桌面窗口覆蓋整個屏幕。桌面窗口是一個要在其上繪制所有的圖標和其他窗口的區域。 /// 【說明】獲得代表整個屏幕的一個窗口(桌面窗口)句柄. /// </summary> /// <returns>返回值:函數返回桌面窗口的句柄。</returns> [DllImport("user32.dll", EntryPoint = "GetDesktopWindow", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr GetDesktopWindow(); /// <summary> /// 該函數返回與指定窗口有特定關系(如Z序或所有者)的窗口句柄。 /// 函數原型:HWND GetWindow(HWND hWnd,UNIT nCmd); /// </summary> /// <param name="hWnd">窗口句柄。要獲得的窗口句柄是依據nCmd參數值相對於這個窗口的句柄。</param> /// <param name="uCmd">說明指定窗口與要獲得句柄的窗口之間的關系。該參數值參考GetWindowCmd枚舉。</param> /// <returns>返回值:如果函數成功,返回值為窗口句柄;如果與指定窗口有特定關系的窗口不存在,則返回值為NULL。 /// 若想獲得更多錯誤信息,請調用GetLastError函數。 /// 備注:在循環體中調用函數EnumChildWindow比調用GetWindow函數可靠。調用GetWindow函數實現該任務的應用程序可能會陷入死循環或退回一個已被銷毀的窗口句柄。 /// 速查:Windows NT:3.1以上版本;Windows:95以上版本;Windows CE:1.0以上版本;頭文件:winuser.h;庫文件:user32.lib。 /// </returns> [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);
/// <summary> /// 窗口與要獲得句柄的窗口之間的關系。 /// </summary> public enum GetWindowCmd : uint { /// <summary> /// 返回的句柄標識了在Z序最高端的相同類型的窗口。 /// 如果指定窗口是最高端窗口,則該句柄標識了在Z序最高端的最高端窗口; /// 如果指定窗口是頂層窗口,則該句柄標識了在z序最高端的頂層窗口: /// 如果指定窗口是子窗口,則句柄標識了在Z序最高端的同屬窗口。 /// </summary> GW_HWNDFIRST = 0, /// <summary> /// 返回的句柄標識了在z序最低端的相同類型的窗口。 /// 如果指定窗口是最高端窗口,則該柄標識了在z序最低端的最高端窗口: /// 如果指定窗口是頂層窗口,則該句柄標識了在z序最低端的頂層窗口; /// 如果指定窗口是子窗口,則句柄標識了在Z序最低端的同屬窗口。 /// </summary> GW_HWNDLAST = 1, /// <summary> /// 返回的句柄標識了在Z序中指定窗口下的相同類型的窗口。 /// 如果指定窗口是最高端窗口,則該句柄標識了在指定窗口下的最高端窗口: /// 如果指定窗口是頂層窗口,則該句柄標識了在指定窗口下的頂層窗口; /// 如果指定窗口是子窗口,則句柄標識了在指定窗口下的同屬窗口。 /// </summary> GW_HWNDNEXT = 2, /// <summary> /// 返回的句柄標識了在Z序中指定窗口上的相同類型的窗口。 /// 如果指定窗口是最高端窗口,則該句柄標識了在指定窗口上的最高端窗口; /// 如果指定窗口是頂層窗口,則該句柄標識了在指定窗口上的頂層窗口; /// 如果指定窗口是子窗口,則句柄標識了在指定窗口上的同屬窗口。 /// </summary> GW_HWNDPREV = 3, /// <summary> /// 返回的句柄標識了指定窗口的所有者窗口(如果存在)。 /// GW_OWNER與GW_CHILD不是相對的參數,沒有父窗口的含義,如果想得到父窗口請使用GetParent()。 /// 例如:例如有時對話框的控件的GW_OWNER,是不存在的。 /// </summary> GW_OWNER = 4, /// <summary> /// 如果指定窗口是父窗口,則獲得的是在Tab序頂端的子窗口的句柄,否則為NULL。 /// 函數僅檢查指定父窗口的子窗口,不檢查繼承窗口。 /// </summary> GW_CHILD = 5, /// <summary> /// (WindowsNT 5.0)返回的句柄標識了屬於指定窗口的處於使能狀態彈出式窗口(檢索使用第一個由GW_HWNDNEXT 查找到的滿足前述條件的窗口); /// 如果無使能窗口,則獲得的句柄與指定窗口相同。 /// </summary> GW_ENABLEDPOPUP = 6 }
三.InCAM實現外掛調試效果
可邊調試,邊操作InCAM

