博文
Attach函数与Detach函数(2010-08-26 19:58:00)
摘要:
首先,你要明白Windows对象和MFC对象的区别。MFC对象实际上并没有把整个Windows对象都包装在其中,它只是有一个窗口句柄而已,这个窗 口句柄如果指向一个实际存在的窗口对象,那么这个MFC对象就是有效的,否则这个MFC对象是空的。如果你还不明白,请回忆一下,当我们使用MFC创建一 个窗口时,是分两步进行的,第一步,new一个CWnd对象,这一步是创建MFC对象,但是其中的HWND还是非法的,因为对应的Windows对象还没 有被创建出来;第二步,调用CWnd的成员函数Create创建真正的Windows对象,同时,把先前创建的MFC的CWnd对象的HWND成员指向该 窗口,这样才算创建完毕一个窗口。而如果你是用SDK方式,那么只要创建一个WNDCLASS结构,然后调用Create或者CreateEx就创建了一 个窗口。
好,现在回答你的问题,你可以假设,现在你已经有了一个有效窗口句柄,那么你想把这个窗口和一个CWnd对象关联起来怎么办?很简单,用Attach,其实就是让一个CWnd对象的HWND成员指向这个窗口句柄。这就是Attach主要完成的任务。
第二个,关于Detach。如前所述,WNDCLASS其实和CWnd根本没有什么关系。它们之间只是通过CWnd的成员HWND联系起来的。如果把 Attach看做“联姻”的话,那么Detach就是“离婚”了,通俗地说,就是切断一个CWnd对象和一个有效窗口的脐带。为什么要切断呢?因为 CWnd是C++的对象,C++的对象有一个生存期的概念,脱离了该对象的作用域,这个对象就要被销毁,但是Windows对象没有这个特点,当销毁 CWnd对象的时候,我们不一定希望WNDCLASS一起被销毁,那么在此之前,我们就先要把这个“脐带”剪断,以免“城门失火,殃及池鱼”。
转:http://hi.baidu.com/lrg319/blog/item/ab0d77ee926e81f1b2fb95cd.html......
(好)(转:五种网络IO模型)winsock IO模型(2010-08-23 15:41:00)
摘要:winsock IO模型
如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的Windows操作系统提供了选择(Select)异步选择(WSAAsyncSelect)事件选择(WSAEventSelect)重叠I/O(Overlapped I/O)和完成端口(Completion Port)共五种I/O模型每一种模型均适用于一种特定的应用场景程序员应该对自己的应用需求非常明确,而且综合考虑到程序的扩展性和可移植性等因素,作出自己的选择
我会以一个回应反射式服务器(与Windows网络编程第八章一样)来介绍这五种I/O模型
我们假设客户端的代码如下(为代码直观,省去所有错误检查,以下同):
#include <WINSOCK2.H>
#include <stdio.h>
#define SERVER_ADDRESS "137.117.2.148"
#define PORT 5150
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
SOCKET sClient;
SOCKADDR_IN server;
char szMessage[MSGSIZE];
int ret;
// Initialize Windows socket libr......
ASSERT(afxCurrentInstanceHandle!=NULL)(2010-08-11 14:58:00)
摘要:afxwin1.inl assert at line:23
好久没更新了,奉献一篇技术贴。
最近使用ATL 7.0 写windows服务,因为以前的程序是用MFC编写的,遇到一些麻烦,解决问题花了些时间.
拿出来共享一下.
其实就是一个经常出现的错误:
afxwin1.inl assert at line:23
现象:打开afxwin1.inl 发现assert(afxCurrentInstanceHandle != NULL)出错
我心想MFC这个垃圾不会要我手动赋吧,所以研究了很久,看看自己初始化是不是缺少什么不骤,还是哪里修改了这个值. 后来发现,手动赋才是王道,因为如果是MFC程序,这个赋值在CWinAPP的里就作了,不过因为嫌太麻烦就懒得找了,呵呵.
另外一个问题,ATL程序如何获得这个句柄呢,其实每个ATL程序都会有一个全局成员 _AtlBaserModule保存这重要的句柄.
ok
solution:
在ATL程序初始化阶段手动赋值
afxCurrentInstanceHandle = _AtlBaseModule.GetModuleInstance();
afxCurrentResourceHandle = _AtlBaseModule.GetResourceInstance(); (这个也要赋一下,呵呵)
引用http://lavadiablo.spaces.live.com/blog/cns!edb786de4aef809a!246.entry
......
C++中头文件相互包含的几点问题[转](2010-08-06 13:59:00)
摘要:一、类嵌套的疑问
C++头文件重复包含实在是一个令人头痛的问题,前一段时间在做一个简单的数据结构演示程序的时候,不只一次的遇到这种问题。假设我们有两个类A和B,分别定义在各自的有文件A.h和B.h中,但是在A中要用到B,B中也要用到A,但是这样的写法当然是错误的:
class B;
class A
{
public:
B b;
};
class B
{
public:
A a;
};
因为在A对象中要开辟一块属于B的空间,而B中又有A的空间,是一个逻辑错误,无法实现的。在这里我们只需要把其中的一个A类中的B类型成员改成指针形式就可以避免这个无限延伸的怪圈了。为什么要更改A而不是B?因为就算你在B中做了类似的动作,也仍然会编译错误,表面上这仅仅上一个先后顺序的问题。
为什么会这样呢?因为C++编译器自上而下编译源文件的时候,对每一个数据的定义,总是需要知道定义的数据的类型的大小。在预先声明语句class B;之后,编译器已经知道B是一个类,但是其中的数据却是未知的,因此B类型的大小也不知道。这样就造成了编译失败,VC++6.0下会得到如下编译错误:
error C2079: 'b' uses undefined class 'B'
将A中的b更改为B指针类型之后,由于在特定的平台上,指针所占的空间是一定的(在Win32平台上是4字节),这样可以通过编译。
二、不同头文件中的类的嵌套
在实际编程中,不同的类一般是放在不同的相互独立的头文件中的,这样两个类在相互引......
醴陵瓷器(2010-07-27 13:49:00)
摘要: 醴陵瓷器
醴陵是一座古老而充满现代气息的江南城市,享有“瓷城”美誉,是举世闻名的釉下五彩瓷原产地。瓷器是中
国独创的发明之一,至今英文仍把瓷器称之为“china”。醴陵陶瓷生产已有近两千年的历史,远在东汉时期,醴陵就有较大规模的作坊,专门从事陶器制作。清朝雍正七年(1729年)醴陵开始烧制粗瓷。清朝末年至民国初年,醴陵瓷业进入到一个新的发展时期。
漫长的历史长河中,有许多仁人志士和能工巧匠,为醴陵瓷业的发展呕心沥血,作出了重大贡献。1904年,湖南凤凰人熊希龄(辛亥革命后担任北洋政府总理)与曾参与“公车上书”的醴陵举人文俊铎,本着实业救国的思想赴日本考察。在日本期间,他们发现日本瓷业技术先进,产品精良。第二年回国后,熊希龄在文俊铎陪同下,前往醴陵的主要粗瓷产地进行调查,找出了醴陵瓷业生产落后的主要原因,同时又看到了醴陵进一步发展瓷业生产的有利条件:消费市场广阔,瓷土资源丰富,劳动力价格低廉。随即提出了“立学堂、设公司”等主张,得到了湖南官府的大力支持。当年,湖南官立瓷业学堂在醴陵正式开办,次年,湖南瓷业制造公司在醴陵成立,熊希龄任公司总经理,文俊铎任学堂监督。公司聘请日本技师和景德镇技术工人,引进了当时日本最先进的生产工艺和设备,开启了醴陵由粗瓷生产到细瓷开发的新纪元。独具特色的醴陵釉下五彩瓷就是在这样的背景下研制出来的。
此前,醴陵瓷器用单一的氧化钴(俗称土墨)作彩饰原料,手工描绘粗犷花草图案后,施釉覆盖,烧成釉下青花瓷。1907年至1908年,湖南瓷业学堂研制出草青、海碧、艳黑、赭色和玛瑙红等多种釉下颜料。湖南瓷业制造公司的绘画名师和瓷业学堂陶画班的毕业生,经过反复研制,采用自制釉下色料,运用国画双勾分水填色和“三烧制”法,生产出令人耳目一新的釉下五彩瓷器。釉下五彩瓷器瓷质细腻,画工精美,清新雅丽,别具一格,釉层下五彩缤纷,呈现出栩栩如生的画面,具有较高的艺术价值和使用价值。它的问世,立即得到业内人士和国内外舆论的极大关注和好评。1909年到1911年,醴陵釉下五彩瓷分别参展武汉劝业会、南洋劝业会和意大利都朗国际赛会,连续获得金牌奖,醴陵瓷器开始名扬华夏,走向世界。“白如玉、明如镜、薄如纸、声如磬”,就是醴陵瓷在当时赢得的良好评价。
1915年,醴陵瓷器远涉重洋,参加了在美国旧金山举行的巴拿马太平洋万国博览会,参展的釉下五彩扁......
线程中CreateEvent和SetEvent及WaitForSingleObj(2010-07-21 17:24:00)
摘要:
首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,程锁定方面.
CreateEvent
函功能描述:创建或打开一个命名的或无名的事件对象.
EVENT有两种状态:发信号,不发信号。
SetEvent/ResetEvent分别将EVENT置为这两种状态分别是发信号与不发信号。
WaitForSingleObject()等待,直到参数所指定的OBJECT成为发信号状态时才返回,OBJECT可以是EVENT,也可以是其它内核对象。
当你创建一个线程时,其实那个线程是一个循环,不像上面那样只运行一次的。这样就带来了一个问题,在那个死循环里要找到合适的条件退出那个死循环,那么是怎么样实现它的呢?在Windows里往往是采用事件的方式,当然还可以采用其它的方式。在这里先介绍采用事件的方式来通知从线程运行函数退出来,它的实现原理是这样,在那个死循环里不断地使用 WaitForSingleObject函数来检查事件是否满足,如果满足就退出线程,不满足就继续运行。当在线程里运行阻塞的函数时,就需要在退出线程时,先要把阻塞状态变成非阻塞状态,比如使用一个线程去接收网络数据,同时使用阻塞的SOCKET时,那么要先关闭SOCKET,再发送事件信号,才可以退出线程的。
当然我感觉重要应用方面还是用来锁定,实现所谓的pv功能。
下面介绍函数功能,参数等
1.CreateEvent
函数功能描述:创建或打开一个命名的或无名的事件对象
函数原型:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性
BOOL bManualReset, // 复位方式
BOOL bInitialState, // 初始状态
LPCTSTR lpName // 对象名称......
函数的调用规则(__cdecl,__stdcall,__fastcall,__p(2010-07-21 15:41:00)
摘要:关于函数的调用规则(调用约定),大多数时候是不需要了解的,但是如果需要跨语言的编程,比如VC写的dll要delphi调用,则需要了解。 microsoft的vc默认的是__cdecl方式,而windows API则是__stdcall,如果用vc开发dll给其他语言用,则应该指定__stdcall方式。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作,如果是__cdecl方式的函数,则函数本身(如果不用汇编写)则不需要关心保存参数的堆栈的清除,但是如果是__stdcall的规则,一定要在函数退出(ret)前恢复堆栈。
1.__cdecl
所谓的C调用规则。按从右至左的顺序压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的。返回值在EAX中因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的时候对这种调用规则的函数生成修饰名的饿时候,仅在输出函数名前加上一个下划线前缀,格式为_functionname。
2.__stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,切记:函数自己在退出时清空堆栈,返回值在EAX中。 __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_functionname@number。如函数int func(int a, double b)的修饰名是_func@12。
3.__fastcall
__fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。__fastca......
进程和线程的区别(2010-06-17 10:58:00)
摘要:进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于:
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。如果有兴趣深入的话,我建议你们看看《现代操作系统》或者《操作系统的设计与实现》。对就个问题说得比较清楚。
本文来自CSDN博客http://blog.csdn.net/andy6355/archive/2008/06/03/2506171.aspx......
C++ 运算符优先级列表(2010-06-12 20:59:00)
摘要:
Precedence
Operator
Description
Example
Associativity
1
()
[]
->
.
::
++
--
Grouping operator
Array access
Member access from a pointer
Member access from an object
Scoping operator
Post-increment
Post-decrement
(a + b) / 4;
array[4] = 2;
ptr->age = 34;
obj.age = 34;
Class::age = 2;
for( i = 0; i < 10; i++ ) ...
for( i = 10; i > 0; i-- ) ...
left to right
2
!
~
++
--
-
+
*
&
(type)
sizeof
Logical negation
Bitwise complement
Pre-increment
Pre-decrement
Unary minus
Unary plus
Dereference
Address of
Cast to a given type
Return size in bytes
if( !done ) ...
flags = ~flags;
for( i = 0; i < 10; ++i ) ...
for( i = 10; i > 0; --i ) ...
int i = -1;
int i = +1;