NX CAM二次开发:用Open C API高效读取操作导航器选中节点信息

发布时间:2026/10/20 3:20:55
NX CAM二次开发:用Open C API高效读取操作导航器选中节点信息 做了这么多年NX CAM二次开发我一直觉得Open C API是比NXOpen C更容易被忽略的一套工具。特别是碰到只需要“把操作导航器里选中的东西拿过来查一查”这种需求用UF_UI_ONT和UF_OPER函数组往往比折腾NXOpen的复杂对象继承关系要省事得多。今天这篇就围绕我自己做的一个小工具详细拆解UF_UI_ONT_ask_selected_nodes、UF_OPER_ask_cutter_group这几个函数到底怎么配合使用如果你正准备写类似的程序信息提取功能这篇应该能让你少走不少弯路。这里说的“OPENC函数”其实就是NX Open C API。老版本的NX二次开发很多都是靠这套C接口实现的至今在官方文档里还占着重要位置。我下面讲的都是基于我实际调试过的代码逻辑不同NX版本里个别枚举名和返回值细节可能略有差异但整体思路不会变。1. 这套API到底在解决什么问题1.1 操作导航器里的节点不只是“一行字”用NX做加工编程的人都知道操作导航器里有四种默认视图程序顺序视图、加工方法视图、几何视图、机床视图。同一个操作在不同视图里会出现在不同节点下。比如一个型腔铣操作在“程序顺序视图”里挂在某个程序组下面在“几何视图”里又挂在工件坐标系和部件下面。这个特性给二次开发带来一个很关键的问题用户选中的节点到底代表什么我们很多时候并不能假设选中的一定是“操作”也有可能是一个程序组、一个加工方法组、一个几何体组甚至是机床视图里的刀具节点。用Open C的函数去处理时第一步永远是判断节点类型而不是直接拿来当操作使用。UF_UI_ONT_ask_selected_nodes这个函数做的就是从当前操作导航器的选中状态里一次性捞出所有被选中的节点并且把每个节点的类型和对象标签tag_t带出来。拿到tag_t之后再去调用UF_OPER系列函数展开详细信息这才是一条完整的链路。1.2 核心函数清单我把这个场景里最常用的几个Open C函数列出来后面会逐个展开讲。函数名作用典型返回值/出参UF_UI_ONT_ask_selected_nodes获取操作导航器中当前选中的节点数组节点信息数组、节点数量UF_UI_ONT_free_node_info释放上面函数返回的节点信息内存无UF_OPER_ask_name获取操作名称字符串指针UF_OPER_ask_program获取操作所属的程序组标签tag_tUF_OPER_ask_cutter_group获取操作使用的刀具组标签tag_tUF_OPER_ask_type获取操作类型编号intUF_PROGRAM_ask_name根据程序组标签获取程序组名称字符串指针UF_initialize / UF_terminate初始化/退出Open C环境状态码这几个函数组合起来基本能覆盖“选中程序/操作 - 获取名称 - 获取刀具组/程序组”这类需求。2. 动手前的准备NX Open C开发环境与基本骨架2.1 include与编译环境Open C的编译环境没有NXOpen C那么复杂但有些细节需要注意。头文件一般放在NX安装目录下的UGII\NXOpen或者UGOpen目录里我实际使用中至少要包含这几个#include uf.h #include uf_ui.h #include uf_oper.h #include uf_prog.h #include uf_ui_ont.h如果你是做NXOpen C的开发可能会觉得C接口的头文件“很古老”但恰恰是这种“古老”让它非常稳定。编译时建议直接用NX自带的VS项目向导生成DLL项目然后把项目附加包含目录指向NX安装目录下的对应路径。我不建议自己手写Makefile不同NX版本与VS版本之间的匹配关系很容易出错。最简单可靠的做法是参考NX安装目录下提供的示例工程复制一份再改。2.2 UF_initialize和UF_terminate这条底线所有Open C函数调用都要求当前线程处于“UF环境”里。你写的入口函数比如NX菜单回调或者用户出口函数第一步必须是UF_initialize退出时用UF_terminate配对。extern void myMenuCallback(int *response) { int stat UF_initialize(); if (stat ! 0) { uc1601(UF initialize failed, 1); return; } /* 这里写你的Open C逻辑 */ do_export_selected_info(); UF_terminate(); }这里有个我自己踩过的坑不要在同一个线程里反复调UF_initialize和UF_terminate。比如你循环处理大量操作每处理一个就初始化和终止一次轻则性能下降重则导致对象句柄失效。正确做法是入口初始化一次整段逻辑跑完再终止。2.3 入口怎么挂到NX界面里获取操作导航器选中节点这种操作必须要有NX的UI环境所以最好做成菜单按钮或者工具条回调而不是做成独立的外部EXE。外部EXE模式跑起来经常拿不到当前会话里的导航器状态。我习惯把这个工具挂在“开始 - 加工”环境下某个自定义菜单里。回调里先检查当前是否处于加工模块如果不是就直接提示用户。这个检查可以用UF_NXCONF之类的接口也可以简单粗暴地尝试调用UF_UI_ONT_ask_selected_nodes如果返回错误就说明当前不在加工环境。3. UF_UI_ONT_ask_selected_nodes从选中节点到tag_t的完整链路3.1 先初始化选择数据UF_UI_ONT_ask_selected_nodes的第一个参数是一个UF_UI_ONT_select_data_t结构体。这个结构体里的过滤条件会直接影响返回结果。我不太建议全靠memset清零更稳妥的办法是调用系统默认初始化函数。在我的代码里是这样处理的UF_UI_ONT_select_data_t sel_data; memset(sel_data, 0, sizeof(sel_data)); UF_UI_ONT_ask_default_select_data(sel_data);如果某个NX版本里没有ask_default_select_data这个接口就直接手动给几个关键字段赋值sel_data.display_properties 0; sel_data.only_leaves 0; sel_data.node_type_filter UF_UI_ONT_TYPE_OPER;重点解释一下only_leaves和node_type_filter这两个字段。only_leaves为1时只获取“叶子节点”也就是最底层的具体操作为0时允许获取程序组这类父节点。node_type_filter则用来指定你要哪些类型的节点可以按位或组合。如果要同时获取程序和操作我会写成sel_data.node_type_filter UF_UI_ONT_TYPE_PROGRAM | UF_UI_ONT_TYPE_OPER;3.2 获取并遍历节点数组调用部分其实很短UF_UI_ONT_node_info_t *node_info NULL; int num_nodes 0; int stat UF_UI_ONT_ask_selected_nodes(sel_data, node_info, num_nodes); if (stat ! 0) { uc1601(读取导航器选中项失败, 1); return; } for (int i 0; i num_nodes; i) { process_ont_node(node_info[i]); } if (node_info ! NULL) { UF_UI_ONT_free_node_info(node_info, num_nodes); }这里第一个容易出错的地方是node_info数组必须由UF_UI_ONT_free_node_info释放不能自己free。这是因为NX内部可能用自建内存池来管理这些对象直接free轻则内存泄漏重则导致崩溃。我早期就吃过这个亏后来把所有返回字符串和数组的Open C接口都养成了“谁分配谁用对应释放函数处理”的习惯。第二个容易忽略的是即使当前导航器里没有任何选中项这个调用也可能返回0只是num_nodes为0。所以必须判断num_nodes后再处理否则空指针遍历直接就崩了。3.3 node_info里的type到底怎么用UF_UI_ONT_node_info_t结构体里包含节点类型和节点标签。type字段的值在不同NX版本里枚举名可能略有差别但常见的有操作节点对应实际加工操作比如平面铣、型腔铣、钻孔。程序组节点对应程序顺序视图里的Program节点。方法节点对应加工方法视图里的粗加工、半精加工、精加工。几何体节点对应几何视图里的MCS_MILL、WORKPIECE等。刀具节点对应机床视图里的刀具组。我通常先用type做分支再决定调用哪一组查询函数。如果你不管type一律当成操作处理遇到程序组节点时UF_OPER_ask_name会返回错误码而且不会给出任何直观提示排查起来很难受。4. 拿到操作tag之后用UF_OPER系列函数挖出名称和刀具组4.1 操作名称用UF_OPER_ask_name过程很直接char *op_name NULL; int stat UF_OPER_ask_name(node_tag, op_name); if (stat 0 op_name ! NULL) { /* 使用op_name */ UF_free(op_name); }这里有三个值得注意的点。第一返回的op_name是NX内部拼接出来的字符串使用完后必须用UF_free释放。第二这个名称是操作在导航器里显示的那个名字不是文件名也不是CLS名称。第三UF_OPER_ask_name接收的tag必须是操作对象如果你把一个程序组对象的tag传进去返回错误码的概率极高。4.2 从操作找所属程序组有时候你选中的是一个具体操作但最终你想输出的是“这个操作挂在哪个程序组下面”。这时要用UF_OPER_ask_programtag_t program_tag NULL_TAG; stat UF_OPER_ask_program(node_tag, program_tag); if (stat 0 program_tag ! NULL_TAG) { char *program_name NULL; if (UF_PROGRAM_ask_name(program_tag, program_name) 0) { /* 使用program_name */ UF_free(program_name); } }这条链路非常典型操作 - 程序组标签 - 程序组名称。没必要去遍历整个程序树直接用API反查就行了。4.3 UF_OPER_ask_cutter_group获取的是“刀具组”对象标题里点到UF_OPER_ask_cutter_group这个函数在文档里描述是“获取操作对应的刀具组”。实际返回的是一个tag_t指向CAM的刀具组对象。注意它返回的不是刀具名称字符串也不是刀具几何参数结构体。tag_t cutter_group_tag NULL_TAG; stat UF_OPER_ask_cutter_group(node_tag, cutter_group_tag); if (stat 0 cutter_group_tag ! NULL_TAG) { /* 继续查询刀具组名称或者进一步获取刀具参数 */ }拿到cutter_group_tag之后如果你想显示刀具名称还需要继续调用对应的查询函数。在Open C环境中不同NX版本提供的刀具组查询接口不太一样有的版本用UF_CUTTER相关函数有的版本则推荐通过NXOpen再去取。我自己的做法是如果只在Open C里做就尝试用UF_CUTTER_ask_name这类函数如果项目本身已经接入了NXOpen C我就会把cutter_group_tag转成NXOpen对象再去查这样更稳。这里想说的是很多初学者拿到cutter_group_tag后一头雾水觉得“怎么是个tag啥也干不了”。其实tag就是NX内部对象的句柄你可以把它理解成一把“钥匙”任何和这个对象相关的查询最后都要通过这把钥匙。4.4 我想遍历整个程序组里的所有操作怎么办还有一种常见需求用户不选具体操作而是选中一个程序组希望程序自动遍历这个组下所有操作。这时候不能用UF_OPER_ask_program反向查需要正向遍历。Open C里有专门遍历子节点的接口比如UF_GROUP_ask_children或者UF_CAM_ask_children。大致逻辑是先从节点信息里拿到程序组tag。调用子节点遍历函数获得下一层所有节点的tag数组。对每个tag判断是否为操作对象。如果是操作继续调用UF_OPER_ask_name、UF_OPER_ask_cutter_group。因为不同NX版本子节点遍历接口名称有差异我这里就不写死代码了。但我强烈建议用“递归遍历”而不是只处理一层因为程序组里可能还嵌套子程序组。5. 完整示例一次导出当前选中节点的加工信息清单5.1 主流程代码我把上面所有逻辑串起来写一个完整函数。这个函数负责从导航器拿到选中节点每次遇到操作节点就输出一段信息遇到程序组节点就输出程序组名称。static void process_ont_node(UF_UI_ONT_node_info_t *node) { if (node NULL) { return; } if (node-type UF_UI_ONT_TYPE_OPER) { char *op_name NULL; char *program_name NULL; tag_t program_tag NULL_TAG; tag_t cutter_group_tag NULL_TAG; if (UF_OPER_ask_name(node-node_tag, op_name) 0 op_name ! NULL) { uc1601(op_name, 1); UF_free(op_name); } if (UF_OPER_ask_program(node-node_tag, program_tag) 0 program_tag ! NULL_TAG) { if (UF_PROGRAM_ask_name(program_tag, program_name) 0 program_name ! NULL) { uc1601(program_name, 1); UF_free(program_name); } } if (UF_OPER_ask_cutter_group(node-node_tag, cutter_group_tag) 0 cutter_group_tag ! NULL_TAG) { /* 这里根据你所在NX版本继续查询刀具组名称 */ } } else if (node-type UF_UI_ONT_TYPE_PROGRAM) { char *prog_name NULL; if (UF_PROGRAM_ask_name(node-node_tag, prog_name) 0 prog_name ! NULL) { uc1601(prog_name, 1); UF_free(prog_name); } } } static void do_export_selected_info(void) { UF_UI_ONT_select_data_t sel_data; UF_UI_ONT_node_info_t *node_info NULL; int num_nodes 0; int stat 0; memset(sel_data, 0, sizeof(sel_data)); UF_UI_ONT_ask_default_select_data(sel_data); sel_data.node_type_filter UF_UI_ONT_TYPE_OPER | UF_UI_ONT_TYPE_PROGRAM; sel_data.only_leaves 0; stat UF_UI_ONT_ask_selected_nodes(sel_data, node_info, num_nodes); if (stat ! 0) { uc1601(读取导航器选中项失败, 1); return; } for (int i 0; i num_nodes; i) { process_ont_node(node_info[i]); } if (node_info ! NULL) { UF_UI_ONT_free_node_info(node_info, num_nodes); node_info NULL; } }这段代码可以直接放进NXOpen C的DLL工程里测试。它没有做太多花哨的事情核心就是“按类型分流 - 取名称 - 释放内存”。5.2 输出效果与字段说明如果我们在加工环境里选中一个型腔铣操作和一个程序组再运行这个菜单回调程序会依次弹出几个对话框“CAVITY_MILL_1”这是操作名称。“PROGRAM_1”这是操作所属的程序组名称。“NC_PROGRAM_2”这是被选中的程序组节点名称。这个输出逻辑虽然简单但已经证明了整个调用链是通的。真正做工具时你只需要把uc1601换成自己封装的信息收集函数把字符串写进文本文件或者Excel即可。5.3 几个容易翻车的小点一定要设置node_type_filter。如果不设置过滤条件却恰好选中了多个不同类型的节点程序处理时很容易把非操作节点当成操作来查导致大量无用的错误码。还有就是在处理完数组之后习惯性把node_info置NULL。很多崩溃都是因为悬空指针在后面的异常分支里被再次释放。6. 经验复盘与容易踩的坑6.1 内存释放顺序要格外小心Open C的开发者经常说“拿到的字符串要UF_free拿到的数组要用专用释放函数”。这个顺序也很重要。我通常的做法是先释放程序组名称再释放操作名称最后再释放node_info数组。如果先释放了node_info数组但后面代码还要用node_info里的tag去查询那就会出现使用了已释放内存的问题。NX内部对象在UF_terminate之后可能全部失效所以尽量避免“拿一点放一点”的写法。最好是一次性把所有要查询的数据都取出来存到自己的普通变量里然后统一释放。6.2 节点类型过滤不是越多越好有些人觉得反正多选几个类型也不影响就把所有类型都放到node_type_filter里。但这会导致一个问题当用户在程序顺序视图里选中一个父节点时遍历逻辑变得非常复杂你不仅要处理操作还要处理方法组、几何体组等每个类型都要写一套查询逻辑。我自己的建议是先明确工具用途。如果只是提取操作信息过滤条件就只留UF_UI_ONT_TYPE_OPER如果还要处理程序组就再加上UF_UI_ONT_TYPE_PROGRAM。不要贪多。6.3 Open C和NXOpen C怎么选说实话如果项目只挂在比较高版本的NX上并且团队里对C比较熟悉我会推荐用NXOpen C。它的对象模型更清晰比如选中节点可以直接转成Operation对象然后调用GetName、GetProgram等成员函数可读性好很多。但Open C接口的优势在于“薄”和“稳”。它不依赖复杂的对象容器直接操作tag_t调用开销小而且在老版本NX之间移植的兼容性通常更好。很多老程序员写的CAM工具至今还是Open C因为那套代码在NX 6和NX 22开头的版本里都能编译运行这种兼容性是NXOpen C比不了的。这次用UF_UI_ONT_ask_selected_nodes加上UF_OPER系列函数做程序信息获取整体思路其实很直白先判断节点类型再拿tag_t再查具体属性。真正花时间的不是调用API而是处理各种“用户没按套路选中节点”的情况。我建议你拿到示例代码后先在测试零件上把程序组、操作、加工方法各种节点都选一遍看看每个类型返回的tag到底有哪些差异。跑通之后再做后续的信息导出、批量改名或者后处理联动就顺理成章了。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询