PCB CAM自动化基于Incam 打造,在测试时经常遇到调试障碍,每次自行对功能测试时,生成了exe脚本后,再到Incam里面运行,发现问题,再回来修改代码,非常不爽, 参考Genesis调试运行模式的方式
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实现外挂调试效果
录制花屏了