Как я могу повторно использовать дескриптор HBITMAP?

#c #winapi

#c #winapi

Вопрос:

Мне приходится рисовать растровое изображение несколько раз. Он загружен из файла. Я могу перезагружать его каждый раз, когда мне нужно его использовать SelectObject следующим образом:

 void drawBitmap(HWND hWnd, int xPos, int yPos) {
    HBITMAP hBmp = (HBITMAP) LoadImage(NULL, "image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    HDC hDC = GetDC(hWnd);
    HDC hdcMem = CreateCompatibleDC(hDC);
    SelectObject(hdcMem, hBmp);
    BitBlt(hDC, xPos, yPos, 7, 7, hdcMem, 0, 0, SRCCOPY);
}
drawBitmap(hMainWnd, 0, 0);
drawBitmap(hMainWnd, 14, 0);
drawBitmap(hMainWnd, 28, 0);
  

Но возможно ли также сделать что-то подобное?

 HBITMAP hBmp = (HBITMAP) LoadImage(NULL, "image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
void drawBitmap(HWND hWnd, int xPos, int yPos) {
    HBITMAP hBmp2 = hBmp;
    HDC hDC = GetDC(hWnd);
    HDC hdcMem = CreateCompatibleDC(hDC);
    SelectObject(hdcMem, hBmp2);
    BitBlt(hDC, xPos, yPos, 7, 7, hdcMem, 0, 0, SRCCOPY);
}
drawBitmap(hMainWnd, 0, 0);
drawBitmap(hMainWnd, 14, 0);
drawBitmap(hMainWnd, 28, 0);
  

Но при этом отображается только одно растровое изображение…

MSDN говорит:

SelectObject Функция выбирает объект в указанном контексте устройства (DC). Новый объект заменяет предыдущий объект того же типа.

Так что, возможно, мой hBmp потрачен впустую после SelectObject вызова. Но сначала я скопировал его в hBmp2 , тогда в чем проблема?

Ответ №1:

Вы не удаляете DC памяти, когда закончите с ним. Это означает утечку DC, и растровое изображение все еще выбрано в этом утеченном DC. И согласно SelectObject документации: «Приложение не может выбрать одно растровое изображение в более чем один DC одновременно».

Итак, второй SelectObject завершается неудачей, потому что растровое изображение все еще выбрано в первом HDC .

Уберите за собой, вызвав DeleteDC в конце drawBitmap функцию (а также вызовите DeleteObject hBmp, когда закончите с ней).

Кроме того, HBITMAP hBmp2 = hBmp; строка ничего не дает. Вы просто присваиваете дескриптор другой переменной. Это все тот же дескриптор для того же растрового изображения.

Комментарии:

1. Спасибо, чувак, это сработало. Я принимаю ваш ответ, по какой-то причине мне нужно подождать всего 5 минут.

2. Кстати, вы могли бы дополнительно оптимизировать этот код, повторно используя сам memory DC вместо просто bitmap (все равно удалите его после того, как закончите с ним, конечно).

3. Все правильно, за исключением, возможно, одной вещи: я не уверен, но я думаю, что когда вы удаляете DC, это также уничтожает выбранное растровое изображение. Так что, если у вас все еще есть дескриптор этого растрового изображения — он недействителен. Более правильным было бы сохранить повторное значение SelectObject , а затем, непосредственно перед повторной попыткой вызова DC SelectObject с этим значением, восстановить исходное растровое изображение в DC (которое представляет собой монохромное растровое изображение 1×1). Это правда?

4. В документации DeleteDC ничего не упоминается об удалении выбранных объектов, поэтому я так не думаю.