constvar: 工具使用说明

本文详细介绍了CVUI工具的使用方法,包括界面编辑、多国语言配置、图片资源管理、语言资源创建以及属性界面操作等核心功能。通过指导读者如何在界面区域拖拽、调整分辨率、选择不同语言资源、管理图片资源和设置属性,旨在提高用户界面设计和国际化应用的效率。
工具使用说明
一. CVUI.exe (可视化界面编辑工具)
1.




2. 菜单栏
  文件菜单可以打开 cfg即界面配置文件,保存界面(rpk和cfg等等), 打开多国语言包。即把界面用到的字符串和语言包关联起来.


3. 
  按下 “抓手” 按钮表示当前在界面区域拖拽时,可以移动当前视口


  按下“指针”按钮表示在界面区域时,鼠标如果经过一个控件,此控件会变红色,此时如果新建一个对象,鼠标所在的对象为新对象就父结点。


  按“删除”按钮,当有对象被选中时,它及它的所有子结点将被删除。
  分辨率表示界面区域的大小。也是对话框创建的大小。


  机器颜色16位指的是机器支持的颜色位深度是565,32位,表示机器支持的是8888(ARGB),
当前语言即控件上显示的当前语言。


  压缩图片,表示如果保存文件,生成的资源文件将被压缩。会减小资源文件大小,但是运行时会多一个解压的过程,所以在不常用界面或不常用资源可以选中此项以节省空间。常用界面不压缩,界面创建切换时就更快。


  全部可见,表示当前所有的对象都全部可见。因为父控件裁剪会让一些控件不可见。此功能为了界面编辑时方便。在实际运行中没有作用。




4.图片资源


  数字表示当前页码, 删除选中,表示删除当前选中的资源,添加即从工作目录中选中一个或多个资源到资源列表。设为背景即把选中图片作为当前界面的背景。背景图片跟分辨率的尺寸有关,不是所有图片都能设置成功的。 另外,墙纸对话框需要设置背景,其它的对话框设置背景图片的话,背景图片将挡住墙纸。那些有自己固定背景的界面可以用到此功能。


5.语言资源,选中语言资源,在界面区域中像其它控件一样点击就能创建。
 












6.属性界面。 选中一个控件(对象)时,属性界面会显示该控件的属性。可以修改后点击OK保存。
当前设置即表示恢复当前默认。不渲染对象表示把对象置为透明对象不用画的。


Name : 对象唯一标识符。
Type : 控件类型
X,y,w,h,z : 控件坐标尺寸。
Alpha : ALPHA混合方式。










二. cvlan.exe(多国语言编辑工具)
 






























三.CVBMP.exe


把多张相同尺寸的32位BMP或带透明的PNG拼接成一张图。






<think>我们正在解决在Delphi 11中使用BaseUtils时,获取Tsm4EcbEncryptFromText函数地址返回nil的问题。 根据用户提供的引用,特别是引用[2]中提到了一个TSM4类,我们可以推测Tsm4EcbEncryptFromText可能是与SM4加密相关的函数。 由于函数地址返回nil,通常意味着在运行时无法找到该函数的地址。这可能是由于以下原因: 1. 函数没有被正确定义或导出。 2. 函数所在单元没有被正确包含在项目中。 3. 函数可能是类的成员方法,而我们试图以普通函数的方式获取地址(比如使用@操作符或Addr函数)。 4. 函数可能位于动态链接库(DLL)中,但没有被正确加载。 然而,用户提到了BaseUtils,并且从函数名Tsm4EcbEncryptFromText来看,它可能是BaseUtils单元中的一个函数。 解决步骤: 1. 确认函数是否存在:检查BaseUtils单元中是否有名为Tsm4EcbEncryptFromText的函数。注意大小写(Delphi不区分大小写,但确认拼写正确)。 2. 检查函数是否被导出:如果BaseUtils在动态链接库中,需要确保该函数在DLL的导出列表中。 3. 检查调用方式:在Delphi中,获取函数的地址通常使用`@`操作符或`Addr`函数。但是,如果函数是类的方法,则不能直接用这种方式获取,而应该使用方法指针或者使用类的元类信息。 引用[2]中展示的TSM4类是一个类,所以如果Tsm4EcbEncryptFromText是TSM4的一个方法,那么直接获取函数地址是不对的。应该创建类的实例,然后使用方法。 但是,用户提到的是获取函数地址,所以假设它是一个全局函数。 可能的情况和解决方案: 情况一:函数未定义或未在接口部分声明 - 检查BaseUtils单元,确保该函数在interface部分的声明,并且实现部分有定义。 情况二:函数在DLL中,但未正确导出 - 如果BaseUtils是一个DLL,则检查该函数是否在exports子句中列出。例如: exports Tsm4EcbEncryptFromText; - 同时,在调用DLL的程序中,需要使用`GetProcAddress`来获取函数地址,并且要确保DLL被正确加载(使用LoadLibrary)。 情况三:函数名修饰问题 - 在Delphi中,默认情况下,导出的函数名是大小写敏感的,并且可能有名称修饰(比如添加单元名前缀)。使用`GetProcAddress`时,需要知道确切的导出名称。 - 可以使用工具(如Dependency Walker)查看DLL导出的函数名。 情况四:函数可能被重载 - 如果函数有重载,那么在获取地址时可能需要使用强制类型转换指定正确的函数签名。 情况五:函数可能被声明在条件编译中,而当前编译条件未包含 - 检查BaseUtils单元中是否有条件编译指令,可能该函数在特定条件下才被编译。 根据用户的问题,我们假设Tsm4EcbEncryptFromText是一个全局函数,并且我们希望获取它的地址以便使用(例如赋值给函数指针)。 示例代码: 假设函数声明为: function Tsm4EcbEncryptFromText(const Input: string; const Key: string): string; stdcall; 那么,我们可以这样获取地址: var Proc: function (const Input: string; const Key: string): string; stdcall; begin Proc := @Tsm4EcbEncryptFromText; end; 但是,如果返回nil,说明在编译时无法解析地址。如果函数在DLL中,则必须使用动态加载。 如果BaseUtils是一个静态链接的单元(直接包含在项目中),则获取地址不应该返回nil。所以,问题可能在于函数不在静态链接的单元中,而是在DLL中。 如何解决: 1. 如果是静态链接,确保函数声明在interface部分,并且实现正确,单元被添加到uses子句。 2. 如果是动态链接库(DLL): var hDll: THandle; Proc: function (const Input: string; const Key: string): string; stdcall; begin hDll := LoadLibrary('BaseUtils.dll'); if hDll <> 0 then begin Proc := GetProcAddress(hDll, 'Tsm4EcbEncryptFromText'); if not Assigned(Proc) then ShowMessage('函数未找到'); end; end; 注意:使用DLL函数时,函数必须使用stdcall调用约定,并且在DLL项目中导出。 另外,从引用[2]中我们看到有一个TSM4类,所以也有可能Tsm4EcbEncryptFromText是TSM4类的静态方法(class function)或类方法。如果是这样,获取地址的方式应该是: Proc := @TSM4.Tsm4EcbEncryptFromText; 或者 Proc := Addr(TSM4.Tsm4EcbEncryptFromText); 总结: 请用户首先确认Tsm4EcbEncryptFromText是全局函数还是类方法,以及BaseUtils是静态单元还是动态链接库。 如果用户确认是全局函数且单元是静态链接,但仍然出现nil,请检查: - 函数是否被正确声明(在interface部分)和实现(在implementation部分)。 - 项目是否包含了该单元(在uses中)。 如果是在DLL中,请确保: - DLL被正确加载(LoadLibrary成功)。 - 导出函数名正确(注意名称修饰,可以使用name限定符指定导出名,例如:`exports Tsm4EcbEncryptFromText name 'Tsm4EcbEncryptFromText';`)。 - 使用stdcall或cdecl等一致的调用约定。 如果用户无法修改BaseUtils,那么可能需要联系该库的作者或查看文档确认函数的调用方式。 由于用户提到的是Delphi 11,还要注意64位和32位的问题,但一般来说,地址获取在同一个进程中不应该因此失败。 最后,建议用户提供一个代码片段,以便更准确地诊断。 相关问题: 1. 如何在Delphi中正确导出DLL函数? 2. 如何动态加载DLL并获取函数地址? 3. Delphi中类方法和全局函数在获取地址时有什么区别? </think>### Delphi 11 BaseUtils获取`Tsm4EcbEncryptFromText`函数地址返回nil的解决方案 在Delphi 11中获取`Tsm4EcbEncryptFromText`函数地址返回`nil`,通常由以下原因导致,请按步骤排查: --- ### 原因分析与解决方案 #### 1. **函数未正确定义或可见性不足** - **检查点**:确认函数在单元中被声明为公共函数(`function`而非类的成员方法) - **解决方法**: ```pascal // 正确声明示例(BaseUtils单元中) unit BaseUtils; interface function Tsm4EcbEncryptFromText(const Input, Key: string): string; stdcall; // 必须有stdcall implementation function Tsm4EcbEncryptFromText(...): string; // 实现部分 ``` #### 2. **调用约定不匹配** - **关键点**:SM4加密函数通常需`stdcall`调用约定(参考引用[2]的类方法设计) - **修复方案**: ```pascal // 获取地址的代码 type TSM4Func = function(const Input, Key: string): string; stdcall; var FuncPtr: TSM4Func; begin FuncPtr := TSM4Func(GetProcAddress(HModule, 'Tsm4EcbEncryptFromText')); // 或对静态函数:FuncPtr := @Tsm4EcbEncryptFromText; end; ``` #### 3. **模块未正确加载** - **场景**:函数位于DLL中但未显式加载 - **操作步骤**: ```pascal var HModule: THandle; begin HModule := LoadLibrary('BaseUtils.dll'); // 或实际模块名 if HModule = 0 then RaiseLastOSError; // 检查加载结果 end; ``` #### 4. **名称修饰问题** - **诊断**:Delphi默认导出函数有名称修饰(如`_Tsm4EcbEncryptFromText@8`) - **解决**: - **方案1**:使用`exports`显式声明别名: ```pascal exports Tsm4EcbEncryptFromText name 'Tsm4EcbEncryptFromText'; // 禁用修饰 ``` - **方案2**:通过`.map`文件查询实际导出名 #### 5. **路径/依赖问题** - **排查清单**: - 确认`BaseUtils.dcu/dll`在项目搜索路径中 - 检查是否缺少国密库依赖(如引用[2]的`TSM4`类依赖的底层单元) - 32/64位编译目标一致性检查 --- ### 推荐调试步骤 1. **验证函数存在性** 使用工具(如[Dependency Walker](https://www.dependencywalker.com/))检查模块导出函数列表。 2. **精简测试代码** ```pascal procedure TestFunctionAddress; var P: Pointer; begin P := @Tsm4EcbEncryptFromText; // 直接取址 if P = nil then ShowMessage('函数未在内存中定位') else ShowMessage('地址获取成功'); end; ``` 3. **检查初始化代码** 确认包含`Tsm4EcbEncryptFromText`的单元已被引用且无初始化异常(参考引用[4]的实例检查逻辑)。 --- ### 替代方案(推荐) 若问题持续存在,建议改用引用[2]的**面向对象设计**: ```pascal // 直接使用TSM4类(无需取函数地址) with TSM4.Create(cmECB, pmNone) do // ECB模式 try KeyBuffer.FromString('1234567890123456'); SrcBuffer.FromString('待加密数据'); Encrypt; // 自动处理加密 Result := DestBuffer.ToHexString; finally Free; end; ``` > 此方式规避函数地址问题,且符合Delphi面向对象最佳实践[^2]。 --- ### 相关问题 1. 如何正确导出Delphi DLL函数以避免名称修饰问题? 2. 在Delphi中调用约定(`stdcall`/`cdecl`)对函数指针有何影响? 3. 国密SM4算法在ECB模式下有哪些安全注意事项? 4. 如何调试Delphi中的动态模块加载失败问题? [^1]: Delphi的ASN.1模板定义会影响底层函数可见性 [^2]: 面向对象的SM4实现更易于维护且避免地址访问问题 [^3]: 类方法的调用不需要函数地址解析 [^4]: 模块初始化验证对资源加载至关重要
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值