基于C#实现非托管 DLL 的计算器程序设计
♻️ 资源大小1.41MB➡️资源下载https://download.csdn.net/download/s1t16/87453210基于非托管 DLL 的计算器程序设计摘要本次实验选取的内容为基于 DLL动态链接库和.NET 平台的计算器程序设计采用的编程语言为 C#负责界面的设计以及 C负责计算方法的实现也是理论课程中所讲述的非托管代码技术。本次计算器主要实现了基本的四则运算同时添加了部分高级功能例如幂运算、阶乘运算等。此外回退、清空等功能也保证了程序具有一定的人机交互性。计算方式采用新型计算器的表达式处理方式核心技术是利用数据结构中栈的相关操作实现中缀表达式转后缀表达式、再对后缀表达式进行处理。关键词非托管代码、动态链接库、表达式转换、数据结构实验的目的和意义实验目的本次实验的目的是利用理论课程中所讲述的关于动态链接库的相关知识通过托管或非托管代码技术实现在.NET 平台上的动态链接库的调用进一步从实际程序发开中体会到动态链接库的运作原理以及程序项目的结构。基于此的同时尝试自行设计一个计算器程序意在培养学生基本的程序设计与开发能力。实验意义本次实验的主要意义在于落实课程中所学到的动态链接库相关知识在理解动态链接库运行机制的同时学会在实践中使用在实际的编程环境中体会其功能的优越性以及存在的不足性同时也培养了自己的程序开发能力。实验的相关理论基础动态链接库动态链接库Dynamic Link LibraryDLL是 Windows 系统中非常有效的运行机制通用功能的函数和数据聚集在 DLL 文件中。DLL 减少程序文件的大小和对内存空间的需求又使公共函数在多个应用程序之间共享。DLL 文件是独立编译和测试的多种编程语言和编译器都支持生成和使用 DLL不同编程语言生成的 DLL 还可以相互调用。托管代码与非托管代码托管代码与非托管代码是微软针对运行中的 windows 程序与公共语言运行库的关系进行的一种划分。托管代码由公共语言运行库环境而不是直接由操作系统执行的代码。托管代码应用程序可以获得公共语言运行库服务例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。非托管代码非托管代码与公共语言运行库环境无关。编写这些程序代码使用专用语言编译工具如 C 与 VB生成的是机器可以直接执行的二进制代码在这些程序中用户必须自己提供内存的申请和释放要保证指针引用的正确性进行类型检查等功能稍有不慎即容易发生地址越界内存泄露等错误而且机器也难由这些错误中恢复回来。逆波兰式也称为后缀表达式由于计算机与人计算思维的不同对于人来说简单的中值表达式在计算机中运行却较为困难但如果将中缀表达式处理成后缀表达式后便可以利用栈的相关操作来解决表达式计算问题。实验设计实验环境本次实验环境为 Windows10 企业版 2016编程工具为 Visual Studio 2017。实验设计思路本次实验基于非托管代码技术即采用的是 C#中调用 C 生成的动态链接库来实现具体的功能。主要分为两部分第一部分是在利用 C#中的 WinForm 程序设计基本的计算器界面主要是通过与用户交互得到需要计算的目标表达式并将目标表达式交给 DLL 中的函数处理第二是基于 C 生成的 DLL 文件来处理目标表达式并将求得的具体值返回给用户。设计思想类似于 B\S 风格的软件结构。实验关键点生成动态链接库先创建一个 C#的 WinForm 工程在解决方案中添加新项目如下图一 创建 DLL 文件在其中的头文件GetResult.h中定义所需要的函数名在源文件GetResult.cpp中定义函数的具体实现方法同时生成一个模块定义文件GetResult.def对 DLL 中的函数进行定义。相关函数定义在 GetResult.h 中自定义了一个栈类型同时定义了基本的出栈、入栈等操作将中缀表达式转后缀表达式trans和后缀表达式计算compvalue定义为动态链接库调用函数图二 动态链接库头文件声明其中 trans 函数具体实现思路为对操作符和数字分开处理如果是操作符需要判断优先级优先级高者入栈如果是数字则直接将其装入后缀表达式数组中用“#”作为结束的识别标志。此外需要强调一下对于减号运算来说存在双目减和单目减这里需要分析减号的性质对于单目减号需要在减号后面的数字进栈之前先压一个 0 入栈例如将-6 改为0-6即将单目运算改为双目运算从而实现不同的效果见图十。部分代码如下图三 转换函数中的括号处理图四 转换函数中的操作符处理“”代表后缀表达式求值函数 compvalue 实现思路利用栈对后缀表达式做相关处理每次取数字压入栈中根据不同操作符决定是否弹出然后根据不同操作符进行不同运算再将新值作为新的代操作数压入栈直到整个表达式处理完毕。部分代码如下图五 操作符运算实现“”代表图六 对字符串数字的转换分为小数和整数C#中调用定义在 C#中主要是通过 using System.Runtime.InteropServices 来定义 DLL 的引用路径以及函数入口然后再在具体位置调用即可。这里同时还对 DLL 中的异常做了相关处理见图八存在问题见 4.2。图七 DLL 文件的引用定义图八 调用 DLL 函数的实现WinForm 界面的设计通过简单的控件拖拽以及双击鼠标生成的事件处理等来完善 WinForm设计界面如图包含了输入框、输出框、四则运算、幂运算、阶乘运算、百分号等以及支持回退清零等功能。图九 WinForm 界面设计运行结果演示图十 进行掺杂括号、浮点数以及正负号的混合表达式计算图十一 幂运算和阶乘的表达式计算此外还增加了一个除零错误处理即在 C#中通过对 DLL 中的异常进行捕获来实现异常处理这个功能存在问题详情见下文效果如下图图十二 除零错误演示实验总结功能方面本次实验采用非托管代码技术成功的通过在 C#中调用 DLL 中的 C 函数实现了计算器程序的设计和开发在满足了实验项目的必须要求和拓展要求之外又添加了幂运算和阶乘运算高级功能同时这种表达式计算方式的计算器极大程度上优于以前那种一次只能计算两个值的计算器而表达式的回退和清零功能又方便用户及时的修改。总的来说是一次相对不错的任务完成。存在不足该实验存在的最大不足是关于错误异常处理由于.NET 的内部机制在.NET4.0 之后 CLR 就不在支持 SEHException 的检测即在 C#中无法捕获到 DLL 中抛出的异常需要在 App.config 文件中插入如下片段或者在函数前面加上[HandleProcessCorruptedStateExceptions]的声明标识符。另一个问题是本人目前还无法实现对 C 异常抛出后的处理即针对不同的异常类型通过不同的 catch 块分别处理。在网上找了很多相关教程后发现也有部分人跟我存在相同困惑但尚未解决主要是.NET 捕获到的异常信息只显示了“外部组件异常”无法细化到具体的异常问题因而无法对于不同非法表达式做不同的报错处理。本人这里全部归纳为除零错误一种实际上是不对的。