CDialogTemplate
От: qaz77  
Дата: 13.08.20 10:20
Оценка: 95 (4)
Здравствуйте, коллеги.

Переносил старый проект на x64 и обнаружил баг в коде MFC.
Код грузит из ресурсов DLL шаблон диалога и передает HTEMPLATE конструктору CDialogTemplate.
HRSRC hres = ::FindResource(hmod, MAKEINTRESOURCE(template_id), RT_DIALOG);
HGLOBAL ht = ::LoadResource(hmod, hres);
CDialogTemplate templ(ht); // << здесь AV
// работаем с templ

В сборке x86 много лет все работает ок, а в сборке x64 только для одного из диалогов в конструкторе AV.
Долго протирал глаза и сравнивал, чем этот диалог отличается от остальных. Переставлял местами, менял значение resource id — все без толку.

Оказалось, что в файле dlgtempl.cpp 119 вместо LockResource зовется GlobalLock/GlobalUnlock.
DLGTEMPLATE* pTemplate = (DLGTEMPLATE*)GlobalLock(hTemplate);

В описании LoadResource явно сказано, что HGLOBAL возвращается не настоящий)).
Для него применимы только LockResource и SizeOfResource...

Для проблемного диалога GlobalLock возвращает NULL (который потом не проверялся, поэтому AV) и
код ошибки 6 — неверный дескриптор.

Проблема рещилась самостоятельным вызовом LockResource и использованием другого конструктора:
HRSRC hres = ::FindResource(hmod, MAKEINTRESOURCE(template_id), RT_DIALOG);
HGLOBAL ht = ::LoadResource(hmod, hres);
const DLGTEMPLATE* pt = static_cast<const DLGTEMPLATE*>(::LockResource(ht));
CDialogTemplate templ(pt);
// работаем с templ


Будьте бдительны!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.