代码之家  ›  专栏  ›  技术社区  ›  bwdy

Windows/C++-从SDL\U SetWindowIcon的第三方exe加载图标-崩溃

  •  1
  • bwdy  · 技术社区  · 7 年前

    我试图从第三方可执行文件加载一个图标,以便在SDL\U SetWindowIcon中使用。

    根据一些调试,我相信我正确加载了图标,但我似乎没有正确填充SDL\U曲面。

    以下是我目前正在尝试的内容:

    //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\u SetWindowIcon崩溃。最后一位应该将图像翻转过来,我认为这是我找到的示例所要求的。移除该部分似乎没有任何效果。

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

    我错过了什么?

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

    编辑2:“icon”是SDL\U曲面*,在别处声明。

    编辑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 回复  |  直到 7 年前
        1
  •  0
  •   Barmak Shemirani    7 年前

    bm.bmBits 在您的代码中,从 HICON ,很可能 NULL . 使用 CopyImage 具有 LR_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 确保它不是 无效的 .

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