Приветствую! Делаю трейнер на АSM, и мне понадобилось отобразить битмап. Прочитал урок Iczelion`а, сделал, как там написано: .asm: Код (Text): IDB_BACK equ 666 ... DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM LOCAL ps:PAINTSTRUCT LOCAL hdc:HDC LOCAL hMemDC:HDC mov eax,uMsg .if eax==WM_CREATE invoke LoadBitmap,hInstance,IDB_BACK mov hBackground, eax .elseif eax==WM_PAINT invoke BeginPaint,hWin,addr ps mov hdc,eax invoke CreateCompatibleDC,hdc mov hMemDC,eax invoke SelectObject,hMemDC,hBackground invoke BitBlt,hdc,0,12,244,57,hMemDC,0,0,SRCCOPY invoke DeleteDC,hMemDC invoke EndPaint,hWin,addr ps .elseif eax==WM_COMMAND mov eax, wParam mov edx, wParam .if lParam==0 .else shr edx, 16 .IF dx==BN_CLICKED .if ax==ID_QUIT invoke EndDialog,hWin,0 .endif .endif .endif .elseif eax==WM_CLOSE invoke DeleteObject,hBackground invoke EndDialog,hWin,0 .else mov eax,FALSE ret .endif mov eax,TRUE ret DlgProc endp .rc: Код (Text): #define IDB_BACK 666 IDB_BACK BITMAP "back.bmp" всё компилируется, но при запуске битмапа нет! Может, подскажете, что делать?
Отладчиком проверь - действительно ли загружается сам битмап. Похоже что сообщение WM_CREATE в данной программе заменяется WM_INITDIALOG, проверить это тоже не мешает.
Да, очень похоже на то, что WM_CREATE надо на WM_INITDIALOG заменить. Кроме того, в целях оптимизации можно вынести CreateCompatibleDC в WM_INITDIALOG для облегчения процедуры прорисовки. Зачем его создавать каждый раз, а потом удалять?
n0p На счет оптимизации, похоже что в этом случае как раз все правильно, и ничего оптимизировать не надо. Сообщение прорисовки в зависимости от условий выполнения программы будет приходить не очень часто (обработка WM_PAINT мало оказывает влияние на производительность проги в целом), тогда как дескрипторы GDI всегда лучше экономить (по крайней мере так всеръез утверждается в MSDN). Другое дело скажем кисти - для сообщения WM_CTLCOLORDLG, их действительно лучше выделять при инициации диалога.
alpet Пожертвовать одним дескриптором ради снижения нагрузки на систему кажется мне разумным. Конечно, если перерисовка происходит не очень часто (хотя даже в состоянии покоя окна это иногда происходит), это не так страшно, а если еще и прога часто обработчик вызывает?
n0p Конечно если регулярность высока - скажем график анимированный рисуется можно и не запрашивать контексты каждый раз. Другое дело что у Windows для большинства окон их всегда находится достаточном количестве готовых для получения - сама операция CreateCompatibleDC возможно выполняется только в пределах USERмода и много времени не занимает. Для трейнера сомнительно что будет использоваться анимированная графика и вообще требования к его производительности не велики. Получать ресурсы по необходимости, и освобождать их когда они больше не нужны (вместо содержания нескольких глобальных переменных) в конечном счете лишь стиль программирования, имеющий больше отношение к надежности и простоте кода, чем к его производительности, и конечно он наиболее применим в крупных программах.
К слову: а где SelectObject() перед DeleteDC()? Из MSDN: "An application should always replace a new object with the original, default object after it has finished drawing with the new object."
Мои 5 копеек. Зачем восстанавливать исходное состояние объекта перед его удалением? Все равно что вызывать CloseHandle перед ExitProcess. Если контекст в памяти будет удален, то будет удалены все связи с другими объектами. Вообще не надо строго вымолнять инструкции Microsofta, Iczeliona и прочих личностей.
Turkish В некоторых случаях это необходимо. Что если после удаления объекта процесс рисования не завершается? Тогда при обращении к удаленному объекту может случится все что угодно. Вот для таких случаев и надо предусматривать восстановление.
Turkish И чтоб это проверить надо каждый раз лезть в ядро? Да ещё и на всех версиях винды? Увольте! Я лучше лишний раз SelectObject вызову лишь бы этот GDI-объект ко мне в кошмарных снах не являлся. Хоть бы смайлик дописали, а то новички могут за чистую монету принять
Контекст устройства, помимо прочего является структурой GDI, описывающей свойства и аттрибуты рисования, и по разному связанную с другими. Как правило свежим контекстам назначаются общие для программ перья и кисти (BLACK_PEN, WHITE_BRUSH), которые можно также получать с помощью GetStockObject (...). Так что систему дефакто не волнует с чем связан контекст, когда приложение решило от него отделаться с помощью ReleaseDC/DeleteDC. Это к примеру показано в MSND примере "Capturing an Image" - там результат работы функции SelectObject используется лишь для проверки, была ли ошибка. И раз тут все равно задета проблема растров, такой вот вопрос: как правильно и полностью (как PrintScreen) скопировать текущий декстоп со всеми окнами на нем в системах Win2k/XP?
Похоже способ неизвестен. Стандартный прием BitBlt то MemoryDC к сожалению не помогает - полупрозрачные окна в скриншоте не отрисовываются.