VC调试入门.doc_第1页
VC调试入门.doc_第2页
VC调试入门.doc_第3页
VC调试入门.doc_第4页
VC调试入门.doc_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

VC调试入门概述调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言。不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件。这里我简要的根据自己的经验列出调试中比较常用的技巧,希望对大家有用。本文约定,在选择菜单时,通过/表示分级菜单,例如File/Open表示顶级菜单File的子菜单Open。设置为了调试一个程序,首先必须使程序中包含调试信息。一般情况下,一个从AppWizard创建的工程中包含的Debug Configuration自动包含调试信息,但是是不是Debug版本并不是程序包含调试信息的决定因素,程序设计者可以在任意的Configuration中增加调试信息,包括Release版本。为了增加调试信息,可以按照下述步骤进行: 打开Project settings对话框(可以通过快捷键ALT+F7打开,也可以通过IDE菜单Project/Settings打开) 选择C/C+页,Category中选择general ,则出现一个Debug Info下拉列表框,可供选择的调试信息 方式包括: 命令行Project settings说明无None没有调试信息/ZdLine Numbers Only目标文件或者可执行文件中只包含全局和导出符号以及代码行信息,不包含符号调试信息/Z7C 7.0- Compatible目标文件或者可执行文件中包含行号和所有符号调试信息,包括变量名及类型,函数及原型等/ZiProgram Database创建一个程序库(PDB),包括类型信息和符号调试信息。/ZIProgram Database for Edit and Continue除了前面/Zi的功能外,这个选项允许对代码进行调试过程中的修改和继续执行。这个选项同时使#pragma设置的优化功能无效 选择Link页,选中复选框Generate Debug Info,这个选项将使连接器把调试信息写进可执行文件和DLL 如果C/C+页中设置了Program Database以上的选项,则Link incrementally可以选择。选中这个选项,将使程序可以在上一次编译的基础上被编译(即增量编译),而不必每次都从头开始编译。 断点断点是调试器设置的一个代码位置。当程序运行到断点时,程序中断执行,回到调试器。断点是 最常用的技巧。调试时,只有设置了断点并使程序回到调试器,才能对程序进行在线调试。设置断点:可以通过下述方法设置一个断点。首先把光标移动到需要设置断点的代码行上,然后 按F9快捷键 弹出Breakpoints对话框,方法是按快捷键CTRL+B或ALT+F9,或者通过菜单Edit/Breakpoints打开。打开后点击Break at编辑框的右侧的箭头,选择 合适的位置信息。一般情况下,直接选择line xxx就足够了,如果想设置不是当前位置的断点,可以选择Advanced,然后填写函数、行号和可执行文件信息。 去掉断点:把光标移动到给定断点所在的行,再次按F9就可以取消断点。同前面所述,打开Breakpoints对话框后,也可以按照界面提示去掉断点。条件断点:可以为断点设置一个条件,这样的断点称为条件断点。对于新加的断点,可以单击Conditions按钮,为断点设置一个表达式。当这个表达式发生改变时,程序就 被中断。底下设置包括“观察数组或者结构的元素个数”,似乎可以设置一个指针所指向的内存区的大小,但是我设置一个比较的值但是改动 范围之外的内存区似乎也导致断点起效。最后一个设置可以让程序先执行多少次然后才到达断点。数据断点:数据断点只能在Breakpoints对话框中设置。选择“Data”页,就显示了设置数据断点的对话框。在编辑框中输入一个表达式,当这个 表达式的值发生变化时,数据断点就到达。一般情况下,这个表达式应该由运算符和全局变量构成,例如:在编辑框中输入 g_bFlag这个全局变量的名字,那么当程序中有g_bFlag= !g_bFlag时,程序就将停在这个语句处。消息断点:VC也支持对Windows消息进行截获。他有两种方式进行截获:窗口消息处理函数和特定消息中断。在Breakpoints对话框中选择Messages页,就可以设置消息断点。如果在上面那个对话框中写入消息处理函数的名字,那么 每次消息被这个函数处理,断点就到达(我觉得如果采用普通断点在这个函数中截获,效果应该一样)。如果在底下的下拉 列表框选择一个消息,则每次这种消息到达,程序就中断。值WatchVC支持查看变量、表达式和内存的值。所有这些观察都必须是在断点中断的情况下进行。观看变量的值最简单,当断点到达时,把光标移动到这个变量上,停留一会就可以看到变量的值。VC提供一种被成为Watch的机制来观看变量和表达式的值。在断点状态下,在变量上单击右键,选择Quick Watch, 就弹出一个对话框,显示这个变量的值。单击Debug工具条上的Watch按钮,就出现一个Watch视图(Watch1,Watch2,Watch3,Watch4),在该视图中输入变量或者表达式,就可以观察 变量或者表达式的值。注意:这个表达式不能有副作用,例如+运算符绝对禁止用于这个表达式中,因为这个运算符将修改变量的值,导致 软件的逻辑被破坏。Memory由于指针指向的数组,Watch只能显示第一个元素的值。为了显示数组的后续内容,或者要显示一片内存的内容,可以使用memory功能。在 Debug工具条上点memory按钮,就弹出一个对话框,在其中输入地址,就可以显示该地址指向的内存的内容。VariblesDebug工具条上的Varibles按钮弹出一个框,显示所有当前执行上下文中可见的变量的值。特别是当前指令涉及的变量,以红色显示。寄存器Debug工具条上的Reigsters按钮弹出一个框,显示当前的所有寄存器的值。进程控制VC允许被中断的程序继续运行、单步运行和运行到指定光标处,分别对应快捷键F5、F10/F11和CTRL+F10。各个快捷键功能如下: 快捷键说明F5继续运行F10单步,如果涉及到子函数,不进入子函数内部F11单步,如果涉及到子函数,进入子函数内部CTRL+F10运行到当前光标处。Call Stack调用堆栈反映了当前断点处函数是被那些函数按照什么顺序调用的。单击Debug工具条上的Call stack就显示Call Stack对话框。在CallStack对话框中显示了一个调用系列,最上面的是当前函数,往下依次是调用函数的上级函数。单击这些函数名可以跳到对应的函数中去。其他调试手段系统提供一系列特殊的函数或者宏来处理Debug版本相关的信息,如下: 宏名/函数名说明TRACE使用方法和printf完全一致,他在output框中输出调试信息ASSERT它接收一个表达式,如果这个表达式为TRUE,则无动作,否则中断当前程序执行。对于系统中出现这个宏 导致的中断,应该认为你的函数调用未能满足系统的调用此函数的前提条件。例如,对于一个还没有创建的窗口调用SetWindowText等。VERIFY和ASSERT功能类似,所不同的是,在Release版本中,ASSERT不计算输入的表达式的值,而VERIFY计算表达式的值。关注一个好的程序员不应该把所有的判断交给编译器和调试器,应该在程序中自己加以程序保护和错误定位,具体措施包括: 对于所有有返回值的函数,都应该检查返回值,除非你确信这个函数调用绝对不会出错,或者不关心它是否出错。 一些函数返回错误,需要用其他函数获得错误的具体信息。例如accept返回INVALID_SOCKET表示accept失败,为了查明 具体的失败原因,应该立刻用WSAGetLastError获得错误码,并针对性的解决问题。 有些函数通过异常机制抛出错误,应该用TRY-CATCH语句来检查错误 程序员对于能处理的错误,应该自己在底层处理,对于不能处理的,应该报告给用户让他们决定怎么处理。如果程序出了异常, 却不对返回值和其他机制返回的错误信息进行判断,只能是加大了找错误的难度。 另外:VC中要编制程序不应该一开始就写cpp/h文件,而应该首先创建一个合适的工程。因为只有这样,VC才能选择合适的编译、连接 选项。对于加入到工程中的cpp文件,应该检查是否在第一行显式的包含stdafx.h头文件,这是Microsoft Visual Studio为了加快编译 速度而设置的预编译头文件。在这个#include stdafx.h行前面的所有代码将被忽略,所以其他头文件应该在这一行后面被包含。对于.c文件,由于不能包含stdafx.h,因此可以通过Project settings把它的预编译头设置为“不使用”,方法是: 弹出Project settings对话框 选择C/C+ Category选择Precompilation Header 选择不使用预编译头。 VC调试小技巧(菜鸟级)1.在调试状态下怎样查看错误消息(GetLastError()?通常可以用GetLastError()得到错误编号然后用FormatMessage(.)得到错误描述。这里有一个更直接的办法:在Watch窗口添加err,hr2.怎样知道程序是否有内存泄漏(Memory Leak)?在VC开发环境下Press F5,在调试状态下运行程序,测试有可能出现内存泄漏的操作,关闭程序,在Output窗口查看运行信息.如果出现泄漏,在Output中会有记录。当然,不能完全依靠这种方式来发现程序运行有内存泄漏。3.当某一变量满足某种条件时,停止在断点.如以下一程序片段: 2 int iLocation; . 30 iLocation+ . 要求: 在line30设有断点,并想在iLocation100时停止在该断点。 解决办法: 1.在line30设置断点,Press Alt+F9 or 选择菜单 Edit|Breakpoints 2.选择Clocation页,在ListBox中选择上面的断点。 3.Click Condition,在第一个编辑框中输入 iLocation1004. OK仅通过崩溃地址找出源代码的出错行作为程序员,我们平时最担心见到的事情是什么?是内存泄漏?是界面不好看?错啦!我相信我的看法是不会有人反对的那就是,程序发生了崩溃! “该程序执行了非法操作,即将关闭。请与你的软件供应商联系。”,呵呵,这句 M$ 的“名言”,恐怕就是程序员最担心见到的东西了。有的时候,自己的程序在自己的机器上运行得好好的,但是到了别人的机器上就崩溃了;有时自己在编写和测试的过程中就莫名其妙地遇到了非法操作,但是却无法确定到底是源代码中的哪行引起的是不是很痛苦呢?不要紧,本文可以帮助你走出这种困境,甚至你从此之后可以自豪地要求用户把崩溃地址告诉你,然后你就可以精确地定位到源代码中出错的那行了。(很神奇吧?呵呵。)首先我必须强调的是,本方法可以在目前市面上任意一款编译器上面使用。但是我只熟悉 M$ 的 VC 和 MASM ,因此后面的部分只介绍如何在这两个编译器中实现,请读者自行融会贯通,掌握在别的编译器上使用的方法。Well,废话说完了,让我们开始! :)首先必须生成程序的 MAP 文件。什么是 MAP 文件?简单地讲, MAP 文件是程序的全局符号、源文件和代码行号信息的唯一的文本表示方法,它可以在任何地方、任何时候使用,不需要有额外的程序进行支持。而且,这是唯一能找出程序崩溃的地方的救星。好吧,既然 MAP 文件如此神奇,那么我们应该如何生成它呢?在 VC 中,我们可以按下 Alt+F7 ,打开“Project Settings”选项页,选择 C/C+ 选项卡,并在最下面的 Project Options 里面输入:/Zd ,然后要选择 Link 选项卡,在最下面的 Project Options 里面输入: /mapinfo:lines 和 /map:PROJECT_NAME.map 。最后按下 F7 来编译生成 EXE 可执行文件和 MAP 文件。在 MASM 中,我们要设置编译和连接参数,我通常是这样做的:rc %1.rcml /c /coff /Zd %1.asmlink /subsystem:windows /mapinfo:exports /mapinfo:lines /map:%1.map %1.obj %1.res 把它保存成 makem.bat ,就可以在命令行输入 makem filename 来编译生成 EXE 可执行文件和 MAP 文件了。在此我先解释一下加入的参数的含义:/Zd 表示在编译的时候生成行信息/map:filename 表示生成 MAP 文件的路径和文件名/mapinfo:lines 表示生成 MAP 文件时,加入行信息/mapinfo:exports 表示生成 MAP 文件时,加入 exported functions (如果生成的是 DLL 文件,这个选项就要加上) OK,通过上面的步骤,我们已经得到了 MAP 文件,那么我们该如何利用它呢?让我们从简单的实例入手,请打开你的 VC ,新建这样一个文件:01 /*02 /程序名称:演示如何通过崩溃地址找出源代码的出错行03 /作者:罗聪04 /日期:2003-2-705 /出处:(老罗的缤纷天地)06 /本程序会产生“除0错误”,以至于会弹出“非法操作”对话框。07 /“除0错误”只会在 Debug 版本下产生,本程序为了演示而尽量简化。08 /注意事项:如欲转载,请保持本程序的完整,并注明:09 /转载自“老罗的缤纷天地”()10 /*11 12 void Crash(void)13 14 int i = 1;15 int j = 0;16 i /= j;17 18 19 void main(void)20 21 Crash();22 很显然本程序有“除0错误”,在 Debug 方式下编译的话,运行时肯定会产生“非法操作”。好,让我们运行它,果然,“非法操作”对话框出现了,这时我们点击“详细信息”按钮,记录下产生崩溃的地址在我的机器上是 0x0040104a 。再看看它的 MAP 文件:(由于文件内容太长,中间没用的部分我进行了省略)CrashDemoTimestamp is 3e430a76 (Fri Feb 07 09:23:02 2003)Preferred load address is 00400000Start Length Name Class0001:00000000 0000de04H .text CODE0001:0000de04 0001000cH .textbss CODE0002:00000000 00001346H .rdata DATA0002:00001346 00000000H .edata DATA0003:00000000 00000104H .CRT$XCA DATA0003:00000104 00000104H .CRT$XCZ DATA0003:00000208 00000104H .CRT$XIA DATA0003:0000030c 00000109H .CRT$XIC DATA0003:00000418 00000104H .CRT$XIZ DATA0003:0000051c 00000104H .CRT$XPA DATA0003:00000620 00000104H .CRT$XPX DATA0003:00000724 00000104H .CRT$XPZ DATA0003:00000828 00000104H .CRT$XTA DATA0003:0000092c 00000104H .CRT$XTZ DATA0003:00000a30 00000b93H .data DATA0003:000015c4 00001974H .bss DATA0004:00000000 00000014H .idata$2 DATA0004:00000014 00000014H .idata$3 DATA0004:00000028 00000110H .idata$4 DATA0004:00000138 00000110H .idata$5 DATA0004:00000248 000004afH .idata$6 DATAAddress Publics by Value Rva+Base Lib:Object0001:00000020 ?CrashYAXXZ 00401020 f CrashDemo.obj0001:00000070 _main 00401070 f CrashDemo.obj0004:00000000 _IMPORT_DESCRIPTOR_KERNEL32 00424000 kernel32:KERNEL32.dll0004:00000014 _NULL_IMPORT_DESCRIPTOR 00424014 kernel32:KERNEL32.dll0004:00000138 _imp_GetCommandLineA0 00424138 kernel32:KERNEL32.dll0004:0000013c _imp_GetVersion0 0042413c kernel32:KERNEL32.dll0004:00000140 _imp_ExitProcess4 00424140 kernel32:KERNEL32.dll0004:00000144 _imp_DebugBreak0 00424144 kernel32:KERNEL32.dll0004:00000148 _imp_GetStdHandle4 00424148 kernel32:KERNEL32.dll0004:0000014c _imp_WriteFile20 0042414c kernel32:KERNEL32.dll0004:00000150 _imp_InterlockedDecrement4 00424150 kernel32:KERNEL32.dll0004:00000154 _imp_OutputDebugStringA4 00424154 kernel32:KERNEL32.dll0004:00000158 _imp_GetProcAddress8 00424158 kernel32:KERNEL32.dll0004:0000015c _imp_LoadLibraryA4 0042415c kernel32:KERNEL32.dll0004:00000160 _imp_InterlockedIncrement4 00424160 kernel32:KERNEL32.dll0004:00000164 _imp_GetModuleFileNameA12 00424164 kernel32:KERNEL32.dll0004:00000168 _imp_TerminateProcess8 00424168 kernel32:KERNEL32.dll0004:0000016c _imp_GetCurrentProcess0 0042416c kernel32:KERNEL32.dll0004:00000170 _imp_UnhandledExceptionFilter4 00424170 kernel32:KERNEL32.dll0004:00000174 _imp_FreeEnvironmentStringsA4 00424174 kernel32:KERNEL32.dll0004:00000178 _imp_FreeEnvironmentStringsW4 00424178 kernel32:KERNEL32.dll0004:0000017c _imp_WideCharToMultiByte32 0042417c kernel32:KERNEL32.dll0004:00000180 _imp_GetEnvironmentStrings0 00424180 kernel32:KERNEL32.dll0004:00000184 _imp_GetEnvironmentStringsW0 00424184 kernel32:KERNEL32.dll0004:00000188 _imp_SetHandleCount4 00424188 kernel32:KERNEL32.dll0004:0000018c _imp_GetFileType4 0042418c kernel32:KERNEL32.dll0004:00000190 _imp_GetStartupInfoA4 00424190 kernel32:KERNEL32.dll0004:00000194 _imp_HeapDestroy4 00424194 kernel32:KERNEL32.dll0004:00000198 _imp_HeapCreate12 00424198 kernel32:KERNEL32.dll0004:0000019c _imp_HeapFree12 0042419c kernel32:KERNEL32.dll0004:000001a0 _imp_VirtualFree12 004241a0 kernel32:KERNEL32.dll0004:000001a4 _imp_RtlUnwind16 004241a4 kernel32:KERNEL32.dll0004:000001a8 _imp_GetLastError0 004241a8 kernel32:KERNEL32.dll0004:000001ac _imp_SetConsoleCtrlHandler8 004241ac kernel32:KERNEL32.dll0004:000001b0 _imp_IsBadWritePtr8 004241b0 kernel32:KERNEL32.dll0004:000001b4 _imp_IsBadReadPtr8 004241b4 kernel32:KERNEL32.dll0004:000001b8 _imp_HeapValidate12 004241b8 kernel32:KERNEL32.dll0004:000001bc _imp_GetCPInfo8 004241bc kernel32:KERNEL32.dll0004:000001c0 _imp_GetACP0 004241c0 kernel32:KERNEL32.dll0004:000001c4 _imp_GetOEMCP0 004241c4 kernel32:KERNEL32.dll0004:000001c8 _imp_HeapAlloc12 004241c8 kernel32:KERNEL32.dll0004:000001cc _imp_VirtualAlloc16 004241cc kernel32:KERNEL32.dll0004:000001d0 _imp_HeapReAlloc16 004241d0 kernel32:KERNEL32.dll0004:000001d4 _imp_MultiByteToWideChar24 004241d4 kernel32:KERNEL32.dll0004:000001d8 _imp_LCMapStringA24 004241d8 kernel32:KERNEL32.dll0004:000001dc _imp_LCMapStringW24 004241dc kernel32:KERNEL32.dll0004:000001e0 _imp_GetStringTypeA20 004241e0 kernel32:KERNEL32.dll0004:000001e4 _imp_GetStringTypeW16 004241e4 kernel32:KERNEL32.dll0004:000001e8 _imp_SetFilePointer16 004241e8 kernel32:KERNEL32.dll0004:000001ec _imp_SetStdHandle8 004241ec kernel32:KERNEL32.dll0004:000001f0 _imp_FlushFileBuffers4 004241f0 kernel32:KERNEL32.dll0004:000001f4 _imp_CloseHandle4 004241f4 kernel32:KERNEL32.dll0004:000001f8 177KERNEL32_NULL_THUNK_DATA 004241f8 kernel32:KERNEL32.dll entry point at 0001:000000f0Line numbers for .DebugCrashDemo.obj(d:msdevmyprojectscrashdemocrashdemo.cpp) segment .text13 0001:00000020 14 0001:00000038 15 0001:0000003f 16 0001:0000004617 0001:00000050 20 0001:00000070 21 0001:00000088 22 0001:0000008d 如果仔细浏览 Rva+Base 这栏,你会发现第一个比崩溃地址 0x0040104a 大的函数地址是 0x00401070 ,所以在 0x00401070 这个地址之前的那个入口就是产生崩溃的函数,也就是这行:0001:00000020 ?CrashYAXXZ 00401020 f CrashDemo.obj 因此,发生崩溃的函数就是 ?CrashYAXXZ ,所有以问号开头的函数名称都是 C+ 修饰的名称。在我们的源程序中,也就是 Crash() 这个子函数。OK,现在我们轻而易举地便知道了发生崩溃的函数名称,你是不是很兴奋呢?呵呵,先别忙,接下来,更厉害的招数要出场了。请注意 MAP 文件的最后部分代码行信息(Line numbers information),它是以这样的形式显示的:13 0001:00000020 第一个数字代表在源代码中的代码行号,第二个数是该代码行在所属的代码段中的偏移量。如果要查找代码行号,需要使用下面的公式做一些十六进制的减法运算:崩溃行偏移 = 崩溃地址(Crash Address) - 基地址(ImageBase Address) - 0x1000 为什么要这样做呢?细心的朋友可能会留意到 Rva+Base 这栏了,我们得到的崩溃地址都是由 偏移地址(Rva)+ 基地址(Base) 得来的,所以在计算行号的时候要把基地址减去,一般情况下,基地址的值是 0x00400000 。另外,由于一般的 PE 文件的代码段都是从 0x1000 偏移开始的,所以也必须减去 0x1000 。好了,明白了这点,我们就可以来进行小学减法计算了:崩溃行偏移 = 0x0040104a - 0x00400000 - 0x1000 = 0x4a如果浏览 MAP 文件的代码行信息,会看到不超过计算结果,但却最接近的数是 CrashDemo.cpp 文件中的:16 0001:00000046 也就是在源代码中的第 16 行,让我们来看看源代码:16 i /= j; 哈!果然就是第 16 行啊!兴奋吗?我也一样! :)方法已经介绍完了,从今以后,我们就可以精确地定位到源代码中的崩溃行,而且只要编译器可以生成 MAP 文件(包括 VC、MASM、VB、BCB、Delphi),本方法都是适用的。我们时常抱怨 M$ 的产品如何如何差,但其实 M$ 还是有意无意间提供了很多有价值的信息给我们的,只是我们往往不懂得怎么利用而已相信这样一来,你就可以更为从容地面对“非法操作”提示了。你甚至可以要求用户提供崩溃的地址,然后就可以坐在家中舒舒服服地找到出错的那行,并进行修正。是不是很爽呢?遭遇MFC系统动态链接库失效我的一次排错经历我的拙作attendance个人考勤软件在VC知识库网站()发表后,陆续有朋友来信提出一些问题,其中有一个朋友告诉我:“下载了您的个人考勤软件源码,为什么一运行就出错误”,当时因为自己没有碰到过这样的问题,答复也就不甚了了,说不到点子上。昨天,因为又有朋友来问起,我就又翻出attendance个人考勤软件,运行了一下,结果真就遇见了“一运行就出错”的问题,下面把我遇到的情况和解决问题的过程介绍出来,可能对曾经碰到过类似问题而不知如何解决的一些朋友会有所帮助和启发。我是在DEBUG状态编译环境下运行attendance.exe的,一运行就出错,经过几次断点运行以后发现出错点位置在CAttendanceApp类的InitInstance()函数中的以下代码行if (RunEmbedded() | RunAutomated()从这儿再往下运行一步就出错,并且报出出错位置在动态链接库“Mfco42d.dll”中。然后我尝试作以下改动:1.程序代码不加改动,把编译环境切换到Release状态下重新编译运行,结果并不出错。2.从VC+开发平台 点击“工程-设置”菜单,弹出Project Settings对话窗口中选Win32 Debug的General选项卡,其上有Microsoft Foundation Classes列表框,点其中的下拉箭头,把原来的“Use MFC in a Shared DLL”改换成“Use MFC a Static Library”。就是把动态库改换成静态库。点“确定”退出。再重新编译运行就可不再出错。但这时查Debug目录下的attendance.exe程序文件的大小将达到2M以上。3在“Windows资源管理器”中点选“工具-查找-文件或文件夹”菜单,在弹出的查找对话框中查找文件“Mfco42d.dll”发现是在Windows操作系统目录的System子目录下。找到这个文件并把它改名(当然要先去掉它的“只读”属性),再来运行attendance.exe程序,结果发现用上面1.2.两种方法编译出来的attendance.exe程序运行依然正常。但是在Debug状态下如果仍然采用动态库编译出来的attendance.exe程序,运行时就会发生“找不到Mfco42d.dll文件”的错误,可见上面1.2.两种方法编译出来程序运行时不依赖于外部的Mfco42d.dll库,毛病就出在Mfco42d.dll文件上了。把它用好的来替换掉,可能会解决问题!从Mfco42d.dll文件名判断,它不会是Windows的系统文件,而是VC+的MFC文件,找来VC+的安装光盘,一找,很幸运,它不曾被塞进打包文件而是与其它的dll文件一起存放在VC98的Debug子目录下,把它拉过来塞到WindowsSystem子目录下再重新编译运行,OK!全部正常。自拙作attendance个人考勤软件发表后,我又作了一些修改,纠正了其中的错误,又对程序的功能作了进一步的完善,主要是增加了全年多页打印等功能,感兴趣的朋友可到/code/viewcode.asp?id=1471下载!清理VC工程一、 问题的提出在学习Visual C+编程的时候,会建立一个又一个的工程,这么多的工程,除了管理上的问题之外,就是要占用大量的磁盘空间,而实际有用的东西并不大。如果VC工程较长的时间不用,而又必须保留,那么清除其中无用的东西就势在必行。在VC工程中,我们可以把工程目录下面的*.ncb、*.opt、*.plg文件删除是不会影响工程的完整性,另外还有比较大的就是debug和release两个文件夹,也可以删除。二、 问题的解决思路要想解决上面的问题,最笨的办法就是手工删除你不想要的东西,但是这样耗时耗力。最好的办法就是写一个程序,来完成你想完成的任务。解决的思路就是用递归的办法查找每一个目录,如果目录下含有*.dsw文件,我们就认为这就是一个VC工程,然后按照要求删除文件。对于生成EXE的工程,为了便于浏览运行结果,也可以只保留debug或release目录下的EXE文件。三、 问题的解决本人在Windows 98下,用Visual C+ 6.0 编写了一程序,程序的内容

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论