
欲看图文版pdf请电邮14518918qq.com。声明本笔记大量引用了AI对话内容。本笔记中的代码基于Windows 11 Visual Studio 2026 .NET 10.0验证。从CVI到C#有三个最关键的思维转变UI是代码不是资源Form1.Designer.cs 就是UI的“代码描述”它和你的业务逻辑代码Form1.cs共同组成一个完整的类。万物皆对象你操作的按钮、字符串、数组甚至错误信息都是“对象”有自己属性和方法。不再是CVI里那种“函数句柄”的分离感。编译器帮你做更多检查C#是强类型语言编译器会检查事件绑定、类型转换等更多错误。这让程序更健壮但也意味着你必须更严谨。如下是CVI与C#的核心概念对照表概念维度 CVI (ANSI C) 的习惯 C# (.NET) 的对应概念 关键区别与点拨程序入口 int main (void) static void Main(string[] args) C#入口在类里是静态方法。CVI的main是全局的。界面构建 拖拽控件生成.uir文件代码里用LoadPanel加载。 拖拽控件生成Form1.Designer.cs和.resx文件。 核心变化CVI的UI是资源文件.uir代码里通过句柄操作C#的UI是类代码.Designer.cs是程序的一部分编译在一起。事件响应 用SetCtrlAttribute或回调函数绑定比如InstallCtrlCallback(panel, PANEL_BUTTON, ButtonCallback, 0); 使用委托Delegate和事件Event如button1.Click Button1_Click; C#的事件是类型安全的方法指针更安全、更规范。CVI的回调更像函数指针。变量声明 int count; 在函数或文件作用域声明。 必须指定访问修饰符如private int count; C#更强调封装即使最简单的变量也要考虑它属于谁public/private。数组操作 固定大小数组int arr[10];通过索引访问。 数组是对象有属性Length还有ArrayList、List等集合。 C#的数组更“智能”集合类更强大但需要理解泛型等概念。字符串处理 字符数组char str[]使用strcpy、sprintf等函数。 string是基本类型直接支持、Contains()、Substring()等方法。 转变最大C#的字符串操作极其方便告别strcat和缓冲区溢出的烦恼。内存管理 手动malloc和free。 垃圾回收GC自动管理不再需要手动释放。 C#程序员很少直接写delete但需要了解GC对性能的影响如IDisposable。错误处理 检查返回值如-1或使用SetErrorHandler。 异常处理try-catch-finally强制处理或上抛。 C#强制你用try-catch能写出更健壮的程序但学习成本稍高。文件与资源 用fopen、fread等C标准库函数或IniFile等CVI专用函数。 使用System.IO命名空间下的类如File、StreamReader。 统一在System.IO下概念更统一功能更丰富。多线程 使用CmtScheduleThreadPoolFunction等CVI线程池函数。 使用System.Threading命名空间包含Thread、Task等。 C#的Task和async/await模型更现代、更易用但概念也更新。项目组织 项目文件.prj包含源文件、库、.uir文件。 解决方案.sln和项目文件.csproj分开。 C#用解决方案管理多个项目结构更清晰适合大工程。编译与部署 编译成.exe依赖CVI引擎库。 编译成.exe或.dll依赖.NET运行时.NET Framework/Core。 现代C#.NET Core/.NET 5支持自包含发布无需安装庞大引擎库。1 创建C#新项目在VS中为C#创建一个新项目选第一个.NET最新框架的winform应用模板。起一个项目名称QOSAEVB位置就是D:勾选“将解决方案和项目放在同一目录”。至此我们得到一个空面板的项目。同时在D:\QOSAEVB目录下得到一个C# winforms工程文件夹。为了用Git管理代码拷贝一个C#项目适用的.gitignore文件过来它规定了哪些文件和文件夹不用上传然后空白处右键选“Git Create repository here…”新增一个.git隐藏子目录。为了访问SQLite数据库还得把SQLite_QOSAEVB.db这个文件拷贝到工程文件夹。然后在VS右侧的解决方案资源管理器中选中这个.db并在右下角的属性窗设置“赋值到输出目录”为“如果较新则复制”。为了访问CH341接口的板子还得把CH341DLLA64.DLL和40GPOWER_A64_DLL.dll这两个文件拷贝到工程文件夹。然后在VS右侧的解决方案资源管理器中选中这两个DLL并在右下角的属性窗设置“复制到输出目录”为“如果较新则复制”。为了访问SQLite数据库需要给本工程添加一个包Microsoft.Data.Sqlite。在VS右侧的解决方案资源管理器中的“依赖项”点右键选“管理NuGet包”然后在左侧窗口的“浏览”标签页的搜索栏填入“Microsoft.Data.Sqlite”回车选中Microsoft.Data.Sqlite这一行点“安装”成功安装后就能在解决方案资源管理器中的“依赖项”下面的“包”中看到新增了一条“Microsoft.Data.Sqlite(10.0.0.11)”。至此项目框架搭建完成。2 CVI的uir界面移植在CVI2010中菜单Tools-- UI to Code Converter…可以将CVI的.uir面板保存为文本文件.tui。tui中保存有面板的全部面板、菜单栏、控件的几乎所有属性和.uir等价只是存储格式不同1、Panel面板窗口信息面板常量名PANEL生成 h 文件的宏名窗口位置、宽高、标题文字、背景色面板样式是否可缩放、是否标题栏、模态、初始显示状态、回调函数指针名称面板字体属性2、每一个控件完整信息按钮、LED、Graph、文本框、旋钮、列表等每个控件全部属性逐条记录控件 ID 常量名PANEL_BUTTON.h头文件的宏控件类型Button、LED、Numeric、Graph…控件 XY 坐标、宽高显示文本、标签、颜色、字体、可见 / 禁用状态回调函数名字符串 就是你填的回调函数名称例如ButtonCallback各类控件特有属性按钮样式、Graph 坐标轴设置、列表条目、热键、默认值等。向deepseek拖拽CVI的.tui文件要求AI转成C#格式的form1.cs和form1.designer.cs源代码然后手工覆盖到相应源文件后应该就能在VS中重新打开Form1.cs[设计]观察到AI还原的面板布局了。当然CVI和C#是两套IDE你还要干两件事处理Graph、Switch、LED、Table这类winforms没有的原生控件可换成C#工具箱中的Chart、RadioButton、PictureBox、DataGridView来替代最后把CVI的回调函数移植成C#的事件方法。注意面板属性的AutoScaleMode推荐配置成None即可关闭WinForms的自动缩放功能窗体、控件大小完全使用设计器写死的像素不跟随系统 DPI、系统字体大小自动放大缩小以避免exe跑在别人电脑上得Windows是高DPI时整套UI控件错位跑位。3 为访问硬件的DLL新增接口类为了方便调试DLL函数可以新建一个DLLProxy类把所有DLL函数都定义成public static extern的方法那么在form1.cs中就可以直接用DLLProxy.DLLFunctionName()这样的代码去调用这个类的静态方法CVI眼中的DLL函数。但也有三个缺点public static extern直接对外暴露底层原生 DLL 接口上层 UI 可以直接调用裸 P‑Invoke没有任何参数校验、异常捕获如果传非法句柄、错误参数直接底层 DLL 崩溃C# 层拦不住DLL缺失的时候第一次调用该函数瞬间抛出DllNotFoundException如果没有 try‑catch整个程序直接闪退。推荐调试跑通之后再重构将底层public static extern全部改为 private static extern不对外暴露再写一层普通public static C# 包装函数在包装函数里面做参数合法性检查、捕获 DLL 缺失异常、日志、错误码封装。先用public跑通再说右键点击VS右侧的“解决方案资源管理器”里的项目名添加一个类再另存为DLLProxy.cs。注意按照下面的格式构建文件头然后把跟硬件交互的 40GPOWER_A64_DLL.dll和CH341A_DLL.dll翻译成C#能看懂的接口把.h头文件给到AI就能得到。using System;using System.Runtime.InteropServices;namespace QOSAEVB // 注意这里的命名空间要和你的 Form1.cs 里一样{public class DLLProxy{//动态调用DLL函数头声明[DllImport(“CH341DLLA64.dll”, CallingConvention CallingConvention.StdCall)]public static extern ulong CH341GetVersion();//这里接着拷贝DLL函数头声明}4 为访问数据库的SQLite新增接口类为了方便管理SQLite数据库的读写还有数据跟面板控件的交互需要新开一个mySQLite.cs文件新建一个ConfigData类对应数据库config表单即配置数据和TestData类对应数据库result表单即测试数据。using System;using Microsoft.Data.Sqlite;namespace QOSAEVB // 注意这里的命名空间要和你的 Form1.cs 里一样{public class ConfigData{//这里填写属性和方法}public class TestData { //这里填写属性和方法 }}注意Microsoft.Data.Sqlite默认不是线程安全的多线程同时写入或读取同一个连接会报错。所以建议所有数据库操作必须通过同一个静态方法内部加锁。注意原先在CVI里面读到了外设数据随即就显示到界面的做法仅适用于CVI。C#编程并不推荐这样干要轻耦合最好是用事件通知机制来刷新界面。比如SerialPort.DataReceived事件在非UI线程即后台线程上触发。如果直接在事件处理函数中访问TextBox等控件会抛出异常InvalidOperationException。正确的做法是使用Control.Invoke或BeginInvoke将UI更新操作封送到UI线程执行。下面是经典的递归调用Invoke模式足以线程安全地更新任意控件的Text属性的实例////// 更新任意控件的Text属性线程安全///private void SafeSetText(Control ctrl, string text){// 步骤1检查当前线程是否拥有该控件的创建权if (ctrl.InvokeRequired){// 步骤2不在UI线程 → 通过Invoke在UI线程上“重新调用”本方法ctrl.Invoke(new Action(() SafeSetText(ctrl, text)));return;}// 步骤3已在UI线程 → 直接更新控件ctrl.Text text;}至此框架文件全部就位。再细心打磨就成功移植CVI2010MySQLCH341DLL到C#SQLiteCH341DLLA64了。附件是C#源码