Win32 - Очистка объекта и глобальные переменные - PullRequest
3 голосов
/ 28 декабря 2010

У меня есть вопрос о глобальных переменных и очистке объектов в 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 в качестве глобальных переменных, а не заново инициализировать их каждый раз?Недостатком, я думаю, были бы тонны глобальных переменных в конце> _>, но с точки зрения производительности это не было бы менее потребляющим процессор?Я знаю, что это не будет иметь большого значения, но я просто стремлюсь к минимализму в образовательных целях.

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 ]

6 голосов
/ 28 декабря 2010

1.- Вы должны удалить все объекты, для которых вы создаете РУЧКУ. Если объект был создан с использованием функции WIN32, его следует освободить с помощью другой функции WIN32. PAINTSTRUCT - это переменная, созданная в стеке, поэтому она будет удалена, когда закончится область функций.

2.- Существует правило, которое гласит: объявляйте переменную настолько близко, насколько вы ее используете. Открытые переменные запутывают код.

3.- Если в документации сказано, что вам необходимо освободить ресурс, вы должны сделать это, чтобы избежать неожиданных результатов: http://msdn.microsoft.com/en-us/library/aa923590.aspx.

Программирование Windows , книга Чарльза Петцолда, является одним из наиболее полных руководств по программированию API-интерфейса WIN32: http://www.charlespetzold.com/books.html.

Другой подход к общедоступным переменным - создать объекты GDI в сообщении WM_CREATE и освободить их в сообщении 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) ;
}
3 голосов
/ 28 декабря 2010
  1. Вы должны очистить каждый созданный вами объект, однако не каждый объект очищается одинаково. DeleteObject удаляет только объекты GDI, контексты устройства и кисти, и т. Д. Лучший способ сказать, что вам нужно сделать с очисткой объекта, - взглянуть на документацию Windows API. Например, документация CreateSolidBrush гласит:

Когда тебе больше не нужен HBRUSH вызовите функцию DeleteObject удалить его.

Так что я не уверен, почему ваша строка DeleteObject(hbruzh); помечена как плохая. И BeginPaint говорит:

Каждый вызов BeginPaint должен иметь соответствующий вызов EndPaint функция.

Еще одна подсказка в том, что PAINTSTRUCT не начинается с буквы «H», обозначающей, что это дескриптор. DeleteObject освобождает только дескрипторы GDI. Вам, вероятно, не нужен вызов DeleteObject на hdz, EndPaint должен очистить все, что сгенерировано из BeginPaint ().

  1. Нет, вы не должны кэшировать PAINTSTRUCT. Он не возвращает одинаковые значения для каждого вызова. Например, он устанавливает область отсечения, если нужно перерисовать только часть вашего окна. Цель BeginPaint / EndPaint заключается в том, чтобы они вызывались при каждом сообщении WM_PAINT (и только там).
  2. Нет, вам не нужен вызов FreeLibrary в конце, все будет очищено, когда процесс будет существовать.
1 голос
/ 28 декабря 2010

DeleteObject в hBrush освобождает все системные ресурсы, связанные с объектом GDI. http://msdn.microsoft.com/en-us/library/aa923962.aspx

Не следует вызывать DeleteObject для PAINTSTRUCT. Разве вы не создали это в стеке? Зачем вам нужно освобождать системные ресурсы, связанные с этим?

1 голос
/ 28 декабря 2010

Как правило, в документах MSDN для каждого API ясно, как нужно очищать дескрипторы или объекты, возвращаемые API:

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

Если вам больше не нужен объект HBRUSH, вызовите функцию DeleteObject, чтобы удалить его.

К сожалению, документация для BeginPaint() немного менее ясна о том, как следует очищать возвращаемый дескриптор (кажется, вообще не упоминается очистка возвращенного HDC - только упоминание о том, что EndPaint() должен называться). Это упомянуто в примере, который указывает на документы API BeginPaint() (http://msdn.microsoft.com/en-us/library/dd162487.aspx):

BeginPaint возвращает дескриптор контекста устройства отображения, используемого для рисования в клиентской области; EndPaint завершает запрос рисования и освобождает контекст устройства.

Таким образом, вы должны позвонить EndPaint(), но вам не нужно явно удалять HDC, который вы получили от BeginPaint()

Объект PAINTSTRUCT, который вы передаете BeginPaint() и EndPaint(), не является дескриптором, возвращаемым системой Win32 (и, в частности, он не является дескриптором «логического пера, кисти, шрифта, растрового изображения, регион, или палитра ", с которой DeleteObject() имеет дело), ​​поэтому ее не нужно удалять, вызывая DeleteObject() - фактически, ее нельзя передать DeleteObject()

...