斜树的空间

集中精力,放弃一切的去做一件事情,只要尽力了,即使失败了,你也不会后悔!

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  47 随笔 :: 0 文章 :: 12 评论 :: 0 Trackbacks

#


一:列文件清单
1. List
(gdb) list line1,line2

二:执行程序
要想运行准备 调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符 (*、?、[、])在内。
如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。
利用 set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。
(gdb)set args –b –x
(gdb) show args
backtrace命令为堆栈提供向后跟踪功能。
Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。

三:显示数据
利用print 命令可以检查各个变量的值。
(gdb) print p (p为变量名)
whatis 命令可以显示某个变量的类型
(gdb) whatis p
type = int *

print 是gdb的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外,还可以包含以下内容:
l 对程序中函数的调用
(gdb) print find_entry(1,0)
l 数据结构和其他复杂对象
(gdb) print *table_start
$8={e=reference=’\000’,location=0x0,next=0x0}
l 值的历史成分
(gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值)
l 人为数组
人为数 组提供了一种去显示存储器块(数组节或动态分配的存储区)内容的方法。早期的调试程序没有很好的方法将任意的指针换成一个数组。就像对待参数一样,让我们 查看内存中在变量h后面的10个整数,一个动态数组的语法如下所示:
base@length
因此,要想显示在h后面的10个元素,可 以使用h@10:
(gdb)print h@10
$13=(-1,345,23,-234,0,0,0,98,345,10)

四: 断点(breakpoint)
break命令(可以简写为b)可以用来在调试的程序中设置断点,该命令有如下四种形式:
l break line-number 使程序恰好在执行给定行之前停止。
l break function-name 使程序恰好在进入指定的函数之前停止。
l break line-or-function if condition 如果condition(条件)是真,程序到达指定行或函数时停止。
l break routine-name 在指定例程的入口处设置断点

如 果该程序是由很多原文件构成的,你可以在各个原文件中设置断点,而不是在当前的原文件中设置断点,其方法如下:
(gdb) break filename:line-number
(gdb) break filename:function-name

要想设置 一个条件断点,可以利用break if命令,如下所示:
(gdb) break line-or-function if expr
例:
(gdb) break 46 if testsize==100

从断点继续运行:countinue 命令
五. 断点的管理

1. 显示当前gdb的断点信息:
(gdb) info break
他会以如下的形式显示所有的断点信 息:
Num Type Disp Enb Address What
1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155
2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168
(gdb)
2.删除指定的某个断点:
(gdb) delete breakpoint 1
该命令将会删除编号为1的断点,如果不带编号参数,将删除所有的断点
(gdb) delete breakpoint
3.禁止使用某个断点
(gdb) disable breakpoint 1
该命令将禁止断点 1,同时断点信息的 (Enb)域将变为 n
4.允许使用某个断点
(gdb) enable breakpoint 1
该 命令将允许断点 1,同时断点信息的 (Enb)域将变为 y
5.清除原文件中某一代码行上的所有断点
(gdb)clean number
注:number 为原文件的某个代码行的行号
六.变量的检查和赋值
l whatis:识别数组或变量的类型
l ptype:比whatis的功能更强,他可以提供一个结构的定义
l set variable:将值赋予变量
l print 除了显示一个变量的值外,还可以用来赋值

七.单步执行
l next
不进入的单步执行
l step
进入的单步执行
如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令finish
八.函数的调 用
l call name 调用和执行一个函数
(gdb) call gen_and_sork( 1234,1,0 )
(gdb) call printf(“abcd”)
$1=4
l finish 结束执行当前函数,显示其返回值(如果有的话)

九. 机器语言工具
有一组专用的gdb变量可以用来检查和修改计算机的通用寄存器,gdb提供了目前每一台计算机中实际使用的4个寄存器的标准名字:
l $pc : 程序计数器
l $fp : 帧指针(当前堆栈帧)
l $sp : 栈指针
l $ps : 处理器状态

十.信号
gdb通常可以捕捉到发送给它的大多数信号,通过捕捉信号,它就可决定对于正在运行的进程要做些什么工 作。例如,按CTRL-C将中断信号发送给gdb,通常就会终止gdb。但是你或许不想中断gdb,真正的目的是要中断gdb正在运行的程序,因 此,gdb要抓住该信号并停止它正在运行的程序,这样就可以执行某些调试操作。

Handle命令可控制信号的处理,他有两个参数,一个 是信号名,另一个是接受到信号时该作什么。几种可能的参数是:
l nostop 接收到信号时,不要将它发送给程序,也不要停止程序。
l stop 接受到信号时停止程序的执行,从而允许程序调试;显示一条表示已接受到信号的消息(禁止使用消息除外)
l print 接受到信号时显示一条消息
l noprint 接受到信号时不要显示消息(而且隐含着不停止程序运行)
l pass 将信号发送给程序,从而允许你的程序去处理它、停止运行或采取别的动作。
l nopass 停止程序运行,但不要将信号发送给程序。
例 如,假定你截获SIGPIPE信号,以防止正在调试的程序接受到该信号,而且只要该信号一到达,就要求该程序停止,并通知你。要完成这一任务,可利用如下 命令:
(gdb) handle SIGPIPE stop print
请注意,UNIX的信号名总是采用大写字母!你可以用信号编 号替代信号名
如果你的程序要执行任何信号处理操作,就需要能够测试其信号处理程序,为此,就需要一种能将信号发送给程序的简便方法,这就是 signal命令的任务。该 命令的参数是一个数字或者一个名字,如SIGINT。假定你的程序已将一个专用的SIGINT(键盘输入,或CTRL-C;信号2)信号处理程序设置成采 取某个清理动作,要想测试该信号处理程序,你可以设置一个断点并使用如下命令:
(gdb) signal 2
continuing with signal SIGINT(2)
该程序继续执行,但是立即传输该信号,而且处理程序开始运行.

十一. 原文件的搜索
search text:该命令可显示在当前文件中包含text串的下一行。
Reverse-search text:该命令可以显示包含text 的前一行。

十二.UNIX接口
shell 命令可启动UNIX外壳,CTRL-D退出外壳,返回到 gdb.

十三.命令的历史
为了允许使用历史命令,可使用 set history expansion on 命令
(gdb) set history expansion on

小结:常用 的gdb命令
backtrace 显示程序中的当前位置和表示如何到达当前位置的栈跟踪(同义词:where)
breakpoint 在程序中设置一个断点
cd 改变当前工作目录
clear 删除刚才停止处的断点
commands 命中断点时,列出将要执行的命令
continue 从断点开始继续执行
delete 删除一个断点或监测点;也可与其他命令一起使用
display 程序停止时显示变量和表达时
down 下移栈帧,使得另一个函数成为当前函数
frame 选择下一条continue命令的帧
info 显示与该程序有关的各种信息
jump 在源程序中的另一点开始运行
kill 异常终止在gdb 控制下运行的程序
list 列出相应于正在执行的程序的原文件内容
next 执行下一个源程序行,从而执行其整体中的一个函数
print 显示变量或表达式的值
pwd 显示当前工作目录
pype 显示一个数据结构(如一个结构或C++类)的内容
quit 退出gdb
reverse-search 在源文件中反向搜索正规表达式
run 执行该程序
search 在源文件中搜索正规表达式
set variable 给变量赋值
signal 将一个信号发送到正在运行的进程
step 执行下一个源程序行,必要时进入下一个函数
undisplay display命令的反命令,不要显示表达式
until 结束当前循环
up 上移栈帧,使另一函数成为当前函数
watch 在程序中设置一个监测点(即数据断点)
whatis 显示变量或函数类型
****************************************************
 GNU的调试器称为gdb,该程序是一个交互式工具,工作在字符模式。在 X Window 系统中,有一个gdb的前端图形工具,称为xxgdb。gdb 是功能强大的调试程序,可完成如下的调试任务:
  * 设置断点;
* 监视程序变量的值;
  * 程序的单步执行;
  * 修改变量的值。
  在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量:
   CFLAGS = -g
运行 gdb 调试程序时通常使用如下的命令:
   gdb progname

  在 gdb 提示符处键入help,将列出命令的分类,主要的分类有:
  * aliases:命令别名
  * breakpoints:断点定义;
  * data:数据查看;
  * files:指定并查看文件;
  * internals:维护命令;
  * running:程序执行;
  * stack:调用栈查看;
  * statu:状态查看;
  * tracepoints:跟踪程序执行。
  键入 help 后跟命令的分类名,可获得该类命令的详细清单。


gdb 的常用命令
命令 解释
  break NUM 在指定的行上设置断点。
  bt 显示所有的调用栈帧。该命令可用来显示函数的调用顺序。
  clear 删除设置在特定源文件、特定行上的断点。其用法为clear FILENAME:NUM
  continue 继续执行正在调试的程序。该命令用在程序由于处理信号或断点而 导致停止运行时。
  display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成。
  file FILE 装载指定的可执行文件进行调试。
  help NAME 显示指定命令的帮助信息。
  info break 显示当前断点清单,包括到达断点处的次数等。
  info files 显示被调试文件的详细信息。
  info func 显示所有的函数名称。
  info local 显示当函数中的局部变量信息。
  info prog 显示被调试程序的执行状态。
  info var 显示所有的全局和静态变量名称。
  kill 终止正被调试的程序。
  list 显示源代码段。
  make 在不退出 gdb 的情况下运行 make 工具。
  next 在不单步执行进入其他函数的情况下,向前执行一行源代码。
  print EXPR 显示表达式 EXPR 的值。

******gdb 使用范例************************
-----------------
清单 一个有错误的 C 源程序 bugging.c
代码:

-----------------
1 #i nclude
2
3 static char buff [256];
4 static char* string;
5 int main ()
6 {
7   printf ("Please input a string: ");
8 gets (string);  
9   printf ("\nYour string is: %s\n", string);
10 }


-----------------
上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该程序使用了一个未经过初始化的字符串地址 string,因此,编译并运行之后,将出现 Segment Fault 错误:
$ gcc -o bugging -g bugging.c
$ ./bugging
Please input a string: asfd
Segmentation fault (core dumped)
为了查找该程序中出现的问题,我们利用 gdb,并按如下的步骤进行:
1.运行 gdb bugging 命令,装入 bugging 可执行文件;
2.执行装入的 bugging 命令 run;
3.使用 where 命令查看程序出错的地方;
4.利用 list 命令查看调用 gets 函数附近的代码;
5.唯一能够导致 gets 函数出错的因素就是变量 string。用print命令查看 string 的值;
6.在 gdb 中,我们可以直接修改变量的值,只要将 string 取一个合法的指针值就可以了,为此,我们在第8行处设置断点 break 8;
7.程序重新运行到第 8行处停止,这时,我们可以用 set variable 命令修改 string 的取值;
8.然后继续运行,将看到正确的程序运行结果。
(http://www.fanqiang.com)

posted @ 2010-10-12 11:56 张贵川 阅读(671) | 评论 (0)编辑 收藏


Unix已经有35年历史了。许多人认为它开始于中世纪,这个中世纪是相对于
计算机技术的产生和发展来说的。在过去的时间里,Unix和它的子分支Linux收集
有许多的历史和一些完全古老的语言。在这篇技巧文章中,我们将介绍一少部分古
老的语言和它们的目的和作用,以及它们真正的来源。 

RC 

在Linux中,最为常用的缩略语也许是“rc”,它是“runcomm”的缩写――即名词
“run   command”(运行命令)的简写。今天,“rc”是任何脚本类文件的后缀,这些
脚本通常在程序的启动阶段被调用,通常是Linux系统启动时。如   
/etc/rs是
Linux启动的主脚本,而.bashrc是当Linux的bash   shell启动后所运行的脚
本。.bashrc的前缀“.”是一个命名标准,它被设计用来在用户文件中隐藏那些用户
指定的特殊文件;“ls”命令默认情况下不会列出此类文件,“rm”默认情况下也不会
删除它们。许多程序在启动时,都需要“rc”后缀的初始文件或配置文件,这对于
Unix的文件系统视图来说,没有什么神秘的。 

ETC 

在“etc
/bin”中的“etc”真正代表的是“etcetera”(附加物)。在早期的Unix系
统中,最为重要的目录是“bin”目录   (“bin”是“binaries”二进制文件――编译后的
程序的缩写),“etc”中则包含琐碎的程序,如启动、关机和管理。运行一个Linux
必须的东西的列表是:一个二进制程序,etcetera,etcetera――换句话说,是一个
底层的重要项目,通常添加一些次等重要的零碎事物。今天,   “etc”包含了广泛
的系统配置文件,这些配置文件几乎包含了系统配置的方方面面,同样非常重要。 

Bin 

今天,许多在Linux上运行的大型子系统,如GNOME或Oracle,所编译成的程
序使用它们自己的“bin”目录(或者是   
/usr/bin,或者是/usr/local/bin)作为标
准的存放地。同样,现在也能够在这些目录看到脚本文件,因为“bin”目录通常添
加到用户的PATH路径中,这样他们才能够正常的使用程序。因此运行脚本通常在
bin中运行良好。 

TTY 

在Linux中,TTY也许是跟终端有关系的最为混乱的术语。TTY是TeleTYpe的
一个老缩写。Teletypes,或者   teletypewriters,原来指的是电传打字机,是
通过串行线用打印机键盘通过阅读和发送信息的东西,和古老的电报机区别并不是
很大。之后,当计算机只能以批处理方式运行时(当时穿孔卡片阅读器是唯一一种
使程序载入运行的方式),电传打字机成为唯一能够被使用的“实时”输入
/输出设
备。最终,电传打字机被键盘和显示器终端所取代,但在终端或   TTY接插的地
方,操作系统仍然需要一个程序来监视串行端口。一个getty“Get   TTY”的处理过
程是:一个程序监视物理的TTY
/终端接口。对一个虚拟网络沮丧服务器(VNC)来说,
一个伪装的TTY(Pseudo
-TTY,即家猫的TTY,也叫做“PTY”)是等价的终端。当你运
行一个xterm(终端仿真程序)或GNOME终端程序时,PTY对虚拟的用户或者如xterm一
样的伪终端来说,就像是一个TTY在运行。“Pseudo”的意思是“duplicating   
in 
a   fake   way”(用伪造的方法复制),它相比“
virtual”或“emulated”更能真实的
说明问题。而在现在的计算中,它却处于被放弃的阶段。 

Dev 

从TTY留下的命令有“stty”,是“
set   tty”(设置TTY)的缩写,它能够生成
一个配置文件
/etc/initab(“initialization   table”,初始表),以配置gettys
使用哪一个串口。在现代,直接附加在Linux窗口上的唯一终端通常是控制台,由
于它是特殊的TTY,因此被命名为“console”。当然,一旦你启动
X11,“console”TTY就会消失,再也不能使用串口协议。所有的TTY都被储存在
/dev”目录,它是“[physical]   devices”([物理]设备)的缩写。以前,你必须在
电脑后面的串口中接入一个新的终端时,手工修改和配置每一个设备文件。现
在,Linux(和   Unix)在安装过程中就在此目录中创建了它所能向导的每一个设备
的文件。这就是说,你很少需要自己创建它。 

随着硬件在电脑中的移出移进,这些名字将变得更加模糊不清。幸运的是,
今天在Linux上的高等级软件块对历史和硬件使用容易理解的名字。举例来说,
嗯,Pango(http:
//www.pango.org/)就是其中之一。 

如果你对这些内容很感兴趣,那么我建议你阅读宏大的,但有些以美国英语
历史为中心的,由Eric   S.   Raymond撰写的Jargon   File。它并没有解释所有
在Unix中使用的术语,但是它给出了这些形成的大致情况。  

posted @ 2010-10-11 23:29 张贵川 阅读(251) | 评论 (0)编辑 收藏

获得CWinApp:
 -在CMainFrame,CChildFrame,CDocument,CView中直接调用AfxGetApp()或用theApp
 -在其它类中只能用AfxGetApp()

获得CMainFrame:
 -在CMinApp中用AfxGetMainWnd()或者m_pMainWnd
 -在CChildFrame中可用GetParentFrame()
 -在其它类中用AfxGetMainWnd()

获得CChildFrame:
 -在CView中用GetParentFrame()
 -在CMainFrame中用MDIGetActive()或GetActiveFrame()
 -在其它类中用AfxGetMainWnd()->MDIGetActive()或AfxGetMainWnd()->GetActiveFrame()

获得CDocument:
 -在CView中用GetDocument()
 -在CChildFrame中用GetActiveView()->GetDocument()
 -在CMainFrame中用
  -if SDI:GetActiveView()->GetDocument()
  -if MDI:MDIGetActive()->GetActiveView()->GetDocument()
 -在其它类中
  -if SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()
  -if MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

获得CView:
 -在CDocument中 POSITION pos = GetFirstViewPosition();GetNextView(pos)
 -在CChildFrame中 GetActiveView()
 -在CMainFrame中
  -if SDI:GetActiveView()
  -if MDI:MDIGetActive()->GetActiveView()
 -在其它类中
  -if SDI:AfxGetMainWnd()->GetActiveView()
  -if MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()


不过要注意在doc中要取得view的指针C*View要注意类C*View声明的问题,
因为默认情况下,mfc在*View.h中已经包含了*Doc.h,如果在*Doc.h中包含
*View.h,就会引起嵌套包含问题,这样要在*Doc.h中加入 class C*View;
而在*Doc.cpp中加入 #include "*View.h"

//////////////////////////////////////////////////////////////////
其实完全可以在CYourApp中添加各种视或文档的指针,在那些视或文档初
始化的时候将指针传给CYourApp中的对应变量,这样以后不管在哪用上面
指针只需(CYourApp*)AfxGetApp()取其属性变量即可,明了而且清楚更是
方便我一直专门操作的说:)

//////////////////////////////////////////////////////////////////
我先抛块砖,有玉的砸过来!
在何时何地,你都可以通过以下方法精确的得到任何一个对象(Application,DocTemplate,Document,View,Frame)
1。通过AfxGetApp()得到当前的App对象;
2。通过AfxGetMainWnd()得到主窗口;
3。通过CMDIFrameWnd::GetActiveFrame得到当前活动窗口;
4。通过GetNextWindow()遍例所有的子窗口;(如果要得到你想要的子窗口,可以通过特定的成员变量来标志);
5。通过CWinApp::GetFirstDocTemplatePostion()以及CWinApp::GetNextDocTemplate()的组合应用来遍历所有的DocTemplate对象,并且用CDocTemplate::GetDocString()来判断当前得到的文档莫板对象是哪个。
6。通过CDocTemplate::GetFirstDocPosition()以及CDocTemplate的GetNextDoc()组合来遍历所有的该模板的文档对象,并用CDocument::GetDocTemplate()来得到文档模板,用CDocment::GetTitle() 或者GetPathName()来判断当前的文档是哪个。
7。通过CDocuemt的GetFirstViewPositon()以及GetNextView()来遍历视图对象,一般通过访问View的成员变量来区别各个视图;通过CView::GetDocument()来得到文档对象;
8。Frame->View: 通过GetActiveView方法;
9。Frame->Doc:通过GetActiveDocument();
10。View->Frame:GetParentFrame();
11。View->Doc:GetDocuemt()//前面已经说了。
12。Doc->View:前面说了;
13。Doc->Frame:不知道有没有很直接的方法。
MFC应用程序中指针的使用

1) 在View中获得Doc指针
2) 在App中获得MainFrame指针
3) 在View中获得MainFrame指针
4) 获得View(已建立)指针
5) 获得当前文档指针
6) 获得状态栏与工具栏指针
7) 获得状态栏与工具栏变量
8) 在Mainframe获得菜单指针
9) 在任何类中获得应用程序类
10) 从文档类取得视图类的指针(1)
11) 在App中获得文档模板指针
12) 从文档模板获得文档类指针
13) 在文档类中获得文档模板指针
14) 从文档类取得视图类的指针(2)
15) 从一个视图类取得另一视图类的指针

VC中编程对于刚刚开始学习的同学,最大的障碍和问题就是消息机制和指针获取与
操作。其实这些内容基本上是每本VC学习工具书上必讲的内容,而且通过MSDN很多
问题都能解决。下面文字主要是个人在编程中指针使用的一些体会,说的不当的地
方请指正。一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架,
无论是多文档还是单文档,都存在指针获取和操作问题。下面这节内容主要是一般
的框架,然后再讲多线程中的指针使用。使用到的类需要包含响应的头文件。首先
一般获得本类(视,文档,对话框都支持)实例指针this,用this的目的,主要可以通
过类中的函数向其他类或者函数中发指针,以便于在非本类中操作和使用本类中的
功能。

 1) 在View中获得Doc指针 CYouSDIDoc *pDoc=GetDocument();一个视只能有一个文
档。
 2) 在App中获得MainFrame指针
CWinApp 中的 m_pMainWnd变量就是MainFrame的指针
也可以: CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();
 3) 在View中获得MainFrame指针 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;
 4) 获得View(已建立)指针 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;
CyouView *pView=(CyouView *)pMain->GetActiveView();
 5) 获得当前文档指针 CDocument * pCurrentDoc =(CFrameWnd *)m_pMainWnd->GetActiveDocument();
 6) 获得状态栏与工具栏指针 CStatusBar * pStatusBar=(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);
CToolBar * pToolBar=(CtoolBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);

 7) 如果框架中加入工具栏和状态栏变量还可以这样
(CMainFrame *)GetParent()->m_wndToolBar;
(CMainFrame *)GetParent()->m_wndStatusBar;

 8) 在Mainframe获得菜单指针 CMenu *pMenu=m_pMainWnd->GetMenu();
 9) 在任何类中获得应用程序类
用MFC全局函数AfxGetApp()获得。

 10) 从文档类取得视图类的指针
我是从http://download.cqcnc.com/soft/program/article/vc/vc405.html学到的,
从文档获得视图类指针目的一般为了控制同一文档的多个视图的定位问题,我的体会
特别是文字处理CEditView当产生多个视图类时,这个功能是非常需要的。
CDocument类提供了两个函数用于视图类的定位:
GetFirstViewPosition()和GetNextView()
virtual POSITION GetFirstViewPosition() const;
virtual CView* GetNextView(POSITION& rPosition) const;

注意:GetNextView()括号中的参数用的是引用方式,因此执行后值可能改变。
GetFirstViewPosition()用于返回第一个视图位置(返回的并非视图类指针,而是一
个POSITION类型值),GetNextView()有两个功能:返回下一个视图类的指针以及用
引用调用的方式来改变传入的POSITION类型参数的值。很明显,在Test程序中,只有
一个视图类,因此只需将这两个函数调用一次即可得到CTestView的指针如下(需定
义一个POSITION结构变量来辅助操作):
CTestView* pTestView;
POSITION pos=GetFirstViewPosition();
pTestView=GetNextView(pos);

这样,便可到了CTestView类的指针pTestView.执行完几句后,变量pos=NULL,因为没
有下一个视图类,自然也没有下一个视图类的POSITION.但是这几条语句太简单,不
具有太强的通用性和安全特征;当象前面说的那样,当要在多个视图为中返回某个指
定类的指针时,我们需要遍历所有视图类,直到找到指定类为止。判断一个类指针指
向的是否某个类的实例时,可用IsKindOf()成员函数时行检查,如:
 pView->IsKindOf(RUNTIME_CLASS(CTestView));
即可检查pView所指是否是CTestView类。

有了以上基础,我们已经可以从文档类取得任何类的指针。为了方便,我们将其作
为一个文档类的成员函数,它有一个参数,表示要获得哪个类的指针。实现如下:
CView* CTestDoc::GetView(CRuntimeClass* pClass)
{
 CView* pView;
 POSITION pos=GetFirstViewPosition();

 while(pos!=NULL){
  pView=GetNextView(pos);
  if(!pView->IsKindOf(pClass))
  break;
 }

 if(!pView->IsKindOf(pClass)){
  AfxMessageBox("Connt Locate the View.\r\n http://www.VCKBASE.com");
  return NULL;
 }

 return pView;
}

其中用了两次视图类的成员函数IsKindOf()来判断,是因为退出while循环有三种
可能:

1.pos为NULL,即已经不存在下一个视图类供操作;
2.pView已符合要求。

1和2同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图
的位置同时返回当前视图指针,因此pos是pView的下一个视图类的POSITION,完全
有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一
个视图类时就如引。因此需采用两次判断。
使用该函数应遵循如下格式(以取得CTestView指针为例):
CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));
RUNTIME_CLASS是一个宏,可以简单地理解它的作用:将类的名字转化为
CRuntimeClass为指针。至于强制类型转换也是为了安全特性考虑的,因为从同一个
基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要,但能避免一
些可能出现的麻烦。

3.从一个视图类取得另一视图类的指针综合1和2,很容易得出视图类之间互相获得
指针的方法:就是用文档类作中转,先用1的方法得到文档类的指针,再用2的方法,
以文档类的视图定位函数取得另一个视图类。同样,可以实现成一个函数:
(假设要从CTestAView中取得指向其它视图类的指针)
CView* CTestAView::GetView(CRuntimeClass* pClass)
{
 CTestDoc* pDoc=(CTestDoc*)GetDocument();
 CView* pView;
 POSITION pos=pDoc->GetFirstViewPosition();
 while(pos!=NULL){
  pView=pDoc->GetNextView(pos);
  if(!pView->IsKindOf(pClass))
  break;
 }
 if(!pView->IsKindOf(pClass)){
  AfxMessageBox("Connt Locate the View.");
  return NULL;
 }

 return pView;
}
这个函数和2中的GetView()相比,一是多了第一句以取得文档类指针,二是在
GetFirstViewPosition()和GetNextView()前加上了文档类指针,以表示它们是文档
类成员函数。有了此函数;当要从CTestAView中取得CTestBView的指针时,只需如
下:CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));
11)对于单文档中也可以加入多个文档模板,但是一般的开发就使用MDI方式开发
多文档模板,其方法与上述视图的获取方法很接近,这里稍做解释,如果不清楚,
请查阅MSDN,(以下四个内容(11、12、13、14)来源:
http://sanjianxia.myrice.com/vc/vc45.htm

可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板
的位置;利用该值来调用CWinApp::GetNextDocTemplate函数,获得第一个
CDocTemplate对象指针。 POSITION GetFirstDocTemplate( ) const;
CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;

第二个函数返回由pos 标识的文档模板。POSITION是MFC定义的一个用于迭代或对象
指针检索的值。通过这两个函数,应用程序可以遍历整个文档模板列表。如果被检索
的文档模板是模板列表中的最后一个,则pos参数被置为NULL。

 12)一个文档模板可以有多个文档,每个文档模板都保留并维护了一个所有对应文
档的指针列表。
用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一
个文档的位置,并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与
模板相关的文档列表。函数原形为:
viaual POSITION GetFirstDocPosition( ) const = 0;
visual CDocument *GetNextDoc(POSITION & rPos) const = 0; 

如果列表为空,则rPos被置为NULL.

 13)在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。
函数原形如下: CDocTemplate * GetDocTemplate ( ) const;
如果该文档不属于文档模板管理,则返回值为NULL。

 14)一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表。
CDocument::AddView将一个视连接到文档上,将该视加入到文档相联系的视的列表
中,并将视的文档指针指向该文档。当有File/New、File/Open、Windows/New或
Window/Split的命令而将一个新创建的视的对象连接到文档上时, MFC会自动调用
该函数,框架通过文档/视的结构将文档和视联系起来。当然,程序员也可以根据自
己的需要调用该函数。
Virtual POSITION GetFirstViewPosition( ) const;
Virtual CView * GetNextView( POSITION &rPosition) cosnt;

应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的
列表中的第一个视的位置,并调用CDocument::GetNextView返回指定位置的视,并将
rPositon的值置为列表中下一个视的POSITION值。如果找到的视为列表中的最后一个
视,则将rPosition置为NULL.

 15)从一个视图类取得另一视图类的指针
这个应用在多视的应用程序中很多见,一般如果自己在主程序或者主框架中做好变
量记号,也可以获得,还有比较通用的就是用文档类作中转,以文档类的视图遍历
定位,取得另一个视图类。这个功能从本文第10项中可以得到。


转自:http://www.cppblog.com/justin-shi/archive/2008/06/14/53196.html

posted @ 2010-08-28 12:33 张贵川 阅读(258) | 评论 (0)编辑 收藏

属性-》C/C++-》预编译头-》创建使用预编译头-》不使用
 

posted @ 2010-08-02 22:42 张贵川 阅读(3106) | 评论 (1)编辑 收藏

   工具栏(ToolBar)是一种非常方便的控件,能大大增加用户操作的效率,但是基于对话框的程序,却不能像使用编辑框(Edit Box)和列表框(List Box)一样,方便地增加工具栏控件。本文将介绍一种在对话框中加入工具栏的方法。

  一、 技术要点分析

  所有的Windows控件(包括工具栏、编辑框等)都派生自CWnd类,这就意味着,我们可以用窗口类的Create()函数把它们“创建”并显示到另一个窗口(例如对话框)上。把工具栏加入到对话框中正是使用了这样的一种方法。

  通常,我们使用CToolBarCtrl类(派生自CWnd类)来创建并管理工具栏控件。使用这个类创建一条工具栏的一般步骤如下:

  1.派生一个CToolBarCtrl的对象;

  2.调用CToolBarCtrl::Create函数创建工具栏对象;

  3.调用CToolBarCtrl::AddBitmap()和CToolBarCtrl::AddString()为工具栏对象加入位图和提示信息;

  4.派生一个TBUTTON数组对象进行工具栏中各按钮的具体设置;

  5.修改主窗口的OnNotify()函数,以显示工具栏上的提示信息。

  以上步骤在下面的范例代码中会有具体体现。


  二、 范例程序的建立与主要代码分析


  利用Visual C++ 的向导生成一个基于对话框的程序,命名为ToolBarInDial。修改主对话框样式如图1。绘出一条工具栏的位图并建立一选单,设置几个子选单项,然后建立一组工具栏的提示信息串(String Table),一旦鼠标在工具栏某项上停留,就会显示提示信息。下面给出程序中的主要代码。

  在主对话框CToolBarInDialDlg的类定义中有如下的变量说明:

  CToolBarCtrl ToolBar;

  int ButtonCount;

  int ButtonBitmap;

  BOOL DoFlag;

  TBBUTTON m_Button[5];

  //设置工具栏上具体信息的变量数组

  //主对话框的初始化函数

  BOOL CToolBarInDialDlg::OnInitDialog()

  {

  RECT rect;

  //设置工具栏的显示范围

  rect.top=0; rect.left=0; rect.right=48; rect.bottom=16;

  ToolBar.Create(WS_CHILD|WS_VISIBLE|CCS_TOP|TBSTYLE_TOOLTIPS|CCS_ADJUSTABLE,rect,this,0);

  //建立工具栏并设置工具栏的样式

  ButtonBitmap=ToolBar.AddBitmap(5,IDB_PLAY); //加入工具栏的位图

  ButtonString=ToolBar.AddString(IDS_FIRST);//加入工具栏的提示信息

  //以下代码开始设置各具体的按钮

  m_Buttons[ButtonCount].iBitmap=

  ButtonBitmap+ButtonCount; //ButtonCount初值为0

  m_Buttons[ButtonCount].idCommand=ID_PLAY; //工具栏与选单上某子项对应

  m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

  //设置工具栏按钮为可选

  m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

  //设置工具栏按钮为普通按钮

  m_Buttons[ButtonCount].dwData=0;

  m_Buttons[ButtonCount].iString=IDS_LAST;

   ++ButtonCount;

  //类似地设置第二个按钮

  m_Buttons[ButtonCount].iBitmap=ButtonBitmap+ButtonCount;

  m_Buttons[ButtonCount].idCommand=ID_STOP;

  m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

  m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

  m_Buttons[ButtonCount].dwData=0;

  m_Buttons[ButtonCount].iString=IDS_NEXT;

  ++ButtonCount;

  ……//省略设置剩下的按钮的代码

   ToolBar.AddButtons(ButtonCount,m_Buttons);

  //为工具栏加入按钮并显示在对话框中

   return TRUE;

  }

  //当鼠标在工具栏上停留时,调用这个函数来显示提示信息

  BOOL CToolBarInDialDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)

  {

  TOOLTIPTEXT* tt;

  tt=(TOOLTIPTEXT*)lParam;

  CString Tip;

  switch(tt->hdr.code)

  {

  case TTN_NEEDTEXT:

  //该信息表明要求显示工具栏上的提示

  switch(tt->hdr.idFrom)

  {

  case ID_PLAY:



  Tip.LoadString(IDS_FIRST); //设置对应于工具栏上ID_PLAY的按钮的提示信息

  break;

  case ID_STOP:

  Tip.LoadString(IDS_NEXT);

  //IDS_FIRST,IDS_NEXT等为一系列CString串

  break;

  ……//类似地设置剩下按钮的提示信息

  }

   strcpy(tt->szText,(LPCSTR)Tip);

   //显示提示信息

  break;

  }

  return CDialog::OnNotify(wParam, lParam, pResult);

  }

  //该演示程序的工具栏能由用户定制,随时增加或删除工具栏中的某一项

  void CToolBarInDialDlg::OnApply()

  {

   switch(DoFlag) //用户选择了增加或删除工具栏中的“退出”按钮

  {

  case TRUE: //增加工具栏上的“退出”按钮

  m_Buttons[ButtonCount].iBitmap=ButtonBitmap+ButtonCount;

  m_Buttons[ButtonCount].idCommand=ID_QUIT;

  m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

  m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

  m_Buttons[ButtonCount].dwData=0;

  m_Buttons[ButtonCount].iString=IDS_FIRST;

  ToolBar.InsertButton(ButtonCount,&&m_Buttons[ButtonCount]);

  //根据m_Buttons的信息在工具栏的尾部加上一个按钮

  break;

  case FALSE:

  if(ToolBar.GetButtonCount()==4) //删除工具栏上某一特定位置的按钮

  {

  ToolBar.DeleteButton(3);

  //删除工具栏上某一按钮

  }

  break;

  }

  }

  void CToolBarInDialDlg::OnPlay() //响应函数举例

  {

  ……

  //对应选单项的响应函数

  }
posted @ 2010-08-01 09:44 张贵川 阅读(985) | 评论 (0)编辑 收藏

安装步骤其实很简单,但是你不知道的话,就真的不会。
1.创建虚拟机,选择光盘镜像。
2.启动后会让分区。分区时会让你重启。
3.重启后按F2进入虚拟机中的BIOS设置为光盘启动。
4.进去后就可以了。一路安装。
5.安装完后再次进入BIOS,设置启动为 硬盘 启动。

接着在教你怎样用虚拟机和DOS共享文件:(源自gagbage同学制作)
/Files/Viking/share.pdf
posted @ 2010-07-24 08:51 张贵川 阅读(244) | 评论 (0)编辑 收藏

大学生活过的挺失败的,我是个不甘心落后的人,在技术上,我不认为自己比别人差,然而我却没有做出什么成绩出来。
 究其原因,我发现:我太浮躁了!
每门技术我都学了一半,没有坚持下去。做的也不认真。才造成了我现在半杯水的样子。看真周围的同学都成功的做出了很多作品。并且能赚到钱了,就感到了什么叫压力。
每门技术都很深奥,每门技术却又是那样的诱人,你会什么都想学,什么都想深入,然而却没有时间,总是被其他事情打断学习进程。从大二接触到学习汇编,玩LINUX,却没有坚持下来。大二下有玩单片机和FPGA,但在硬件的基础课程上模电和数字逻辑上学的是在是太烂,最终也放弃了。我就没想过认真的去复习一下课程。后面接触了MFC,又是从0开始学起,为了图快,便只看书,程序写的少的,基础没打的结实,花费了大量的时间然而却没有成果。
后来遇到了一群驱动爱好着,终于理解到什么叫做学习的氛围,一个人学习真的是很累人,进步很慢。也终于理解了为什么布施定律是成功之道。
当然自己也终结了很多的学习方法,但最重要的一条还是:技术的路上踏实认真才是捷径。
同时发现数学课程是多么的重要。
同时发现自己浪费了好多时间在女孩的身上,结果她们最后的话都是不想谈恋爱。我决定以后谈恋爱都找女人,胸部至少有明显的突出,这样的女人谈恋爱会更容易些交互些(母性特征)。
还有男人成熟的开始:就是开始想赚钱买车,买房的时候。
我是看到我同学这学期都赚钱买车,买房和女友出去同居了,才意识到这些东西。想想,自己真的太浮躁,不认真,浪费了太多认真积累的时间,真的太失败!
大家有幸看到我的帖子的话,记住只要选好一个你喜欢的方向,踏实认真的专研下去就可以了,因为没门技术都很深奥,你没有那么多的时间成为全才,看看你自己究竟学了什么东西!至于他踏实认真的方法,因个体而异。
 我目前认为最踏实的方法就是
1.认认真真总结每章所学的内容,可以放到自己的blog上,也可以找个笔记本来认真做笔记,现在才深刻认识到写好字的重要性。
2.课后习题每一题都要认真做,最好把答案都发布到自己的blog上。
3.系统的学习。不要介意你从0开始看,简单就看快一点,不能不看。
4.慢即是快。不要浮躁,你不可能是全才,找准一个方向,不要总是换。一本书一本书的看,认真看完一本在看下一本。相信自己是正确的。因为厚积才能薄发。
posted @ 2010-07-09 11:01 张贵川 阅读(157) | 评论 (0)编辑 收藏

assume cs:codeseg
codeseg segment
        mov ax,2000H
        mov ss,ax
        mov sp,0
        add sp,4
        pop ax
        pop bx
        push ax
        push bx
        pop ax
        pop bx
        mov ax,4c00H
        int 21h
codeseg ends
end

按理来说是DOS中没有栈保护的啊?怎么会就溢出了呢?

经过大量的调试测试:

我试过了,只有ADD SP,N

N <= 10H

并且 N = 奇数 的时候就会崩溃


偶数不崩溃?

N >= 10H  的时候,奇偶都可以
N=7,9,B就直接崩溃
偶数在<=4就触发 DEBUG 的断点中断 INT 3中断

可能关乎 16位机的取数原则:16位机取每次取2个字节,并且最好取偶数地址,取奇数地址则要读取内存2次。意思是栈中的内存SP地址(包括DI,SI等)最好是2的倍数(16位机),这样访存时间最快。32则是4的倍数。

但是为什么会崩溃我还是不明白??
posted @ 2010-06-29 16:19 张贵川 阅读(223) | 评论 (0)编辑 收藏

在使用  重叠IO模型 的时候遇到一个连个 头文件 包含错误,windows.h 和 winsock2.h。在网上找到一篇文章,觉得方法很好,特转载:

在我初学Windows网络编程时,曾经遇到过两类编译错误(VC6的Build窗口哗哗的显示了102个Errors),都是些类型未定义或者重复定义问题,让我感到很郁闷。这两种错误情况下的第一条错误信息分别为:

错误情形1:mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
错误情形2:winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition
后来,我静下心来仔细分析一下错误提示及相关文件,终于找到了原因。

我们知道,Windows网络编程至少需要两个头文件:winsock2.h和windows.h,而在WinSock2.0之前还存在一个老版本的winsock.h。正是这三个头文件的包含顺序,导致了上述问题的出现。

先让我们看看winsock2.h的内容,在文件开头有如下宏定义:

#ifndef _WINSOCK2API_
#define _WINSOCK2API_
#define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
_WINSOCK2API_很容易理解,这是最常见的防止头文件重复包含的保护措施。_WINSOCKAPI_的定义则是为了阻止对老文件winsock.h的包含,即是说,如果用户先包含了winsock2.h就不允许再包含winsock.h了,否则会导致类型重复定义。这是怎样做到的呢?很简单,因为winsock.h的头部同样存在如下的保护措施:

#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_
再回过头来看winsock2.h,在上述内容之后紧跟着如下宏指令:

/*
 * Pull in WINDOWS.H if necessary
 */
#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
其作用是如果用户没有包含windows.h(_INC_WINDOWS在windows.h中定义)就自动包含它,以定义WinSock2.0所需的类型和常量等。

现在切换到windows.h,查找winsock,我们会惊奇的发现以下内容:

#ifndef WIN32_LEAN_AND_MEAN
#include <cderr.h>
#include <dde.h>
#include <ddeml.h>
#include <dlgs.h>
#ifndef _MAC
#include <lzexpand.h>
#include <mmsystem.h>
#include <nb30.h>
#include <rpc.h>
#endif
#include <shellapi.h>
#ifndef _MAC
#include <winperf.h>
#if(_WIN32_WINNT >= 0x0400)
#include <winsock2.h>
#include <mswsock.h>
#else
#include <winsock.h>
#endif /* _WIN32_WINNT >=  0x0400 */

#endif
// 这里省略掉一部分内容
#endif /* WIN32_LEAN_AND_MEAN */

看到没?windows.h会反向包含winsock2.h或者winsock.h!相互间的包含便是万恶之源!

下面具体分析一下问题是怎么发生的。

错误情形1:我们在自己的工程中先包含winsock2.h再包含windows.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT大于或等于0x400,那么windows.h会在winsock2.h开头被自动引入,而windows.h又会自动引入mswsock.h,此时,mswsock.h里所用的socket类型还尚未定义,因此会出现类型未定义错误。

错误情形2:先包含windows.h再包含winsock2.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT未定义或者其版本号小于0x400,那么windows.h会自动导入旧有的winsock.h,这样再当winsock2.h被包含时便会引起重定义。

这里要说明的是,宏WIN32_LEAN_AND_MEAN的作用是减小win32头文件尺寸以加快编译速度,一般由AppWizard在stdafx.h中自动定义。_WIN32_WINNT的作用是开启高版本操作系统下的特殊函数,比如要使用可等待定时器(WaitableTimer),就得要求_WIN32_WINNT的值大于或等于0x400。因此,如果你没有遇到上述两个问题,很可能是你没有在这些条件下进行网络编程。

问题还没有结束,要知道除了VC自带windows库文件外,MS的Platform SDK也含有这些头文件。我们很可能发现在之前能够好好编译的程序在改变了windows头文件包含路径后又出了问题。原因很简单,Platform SDK中的windows.h与VC自带的文件存在差异,其相同位置的代码如下:

#ifndef WIN32_LEAN_AND_MEAN
#include <cderr.h>
#include <dde.h>
#include <ddeml.h>
#include <dlgs.h>
#ifndef _MAC
#include <lzexpand.h>
#include <mmsystem.h>
#include <nb30.h>
#include <rpc.h>
#endif
#include <shellapi.h>
#ifndef _MAC
#include <winperf.h>
#include <winsock.h>  // 这里直接包含winsock.h
#endif
#ifndef NOCRYPT
#include <wincrypt.h>
#include <winefs.h>
#include <winscard.h>
#endif
#ifndef NOGDI
#ifndef _MAC
#include <winspool.h>
#ifdef INC_OLE1
#include <ole.h>
#else
#include <ole2.h>
#endif /* !INC_OLE1 */
#endif /* !MAC */
#include <commdlg.h>
#endif /* !NOGDI */
#endif /* WIN32_LEAN_AND_MEAN */

唉,我们不禁要问MS为什么要搞这么多花样,更让人气愤的是,既然代码不一样,windows.h里却没有任何一个宏定义能够帮助程序辨别当前使用的文件是VC自带的还是PSDK里的。

后来,我写了一个头文件专门处理winsock2.h的包含问题,名为winsock2i.h,只需在要使用WinSock2.0的源文件里第一个包含此文件即可,不过由于前面提到的问题,当使用PSDK时,需要手工定义一下USING_WIN_PSDK,源码如下:

//
// winsock2i.h - Include winsock2.h safely.
//
// Copyleft  02/24/2005  by freefalcon
//
//
// When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is LESS THAN 0x400,
// if we include winsock2.h AFTER windows.h or winsock.h, we get some compiling
// errors as following:
//   winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition
//
// When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is NOT LESS THAN 0x400,
// if we include winsock2.h BEFORE windows.h, we get some other compiling errors:
//   mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
//
// So, this file is used to help us to include winsock2.h safely, it should be
// placed before any other header files.
//
#ifndef _WINSOCK2API_

// Prevent inclusion of winsock.h
#ifdef _WINSOCKAPI_
#error Header winsock.h is included unexpectedly.
#endif

// NOTE: If you use Windows Platform SDK, you should enable following definition:
// #define USING_WIN_PSDK

#if !defined(WIN32_LEAN_AND_MEAN) && (_WIN32_WINNT >= 0x0400) && !defined(USING_WIN_PSDK)
#include <windows.h>
#else
#include <winsock2.h>
#endif

#endif//_WINSOCK2API_

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/freefalcon/archive/2006/11/09/1374733.aspx

按照freefalcon提供的方法,到winsock2.h中看到:
#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
其实只需包含#include <winsock2.h>就可以了,把#include <windows.h>放在#include <winsock2.h>后其实也是可以的,没有包含错误的问题。

但如果又出现这样的错误:
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__closesocket@4,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__WSAGetLastError@0,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__WSARecv@28,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__WSACreateEvent@0,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__accept@12,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__listen@8,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__bind@12,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__htons@4,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__htonl@4,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__socket@12,该符号在函数 _main 中被引用
1>server.obj : error LNK2019: 无法解析的外部符号 __imp__WSAStartup@8,该符号在函数 _main 中被引用

如果出现这样的错误,那就是库没包含了,只要查查MSDN,找到包含这个函数的库就行了,加入一句:

#pragma   comment(lib,   "ws2_32.lib")

posted @ 2010-05-18 20:51 张贵川 阅读(979) | 评论 (0)编辑 收藏

刚遇到一个问题,在MFC中我将映射方式由 MM_TEXT 改为 MM_HIENGLISH 后,竟然无法输出汉字!!但改回 MM_TEXT 后就可以输出汉字了。
这个问题很郁闷,找了很久也不知道是怎么回事....暂时先记在这里。。。

posted @ 2010-05-16 22:17 张贵川 阅读(87) | 评论 (0)编辑 收藏

仅列出标题
共5页: 1 2 3 4 5