1.添加 Dialog 资源(普通 DLL 中创建对话框,可视化操作)
普通 DLL 项目添加 Dialog 资源和 BRX 模板项目操作一致,全程可视化,无需手动写复杂脚本:
1.1 添加资源脚本文件(.rc)
- 右键项目名称 →「添加」→「新建项」;
- 左侧切换「Visual C++」→「资源」,右侧选择「资源脚本 (.rc)」;
- 文件名填写
Resource.rc(默认即可),点击「添加」; - VS 自动生成
Resource.rc(资源脚本)和resource.h(资源 ID 管理),在「解决方案资源管理器」中可见。
1.2 新建 Dialog 资源(可视化创建)
- 双击「Resource.rc」,打开「资源视图」(若未显示:点击「视图」→「其他窗口」→「资源视图」);
- 在「资源视图」中,右键
Resource.rc→「添加资源」; - 弹出「添加资源」窗口,选择「Dialog」→ 点击「新建」;
- VS 自动创建默认对话框(ID:
IDD_DIALOG1),并打开可视化对话框编辑器。
1.3 修改 Dialog 属性(匹配立方体参数需求)
- 选中对话框(点击标题栏 / 空白区域,不选中内部按钮),按
F4调出「属性窗口」; - 逐一修改以下属性(确保后续代码能识别):
- ID:删除默认
IDD_DIALOG1,输入IDD_DIALOG_CUBE_PARAM(自定义唯一标识); - Caption:输入
创建立方体参数(对话框标题,显示中文); - Font:下拉选择「Microsoft YaHei UI」,字号「9」(避免中文字体乱码);
- Width:250(对话框宽度),Height:180(对话框高度)(属性窗口「布局」分类下);
- Style:保持「Popup」+「Dialog Frame」(弹窗样式,默认即可);
- ID:删除默认
- 点击「文件」→「保存」,暂不关闭对话框编辑器。
1.4 添加 Dialog 控件(编辑框 + 标签,实现参数输入)
- 调出「工具箱」(若未显示:
Ctrl+Alt+X,或「视图」→「工具箱」); - 添加 3 个「Static Text」(静态标签,说明文字):
- 第 1 个标签:
- 拖拽到对话框内,选中后按
F4打开属性; - Caption:
长度:,ID:保留IDC_STATIC(无需修改); - 布局位置:
X=20,Y=30(属性窗口「布局」分类下);
- 拖拽到对话框内,选中后按
- 第 2 个标签:
- Caption:
宽度:,布局位置:X=20,Y=70;
- Caption:
- 第 3 个标签:
- Caption:
高度:,布局位置:X=20,Y=110;
- Caption:
- 第 1 个标签:
- 添加 3 个「Edit Control」(编辑框,输入长宽高):
- 第 1 个编辑框(对应长度):
- 拖拽到对话框内,选中后按
F4打开属性; - ID:
IDC_EDIT_LENGTH(自定义唯一 ID,后续代码调用); - 勾选「Auto HScroll」(自动横向滚动,优化输入体验);
- 布局位置:
X=70,Y=30,尺寸:Width=150,Height=20;
- 拖拽到对话框内,选中后按
- 第 2 个编辑框(对应宽度):
- ID:
IDC_EDIT_WIDTH,布局位置:X=70,Y=70,尺寸同前;
- ID:
- 第 3 个编辑框(对应高度):
- ID:
IDC_EDIT_HEIGHT,布局位置:X=70,Y=110,尺寸同前;
- ID:
- 第 1 个编辑框(对应长度):
- 保留默认「确定」「取消」按钮(BricsCAD 识别默认 ID
IDOK/IDCANCEL):- 「确定」按钮:位置
X=60,Y=145,尺寸60×25; - 「取消」按钮:位置
X=130,Y=145,尺寸60×25;
- 「确定」按钮:位置
- 调整完成后,点击「文件」→「保存全部」,VS 自动更新
Resource.rc和resource.h。
1.5 验证资源 ID(确保resource.h自动生成)
双击打开resource.h,确认以下 ID 已自动添加(VS 自动生成,无需手动编写,数值可不同,名称一致即可):
#ifndef RESOURCE_H #define RESOURCE_H #define IDD_DIALOG_CUBE_PARAM 101 #define IDC_EDIT_LENGTH 1001 #define IDC_EDIT_WIDTH 1002 #define IDC_EDIT_HEIGHT 1003 #define IDC_STATIC -1 #endif // RESOURCE_H2. 一段代码示例
#include "StdAfx.h" #include "Box.h" #include "resource.h" #include <windows.h> #include <tchar.h> // 全局变量:保存插件自身模块句柄(用于获取对话框资源) static HMODULE g_hPluginModule = NULL; // 全局结构体:存储立方体参数 typedef struct { double dLength; // 长度 double dWidth; // 宽度 double dHeight; // 高度 BOOL bDialogActive; // 对话框是否激活 HWND hDialog; // 对话框句柄 } CubeParamStruct; // 全局变量:初始化默认参数(100×100×100) static CubeParamStruct g_CubeParam = { 100.0, 100.0, 100.0, FALSE, NULL }; // 对话框过程函数(非模态) INT_PTR CALLBACK CubeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //对话框句柄、消息类型、消息的附加细节(如控件ID和通知码) { switch (uMsg) //判断消息类型 { // 对话框初始化 case WM_INITDIALOG: { g_CubeParam.hDialog = hDlg; g_CubeParam.bDialogActive = TRUE; // 初始化编辑框显示默认值 TCHAR szValue[64]; _stprintf_s(szValue, _T("%.2f"), g_CubeParam.dLength); SetDlgItemText(hDlg, IDC_EDIT_LENGTH, szValue); _stprintf_s(szValue, _T("%.2f"), g_CubeParam.dWidth); SetDlgItemText(hDlg, IDC_EDIT_WIDTH, szValue); _stprintf_s(szValue, _T("%.2f"), g_CubeParam.dHeight); SetDlgItemText(hDlg, IDC_EDIT_HEIGHT, szValue); return TRUE; } // 按钮点击消息处理 case WM_COMMAND: { switch (LOWORD(wParam)) { // 确定按钮(创建立方体) case IDOK: { TCHAR szBuffer[64]; // 读取编辑框参数 GetDlgItemText(hDlg, IDC_EDIT_LENGTH, szBuffer, 64); g_CubeParam.dLength = _tstof(szBuffer); GetDlgItemText(hDlg, IDC_EDIT_WIDTH, szBuffer, 64); g_CubeParam.dWidth = _tstof(szBuffer); GetDlgItemText(hDlg, IDC_EDIT_HEIGHT, szBuffer, 64); g_CubeParam.dHeight = _tstof(szBuffer); // 合法性校验 if (g_CubeParam.dLength <= 0.001 || g_CubeParam.dWidth <= 0.001 || g_CubeParam.dHeight <= 0.001) { MessageBox(hDlg, _T("长宽高必须大于0.001!"), _T("错误"), MB_OK | MB_ICONERROR); return TRUE; } // 创建立方体 try { Box::createBoxSolid( g_CubeParam.dLength, g_CubeParam.dWidth, g_CubeParam.dHeight, AcGeVector3d(100, 100, 100), 1 // 红色 ); acutPrintf(_T("\n* 立方体创建成功!尺寸:%.2f×%.2f×%.2f"), g_CubeParam.dLength, g_CubeParam.dWidth, g_CubeParam.dHeight); } catch (...) { MessageBox(hDlg, _T("创建立方体失败!"), _T("错误"), MB_OK | MB_ICONERROR); } return TRUE; } // 取消按钮(关闭对话框) case IDCANCEL: { DestroyWindow(hDlg); g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; return TRUE; } } break; } // 对话框关闭消息 case WM_CLOSE: DestroyWindow(hDlg); g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; return TRUE; case WM_DESTROY: g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; return TRUE; } return FALSE; } // 插件核心类:继承 AcRxArxApp 基类(BRX 模板规范) class CubePlugin : public AcRxArxApp { public: // 构造函数:调用父类构造,初始化插件基础信息 CubePlugin() : AcRxArxApp() {} // 服务器组件注册:空实现(满足 BRX 框架要求,无复杂组件需注册) virtual void RegisterServerComponents() { } // 插件加载时触发:初始化配置 + 打印提示信息 virtual AcRx::AppRetCode On_kInitAppMsg(void* pAppData) { // 调用父类默认初始化,完成底层绑定 AcRx::AppRetCode result = AcRxArxApp::On_kInitAppMsg(pAppData); // 配置插件支持多文档 + 允许运行时卸载 acrxRegisterAppMDIAware(pAppData); acrxUnlockApplication(pAppData); // 打印加载成功提示 acutPrintf(_T("\n* 立方体 DLL 插件加载成功!")); acutPrintf(_T("\n* 可用命令:BCreateCube、CubeDlg")); return result; } // 插件卸载时触发:清理命令 + 关闭对话框 virtual AcRx::AppRetCode On_kUnloadAppMsg(void* pAppData) { // 清理已打开的对话框 if (g_CubeParam.bDialogActive && g_CubeParam.hDialog && IsWindow(g_CubeParam.hDialog)) { DestroyWindow(g_CubeParam.hDialog); } g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; // 调用父类默认卸载逻辑 return AcRxArxApp::On_kUnloadAppMsg(pAppData); } // 其他生命周期方法:空实现(保证类的完整性,满足 BRX 框架要求) virtual AcRx::AppRetCode On_kLoadDwgMsg(void* pAppData) { return AcRxArxApp::On_kLoadDwgMsg(pAppData); } virtual AcRx::AppRetCode On_kUnloadDwgMsg(void* pAppData) { return AcRxArxApp::On_kUnloadDwgMsg(pAppData); } // BRX 命令1:快速创建默认立方体(静态成员函数,符合 BRX 命令规范) static void CubePluginBCreateCube(void) { Box::createBoxSolid(100.0, 100.0, 100.0, AcGeVector3d(100, 100, 100), 1); acutPrintf(_T("\n* 默认立方体创建成功!(尺寸:100×100×100)")); } // BRX 命令2:打开参数对话框(静态成员函数,符合 BRX 命令规范) static void CubePluginCubeDlg(void) { // 若对话框已打开,直接激活 if (g_CubeParam.hDialog && IsWindow(g_CubeParam.hDialog) && g_CubeParam.bDialogActive) { SetForegroundWindow(g_CubeParam.hDialog); ShowWindow(g_CubeParam.hDialog, SW_SHOW); return; } // 获取BricsCAD主窗口句柄(兜底使用桌面窗口) HWND hWndAcad = adsw_acadMainWnd(); if (hWndAcad == NULL) { hWndAcad = GetDesktopWindow(); } // 创建非模态对话框 HWND hDlg = CreateDialogParam( g_hPluginModule, MAKEINTRESOURCE(IDD_DIALOG_CUBE_PARAM), hWndAcad, CubeDlgProc, 0 ); if (hDlg == NULL) { acutPrintf(_T("\n* 错误:无法创建对话框!错误代码:%d"), GetLastError()); return; } // 显示对话框 ShowWindow(hDlg, SW_SHOW); UpdateWindow(hDlg); // 更新全局变量 g_CubeParam.hDialog = hDlg; g_CubeParam.bDialogActive = TRUE; } }; // 关键入口宏:告诉 BRX 框架核心插件类(无法省略) IMPLEMENT_ARX_ENTRYPOINT(CubePlugin) // DLL 入口函数:保存插件模块句柄 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // 插件加载时,保存自身模块句柄 g_hPluginModule = hModule; break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // 命令1:自动注册 BCreateCube(遵循 BRX 模板自动注册宏规范) ACED_ARXCOMMAND_ENTRY_AUTO(CubePlugin, CubePlugin, BCreateCube, BCreateCube, ACRX_CMD_TRANSPARENT, NULL) // 命令2:自动注册 CubeDlg(遵循 BRX 模板自动注册宏规范) ACED_ARXCOMMAND_ENTRY_AUTO(CubePlugin, CubePlugin, CubeDlg, CubeDlg, ACRX_CMD_TRANSPARENT, NULL)3. 对代码进行解释
3.1 关于对话框消息处理函数(回调函数)
Windows 系统会在对话框有事件发生(比如点击按钮、关闭窗口)时,自动调用这个函数,并把相关信息通过这四个参数传递给你,让你决定如何处理这些事件。
逐个拆解参数含义
函数原型:
INT_PTR CALLBACK CubeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)1.HWND hDlg
- 类型:
HWND= Handle to Window(窗口句柄),是 Windows 给每个窗口 / 对话框分配的唯一 “身份证号”。 - 含义:这个参数指向当前触发消息的对话框窗口本身。
- 实际用途:你可以通过这个句柄操作对话框,比如:
- 给对话框里的编辑框设置内容(
SetDlgItemText(hDlg, IDC_EDIT1, "内容")); - 关闭这个对话框(
EndDialog(hDlg, IDOK)); - 获取对话框中控件的句柄(
GetDlgItem(hDlg, IDC_BUTTON1))。
- 给对话框里的编辑框设置内容(
- 通俗类比:相当于你收到了一封信,
hDlg就是信封上写的 “收件人地址”,告诉你这是给哪个对话框的消息。
2.UINT uMsg
- 类型:
UINT= Unsigned Integer(无符号整数),本质是 Windows 定义的消息常量。 - 含义:这个参数是消息类型,告诉函数 “发生了什么事”。Windows 预定义了大量消息常量,每个常量对应一个具体事件。
- 常见取值示例:
消息常量 含义 WM_INITDIALOG对话框刚创建、初始化时触发 WM_COMMAND用户点击了按钮 / 菜单等控件 WM_CLOSE用户点击了对话框的关闭按钮 WM_DESTROY对话框即将被销毁时触发 - 实际用途:你会在函数里用
switch(uMsg)分支判断消息类型,然后针对性处理。 - 通俗类比:相当于信封里的 “事件说明”,比如 “有人按了确认按钮”“要关闭窗口了”。
3.WPARAM wParam
- 类型:
WPARAM= Window Parameter(窗口参数),本质是一个 32/64 位的整数(根据系统位数)。 - 含义:消息的附加参数 1,具体值取决于
uMsg的类型 —— 不同的消息,wParam承载的信息不同。 - 常见示例:
- 当
uMsg = WM_COMMAND时,wParam的低 16 位是控件 ID(比如点击的按钮 IDIDC_BUTTON_OK),高 16 位是通知码(比如BN_CLICKED表示按钮被点击); - 当
uMsg = WM_KEYDOWN时,wParam是按下的键盘按键码(比如VK_ENTER表示回车键);
- 当
- 通俗类比:相当于事件说明的 “补充细节 1”,比如 “按了确认按钮” 这个事件里,
wParam告诉你 “是 ID 为 1001 的那个确认按钮”。
4.LPARAM lParam
- 类型:
LPARAM= Long Parameter(长参数),也是 32/64 位整数,和WPARAM是一对 “搭档参数”。 - 含义:消息的附加参数 2,同样取决于
uMsg的类型,通常承载更复杂的信息(比如指针、坐标、控件句柄等)。 - 常见示例:
- 当
uMsg = WM_COMMAND时,lParam是触发事件的控件句柄(比如被点击按钮的句柄); - 当
uMsg = WM_MOUSEMOVE时,lParam的低 16 位是鼠标 X 坐标,高 16 位是 Y 坐标; - 当
uMsg = WM_INITDIALOG时,lParam可能携带创建对话框时传递的自定义数据;
- 当
- 通俗类比:相当于事件说明的 “补充细节 2”,比如 “按了确认按钮” 这个事件里,
lParam告诉你 “这个按钮的具体句柄是多少”。
补充:函数返回值和修饰符
为了让你理解更完整,额外说明函数头部的其他标识:
INT_PTR:函数返回值类型,通常返回TRUE/FALSE或特定值(比如处理了消息返回TRUE,未处理返回FALSE,让系统默认处理);CALLBACK:是 Windows 定义的宏,本质是__stdcall,指定函数的调用约定(参数传递、栈清理的规则),确保系统能正确调用这个回调函数。
实战示例(帮你理解参数配合使用)
下面是一个简化的CubeDlgProc实现,直观展示参数如何配合:
INT_PTR CALLBACK CubeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: // 对话框初始化 // 用hDlg(对话框句柄)给编辑框设置初始内容 SetDlgItemText(hDlg, IDC_EDIT1, "请输入内容"); return TRUE; // 表示处理了这个消息 case WM_COMMAND: // 控件事件 // wParam低16位是控件ID,HIWORD/LOWORD是提取高低位的宏 int nCtrlID = LOWORD(wParam); int nNotifyCode = HIWORD(wParam); HWND hCtrl = (HWND)lParam; // lParam是控件句柄 if (nCtrlID == IDC_BUTTON_OK && nNotifyCode == BN_CLICKED) { // 点击了“确认”按钮,用hDlg操作对话框 MessageBox(hDlg, "你点击了确认按钮", "提示", MB_OK); EndDialog(hDlg, IDOK); // 关闭对话框 return TRUE; } break; case WM_CLOSE: // 关闭对话框 EndDialog(hDlg, IDCANCEL); return TRUE; } // 未处理的消息,交给系统默认处理 return FALSE; }总结
hDlg:当前对话框的 “身份证”(句柄),用于操作对话框本身;uMsg:核心消息类型,告诉函数 “发生了什么事”(初始化、点击按钮、关闭等);wParam/lParam:消息的附加细节,不同消息对应不同含义,是处理具体事件的关键;- 四个参数由 Windows 系统自动传递,你只需在函数里根据
uMsg判断类型,结合wParam/lParam处理逻辑,再通过hDlg操作对话框。