При обратном вызове EnumResourceNames()
вы не можете сохранить необработанные указатели для lpType
и lpName
, когда IS_INTRESOURCE()
возвращает для них значение false. Эти данные исчезают после завершения обратного вызова, оставляя ваш resources
контейнер с неверными указателями. Таким образом, в этом случае вам необходимо скопировать символьные данные с нулевым символом в конце, на которые они указывают (что вы пытаетесь сделать, но делаете это неправильно).
Чтобы избежать утечки памяти, добавьтедеструктор для Resource
для освобождения данных lpName
/ lpType
, когда для них IS_INTRESOURCE()
ложно. Кроме того, вам необходимо добавить конструктор копирования и оператор назначения копирования в Resource
для глубокого копирования данных lpType
/ lpName
(согласно Правило 3 ).
Кроме того, ваш обратный вызов должен возвращать BOOL
вместо bool
, и ему нужно использовать __stdcall
соглашение о вызовах (заключенное в WINAPI
и CALLBACK
макросов).
Попробуйте что-то еще подобное:
struct Resource
{
LPWSTR lpType;
LPWSTR lpName;
HANDLE lpData;
DWORD dwSize;
Resource(LPCWSTR, LPWSTR, HANDLE, DWORD);
Resource(const Resource &);
~Resource();
Resource& operator=(const Resource &);
};
LPWSTR MakeResourceCopy(LPCWSTR Value)
{
if (IS_INTRESOURCE(Value))
return const_cast<LPWSTR>(Value);
int len = wcslen(Value) + 1;
LPWSTR copy = new WCHAR[len];
memcpy(copy, Value, sizeof(WCHAR) * len);
return copy;
}
Resource::Resource(LPCWSTR Type, LPWSTR Name, HANDLE Data, DWORD Size)
{
lpType = MakeResourceCopy(Type);
lpName = MakeResourceCopy(Name);
lpData = Data;
dwSize = Size;
}
Resource::Resource(const Resource &src)
{
lpType = MakeResourceCopy(src.lpType);
lpName = MakeResourceCopy(src.lpName);
lpData = src.lpData;
dwSize = src.dwSize;
}
Resource::~Resource()
{
if (!IS_INTRESOURCE(lpType))
delete[] lpType;
if (!IS_INTRESOURCE(lpName))
delete[] lpName;
}
Resource& Resource::operator=(const Resource &rhs)
{
if (&rhs != this)
{
Resource copy(rhs);
using std::swap;
swap(lpType, copy.lpType);
swap(lpName, copy.lpName);
swap(lpData, copy.lpData);
swap(dwSize, copy.dwSize);
}
return *this;
}
BOOL CALLBACK EnumNamesFunc(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
{
if (!IS_INTRESOURCE(lpType))
std::wcout << "lpType is not an integer. " << lpType << std::endl;
else
std::cout << "lpType is an integer. #" << reinterpret_cast<int>(lpType) << std::endl;
if (!IS_INTRESOURCE(lpName))
std::wcout << "lpName is not an integer. " << lpName << std::endl;
else
std::cout << "lpName is an integer. #" << reinterpret_cast<int>(lpName) << std::endl;
HRSRC hResource = FindResource(hModule, lpName, lpType);
if (!hResource)
return FALSE;
DWORD dwSize = SizeofResource(hModule, hResource);
HGLOBAL hGlobal = LoadResource(hModule, hResource);
if (!hGlobal)
return FALSE;
LPVOID lpResource = LockResource(hGlobal);
if (!lpResource)
return FALSE;
Resource res(lpType, lpName, hGlobal, dwSize);
resources.push_back(res);
return TRUE;
}
Тем не менее, я бы предложил изменить Resource
'* lpType
/ lpName
поля вместо std::wstring
. Если вы получили числовое значение lpType
/ lpName
, просто преобразуйте его в формат "#..."
. Пусть компилятор обрабатывает все управление памятью за вас:
struct Resource
{
std::wstring lpType;
std::wstring lpName;
HANDLE lpData;
DWORD dwSize;
};
std::wstring MakeResourceWString(LPCWSTR Value)
{
if (IS_INTRESOURCE(Value))
return L"#" + std::to_wstring(reinterpret_cast<int>(Value));
else
return Value;
}
BOOL CALLBACK EnumNamesFunc(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
{
if (!IS_INTRESOURCE(lpType))
std::wcout << "lpType is not an integer. " << lpType << std::endl;
else
std::cout << "lpType is an integer. #" << reinterpret_cast<int>(lpType) << std::endl;
if (!IS_INTRESOURCE(lpName))
std::wcout << "lpName is not an integer. " << lpName << std::endl;
else
std::cout << "lpName is an integer. #" << reinterpret_cast<int>(lpName) << std::endl;
HRSRC hResource = FindResource(hModule, lpName, lpType);
if (!hResource)
return FALSE;
DWORD dwSize = SizeofResource(hModule, hResource);
HGLOBAL hGlobal = LoadResource(hModule, hResource);
if (!hGlobal)
return FALSE;
LPVOID lpResource = LockResource(hGlobal);
if (!lpResource)
return FALSE;
Resource res;
res.lpType = MakeResourceWString(lpType);
res.lpName = MakeResourceWString(lpName);
res.lpData = hGlobal;
res.dwSize = dwSize;
resources.push_back(res);
return TRUE;
}
В качестве альтернативы используйте std::variant
вместо:
struct Resource
{
std::variant<int, std::wstring> lpType;
std::variant<int, std::wstring> lpName;
HANDLE lpData;
DWORD dwSize;
};
std::variant<int, std::wstring> MakeResourceVariant(LPCWSTR Value)
{
if (IS_INTRESOURCE(Value))
return reinterpret_cast<int>(Value);
else
return std::wstring(Value);
}
BOOL CALLBACK EnumNamesFunc(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
{
if (!IS_INTRESOURCE(lpType))
std::wcout << "lpType is not an integer. " << lpType << std::endl;
else
std::cout << "lpType is an integer. #" << reinterpret_cast<int>(lpType) << std::endl;
if (!IS_INTRESOURCE(lpName))
std::wcout << "lpName is not an integer. " << lpName << std::endl;
else
std::cout << "lpName is an integer. #" << reinterpret_cast<int>(lpName) << std::endl;
HRSRC hResource = FindResource(hModule, lpName, lpType);
if (!hResource)
return FALSE;
DWORD dwSize = SizeofResource(hModule, hResource);
HGLOBAL hGlobal = LoadResource(hModule, hResource);
if (!hGlobal)
return FALSE;
LPVOID lpResource = LockResource(hGlobal);
if (!lpResource)
return FALSE;
Resource res;
res.lpType = MakeResourceVariant(lpType);
res.lpName = MakeResourceVariant(lpName);
res.lpData = hGlobal;
res.dwSize = dwSize;
resources.push_back(res);
return TRUE;
}