Win32 - 对象清理和全局变量

时间:2010-12-28 00:36:36

标签: c++ winapi free

我在c ++中有一个关于全局变量和对象清理的问题。

例如,请查看此处的代码;

case WM_PAINT:
    paintText(&hWnd);
    break;



void paintText(HWND* hWnd) {
     PAINTSTRUCT ps;

     HBRUSH hbruzh = CreateSolidBrush(RGB(0,0,0));
     HDC hdz = BeginPaint(*hWnd,&ps);   
     char s1[] = "Name";
    char s2[] = "IP";

    SelectBrush(hdz,hbruzh);
    SelectFont(hdz,hFont);
    SetBkMode(hdz,TRANSPARENT);
    TextOut(hdz,3,23,s1,sizeof(s1));
    TextOut(hdz,10,53,s2,sizeof(s2));

    EndPaint(*hWnd,&ps);
    DeleteObject(hdz);
    DeleteObject(hbruzh);   // bad?
    DeleteObject(ps);       // bad?
}

1)首先;删除哪些对象以及哪些对象不适合删除?为什么?不是100%肯定这一点。

2)由于每次重绘窗口时都会调用WM_PAINT,因此简单地更好 将ps,hdz和hbruzh存储为全局变量而不是每次都重新初始化它们?我猜测的缺点是最终的吨全局变量> _>但性能方面是否会降低CPU消耗?我知道这并不重要,但我只是为了教育目的而尽可能简约。

3)加载的库怎么样?例如:

//
// Main
//
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
               LPSTR lpCmdLine, int nCmdShow) {
    // initialize vars
    HWND hWnd;
    WNDCLASSEX wc;
    HINSTANCE hlib = LoadLibrary("Riched20.dll");
    ThishInstance = hInstance;
    ZeroMemory(&wc,sizeof(wc));

    // set WNDCLASSEX props
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = ThishInstance;
   wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MYICON));
    wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = TEXT("PimpClient");
    RegisterClassEx(&wc);

    // create main window and display it
    hWnd = CreateWindowEx(NULL, 
                            wc.lpszClassName,
                            TEXT("PimpClient"),
                            0,
                            300,
                            200,
                            450,
                            395,
                            NULL,
                            NULL,
                            hInstance,
                            NULL);
     createWindows(&hWnd);
    ShowWindow(hWnd,nCmdShow);

    // loop message queue
    MSG msg;
    while (GetMessage(&msg, NULL,0,0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);

    }

    // cleanup?
    FreeLibrary(hlib);
    return msg.wParam;
 }

3cont)FreeLibrary到底有没有理由?我的意思是当进程终止时,所有资源都被释放了?由于该库用于在整个程序中绘制文本,为什么我要在此之前释放?

干杯

4 个答案:

答案 0 :(得分:6)

1.-您应删除为其创建HANDLE的所有对象。如果对象是使用WIN32函数创建的,则应使用另一个WIN32函数释放它。 PAINTSTRUCT是在Stack上创建的变量,因此当函数范围结束时它将被删除。

2.-有一条规则说:声明一个变量就像你使用它一样近。公共变量模糊了代码。

3.-如果文档说您需要释放资源,那么您必须这样做才能避免出现意外结果:http://msdn.microsoft.com/en-us/library/aa923590.aspx

编程Windows ,CHARLES PETZOLD的书籍是编写WIN32 API的最完整指南之一:http://www.charlespetzold.com/books.html

公共变量的另一种方法是在WM_CREATE消息上创建GDI对象并在WM_DESTROY消息上释放它们:

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HBRUSH hBrushRed;
     HDC           hdc;
     PAINTSTRUCT   ps;    
     switch (message)
     {
     case WM_CREATE: hBrushRed = CreateSolidBrush (RGB (255, 0, 0)) ;
     case WM_PAINT: 
          hdc = BeginPaint (hwnd, &ps) ;
          /* .. use gdi objects ... */
          SelectObject (hdc, GetStockObject (NULL_PEN)) ;
          SelectObject (hdc, hBrushRed) ;              
          EndPaint (hwnd, &ps) ;
          return 0 ;    
     case WM_DESTROY:
          DeleteObject (hBrushRed) ;
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

答案 1 :(得分:3)

  1. 您必须清理您创建的每个对象 - 但不是每个对象都以相同的方式清理。 DeleteObject只删除GDI对象,设备上下文和画笔等。最好的方法是告诉你需要做什么来清理对象,看看Windows API文档。例如CreateSolidBrush的文档说:
  2.   

    当您不再需要HBRUSH时   对象,调用DeleteObject函数   删除它。

    所以我不确定为什么你的行DeleteObject(hbruzh);标记为坏。并且BeginPaint说:

      

    每次调用BeginPaint都必须有一个   相应的调用EndPaint   功能

    另一个线索是PAINTSTRUCT不是以'H'开头,表示它是一个句柄。 DeleteObject仅释放GDI句柄。您可能不需要在hdz上调用DeleteObject,EndPaint应该清除从BeginPaint()生成的任何内容。

    1. 不,你不应该缓存PAINTSTRUCT。它不会为每个调用返回相同的值。例如,如果只需要重绘部分窗口,它会设置剪切区域。 BeginPaint / EndPaint的目的是它们应该调用每个WM_PAINT消息(并且只在那里)。
    2. 不,你最后不需要FreeLibrary调用,当进程存在时,所有内容都会被清除。

答案 2 :(得分:1)

通常,每个API的MSDN文档都清楚如何清除API返回的句柄或对象:

CreateSolidBrush()http://msdn.microsoft.com/en-us/library/dd183518.aspx):

  

当您不再需要HBRUSH对象时,请调用DeleteObject函数将其删除。

不幸的是,BeginPaint()的文档有点不清楚它应该如何清理它返回的句柄(它似乎根本没有提到返回的HDC的清理 - 只提到{{} 1}}必须被调用)。在一个示例中提到EndPaint() API文档指向(http://msdn.microsoft.com/en-us/library/dd162487.aspx):

  

BeginPaint返回用于在客户区绘制的显示设备上下文的句柄; EndPaint结束绘制请求并释放设备上下文。

因此,您必须致电BeginPaint(),但不需要明确删除您从EndPaint()获得的HDC

您为BeginPaint()PAINTSTRUCT提供的BeginPaint()对象不是Win32系统返回的句柄(具体来说,它不是“逻辑笔的句柄, “EndPaint()处理的画笔,字体,位图,区域或调色板”,因此不需要通过调用DeleteObject()来删除它 - 事实上,它不能传递给{{1 }}

答案 3 :(得分:1)

hBrush上的DeleteObject释放与GDI对象关联的所有系统资源。 http://msdn.microsoft.com/en-us/library/aa923962.aspx

不应该在PAINTSTRUCT上调用DeleteObject。你没有在堆栈上创建这个吗?为什么需要释放与之相关的系统资源?