简体   繁体   English

Win32 - 对象清理和全局变量

[英]Win32 — Object cleanup and global variables

I've got a question about global variables and object cleanup in c++. 我在c ++中有一个关于全局变量和对象清理的问题。

For example, look at the code here; 例如,看看这里的代码;

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)First of all; 1)首先; which objects are good to delete and which ones are NOT good to delete and why? 删除哪些对象以及哪些对象不适合删除?为什么? Not 100% sure of this. 不是100%肯定这一点。

2)Since WM_PAINT is called everytime the window is redrawn, would it be better to simply store ps, hdz and hbruzh as global variables instead of re-initializing them everytime? 2)由于每次重绘窗口时都会调用WM_PAINT,将ps,hdz和hbruzh作为全局变量存储而不是每次都重新初始化它会更好吗? The downside I guess would be tons of global variables in the end >_> but performance-wise would it not be less CPU-consuming? 我认为最终的缺点是大量的全局变量> _>但是在性能方面它会不会减少占用CPU的数量? I know it won't matter prolly but I'm just aiming for minimalistic as possible for educational purposes. 我知道这并不重要,但我只是为了教育目的而尽可能简约。

3) What about libraries that are loaded in? 3)加载的库怎么样? For example: 例如:

//
// 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) is there a reason to FreeLibrary at the end? 3cont)FreeLibrary到底有没有理由? I mean when the process terminates all resources are freed anyway? 我的意思是当进程终止时,所有资源都被释放了? And since the library is used to paint text throughout the program, why would I want to free before that? 由于该库用于在整个程序中绘制文本,为什么我要在此之前释放?

Cheers 干杯

1.- You should delete all object for which you create a HANDLE. 1.-您应删除为其创建HANDLE的所有对象。 If the object was created by using a WIN32 function it should be released by using another WIN32 function. 如果对象是使用WIN32函数创建的,则应使用另一个WIN32函数释放它。 PAINTSTRUCT is a variable created on the Stack so it will be deleted when the functions scope ends. PAINTSTRUCT是在堆栈上创建的变量,因此在函数范围结束时将删除它。

2.- There is a rule that says: declare a variable as near as you use it. 2.-有一条规则说:声明一个变量就像你使用它一样近。 Public variables obfuscate the code. 公共变量模糊了代码。

3.- If the documentation says you need to free the resource then you must do it for avoiding unexpected results: http://msdn.microsoft.com/en-us/library/aa923590.aspx . 3.-如果文档说您需要释放资源,那么您必须这样做以避免意外结果: http//msdn.microsoft.com/en-us/library/aa923590.aspx

The Programming Windows , CHARLES PETZOLD's Book is one of the most complete guide for programming the WIN32 API: http://www.charlespetzold.com/books.html . 编程Windows ,CHARLES PETZOLD的书籍是WIN32 API编程最完整的指南之一: http//www.charlespetzold.com/books.html

Another approach to public variables is to create your GDI objects on the WM_CREATE message and free them on WM_DESTROY message: 公共变量的另一种方法是在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. You must cleanup every object that you create - however not every object is cleaned up the same way. 您必须清理您创建的每个对象 - 但不是每个对象都以相同的方式清理。 DeleteObject only deletes GDI objects, device contexts and brushes, etc. The best way to tell what you need to do with the cleanup the object is to take a look at the Windows API documentation. DeleteObject只删除GDI对象,设备上下文和画笔等。最好的方法是告诉你需要做什么来清理对象,看看Windows API文档。 For example CreateSolidBrush 's documentation says: 例如, CreateSolidBrush的文档说:

When you no longer need the HBRUSH object, call the DeleteObject function to delete it. 当您不再需要HBRUSH对象时,请调用DeleteObject函数将其删除。

So I'm not sure why you have your line DeleteObject(hbruzh); 所以我不确定为什么你的行有DeleteObject(hbruzh); marked as bad. 标记为坏。 And BeginPaint 's says: BeginPaint的说:

Each call to BeginPaint must have a corresponding call to the EndPaint function. 每次调用BeginPaint都必须对EndPaint函数进行相应的调用。

Another clue is that PAINTSTRUCT does not start with an 'H', designating that it is a handle. 另一个线索是PAINTSTRUCT不是以'H'开头,表示它是一个手柄。 DeleteObject only frees GDI handles. DeleteObject仅释放GDI句柄。 You probably don't need the call to DeleteObject on hdz, EndPaint should take take of cleaning up anything generated from BeginPaint(). 您可能不需要在hdz上调用DeleteObject,EndPaint应该清除从BeginPaint()生成的任何内容。

  1. No you shouldn't cache the PAINTSTRUCT. 不,你不应该缓存PAINTSTRUCT。 It does not return the same values for every call. 它不会为每个调用返回相同的值。 For example it sets up a clipping region if only part of your window need to be redrawn. 例如,如果只需要重绘部分窗口,它会设置剪切区域。 The intention of BeginPaint/EndPaint is that they should called on every WM_PAINT message (and only there). BeginPaint / EndPaint的目的是它们应该调用每个WM_PAINT消息(并且仅在那里)。
  2. No you don't need the FreeLibrary call at the end, everything will be cleaned up when the process exist. 不,您最后不需要FreeLibrary调用,当进程存在时,所有内容都将被清除。

Generally, the MSDN docs for each API is clear about how handles or objects returned by APIs need to be cleaned up: 通常,每个API的MSDN文档都清楚如何清除API返回的句柄或对象:

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

When you no longer need the HBRUSH object, call the DeleteObject function to delete it. 当您不再需要HBRUSH对象时,请调用DeleteObject函数将其删除。

Unfortunately, the documentation for BeginPaint() is a little less clear about how the handle it returns should be cleaned up (it doesn't seem to mention clean up of the returned HDC at all - only mentioning that EndPaint() must be called). 不幸的是, BeginPaint()的文档有点不清楚它应该如何清理它返回的句柄(它似乎根本没有提到返回的HDC的清理 - 只提到必须调用EndPaint() ) 。 There is this mention in an example that the BeginPaint() API docs point to ( http://msdn.microsoft.com/en-us/library/dd162487.aspx ): 在一个示例中提到BeginPaint() API文档指向( http://msdn.microsoft.com/en-us/library/dd162487.aspx ):

BeginPaint returns a handle to the display device context used for drawing in the client area; BeginPaint返回用于在客户区绘制的显示设备上下文的句柄; EndPaint ends the paint request and releases the device context. EndPaint结束绘制请求并释放设备上下文。

So you must call EndPaint() , but do not need to explicitly delete the HDC you got from BeginPaint() 所以你必须调用EndPaint() ,但不需要显式删除你从BeginPaint()获得的HDC

The PAINTSTRUCT object you give to BeginPaint() and EndPaint() isn't a handle returned by the Win32 system (and specifically, it isn't a handle to "a logical pen, brush, font, bitmap, region, or palette" that DeleteObject() deals with) so it doesn't need to be deleted by calling DeleteObject() - in fact, it can't be passed to DeleteObject() 您为BeginPaint()EndPaint()提供的PAINTSTRUCT对象不是Win32系统返回的句柄(具体而言,它不是“逻辑笔,画笔,字体,位图,区域或调色板”的句柄“ DeleteObject()处理)所以它不需要通过调用DeleteObject()删除 - 实际上,它不能传递给DeleteObject()

DeleteObject on hBrush releases all system resources associated with the GDI object. hBrush上的DeleteObject释放与GDI对象关联的所有系统资源。 http://msdn.microsoft.com/en-us/library/aa923962.aspx http://msdn.microsoft.com/en-us/library/aa923962.aspx

One should not call DeleteObject on the PAINTSTRUCT. 不应该在PAINTSTRUCT上调用DeleteObject。 Didn't you create this on the stack? 你没有在堆栈上创建这个吗? Why would you need to free system resources associated with it? 为什么需要释放与之相关的系统资源?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM