文档库 最新最全的文档下载
当前位置:文档库 › C语言源程序的自动评判毕业设计

C语言源程序的自动评判毕业设计

(此文档为word格式,下载后您可任意编辑修改!)

目录

第1章引言 (1)

1.1 背景介绍 (1)

1.1.1 研究背景简介 (1)

1.1.2 C语言简介 (1)

第2章概要设计 (3)

2.1 方案设计 (3)

2.1.1 开发环境 (3)

2.1.2 工作方式 (3)

2.1.3 系统目标 (3)

2.2 系统功能 (3)

2.3 需要解决问题 (4)

2.4 系统流程 (4)

2.4.1 基本流程 (4)

2.4.2 具体实现 (5)

第3章详细设计 (7)

3.1 系统模块化分 (7)

3.1.1 添加文件对话框 (7)

3.1.2 编译链接函数 (8)

3.1.3 运行评判对话框 (9)

3.2 系统模块具体实现 (10)

3.2.1 准备工作 (10)

3.2.2 实现添加文件对话框 (11)

3.2.3 实现编译链接函数 (15)

3.2.4 实现运行评判对话框 (19)

第4章测试 (26)

4.1 测试方案 (26)

4.2 运行界面 (26)

4.2.1 准备系统运行 (26)

4.2.2 系统测试 (27)

结论 (30)

致谢 (32)

参考文献 (33)

附录A 外文参考文献(译文) (34)

附录B 外文参考文献(原文) (48)

第1章引言

1.1 背景介绍

1.1.1 研究背景简介

C语言是目前国际上广泛流行的、重要的计算机高级语言之一。它适合作为系统描述语言,即可用来编写系统软件,也可用来编写应用软件。对于学习计算机专业的学生来说,学好C语言将为今后学习其他编程语言打下良好的基础,而随着计算机应用的普及,更多的其他非计算机专业也会需要学习编写简单的程序,C语言也是一个很不错的选择。

学习C语言,首先是要学习理论知识,阅读编程思想,阅读源代码,其次就是动手实践上机编写程序了。只有通过自己编写程序,才能更好的掌握理论知识,发现不足,取得进步。

传统的教学方式中,学生采用FTP,Email甚至手写的方式提交编程作业,老师一般采用逐一检查并试运行的手工检查方式,然后给出相应的得分。由于在编程作业的提交过程中,很多学生可能会把一些有语法错误以及结果不正确的程序提交上来,这就需要花费老师很多的精力和时间,效果也不是很好。当前,采用计算机对源程序直接进行评判还不是很普遍。因此,有必要开发一套简单易用的C语言源程序的自动评判系统,帮助老师检查学生的编程作业,提高老师工作效率,减轻老师负担。

1.1.2 C语言简介

C语言是国际上广泛流行的、很有发展前途的计算机高级语言。它适合作为系统描述语言,即可用来编写系统软件,也可用来编写应用软件。

早期的操作系统等系统软件主要是用汇编语言编写的(包括UNIX操作系统在内)。由于汇编语言依赖于计算机硬件,程序的可读性和可移植性都比较差。为了提高可读性和可移植性,最好改用高级语言,但一般的高级语言难以实现汇编语言的某些功能(汇编语言可以直接对硬件进行操作),例如:对内存地址的操作、位操作等)。人们设想能否找到一种既具有一般高级语言特性,又具有低级语言特性的语言,集它们的优点于一身。于是,C语言就在这种情况下应运而生了。

C语言是在B语言的基础上发展起来的,它的根源可以追溯到ALGOL 60。1960年出现的ALGOL 60是一种面向问题的高级语言,它离硬件比较远,不宜用来编写系统程序。1963年英国的剑桥大学推出了CPL语言。1967年英国剑

桥大学的Matin Richards对CPL语言作了简化,推出了BCPL语言。1970年美国贝尔实验室的Ken Thompson以BCPL语言为基础,又作了进一步简化,设计出了很简单的而且很接近硬件的B语言,并用B语言写第一个UNIX操作系统,在PDP-7上实现。1971年在PDP-1120上实现了B语言,并写了UNIX 操作系统。但B语言过于简单,功能有限。1972年至1973年间,贝尔实验室的D.M.Ritchie在B语言的基础上设计出了C语言(取BCPL的第二个字母)。最初的C语言只是为描述和实现UNIX操作系统提供一种工作语言而设计的。1973年,K.Thom- pson和D.M.ritchie两人合作把UNIX的90%以上用C改写。

后来,C语言多次作了改进,但主要还是在贝尔实验室内部使用。直到1- 975年UNIX第6版公布后,C语言的突出优点才引起人们普遍注意。1977年出现了不依赖于具体机器的C语言编译文本《可移植C语言编译程序》,使C移植到其它机器时所做的工作大大简化了,这也推动了UNIX操作系统迅速地在各种机器上实现。随着UNIX的日益广泛使用,C语言也迅速得到推广。C语言和UNIX可以说是一对孪生兄弟,在发展过程中相辅相成。1978年以后,C语言已先后移植到大、中、小、微型机上,已独立于UNIX和PDP了。现在C语言已风靡全世界,成为世界上应用最广泛的几种计算机语言之一。

C语言主要有以下一些特点:(1)语言表达能力强。(2)语言简洁、紧凑,使用灵活,易于学习和使用。(3)数据类型丰富,具有很强的结构化控制语句。(4)语言生成的代码质量高。(5) 语法限制不严格,程序设计自由度大。(6)可移植性好。

第2章概要设计

2.1 方案设计

本课题的任务是完成一个C源程序的自动评判系统。首先需要解决的问题是确定整个系统的开发环境和工作方式,然后是确定系统所要达到的目标,接着分析系统所应完成的功能以及可能遇到的问题,最后给出具体实现的步骤。

2.1.1 开发环境

经过与指导老师的交流,查阅有关资料,分析系统的整体情况,本系统更加类似于一个应用程序,再结合自己所学知识,决定采用微软的Visual C++集成开发环境来开发整个程序。Visual C++是Windows环境下最强大、最流行的程序设计语言之一。Visual C++可以用来开发各种类型、不同规模和复杂程度的应用程序,开发效率很高,生成的应用软件代码品质优良。

2.1.2 工作方式

分析整个系统,最主要的功能是:编译链接源程序,运行目标程序,目标程序输入输出的重定向。结合Visual C++开发环境来看,有批处理方式、普通应用程序方式、Add-in方式。考虑到Add-in的方式在使用Visual C++编译器去编译链接C源程序的时候更加方便,并且Add-in的方式也可以利用Visual C++的可视化界面的开发功能,所以工作方式采用Visual C++下的Add-in方式。Visual C++ Add-In基本上就是实现了IDSAddIn接口的COM对象。通过这个接口,Add-in能够掌管Visual C++环境,并且执行特定的任务,例如在Visual C++环境下打开工作空间,编译工程等等。在使用Add-in方式的时候,首先需要打开Visual C++环境,然后加载add-in文件(*.dll)。

2.1.3 系统目标

本系统最终目的是为了减轻老师负担,利用计算机自动评判编程作业,替代手工检查方式。要求学生将编写好的作业交至指定文件夹,然后老师运行本系统,编译链接,运行生成目标程序,通过比较程序输出与标准答案,可以得到每个源程序的评判结果。

2.2 系统功能

详细的分析整个系统功能应该包括:

1. 从文件夹抽取源程序。

2. 控制Visual C++编译器编译链接源程序。

3. 以测试数据运行生成的目标程序。

4. 程序输出与标准输出比较。

5. 根据比较结果得到评判结果。

2.3 需要解决问题

1. 存放C源程序的文件夹的组织方式和文件夹中C源程序的命名方式。

2. 程序通过何种方式提取C源程序。

3. 用程序控制Visual C++编译器去编译链接C源程序。

4. 如何处理编译链接时出错,没有生成目标程序的C源程序。

5. 通过何种方式运行编译链接之后生成的目标程序。

6. 在运行目标程序时,如何自动完成目标程序的输入和输出。

7. 对于运行目标程序时异常情况的处理。

8. 采用何种方式比较输出结果和正确答案,以及如何存储比较结果。2.4 系统流程

2.4.1 基本流程

基本上本系统是一个顺序执行的过程,系统的实现也是一步一步来的。下一个模块需要用到上一个模块的数据。系统流程图如图1-1所示。

1. 系统从文件夹提取出所有的C源程序。

2. 系统控制Visual C++的编译器去编译链接提取出的C源程序,得到相应的生成的目标程序(exe)。

3. 系统以正确输入数据运行生成的目标程序(exe)。

4. 系统提取运行目标程序(exe)得到的输出数据。

5. 系统将输出数据与正确答案进行比较。

6. 根据比较结果得到评判结果。

图1-1 系统流程图

2.4.2 具体实现

根据系统应该完成的功能,结合需要解决的问题,系统的具体实现如下:

1. 文件夹的组织方式:每一个题目设置一个文件夹,同一题目的所有编程

作业(只交后缀名为*.c的文件)交至对应的唯一文件夹下。

2. 每个文件夹中C源程序的命名方式:以学号命名,后缀名为*.c,这样每个文件夹中的C源程序是唯一的,在评判时能更直观的得到结果。

3. 设置一个基本对话框,通过列表控件来提取选择的一个文件夹下的所有C源程序。

4. 编译链接方面,Visual C++不能直接编译链接后缀名为*.c的C源程序,因此提前新建一个WIN32空白工程文件,然后将C源程序的后缀名改为*.cpp,放至空白工程中,便可以解决不能直接编译链接的问题。通过Add-in接口,控制整个Visual C++环境,打开已放入改了后缀名的C源程序的空白工程文件,然后便可进行编译链接。在这里要设置循环,对列表框中的每一个C源程序都进行编译链接。

5. 循环过程中,编译链接后生成目标程序的C源程序,从空白工程文件的Debug文件夹中复制其目标程序到暂存的文件夹,并用其学号来命名生成的目标程序。然后循环继续直到所有C源程序都完成编译链接。

6. 对于编译链接后没有生成目标程序的C源程序,视为编译链接错误,将此结果先一步存至评判结果处。

7. 编译链接全部完成后,设置弹出一个对话框,用于输入测试数据、运行正确的目标程序,得到正确答案。同时通过列表框提取已经生成的所有以学号命名的目标程序。

8. 对于编译链接正确,已经生成的目标程序,设置循环,每次循环中通过新建一个进程来运行应用程序,如果程序正常结束,则关闭进程,循环继续去运行下一个目标程序。

9. 在运行目标程序时,通过管道技术来完成输入输出数据的重定向问题。

10. 对于目标程序运行时可能出现的种种异常情况,例如死循环等,通过设定一个时间,超出这个时间后进程强制结束来处理,进程强制结束后主循环继续,同时判定为运行时错误。

11. 在开始循环运行所有目标程序之前,需要老师首先运行此题目正确程序生成的应用程序,并且输入运行数据(如无需数据输入则省略此步骤),得到正确的输出数据,存入一个编辑框。然后每次运行生成的目标程序得到输出时与编辑框中字符串比较,来得到比较结果。结果是相同或是不同。

12. 最后的评判结果:没有生成目标程序,判为编译链接出错-50分;生成了目标程序,但是输出与正确答案不同,判为运行错误-60分;生成了目标程序,并且输出结果与正确答案相同,判为程序正确-100分。

第3章详细设计

3.1 系统模块化分

根据系统所应该完成的功能,以及考虑到使用的方便性,将系统划分为三个模块,其中包括两个基本对话框和一个函数。

3.1.1 添加文件对话框

此对话框需要完成的功能、遇到的问题及解决办法:

1. 初始化:在系统运行之前删除空白工程文件中不需要的文件,清空相关的文件夹。此功能通过对话框上的一个“初始化”按钮完成。

在系统运行选择C源程序文之前,需要对相关文件夹和文件进行处理,有删除文件夹、清空文件夹、删除文件。而在Visual C++中是不能直接删除非空的文件夹的,也没有清空文件夹的函数,文件是可以通过库函数DeleteFile()直接删除的。因此这里需要自己添加函数来清空文件夹,在清空文件夹之后调用库函数RemoveDirectory()来删除已空文件夹。

2. 添加文件:初始化之后,从相应的存放相同题目的文件夹中提取所有的C源程序文件(过滤器设置为只能选取后缀名为*.c的文件),将所有的文件添加至对话框的一个列表控件中,列表控件的每一行项目为C源程序文件的绝对路径。完成添加C源程序后,取得项目总数的信息存入注册表,并且以项目总数设置循环,将每个C源程序文件的绝对路径信息存入注册表,然后调用编译链接函数。此功能通过对话框的一个“添加文件”按钮和一个列表控件完成。

在添加文件时选择用列表控件的方式,这样在之后设置循环对每个C源程序文件进行操作时比较方便。同时每个项目中取的是C源程序文件的绝对路径(包括文件名),因为之后的好多操作需要文件的路径,取得学号信息时也比较方便。因为在Add-in方式下,对话框类和Add-in类之间的数据传递比较特殊,所以采用将列表控件中的相关信息存至注册表的方式,以便今后在编译链接时调用。

3. 确认:新建对话框时,默认的代码,无实际功能。通过点击此按钮,得到“OK”按钮按下的消息,调用编译链接函数。通过对话框的“OK”按钮完成。

此对话框的数据输入是:文件夹中选取的所有后缀名为(*.c)的C源程序文件。

此对话框的数据输出是:列表控件中的项目总数和列表控件每个项目中C 源程序文件的绝对路径。

3.1.2 编译链接函数

此函数需要完成的功能、遇到的问题及解决办法:

编译链接:从注册表提取出添加文件对话框中列表控件的项目总数,以此设置循环。在每次循环中,首先进行初始化操作,删除空白工程文件夹中相关不用的文件和文件夹,然后通过从注册表提取出添加文件对话框列表控件的项目中的C源程序文件的绝对路径,将后缀名为*.c的C源程序文件改名为与建立空白工程时建立的关联的*.cpp文件。通过Add-in的接口,在Visual C++工作空间打开空白工程文件,此时它已经成为C源程序文件的工程文件,进行编译链接。编译链接完成之后如果在空白工程文件的Debug文件夹中找到生成的目标程序,则以此C源程序文件中的学号信息来命名此目标程序(即,此时目标程序改名为学号.exe)并且将改名后的目标程序复制到暂存所有生成的目标程序的文件夹中,以备运行时使用。而如果编译链接完成之后在空白工程文件的Debug 文件夹中没有找到生成的目标程序,则视为编译链接错误,直接在结果文件夹中以学号为信息给出评判结果。处理结束后进行下一个循环直到循环结束,给出编译链接已完成的信息提示框。

首先编译链接时取用的数据是刚才添加文件对话框中列表控件中添加入注册表的信息。在每次循环开始前,都需要对test文件夹进行处理,删除Debug 文件夹,删除0.cpp文件,清空result、outcome文件夹,这些问题同添加文件对话框问题中的初始化一样,都需要自己编写函数来清空文件夹和删除非空文件夹。然后因为是将C源程序文件加入空白工程文件中编译,且空白的关联cpp 文件已经命名为0.cpp,所以C源程序文件在编译链接前都需要改名为0.cpp文件。之后通过Add-in,控制整个Visual C++的开发环境,首先打开工作空间,然后载入工程,之后编译链接,当然这些都是Visual C++自动完成的,相当于按下了Build按钮,这也就是使用Add-in方式的关键所在。编译链接结束后,如果在Debug文件夹中生成0.exe文件,则视为编译链接成功,且此时需要将此文件转移出来,因为如不转移,编译链接下一个C源程序文件时会覆盖此0.exe 文件。

此函数的数据输入是:列表控件中的项目总数和列表控件每个项目中C源程序文件的绝对路径。

此函数的数据输出是:编译链接成功后以学号命名的存至相同文件夹下的目标程序;编译链接错误后以学号为区分信息的存至结果文件夹下的评判结果。

3.1.3 运行评判对话框

此对话框需要完成的功能及其解决办法:

1. 输入数据、运行正确程序:弹出此对话框后,进入运行目标程序,评判阶段,首先运行此题目正确程序编译链接后生成的exe程序,如果需要输入数据才能运行的,先输入数据,得到此题目正确的输出。此功能通过“选择正确程序”按钮来选择此题目正确程序生成的exe文件,通过一个编辑框显示运行的正确exe文件路径,通过另一个编辑框来实现数据输入,通过第三个编辑框来得到运行正确exe文件后得到的数据输出,即标准答案。

在编译链接结束后,进入运行评判阶段,首先需要运行正确的程序,这是老师之前通过编译链接正确题目程序得到的正确的exe程序。如果程序需要输入数据之后运行的,在“正确输入”编辑框中输入正确数据。通过编辑框的方式输入数据方便直观。因为这里是老师输入正确程序的正确数据输入,所以老师会确保输入数据的正确性。而如果不需输入数据即可得到输出数据的话就不用输入数据即可。之后通过CreateProcess()函数运行正确程序,这里通过重定向技术使用管道来完成自动的使用输入数据运行程序并且自动的将输出数据送入编辑框而不是在显示屏显示。在正确输出编辑框中会显示出正确的结果,这样子也便于观察。

2. 选择目标文件:输入正确数据,以此数据运行正确的exe文件后,得到正确输出,即标准答案。选取暂存文件夹中所有C源程序文件编译链接正确后生成的所有以学号命名的目标程序至列表控件,列表控件项目为选取的目标程序的绝对路径。此功能通过一个“添加文件”完成选取所有目标程序,通过一个列表控件来完成添加所有目标文件。

这里也是通过列表控件来完成选择文件的工作,因为知道生成的所有目标程序在test文件夹下的result文件夹中,所以在打开文件时直接定位到此程序所在的文件夹。每个项目中同样也是放的目标程序的绝对路径(包括文件名),因为之后使用函数运行程序是需要使用程序的绝对路径。

3. 运行目标文件、进行评判:完成选取所有目标程序后,以列表控件的项目总数即目标程序总数设置循环。在每次循环中,以运行正确程序的exe文件时的数据输入作为运行目标程序的数据输入,即使用正确输入编辑框中的输入数据,去运行目标程序,得到输出数据,将此输出数据与正确输出编辑框中的数据比较,这两个数据都是CString类型的。如果比较结果相同,则视为运行正确,将此结果以学号信息为区别存至结果文件夹中作为评判结果;如果比较结果不同,则视为运行时错误,也将此结果以学号信息为区别存至结果文件夹作

为评判结果。完成一个目标程序的运行、评判之后,循环继续,去运行、评判下一个C源程序。直到处理完所有的目标程序,至此运行、评判结束。此功能通过一个“开始”按钮完成。

在这里运行程序时的原理和运行正确程序时的一样,正确的数据输入就采用正确输入编辑框中的数据,这样可以确保程序正确时得到的输出与正确输出相同,方便评判。一个问题是需要考虑到这里运行的是学生的程序而不是老师的正确程序,所以可能出现运行异常、死循环的进程不结束的问题,那么就会出现死机的情况,主程序运行不下去,所以这里需要设置进程运行超时的处理。因为是教学中的C源程序文件作业,相对较为简单,所以设置运行时间为4秒,如果进程运行超时还没有自动结束,则强制结束,判为运行时错误。若果进程自动结束,则于正确结果比较得到评判结果。

此对话框的数据输入是:题目正确源程序生成的exe文件,正确的测试数据输入,所有C源程序文件编译链接正确后生成的目标程序。

此对话框的数据输出是:以输入的正确测试数据运行正确程序后的正确数据输出;比较运行目标程序后的数据输出与正确数据输出,结果相同后得到的以学号信息区别的存至结果文件夹的运行正确的评判结果;比较运行目标程序后的数据输出与正确数据输出,结果不同后得到的以学号信息区别的存至结果文件夹的运行错误的评判结果。

3.2 系统模块具体实现

在这一节中,将会对各个模块中系统那个实现的难点、遇到的问题、解决的方法、重点技术问题的给出详细的说明。

3.2.1 准备工作

在开始系统设计之前,在Visual C++中新建一个Win32空白工程,这里工程名为test,然后在此空白工程中新建一个C++文件,文件名为0.cpp。以后编译链接选取的C源程序文件时则将C源程序文件改名为0.cpp并替换空白工程中的0.cpp文件即可。为防止编译链接时编译链接两次,选择组件->配置,移除Win32 Release只保留Win32 Debug。在此空白工程文件夹test中,新建一个文件夹result用于保存编译链接成功后生成的以学号命名的目标程序,新建一个文件夹outcome用于存放最后的评判信息,新建一个空白文本文件file.txt。

在每次开始使用系统之前,进行的初始化操作就包括删除Debug文件夹、删除0.cpp文件,清空result和outcome文件夹。

接着开始系统的具体功能实现阶段。首先Visual C++中新建一个DevStudio Add-in Wizard工程,工程名称为Auto,并且在CCommands->ICommands中自动

添加一个函数AutoCommandMethod()。这个函数是系统的切入点。这时编译链接工程之后,生成DLL文件,加载此文件后,工具栏会添加一个按钮,此按钮实现的是AutoCommandMethod()的函数功能。系统的使用从点击这个按钮开始。

3.2.2 实现添加文件对话框

建立起DevStudio Add-in Wizard工程后,在工作空间,右击Auto Classes 添加一个对话框类AddFile,即添加文件对话框。编辑此对话框,添加“初始化”、“添加文件”按钮和一个列表控件,保留默认的“OK”、“Cancle”按钮。

1. “初始化”按钮:此按钮完成的功能是删除Debug文件夹、删除0.cpp文件,清空result和outcome文件夹。在Visual C++中可以通过库函数DeleteFile()删除一个文件。

(1). 在此遇见的问题是在Visual C++中不能直接删除一个不为空的文件夹以及没有现成的库函数来清空一个文件夹,因此自己添加两个函数DeleteFolder 和ClearFolder,分别用于删除文件夹(不管其是否为空)和清空文件夹(清空其中的文件而保留文件夹),函数代码如下:

a. DeleteFolder函数

void AddFile::DeleteFolder(CString sPath)

{

CFileFind ff;

BOOL bFound;

bFound = ff.FindFile(sPath + "\\*.*");

while(bFound)

{

bFound = ff.FindNextFile();

CString sFilePath = ff.GetFilePath();

if(ff.IsDirectory())

{

if(!ff.IsDots())

DeleteFolder(sFilePath);

}

else

{

if(ff.IsReadOnly())

{

SetFileAttributes(sFilePath, FILE_ATTRIBUTE_NORMAL); }

DeleteFile(sFilePath);

}

}

ff.Close();

SetFileAttributes(sPath, FILE_ATTRIBUTE_NORMAL); RemoveDirectory(sPath);

}

b. ClearFolder函数

void AddFile::ClearFolder(CString sPath)

{

CFileFind ff;

BOOL bFound;

bFound = ff.FindFile(sPath + "\\*.*");

while(bFound)

{

bFound = ff.FindNextFile();

CString sFilePath = ff.GetFilePath();

if(ff.IsDirectory())

{

if(!ff.IsDots())

DeleteFolder(sFilePath);

}

else

{

if(ff.IsReadOnly())

{

SetFileAttributes(sFilePath, FILE_ATTRIBUTE_NORMAL); }

DeleteFile(sFilePath);

}

}

ff.Close();

SetFileAttributes(sPath, FILE_ATTRIBUTE_NORMAL);

}

(2). 完整的“初始化”按钮代码如下:

{

CString StrDestFile="D:\\test\\0.cpp";

DeleteFile(StrDestFile);删除0.cpp文件

CString DirectoryDebugName="D:\\test\\Debug";

DeleteFolder(DirectoryDebugName);删除DEBUG文件夹

CString DirectoryResultName="D:\\test\\result";

ClearFolder(DirectoryResultName);清空result文件夹

ClearFolder("D:\\test\\outcome");清空outcome文件夹

GetDlgItem(IDC_addfile_BUTTON)->EnableWindow(true);设置“添加文

件”按钮禁用,点击“初始化”后启用

GetDlgItem(IDOK)->EnableWindow(true); 设置“OK”按钮禁用,点击“初

始化”后启用

}

2. “添加文件”按钮:点击之后弹出选择文件对话框,完成选择所有的C 源程序文件,然后将所有的C源程序文件添加至对话框的列表控件中,列表控件的每一行项目为C源程序文件的绝对路径。然后将列表控件中的项目总数和每个项目所指向的C源程序文件的绝对路径存入注册表,以备编译链接时使用。

(1). 列表控件的初始化工作需要首先设置列表控件的属性属性->样式->查看->报告,然后在AddFile类的Message中选择WM_INITDIALOG添加函数OnInitDialog(),最后在此函数中添加代码如下:

(2). 点击“添加文件”按钮后弹出打开文件对话框,通过CFileDialog来实现,设置过滤器以便只能选择后缀名为*.c的C源程序文件,同时相关参数设置为能够选择多个文件,其代码如下:

CFileDialog

Dlg(TRUE,"*.c",NULL,OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT," C文件(*.c)|*.c|",NULL);

(3). 对于选择多个文件添加至列表控件中,需要设置指针,通过GetStartPosition()函数使指针指向选取的第一个文件开始,直至最后一个文件,然后通过GetNextPathName()函数来将选取的C源程序文件的绝对路径添加入列表控件,代码如下:

POSITION pos=Dlg.GetStartPosition();

while(pos!=NULL)

{

CString FileName="";

FileName = Dlg.GetNextPathName(pos);

m_list.InsertItem(0, "", 0);

m_list.SetItem(0, 0, LVIF_TEXT, FileName,0, 0, 0, 0);

}

(4). 将选取的所有C源程序文件的绝对路径存入列表控件后,通过AfxGetApp()->WriteProfileInt将列表框项目总数写入注册表,然后以项目总数设置循环,通过AfxGetApp()->WriteProfileString依次将每个C源程序文件的绝对路径写入注册表,以备编译链接时使用,其代码如下:

AfxGetApp()->WriteProfileInt("Configure", "count",m_list.GetItemCount());

for (int i = 0 ; i < m_list.GetItemCount() ; i++)

{

char szRegKey[50];

wsprintf(szRegKey, "%d", i);

AfxGetApp()->WriteProfileString("Configure", szRegKey,

m_list.GetItemText(i, 0));

}

(5). 完整的“添加文件”按钮代码如下:

{

CFileDialog

Dlg(TRUE,"*.c",NULL,OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT," C文件(*.c)|*.c|",NULL);

if(Dlg.DoModal()==IDOK)

{

POSITION pos=Dlg.GetStartPosition();

while(pos!=NULL)

{

CString FileName="";

FileName = Dlg.GetNextPathName(pos);

m_list.InsertItem(0, "", 0);

m_list.SetItem(0, 0, LVIF_TEXT, FileName,0, 0, 0, 0);

}

AfxGetApp()->WriteProfileInt("Configure",

"count",m_list.GetItemCount());

for (int i = 0 ; i < m_list.GetItemCount() ; i++)

{

char szRegKey[50];

wsprintf(szRegKey, "%d", i);

AfxGetApp()->WriteProfileString("Configure", szRegKey,

m_list.GetItemText(i, 0));

}

}

}

3. “OK”按钮:此按钮的代码是新建对话框时的默认代码,无实际功能,其按下的意义在于,取得按下“OK”的消息,调用编译链接函数。此消息的实现是在系统切入点AutoCommandMethod()函数出,点击工具栏按钮后弹出添加文件对话框,进行完选取C源程序文件的操作后,点击“OK”按钮,AutoCommandMethod()函数得到按下“OK”按钮的消息,然后调用编译链接函数,进入下一步工作,这里AutoCommandMethod()函数相关代码如下:AddFile AddFileDlg;弹出添加文件对话框

if(AddFileDlg.DoModal()==IDOK)若按下添加文件对话框的“OK”按钮

{

build();调用编译链接函数

}

3.2.3 实现编译链接函数

首先建立编译链接函数,这个函数是在Add-in方式下建立的,目的是操控Visual C++的开发环境,实现在工作空间打开工程文件,调用Visual C++自带的编译器去编译链接工程。建立此函数的过程是:右击CCommands类下的ICommands,选择Add Method,然后方法名称为build,即建立了一个build()函数,此时函数代码为空,不实现功能。

在添加文件对话框完成所有工作后,点击“OK”按钮,发出按钮按下的消息,在AutoCommandMethod()函数中调用build()函数。

此函数要实现的功能是:

1. 初始化工作,在每次编译链接C源程序文件前需要删除Debug文件夹和o.cpp文件,以保证编译链接成功后在Debug文件夹中生成的目标程序是对应当前的C源程序文件的,其代码如下:

DeleteFile("D:\\test\\0.cpp");删除0.cpp文件

DeleteFolder("D:\\test\\Debug");删除Debug文件夹

2. 取得C源程序文件中的学号信息,因为C源程序文件存至列表控件中的是其绝对路径,包括路径和完整的文件名(因为在命名时有要求,所以文件名也就是“学号.c”),所以需要提取出文件名中的学号(即文件标题),学号是唯一区别标志,以便在给出评判结果时使用学号信息,代码如下:

CString stillfilename;

CString filetitle;

CString StrFile=AfxGetApp()->GetProfileString("Configure", RegKey, "");获取文件路径和完整文件名

stillfilename=StrFile.Right(StrFile.GetLength()-StrFile.ReverseFind('\\')-1);获取文件名,带后缀

filetitle=stillfilename.Left(stillfilename.ReverseFind('.'));获取文件标题(学号),即文件名去掉后缀

3. 取得注册表中存入的添加文件对话框中列表控件的项目总数和每个项目中选取的C源程序文件的绝对路径,并以项目总数设置循环。每次循环中首先进行初始化操作,然后将C源程序文件改名为o.cpp文件并复制到空白工程test文件夹下。新打开一个工作空间,打开此时的test工程文件(test.dsw),最后编译链接此工程文件。

(1). 取得项目总数,并以此设置循环的代码如下:

int nNumWorkspaces=

AfxGetApp()->GetProfileInt("Configure","count",0);

for (int nWorkspaceNumber = nNumWorkspaces;

nWorkspaceNumber >= 1;nWorkspaceNumber--)

(2). 改名复制C源程序文件,新建工作空间,打开工程文件,编译链接的代码如下:

long lCount;

char RegKey[50];

wsprintf(RegKey, "%d", nWorkspaceNumber-1);

CString StrDestFile="D:\\test\\0.cpp";

CopyFile(StrFile,StrDestFile,false);拷贝并改名C文件至空白工程CComBSTR bszWorkspacePathName = "D:\\test\\test.dsw";

CComPtr pDispDocuments;

VERIFY_OK(m_pApplication->get_Documents(&pDispDocuments)); CComVariant OleVariant;

CComQIPtr pDocuments(pDispDocuments); CComPtr pWorkspace;

VERIFY_OK(pDocuments->Open(bszWorkspacePathName, OleVariant,

OleVariant, &pWorkspace)); CComPtr pDispProjects;

VERIFY_OK(m_pApplication->get_Projects(&pDispProjects)); CComQIPtr pProjects(pDispProjects);

VERIFY_OK(pProjects->get_Count(&lCount));

for (long i = 1 ; i < lCount+1 ; i++)

{

long lNumConfigs;

CComVariant Vari = i;

CComPtr pGenProject;

VERIFY_OK(pProjects->Item(Vari, &pGenProject));

CComQIPtr

&IID_IBuildProject>pProject(pGenProject);

CComPtr pConfigs;

VERIFY_OK(pProject->get_Configurations(&pConfigs));

VERIFY_OK(pConfigs->get_Count(&lNumConfigs));

for (long j = 1 ; j < lNumConfigs+1 ; j++)

{

CComVariant Varj = j;

CComPtr pConfig;

VERIFY_OK(pConfigs->Item(Varj, &pConfig));

CComVariant VarDisp = pConfig;

CComBSTR bszStr;

VERIFY_OK(pConfig->get_Name(&bszStr));

VERIFY_OK(m_pApplication->Build(VarDisp));

}

}

(3). 在循环中遇到的问题是每次打开一个工作空间并对工程进行编译链接后没有关闭文档,从而使每次开始新循环后无法实现删除Debug文件夹和o.cpp文件,造成目标程序永远是对应第一个C源程序文件的,解决的办法是在编译链接结束后关闭文档,即工作空间,代码如下:

DsSaveStatus d;

V ARIANT vtSaveChanges;

vtSaveChanges.lVal=dsSaveChangesNo;

vtSaveChanges.vt=VT_I4;

VERIFY_OK(pDocuments->CloseAll(vtSaveChanges,&d));

4. 每次循环中,编译链接结束后,关闭工作空间,在空白工程test文件夹中的Debug下,如果能找到生成的目标程序test.exe文件,则视为编译链接正确,将此test.exe文件复制到暂存目标程序的result文件夹,并改名为以学号命名的exe文件,即学号.exe文件,作为此C源程序文件编译链接成功生成的目标程序。而如果编译链接结束后,在Debug文件夹中没有找到生成的目标程序test.exe 文件,则视为编译链接错误,复制空白的文本文件file.txt并改名为以此C源程序文件的学号命名的“学号-编译错误-50”文本文件,作为评判结果存至结果文件夹outcome。这一部分代码如下:

CFileFind find;

CFileFind findexe;

if(find.FindFile(exefile))

{

CopyFile(exefile,"D:\\test\\result\\test.exe",false);

{if(findexe.FindFile("D:\\test\\result\\test.exe"))

{

CString newexefile="D:\\test\\result\\"+filetitle+".exe";

MoveFile("D:\\test\\result\\test.exe",newexefile);

}

}

}

else

{

CString errorfile;

CString file="D:\\test\\file.txt";

errorfile="D:\\test\\outcome\\"+filetitle+"编译错误-50"+".txt";

CopyFile(file,errorfile,false);

}

5. 编译链接完所有的C源程序文件,在result文件夹中存储所有编译链接成功后得到的以学号命名的目标程序,在outcome文件夹中存储所有编译链接错误没有得到目标程序的以学号为区别信息的评判结果之后,弹出消息提示框,提示编译链接已经结束,点击确认进入运行评判对话框。代码如下:CString StrInfo="编译连接结束,点击进行运行评判";

if(AfxMessageBox(StrInfo,MB_YESNO)==IDYES)

{

run RunDlg; 这里run是建立的运行评判对话框的类名

RunDlg.DoModal();

}

3.2.4 实现运行评判对话框

调用编译链接函数,对所有的C源程序文件进行编译链接,处理生成的目标文件,并且先一步给出编译链接不正确的C源程序文件的评判结果后,弹出运行评判对话框。这就首先需要在工作空间,右击Auto Classes添加一个对话框类run,即添加运行评判对话框。编辑此对话框,首先添加一些必要的用于说明性的静态文本,再添加编辑框一用于显示运行的正确的exe程序绝对路径;编辑框二用于输入运行正确程序的输入数据,此数据也用于作为运行所有生成的目标程序的输入数据;编辑框三用于输出运行正确exe程序后的正确输出结果,并且在运行所有的目标程序得到输出结果后与此编辑框中的正确输出结果比较以得到评判结果。另外,添加一个列表控件,添加一个“选择正确程序”按钮,一个“运行正确程序”按钮,一个“选择文件”按钮,保留默认的“OK”按钮和“Cancle”按钮。

1. “选择正确程序”按钮:在开始选择C源程序文件之前,需要老师先在Visual C++下运行一次题目正确的程序,得到正确的exe程序。之后点击这个按

相关文档
相关文档 最新文档