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

时间:2017-12-29 16:31:05

标签: 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:“icon”是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);
}

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

1 个答案:

答案 0 :(得分:0)

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);
}