2011年9月

C 内存管理详解

  程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。



1、内存分配方式


- 阅读剩余部分 -

windows下的错误代码处理

看了下《windows核心编程》的错误代码处理部分。我这才知道错误代码处理的重要性,以前的时候有错误就埋头苦调,现在发现当初好傻。埋头苦调根本就是又费力又费时,而且错误代码还不一定能调的出来。以后就用Windows下面的错误代码处理额···

下面是一个例子

#include 
DWORD GetLastErrorBox(HWND hWnd, LPSTR lpTitle);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

- 阅读剩余部分 -

WM_PAINT消息的异常情况

碰到了一个很纠结的事情,结果我找了很久才找到问题所在,竟然出在了WM_PAINT消息里面。我本来是想写些GDI的东西的,想设个定时器每隔点时间画个点。结果纠结的事情就是定时器不起作用了,就是画不出点。后来我做了一个精简,写了个小程序,在按下左键的时候触发定时器,然后每1S钟触发WM_TIMER消息,弹出一个框。奇怪的事情就是在这里,老弹不出框。

先看代码:

#include 
#include 

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

#define ID_TIMER 1

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("LineDemo") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;

wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow (szAppName, TEXT ("Line Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HANDLE h_Handle;
HDC hdc ;
static HPEN hPen;
static COLORREF colorrrefRGB =RGB(0,0,0);
static POINT pt;
switch (message)
{
case WM_TIMER:
MessageBox(NULL,"","",MB_OK);
return 0;
case WM_PAINT:

return 0;
case WM_LBUTTONDOWN:
SetTimer(hwnd,ID_TIMER,1000,NULL);
break;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

难道是没有收到WM_TIMER消息?于是我就在WM_LBUTTONDOWN消息里面SendMessage(hwnd,WM_TIMER,NULL,1);
调试的时候发现消息是传到了WM_TIMER里面的,但是就是卡在了MessageBox函数那。这可纠结了···

过了一两个小时,我终于发现问题出在哪里了,就是在WM_PAINT那里!我重新去找了WM_PAINT消息的资料,总算了解了些。
下面是我参考http://www.examda.com/ncre2/cpp/jichu/20090613/082508824-2.html的。

首先,什么时候会触发WM_PAINT消息?在以下情况下,Windows可能发送WM_PAINT消息:
Windows擦除覆盖了部分窗口的对话框或消息框。
菜单下拉出来,然后被释放。
显示工具提示消息。
在某些情况下,Windows总是保存它所覆盖的显示区域,然后恢复它。这些情况是:
鼠标光标穿越显示区域。
图标拖过显示区域。
1. 系统何时发送WM_PAINT消息?
系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由 系统管理的,应用只是被动地接收该消息,在消息处理函数中进行绘制操作;大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和 InvalidateRgn函数来完成的。InvalidateRect和InvalidateRgn把指定的区域加到窗口的Update
Region中,当应用的消息队列没有其他消息时,如果窗口的Update Region不为空时,系统就会自动产生WM_PAINT消息。
系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽 可能地推后做。不过这样也有利于提高绘制的效率:两个WM_PAINT消息之间通过InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到 更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。像这种通过InvalidateRect和InvalidateRgn来使窗口区域无效,依赖于系统在合适的时机发送WM_PAINT消息的机
制实际上是一种异步工作方式,也就是说,在无效化窗口区域和发送WM_PAINT消息之间是有延迟的;有时候这种延迟并不是我们希望的,这时我们当然可以在无效化窗口区域后利用SendMessage 发送一条WM_PAINT消息来强制立即重画,但不如使用Windows GDI为我们提供的更方便和强大的函数:UpdateWindow和RedrawWindow。UpdateWindow会检查窗口的Update
Region,当其不为空时才发送WM_PAINT消息;RedrawWindow则给我们更多的控制:是否重画非客户区和背景,是否总是发送WM_PAINT消息而不管Update Region是否为空等。
2. BeginPaint
BeginPaint函数的作用就是将窗口需要重绘的区域设置为空(也就是Update Region置空)。在正常情况下,我们接收到了WM_PAINT消息后,窗口的Update
Region都是非空的(如果为空就不需要发送WM_PAINT消息了)。而当你响应这个消息的时候又不调用BeginPaint来清空,窗口的Update Region就一直是非空的,系统就会一直发送WM_PAINT消息。这样就形成了一个处理WM_PAINT消息的死循环。BeginPaint和WM_PAINT消息紧密相关。试一试在WM_PAINT处理函数中不写BeginPaint会怎样?程序会像进入了一个死循环一样达到惊人的CPU占用率,你会发现程序总在处理一个接
一个的WM_PAINT消息。这是因为在通常情况下,当应用收到WM_PAINT消息时,窗口的Update Region都是非空的(如果为空就不需要发送WM_PAINT消息了),BeginPaint的一个作用就是把该Update Region置为空,这样如果不调用BeginPaint,窗口的Update
Region就一直不为空,如前所述,系统就会一直发送WM_PAINT消息。另外要注意的一点是,BeginPaint只能在WM_PAINT处理函数中使用,并且在调用了BeginPaint函数后,不要忘记了调用EndPaint函数,他们可是一对的。

再回来上面的代码,这下解决起来就很轻松了。
下面有两种解决方法

1. case WM_PAINT:

hdc = BeginPaint (hwnd, &ps) ;
EndPaint(hwnd, &ps);
return 0 ;
这样就windows就会把无效区域重画了,就不会一直产生WM_PAINT消息,阻塞队列了。这样就自然能弹出对话框了。

2. case WM_PAINT:

break;
直接用break就能跳出switch结构,调用DefWindowProc (hwnd, message, wParam, lParam) ; 交还给Windows自己处理。
Windows自己会处理WM_PAINT消息。

今天就到这里了(*^__^*)

gcc/g++基本命令简介

gcc & g++现在是gnu中最主要和最流行的c & c++编译器 。
g++是c++的命令,以.cpp为主,对于c语言后缀名一般为.c。这时候命令换做gcc即可。其实是无关紧要的。
其实编译器是根据gcc还是g++来确定是按照C标准还是C++标准编译链接。

下面以Test.cpp为例:

- 阅读剩余部分 -

windows程序设计之动态链接库

今天很高兴大笑,因为军训结束了,真是累啊,变得黑人一样。。。(泪奔)委屈

切入正题,最近使用到了HOOK技术,就顺便学习了下DLL的知识,不过只是大概地看了下而已,概念性的东西很多,也就只能了解下,还有很多涉及到操作系统层面的,所以看的云里雾里快哭了。最后东拼西凑写了点,便于以后自己学习。

- 阅读剩余部分 -