c++ - Windows/C++ - 从 SDL_SetWindowIcon 的第三方 exe 加载图标 - 崩溃

标签 c++ windows sdl

我正在尝试从第三方可执行文件加载图标以用于 SDL_SetWindowIcon。

基于一些调试,我相信我正在正确加载图标,但我似乎没有正确填充 SDL_Surface。

这是我目前正在尝试的:

//attempts to load an icon resource from the specified assembly
//uses rcName if provided, or rcId (as an int resource id) if rcName is null
//if successful, convert and set it as SDL's window icon

void LoadIconFrom(std::string assembly, int rcId, const char* rcName) {

    //get a module handle for the target assembly
    HMODULE hModule = LoadLibrary(assembly.c_str());
    if (hModule == NULL) {
        ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hModule is null!");
        return;
    }
    //get a handle for the desired icon
    HICON hIcon = NULL;
    if (rcName == NULL) {
        hIcon = LoadIcon(hModule, MAKEINTRESOURCE(rcId));
    }
    else {
        hIcon = LoadIcon(hModule, rcName); 
    }
    if (hIcon == NULL) {
        ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hIcon is null!");
        return;
    }
    //load some info regarding the selected icon, make sure it has bitmap data
    ICONINFO ii;
    if (!GetIconInfo(hIcon, &ii)) {
        ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "IconInfo is null!");
        return;
    }
    if (!ii.hbmColor) {
        ShowError("Icon Error", "Icon does not have bitmap data!");
        return;
    }
    //attempt to determine the size of the icon
    int iWidth, iHeight;
    BITMAP bm;
    if (!GetObject(ii.hbmColor, sizeof(bm), &bm)) {
        ShowError("Icon Error", "Could not read bitmap data!");
        return;
    }

    iWidth = bm.bmWidth;
    iHeight = bm.bmHeight;
    //ShowError("Icon Win!!!",(std::string("Loaded icon of size: ") + std::to_string(iWidth) + "x" + std::to_string(iHeight)).c_str());

    icon = SDL_CreateRGBSurface(SDL_SWSURFACE, bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
    Uint8 * bits = NULL;
    Uint8 * temp = NULL;
    bits = new Uint8[bm.bmWidthBytes*bm.bmHeight];
    temp = new Uint8[bm.bmWidthBytes*bm.bmHeight];
    memcpy(temp, bm.bmBits, bm.bmWidthBytes*bm.bmHeight);
    Uint8 *ptemp;
    Uint8 *pbits = bits;
    for (int j = bm.bmHeight - 1; j >= 0; j--)
    {
        ptemp = temp + j * bm.bmWidthBytes;
        for (int x = 0; x < bm.bmWidthBytes; x++)
        {
            *pbits = *ptemp;
            pbits++;
            ptemp++;
        }
    }
    if (SDL_MUSTLOCK(icon)) SDL_LockSurface(icon);
    memcpy(icon->pixels, bits, bm.bmWidthBytes*bm.bmHeight);
    if (SDL_MUSTLOCK(icon)) SDL_UnlockSurface(icon);

    delete[] bits;
    delete[] temp;

    SDL_SetWindowIcon(mainWindow, icon);
}

它在 SDL_SetWindowIcon 处崩溃。最后一点应该翻转图像,我认为这是我发现的示例所必需的。删除该部分似乎没有任何效果。

如果我根本不修改“位”并将其留空,程序不会崩溃,但我会得到一个空白图标。

我在这里错过了什么?

编辑:我也尝试过 CreateRGBSurfaceFrom,它似乎具有相同的行为 - 要​​么在空白数组上为空白,要么在其中有任何数据时崩溃。

编辑 2:“图标”是一个 SDL_Surface*,在别处声明。

编辑 3:使用 SDL 2.0.7。

编辑 4:固定代码:

//attempts to load an icon resource from the specified assembly
//uses rcName if provided, or rcId (as an int resource id) if rcName is null
//if successful, convert and set it as SDL's window icon
void LoadIconFrom(std::string assembly, int rcId, const char* rcName) {
    //todo: make error throwing here only happen in debug, while
    //release should just continue on its merry way, iconless

    //get a module handle for the target assembly
    HMODULE hModule = LoadLibrary(assembly.c_str());
    if (hModule == NULL) {
        ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hModule is null!");
        return;
    }
    //get a handle for the desired icon
    HICON hIcon = NULL;
    if (rcName == NULL) {
        hIcon = LoadIcon(hModule, MAKEINTRESOURCE(rcId));
    }
    else {
        hIcon = LoadIcon(hModule, rcName); 
    }
    if (hIcon == NULL) {
        ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hIcon is null!");
        return;
    }
    //load some info regarding the selected icon, make sure it has bitmap data
    ICONINFO ii;
    if (!GetIconInfo(hIcon, &ii)) {
        ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "IconInfo is null!");
        return;
    }
    if (!ii.hbmColor) {
        ShowError("Icon Error", "Icon does not have bitmap data!");
        return;
    }
    BITMAP bm;
    if (!GetObject(ii.hbmColor, sizeof(bm), &bm)) {
        ShowError("Icon Error", "Bitmap data does not exist!");
        return;
    }

    HBITMAP hbitmap = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP, bm.bmWidth, bm.bmHeight, LR_CREATEDIBSECTION);

    if (!GetObject(hbitmap, sizeof(BITMAP), &bm)) {
        ShowError("Icon Error", "Could not read bitmap data!");
        return;
    }

    // Verify that the data we have obtained is a 32bpp bitmap with color info
    if (bm.bmBitsPixel != 32) {
        ShowError("Icon Error", "Bitmap data not in a 32bpp format!");
        return;
    }
    if (bm.bmBits == NULL) {
        ShowError("Icon Error", "Extracted bitmap data is null!");
        return;
    }

    // Create an SDL surface - note the mask varies by platform endian-ness
    int rmask = 0x00FF0000;
    int gmask = 0x0000FF00;
    int bmask = 0x000000FF;
    int amask = 0xFF000000;
    icon = SDL_CreateRGBSurface(SDL_SWSURFACE, bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, rmask, gmask, bmask, amask);
    if (icon == NULL) {
        ShowError("Icon Error", (std::string("SDL surface creation failed: ") + SDL_GetError()).c_str());
        return;
    }

    // Re-orient the bytes to flip the image vertically
    Uint8 * bits = NULL;
    Uint8 * temp = NULL;
    bits = new Uint8[bm.bmWidthBytes*bm.bmHeight];
    temp = new Uint8[bm.bmWidthBytes*bm.bmHeight];
    memcpy(temp, bm.bmBits, bm.bmWidthBytes*bm.bmHeight);
    Uint8 *ptemp;
    Uint8 *pbits = bits;
    for (int j = bm.bmHeight - 1; j >= 0; j--)
    {
        ptemp = temp + j * bm.bmWidthBytes;
        for (int x = 0; x < bm.bmWidthBytes; x++)
        {
            *pbits = *ptemp;
            pbits++;
            ptemp++;
        }
    }

    // Copy the formatted bits to the surface
    if (SDL_MUSTLOCK(icon)) SDL_LockSurface(icon);
    memcpy(icon->pixels, bits, bm.bmWidthBytes*bm.bmHeight);
    if (SDL_MUSTLOCK(icon)) SDL_UnlockSurface(icon);

    // Set the window icon to the loaded surface
    SDL_SetWindowIcon(mainWindow, icon);

    // Cleanup
    delete[] bits;
    delete[] temp;
    DeleteObject(hbitmap);
    SDL_FreeSurface(icon);
}

感谢所有提供帮助的人。我很感激。 (如果我在错误测试或清理中遗漏了任何内容,请随时指出,我会进行更新。)

最佳答案

bm.bmBits 在您的代码中,从 HICON 获得,很可能是 NULL。使用 CopyImageLR_CREATEDIBSECTION 访问 bmBits

HBITMAP hbitmap = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP, 
    bm.bmWidth, bm.bmHeight, LR_CREATEDIBSECTION);
BITMAP bm2;
GetObject(hbitmap, sizeof(BITMAP), &bm2);
...
DeleteObject(hbitmap);

检查 bm2.bmBitsPixel 以确保它是 32 位的。检查 bm2.bmBits 以确保它不是 NULL

void LoadIconFrom(std::string assembly, int rcId, const char* rcName)
{
    ...
    ICONINFO ii;
    GetIconInfo(hicon, &ii);
    BITMAP bm;
    GetObject(ii.hbmColor, sizeof(bm), &bm);

    HBITMAP hbitmap = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP,
            bm.bmWidth, bm.bmHeight, LR_CREATEDIBSECTION);
    GetObject(hbitmap, sizeof(BITMAP), &bm);

    if (bm.bmBitsPixel != 32) {error(); ...}
    if (bm.bmBits == NULL) {error(); ...}

    ...
    icon = SDL_CreateRGBSurface(SDL_SWSURFACE, bm.bmWidth, bm.bmHeight,
            bm.bmBitsPixel, rmask, gmask, bmask, amask);

    //copy bits upside down
    if(SDL_MUSTLOCK(icon)) SDL_LockSurface(icon);
    int wb = bm.bmWidthBytes;
    BYTE* bits = icon->pixels;
    BYTE* src = (BYTE*)bm.bmBits;
    for(int j = 0; j < bm.bmHeight; j++)
        memcpy(bits + j * wb, src + (bm.bmHeight - j - 1) * wb, wb);
    if(SDL_MUSTLOCK(icon)) SDL_UnlockSurface(icon);

    SDL_SetWindowIcon(mainWindow, icon);

    // Cleanup
    SDL_FreeSurface(icon);
    DeleteObject(hbitmap);
}

关于c++ - Windows/C++ - 从 SDL_SetWindowIcon 的第三方 exe 加载图标 - 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48025536/

相关文章:

c - 尝试将 SDL_Surface 的大小加倍严重失败

c++ - OpenGL 纹理映射空白屏幕

c++ - 在单个排序调用 C++ 中对多个 vector 进行排序

c++ - 无锁堆栈 - 这是 c++11 宽松原子的正确用法吗?可以证明吗?

windows - 文件夹名称转换在国际 Windows 7 版本中如何工作?

c - 发送和接收文件 - 套接字 - c - windows

mysql - 为 windows 的 mysql 数据库绘制 ERD 的最佳软件是什么

c - 使用 Dev C++ 时未定义对 'SDL_main' 的引用

c++ - Eclipse不会在断点处停止并将线程状态置于Running : User Request

c++ - 修改包含 break 语句的 while 循环