У меня есть программа, созданная с использованием WinAPI. В программу я встроил растровое изображение в качестве ресурса, и программа загружает этот ресурс и отображает его как фоновое изображение с помощью bitblt.
Ниже я создал консольную программу для замены фона в программе WinAPI. Он успешно заменяет растровое изображение, но теперь программа WinAPI больше не отображает фон. Я знаю, что замена сработала, потому что с помощью ResourceHacker я могу нажать на ресурс, и он будет отображаться нормально.
Этот скриншот показывает, что он был успешно заменен:
Однако, если я использую ResourceHacker для сохранения изображения обратно на диск, изображение не может быть предварительно просмотрено или открыто с помощью любых редакторов:
Если я использую resourcehacker для замены изображения в программе WinAPI, он работает просто отлично, и программа отображает его в качестве фона.
С учетом всего сказанного, кто-нибудь может объяснить, что я сделал не так ниже?
//In my resource file of the WINAPI PROGRAM:
//IDI_ICON ICON "Resources/Icon.ico"//IDB_BACKGROUND BITMAP DISCARDABLE "Resources/BackgroundImg.bmp"
#include <windows.h>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
bool Update(int ResourceID, std::string ModulePath, string FilePath)
{
HANDLE hResource = BeginUpdateResource(ModulePath.c_str(), false);
if (hResource != nullptr)
{
std::fstream File(FilePath.c_str(), std::ios::in | std::ios::binary);
if (File.is_open())
{
File.seekg(0, std::ios::end);
std::size_t FileSize = File.tellg();
File.seekg(0, std::ios::beg);
std::vector<std::uint8_t> Data(FileSize); //Also used a pointer.. makes no difference..
File.read(reinterpret_cast<char*>(Data.data()), FileSize);
File.close();
if (UpdateResource(hResource, RT_BITMAP, MAKEINTRESOURCE(ResourceID), MAKELANGID(0x0409, 0x1), Data.data(), FileSize))
{
EndUpdateResource(hResource, false);
return true;
}
}
}
return false;
}
int main()
{
if (Update(1001, "Module.exe", "Resources/BackgroundImg.bmp"))
{
std::cout<<"Updated Successfully";
}
else
{
std::cout<<"Failed To Update";
}
return 0;
}
GAAHHH! Я решил это! Просто для тех, кто читает, это ответ. Это старая статья о поддержке Microsoft: http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b67883
Теперь, если вы этого не понимаете:
В нем говорится, что единственное отличие между растровым изображением из файла и растровым изображением, хранящимся в качестве ресурса, состоит в том, что одно является DIB, а другое — упакованным DIB. Разница между этими двумя заключается в том, что у одного есть BITMAPFILEHEADER, а у другого нет. Ресурсы хранятся без FileHeaders, поэтому они должны быть удалены.
Таким образом, при обновлении растрового ресурса вы должны УДАЛИТЬ BitmapFileHeader (обратите внимание на смещение SizeOf ниже):
bool UpdateBitmap(int ResourceID, std::string ModulePath, string FilePath)
{
HANDLE hResource = BeginUpdateResource(ModulePath.c_str(), false);
if (hResource != nullptr)
{
std::fstream File(FilePath.c_str(), std::ios::in | std::ios::binary);
if (File.is_open())
{
File.seekg(0, std::ios::end);
std::size_t FileSize = File.tellg();
File.seekg(0, std::ios::beg);
std::vector<std::uint8_t> Data(FileSize);
File.read(reinterpret_cast<char*>(Data.data()), FileSize);
File.close();
if (UpdateResource(hResource, RT_BITMAP, MAKEINTRESOURCE(ResourceID), MAKELANGID(0x0409, 0x1), Data.data() + sizeof(BITMAPFILEHEADER), FileSize - sizeof(BITMAPFILEHEADER))) //Notice the sizeof.
{
EndUpdateResource(hResource, false);
return true;
}
}
}
return false;
}
Единственная разница между этим кодом и кодом в OP — это смещение по размеру (BITMAPFILEHEADER).
Других решений пока нет …