FindResource найти ресурс по имени не удается - PullRequest
1 голос
/ 25 октября 2019
HRSRC test = FindResourceW(hModule, L"TEST", RT_MANIFEST);

Сбой FindResource с ERROR_RESOURCE_NAME_NOT_FOUND . Я только переименовал имя ресурса манифеста в строку, а затем попытался найти его. Я верю, что это как-то связано с MAKEINTRESOURCE / IS_INTRESOURCE или я не совсем уверен. Есть идеи? Однако это работало нормально, когда ресурс был назван просто 1.

ERROR_RESOURCE_NAME_NOT_FOUND

1814 (0x716)

Указанный ресурсимя не может быть найдено в файле изображения.

enter image description here

Редактировать:

1-я итерация: enter image description here

2-я итерация: enter image description here

struct Resource
{
    LPVOID lpData;
    LPCWSTR lpType;
    LPCWSTR lpName;
    DWORD dwSize;
};

bool EnumNamesFunc(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
{
    HRSRC hResource = nullptr;

    if (!IS_INTRESOURCE(lpName))
    {
        hResource = FindResource(hModule, lpName, lpType);

        std::wcout << "It is not. " << lpName << std::endl;
    }
    else if (IS_INTRESOURCE(lpName))
    {
        hResource = FindResource(hModule, lpName, lpType);

        std::cout << "It is" << std::endl;
    }

    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 temp;
    temp.lpData = hGlobal;
    temp.lpType = lpType;
    temp.lpName = lpName;
    temp.dwSize = dwSize;

    resources.push_back(temp);

    FreeResource(lpResource);

    return true;
}

Этот кодработает, но течет:

Resource temp;
temp.lpData = hGlobal;
temp.lpType = lpType;

if (!IS_INTRESOURCE(lpName))
{
    LPVOID temp = malloc(sizeof(LPCWSTR) * wcslen(lpName));
    memcpy(temp, lpName, sizeof(LPCWSTR) * wcslen(lpName));
    temp.lpName = temp;
}
else
{
    temp.lpName = lpName;
}

1 Ответ

3 голосов
/ 26 октября 2019

При обратном вызове 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...