ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

应用程序进入中断模式

应用程序进入中断模式 大白话解释这个报错你的应用进入了中断状态但当前未执行任何受选定调试引擎支持的代码说白了VS断点没扎到你写的C#代码上 ZwCAD本身程序崩/卡住了停在了ZWCAD内部原生代码里不是你的托管C#代码。所以VS看不到代码就弹出这个中断页面。最常见4个触发原因ZWCAD二次开发高频坑你代码里面CAD事务没有关闭、没有提交事务卡死窗体弹出的时候跨线程访问CAD对象访问了一个已经被删除、无效的实体IdXData扩展数据读取出错、ResultBuffer读取异常ZWCAD底层C代码直接崩溃一步一步解决照着顺序操作第1步先点【继续】按钮点继续执行。如果点完软件正常跑起来属于偶然底层异常不一定是bug如果一点继续ZWCAD直接闪退百分百你的C#代码有问题。第2步看线程堆栈最关键找问题顶部工具栏找到堆栈帧下拉框点开切换线程找到带你项目文件名XDataParser.cs、EntityXDataFilter.cs那一条堆栈。 能切到你的代码就能看到报错在哪一行。 如果堆栈列表里完全没有你写的代码就是ZWCAD原生代码炸了。第3步90%ZWCAD插件踩坑根源坑1事务忘记Dispose❌坏代码示范Transactiontrdb.TransactionManager.StartTransaction();//你读取XData代码//漏掉 tr.Commit(); tr.Dispose();事务开了不关下次一操作CAD直接卡死中断。✅标准写法using(Transactiontrdb.TransactionManager.StartTransaction()){//读写实体、读取XData扩展数据tr.Commit();}//using结束自动释放永远不会忘关闭事务坑2WinForm弹窗阻塞CAD主线程你打开FilterForm筛选窗口的时候千万不要在窗体后台代码里面访问CAD实体窗体属于WinForms消息循环很容易造成线程冲突触发这种中断。正确做法CAD主线程预先把所有实体数据读到普通List集合再传给窗体窗体只操作内存数据窗体关闭以后再回CAD主线程定位图元。坑3读取XData扩展数据空对象没判空ResultBufferrbent.GetXData(你的AppName);//如果rbnull 直接往下读ZWCAD底层直接崩读取扩展数据前必须加空判断if(rbnull)return;调试设置优化根治这个弹窗频繁出现顶部VS菜单 →调试 → 窗口 → 异常设置把【公共语言运行时异常】全部勾选。以后代码报错VS会直接跳到你出错的那一行C#代码而不是跳到这个无代码的中断页面。快速排查清单所有读写CAD实体代码全部套上using Transaction读取XData扩展数据每一步都判空Winform窗体不要在窗体事件内访问数据库、实体断点不要打在窗体的按钮点击事件里面调试CAD代码极易触发这个中断先说核心结论调用语法本身没错无模式弹窗写法是对的XDataFilterTool.FilterForm form new XDataFilterTool.FilterForm(); ZwSoft.ZwCAD.ApplicationServices.Application.ShowModelessDialog(form);ShowModelessDialog 就是ZWCAD官方给你弹出非模态(无模式)窗体的标准API别的窗体能跑代表这个调用方式没问题。为什么别的窗体正常唯独这个FilterForm会触发「中断模式、无托管代码」崩溃问题不在打开窗体这一行代码而在窗体里面的代码分3类高频元凶针对你的XData筛选窗体元凶1窗体构造函数 / Form_Load事件里直接读取CAD实体、XData扩展数据头号杀手⭐90%概率//FilterForm里面危险写法 public FilterForm() { InitializeComponent(); //❌ 错误窗体构造阶段就去读数据库、遍历实体、读XData ReadAllEntityXData(); }ShowModelessDialog 弹出Winform后窗体有自己独立的消息循环。你在Load事件里面访问ZwCAD数据库、实体、事务相当于跨消息线程碰CAD对象ZWCAD底层C直接卡死崩溃 → VS就弹出你看到的【中断模式找不到托管代码】根本不会抛C#异常给你。✅安全规则窗体Load里面绝对不要访问任何CAD实体/数据库正确流程CAD主线程命令函数里面先把所有筛选需要的数据读出来放到普通内存List再把这个纯内存列表传给FilterForm窗体窗体只操作内存里的数据完全不碰Database、Entity、XData用户点【定位】按钮的时候发一个回调回到CAD主线程再去选中、高亮实体元凶2窗体里面的定时器(Timer)如果你FilterForm拖了System.Windows.Forms.Timer之外的定时器比如System.Timers.Timer定时器回调是子线程只要里面碰一下CAD实体立刻底层崩溃报这个中断。元凶3窗体上绑定了数据关闭窗体的时候资源没释放事务/ResultBuffer没清理比如你窗体里面缓存了EntityId窗体关闭后你又去操作已经失效的ID回头触发崩溃。两种窗体安全调用方案给你现成可复制代码方案A推荐无模式弹窗数据分离根治崩溃// 在CAD命令主线程执行不要放到窗体里面 //第一步预先读取好所有XData筛选数据纯内存数据不要传Entity对象 ListMyXDataModel dataList LoadXDataList(); //第二步打开窗体把内存数据丢进去 FilterForm form new FilterForm(); form.DataSource dataList; //给窗体传入纯内存数据 ZwSoft.ZwCAD.ApplicationServices.Application.ShowModelessDialog(form);MyXDataModel是一个普通C#类只存字符串、long(实体ID)这些值绝对不能存Entity、DBObject、ResultBuffer窗体定位回调写法窗体点击定位通知CAD主线程干活在FilterForm中定义回调委托public Actionlong LocateEntityAction;窗体按钮点击private void btnLocate_Click(object sender, EventArgs e) { //只把实体ID抛出去窗体自己不去选实体 LocateEntityAction?.Invoke(selectedEntityId); }打开窗体的时候绑定回调form.LocateEntityAction (entId) { //这里回到CAD主线程执行安全地定位高亮实体 LocateEntityById(entId); };方案B临时改成【模态弹窗】测试快速定位问题如果改成ShowDialog()弹窗后崩溃消失了那百分百就是窗体Load事件访问CAD对象导致的线程冲突FilterForm form new FilterForm(); form.ShowDialog();仅用来排查问题最后无模式窗体还是用ShowModelessDialog快速排查步骤照着做一遍打开FilterForm.cs把Form_Load、构造函数里面所有读取XData、遍历实体、访问Database的代码全部注释掉重新调试再点按钮打开窗体✅ 不崩溃实锤就是Load事件访问CAD对象导致把读数据逻辑挪到命令主线程❌ 依旧崩溃去检查窗体有没有定时器、后台线程补充一个极易踩坑的细节别的窗体可以ShowModelessDialog不代表所有窗体都行。那些正常窗体打开的时候没有立刻读取CAD数据而你的Filter筛选窗体一打开就要加载XData列表这就是唯一区别。一眼找到根因崩溃元凶public FilterForm() { InitializeComponent(); Load FilterForm_Load; } private void FilterForm_Load(object sender, EventArgs e) { RefreshData(); //问题就在这一行 }RefreshData()里面直接访问了CadApplication.DocumentManager.MdiActiveDocument、遍历图纸数据库读取XData。你用的是ShowModelessDialog无模式窗体窗体的Load事件跑在WinForms独立消息循环线程不是ZWCAD主线程。你在线程非CAD主线程去碰CAD的Database/Entity对象ZWCAD底层C直接卡死崩溃然后VS弹出那个「中断模式没有托管代码」C#的try‑catch根本捕获不到这种底层崩溃✅别的无模式窗体没事是因为别的窗体Load里面没有读取CAD图纸数据唯独你这个窗体一加载就扫描全图。还有第二个隐藏炸弹定位按钮private void BtnSelectInCad_Click(object sender, EventArgs e) { Document doc CadApplication.DocumentManager.MdiActiveDocument; Editor ed doc.Editor; ObjectId[] ids _filterResult.Select(item item.EntityId).ToArray(); ed.SetImpliedSelection(ids); doc.SendStringToExecute(_.ZOOM _Object _P \n, true, false, false); }无模式窗体的按钮点击事件同样不一定在CAD主线程这里直接操作选择集、SendStringToExecute有很高概率随机闪退。修复完整方案2种推荐方案一彻底根治方案一最优数据和窗体彻底分离推荐1、FilterForm删掉Load事件自动刷新修改窗体构造函数删掉Load绑定public FilterForm() { InitializeComponent(); //Load FilterForm_Load; // 注释掉删掉自动加载 }RefreshData()不要再在窗体内部调用扫描图纸的代码全部挪到CAD命令主线程2、给FilterForm加一个对外属性接收已经扫描好的纯内存数据在FilterForm类里面添加//由外部CAD主线程赋值窗体不再自己读CAD public ListEntityXDataInfo SourceData { set { _allData value; //外部传进来数据后在这里填充界面下拉框 FillUiFromLoadedData(); } } //新建一个方法只负责填充界面控件不再访问CAD private void FillUiFromLoadedData() { if(_allData null) return; //从_allData内存集合提取图层、appName不要再读图纸 _allLayers new HashSetstring(_allData.Select(xx.LayerName).Distinct()); _allAppNames new HashSetstring(_allData.Select(xx.AppName).Distinct()); clbLayers.Items.Clear(); foreach (var layer in _allLayers.OrderBy(l l)) { clbLayers.Items.Add(layer, true); } clbAppNames.Items.Clear(); foreach (var app in _allAppNames.OrderBy(a a)) { clbAppNames.Items.Add(app, true); } cboFields.Items.Clear(); cboFields.Enabled false; cboOperator.Items.Clear(); cboOperator.Enabled false; txtValue1.Text ; txtValue1.Enabled false; txtValue2.Text ; txtValue2.Visible false; lblValue2.Visible false; lblStatus.Text $数据加载完成共扫描到 {_allData.Count} 个带扩展数据的实体; }然后把原来RefreshData()里面读CAD数据库那一大段删掉窗体里面的RefreshData按钮点击事件改成调用FillUiFromLoadedData可选刷新图纸数据交给外面。3、打开窗体的命令代码CAD主线程改成这样//CAD命令主线程安全区域 Document doc ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db doc.Database; //第一步主线程扫描图纸XData读出纯内存数据 ListEntityXDataInfo scanData XDataParser.ParseModelSpace(db, out var layers, out var appNames); //第二步打开无模式窗体把数据丢进去 XDataFilterTool.FilterForm form new XDataFilterTool.FilterForm(); form.SourceData scanData; //传入内存数据窗体不用碰CAD ZwSoft.ZwCAD.ApplicationServices.Application.ShowModelessDialog(form);4、定位CAD实体的炸弹修复用回调委托窗体添加回调窗体不再自己执行CAD选中操作把实体ID抛回CAD主线程执行在FilterForm类内增加委托/// summary定位回调由外部主线程实现CAD选中/summary public ActionObjectId[] OnLocateEntities;修改【定位选中】按钮点击代码private void BtnSelectInCad_Click(object sender, EventArgs e) { if (_filterResult null || _filterResult.Count 0) { MessageBox.Show(没有可选中的实体请先执行筛选); return; } ObjectId[] ids _filterResult.Select(item item.EntityId).ToArray(); //窗体只向外抛出ID不碰CAD编辑器 OnLocateEntities?.Invoke(ids); lblStatus.Text $已发起定位 {ids.Length} 个实体; }打开窗体的时候绑定回调CAD主线程负责选中缩放form.OnLocateEntities (ids) { Document doc ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed doc.Editor; ed.SetImpliedSelection(ids); doc.SendStringToExecute(_.ZOOM _Object _P \n, true, false, false); };方案二快速临时规避不改大架构应急测试如果你暂时不想大改代码放弃窗体Load自动加载删掉Load事件绑定。打开窗体后用户手动点【刷新数据】按钮再扫描图纸。按钮点击在无模式窗体虽然也有风险但人为点击触发的消息大概率刚好落在CAD主线程崩溃概率大幅下降。public FilterForm() { InitializeComponent(); // Load FilterForm_Load; //直接注释禁止窗体一打开就读CAD }⚠️方案二只是治标依然有随机闪退风险正式上线必须用方案一补充一个额外检查点你的EntityXDataInfo类只允许存字符串、long、ObjectId等值数据绝对不能保存Entity、ResultBuffer、Database对象引用否则后续访问照样崩溃。
返回列表