基于C/C++的UG二次开发流程

文章目录

  • 基于C/C++的UG二次开发流程
    • [1 环境搭建](#1 环境搭建)
      • [1.1 新建工程](#1.1 新建工程)
      • [1.2 项目属性设置](#1.2 项目属性设置)
      • [1.3 添加入口函数并生成dll文件](#1.3 添加入口函数并生成dll文件)
      • [1.4 执行程序](#1.4 执行程序)
      • [1.5 ufsta入口](#1.5 ufsta入口)
        • [1.5.1 创建程序部署目录结构](#1.5.1 创建程序部署目录结构)
        • [1.5.2 创建菜单文件](#1.5.2 创建菜单文件)
        • [1.5.3 设置系统环境变量](#1.5.3 设置系统环境变量)
        • [1.5.4 制作对话框](#1.5.4 制作对话框)
        • [1.5.5 创建代码](#1.5.5 创建代码)
        • [1.5.6 部署和执行](#1.5.6 部署和执行)

基于C/C++的UG二次开发流程

1 环境搭建

UG/Open API(UG 开放应用程序接口),也称 User Function(用户函数,简称 UF)。

UF 的编程可以采用标准 C 或 C++两种方式作为开发语言(这里我们使用C++)。

针对程序运行的环境不同,UF 程序又分为外部 UF内部 UF 两种形式。

外部 UF 程序是可执行程序(*.EXE)。优点是不必启动 UG,属于后台运行,缺点是不能实现用户的交互操作。一般多用于 Part 文件大量创建、存取和管理或控制出图,而不适用于用户交互性的几何建模和修改。

内部 UF 是以**动态链接库(*.DLL)**的形式创建并编译的。UG 调用内部 UF 的方式有两种,一种是启动 UG 后,点击菜单:【文件】→【执行】→【NX 打开】,从中选择需要执行的 DLL 文件(程序入口点:ufusr),另一种则是从用户创建的菜单中(Menu Script)调出用户定制的界面(UI Styler)来运行(程序入口点:ufsta)。内部 UF在用户的交互、屏幕选取等的复杂操作上具有优势。

下文中我们主要介绍内部UF程序的开发。

1.1 新建工程

启动VS2022,由于是内部UF的开发,新建动态链接库(DLL)项目。

1.2 项目属性设置



复制代码
libufun.lib
libugopenint.lib
libvmathpp.lib
libnxopencpp.lib
libnxopenuicpp.lib

1.3 添加入口函数并生成dll文件

新建项目后,VS2022会默认生成framework.h、pch.h、pch.cpp、dllmain.cpp 文件。接下来我们只需要修改dllmain.cpp,修改后内容如下:

cpp 复制代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "uf.h"				// 包含常用 UF 函数的声明
#include "uf_modl.h"		// 包含建模相关的 UF 函数声明
#include "uf_ui.h"			// 包含界面操作相关的 UF 函数声明
#include <stdio.h>

#define UF_CALL(X) (report( __FILE__, __LINE__, #X, (X)))

// 用于程序调试
static int report(char* file, int line, char* call, int irc)
{
	if (irc)
	{
		char msg[133];
		printf("%s, line %d: %s\n", file, line, call);
		(UF_get_fail_message(irc, msg)) ?
			printf("returned a %d\n", irc) :
			printf("returned error %d: %s\n", irc, msg);
	}
	return(irc);
}

// 实际工作函数
static void do_ugopen_api(void)
{
	/* 用户在此编写自己的 UF 程序 */
	/* 下面示例为创建长方体 */
	UF_FEATURE_SIGN sign = UF_NULLSIGN;
	double block_orig[3] = { 0.0,0.0,0.0 }; // 原点
	char* block_len[3] = { "1","2","3" };	// 三边长
	tag_t blk_obj;
	UF_CALL(UF_MODL_create_block1(sign, block_orig, block_len, &blk_obj)); // 调用UF_MODL_create_block1函数创建长方体
}


void ufusr(char* param, int* retcode, int paramLen)
{
	if (!UF_CALL(UF_initialize()))//获取二次开发许可 
	{
		do_ugopen_api();//实际工作函数 
		UF_CALL(UF_terminate());//释放二次开发许可 
	}
	else
	{
		uc1601("获取开发许可失败,退出!", 1);//获取二次开发许可失败,提示用户 
	}
}

// 卸载函数
int ufusr_ask_unload(void)
{
	return (UF_UNLOAD_IMMEDIATELY);//完成操作后立即从内存中卸载
}

修改属性页,将符合模式改为 ,防止编译运行报错"const char *" 类型的实参与 "char *" 类型的形参不兼容

参考文章:「VS」"const char *" 类型的实参与 "char *" 类型的形参不兼容

最后点击运行,即可得到内部UF的dll文件。

1.4 执行程序

打开UG,新建一个part文件。Ctrl+U打开上一步生成的DLL文件(test.dll )。UG 会执行此动态库中的入口函数ufusr,在 UG 建模工作区中生成一个长方体。

1.5 ufsta入口

在上面我们执行内部UF程序的方法是从ufusr入口进入(即Ctrl+U执行DLL文件),接下来我们介绍从ufsta入口进入的方法(即UI交互执行对应回调函数)。

1.5.1 创建程序部署目录结构

首先创建一个工作目录,其中分别再创建两个子目录"startup"和"application"。前者用来存放菜单文件(*.men )和动态库文件(*.dll ),后者存放对话框文件(*.dlg )。
-

1.5.2 创建菜单文件

startup目录下创建一个菜单文件(test_ufsta.men),内容如下:

复制代码
VERSION 120
EDIT UG_GATEWAY_MAIN_MENUBAR
HIDE UG_HELP
!一级菜单编辑,在帮助菜单后
BEFORE UG_HELP
 CASCADE_BUTTON MENU_TestUfsta
 LABEL TestUfsta
END_OF_BEFORE 
!二级菜单编辑
MENU MENU_TestUfsta 
 BUTTON BUTTON_TestUfsta 
 LABEL 测试ufsta 
 ACTIONS TestUfsta.dlg
END_OF_MENU
1.5.3 设置系统环境变量

新建一个环境变量UGII_USER_DIR,将上面的程序工作目录作为值。

新建完成后,打开UG,点击菜单,即可得到我们想要的效果。

如果出现中文乱码的问题,将men文件采用ANSI 编码保存即可解决。

1.5.4 制作对话框

UG中提供了UI Styler模块用于制作对话框UI,支持图形化操作,自动生成代码框架(类似于Qt Designer)。该模块的打开方式如下(需要先打开一个部件):

我们便可以得到一个最基础的对话框,左下角为预览效果,左上角为控件对象层级树,右边为控件对象属性。

点击界面上方工具栏中的按钮,即可在对话框中添加一个按钮。

接着我们将按钮的标签更改成一个我们想要名称,最后点击保存,选择使用的语言(这里选择C++),文件名为TestUfsta.dlg,保存到application目录下,

  • xxx.dlg。对话框资源文件。

  • xxx.hxx。对此对话框编程使用的头文件。

  • xxx_template.c。对此对话框编程使用的代码框架。

1.5.5 创建代码

和ufusr入口一样,新建一个命名为TestUfsta 的DLL工程,将上一步生成的xxx.h文件拷贝到工程目录下,再将xxx_template.c文件中的一个宏定义和两个静态变量,以及ufsta(UF 的入口点)、CHANGE_apply_cb(对话框上【apply】按钮的回调函数)、CHANGE_action_0_act_cb(对话框上用户定制的【创建长方体】按钮的回调函数)三个函数复制到TestUfsta.cpp中。修改后内容如下:

cpp 复制代码
#include <stdio.h> 
#include <uf.h> 
#include <uf_defs.h> 
#include <uf_exit.h> 
#include <uf_ui.h> 
#include <uf_styler.h> 
#include <uf_mb.h> 
#include <stdio.h>
#include <uf_modl.h>
#include "TestUfsta.h"

#define CHANGE_CB_COUNT ( 2 + 1 ) /* Add 1 for the terminator */
#define UF_CALL(X) (report( __FILE__, __LINE__, #X, (X)))

// 用于程序调试
static int report(char* file, int line, char* call, int irc)
{
    if (irc)
    {
        char msg[133];
        printf("%s, line %d: %s\n", file, line, call);
        (UF_get_fail_message(irc, msg)) ?
            printf("returned a %d\n", irc) :
            printf("returned error %d: %s\n", irc, msg);
    }
    return(irc);
}

// 实际工作函数
static void do_ugopen_api(void)
{
    /* 用户在此编写自己的 UF 程序 */
    /* 下面示例为创建长方体 */
    UF_FEATURE_SIGN sign = UF_NULLSIGN;
    double block_orig[3] = { 0.0,0.0,0.0 }; // 原点
    char* block_len[3] = { "1","2","3" };	// 三边长
    tag_t blk_obj;
    UF_CALL(UF_MODL_create_block1(sign, block_orig, block_len, &blk_obj)); // 调用UF_MODL_create_block1函数创建长方体
}

static UF_STYLER_callback_info_t CHANGE_cbs[CHANGE_CB_COUNT] =
{
 {UF_STYLER_DIALOG_INDEX, UF_STYLER_APPLY_CB        , 0, CHANGE_apply_cb},
 {CHANGE_ACTION_0       , UF_STYLER_ACTIVATE_CB     , 0, CHANGE_action_0_act_cb},
 {UF_STYLER_NULL_OBJECT, UF_STYLER_NO_CB, 0, 0 }
};

static UF_MB_styler_actions_t actions[] = {
    { "TestUfsta.dlg",  NULL,   CHANGE_cbs,  UF_MB_STYLER_IS_NOT_TOP },
    { NULL,  NULL,  NULL,  0 } /* This is a NULL terminated list */
};

extern void ufsta(char* param, int* retcode, int rlen)
{
    int  error_code;

    if ((UF_initialize()) != 0)
        return;

    if ((error_code = UF_MB_add_styler_actions(actions)) != 0)
    {
        char fail_message[133];

        UF_get_fail_message(error_code, fail_message);
        printf("%s\n", fail_message);
    }

    UF_terminate();
    return;
}

int CHANGE_apply_cb(int dialog_id,
    void* client_data,
    UF_STYLER_item_value_type_p_t callback_data)
{
    /* Make sure User Function is available. */
    if (UF_initialize() != 0)
        return (UF_UI_CB_CONTINUE_DIALOG);

    /* ---- Enter your callback code here ----- */

    UF_terminate();

    /* Callback acknowledged, do not terminate dialog                 */
    /* A return value of UF_UI_CB_EXIT_DIALOG will not be accepted    */
    /* for this callback type.  You must respond to your apply button.*/
    return (UF_UI_CB_CONTINUE_DIALOG);

}

int CHANGE_action_0_act_cb(int dialog_id,
    void* client_data,
    UF_STYLER_item_value_type_p_t callback_data)
{
    /* Make sure User Function is available. */
    if (UF_initialize() != 0)
        return (UF_UI_CB_CONTINUE_DIALOG);

    /* ---- Enter your callback code here ----- */
    do_ugopen_api();

    UF_terminate();

    /* Callback acknowledged, do not terminate dialog */
    return (UF_UI_CB_CONTINUE_DIALOG);

    /* or Callback acknowledged, terminate dialog.    */
    /* return ( UF_UI_CB_EXIT_DIALOG );               */

}

运行生成DLL。

对于VS2022,新建DLL工程后会默认生成和使用pch.h作为预编译头文件,为了不必要的麻烦,我们将工程属性设置为不使用预编译头文件,即可删除pch相关的文件。

1.5.6 部署和执行

将所生成的DLL文件拷贝到startup目录下,打开UG即可成功运行。

相关推荐
Logic1011 小时前
C程序设计(第五版)谭浩强 第七章课后习题优化算法与核心步骤解析
c语言·visualstudio·程序员·学习笔记·软件开发·编程基础·c语言入门
青春pig头少年2 小时前
决战408:计网大题我啃啃啃
计算机网络·学习笔记·408
map_3d_vis2 小时前
JSAPIThree 加载单体三维模型学习笔记:SimpleModel 简易加载方式
学习笔记·three.js·gltf·glb·初学者·三维模型·mapvthree·jsapithree·simplemodel
青春pig头少年5 小时前
决战408:OS大题我拿拿拿(非PV)
操作系统·学习笔记·408
Logic1011 天前
《Mysql数据库应用》 第2版 郭文明 实验5 存储过程与函数的构建与使用核心操作与思路解析
数据库·sql·mysql·学习笔记·计算机网络技术·形考作业·国家开放大学
全栈小51 天前
【数据库】浙人医携手金仓数据库,打造全国首个多院区异构多活容灾架构
数据库·1024程序员节·金仓
Logic1011 天前
《Mysql数据库应用》 第2版 郭文明 实验1 在MySQL中创建数据库和表核心操作与思路解析
数据库·sql·mysql·学习笔记·计算机网络技术·形考作业·国家开放大学
一马平川的大草原2 天前
AI Agent常见问题和核心术语
人工智能·学习笔记·agent
Logic1013 天前
《Mysql数据库应用》 第2版 郭文明 实验6 数据库系统维护核心操作与思路解析
数据库·sql·mysql·学习笔记·计算机网络技术·形考作业·国家开放大学
CoderYanger3 天前
贪心算法:7.最长连续递增序列
java·算法·leetcode·贪心算法·1024程序员节