SyntaxVoid
SyntaxVoid

Reputation: 2633

Wrong icon is loaded into Visual Studio project when using resources

I am trying to embed an icon in my WIN32 GUI application to use as the background for a button using Visual Studio. I am able to add the resource without a problem and can view it in the 'Resource View' tab. When I compile and run my program, I get no errors and I can run the EXE fine, however the icon that is displayed over my button seems to be one of Windows' default icons.

The default identifier for my icon when I add it to visual studio is 102. I have tried changing this to other numbers but still end up with the wrong icon being displayed on the button. The strange thing is that using the same reference to the icon resource, I can set the application icons just fine

From the "WinUser.h" file: (those are my comments):

#define IDI_APPLICATION     MAKEINTRESOURCE(32512) // Shows when my iconid=100
#define IDI_HAND            MAKEINTRESOURCE(32513) // " " = 101
#define IDI_QUESTION        MAKEINTRESOURCE(32514) // " " = 102
#define IDI_EXCLAMATION     MAKEINTRESOURCE(32515) // " " = 103
#define IDI_ASTERISK        MAKEINTRESOURCE(32516) // " " = 104
#define IDI_WINLOGO         MAKEINTRESOURCE(32517) // " " = 105
#define IDI_SHIELD          MAKEINTRESOURCE(32518) // " " = 106

If I change the identifier to be outside of this range, the LoadImage function fails and no icon is loaded. I can't explain this and have no idea how to proceed.

My resource.h file:

#define IDI_ICON1                       102
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

My resource.rc file (generated by Visual Studio.. I removed the comments):

#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END
2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END
3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END
#endif    // APSTUDIO_INVOKED
IDI_ICON1               ICON                    "angery.ico"
#endif    

My source file:

// main.cpp
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c

#include "resource.h"
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <CommCtrl.h>
#include <ShlObj.h>
#include <ShlObj_core.h>
#include <stdio.h>


HINSTANCE hInstMain;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);


int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR     lpCmdLine, _In_ int       nCmdShow) {
    // Define and set parameters for the windows class attribute
    WNDCLASSEX wcex;
    HWND hWnd;
    MSG msg;

    hInstMain = hInstance; // Adding this line solved my problem.
    // ZeroMemory(&wcex, sizeof(WNDCLASSEX));
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstMain;
    wcex.lpfnWndProc = (WNDPROC)WndProc;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = _T("Dummy");
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1));

    if (!RegisterClassEx(&wcex)) {
        MessageBox(NULL, _T("Failed"), _T("Failed"), MB_OK);
        return -1;
    }

    hWnd = CreateWindow(_T("Dummy"), _T("Example"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
                        100, 100, NULL, NULL, hInstMain, NULL);
    if (!hWnd) {
        MessageBox(NULL, _T("AHH"), _T("AHH"), MB_OK);
        return -1;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;

    HDC hdc;
    HWND myButton;
    HICON myIcon;

    switch (message) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        EndPaint(hWnd, &ps);
        break;
    case WM_CREATE:

        myButton = CreateWindow(_T("Button"), NULL, WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP | BS_ICON,
            10, 10, 50, 50, hWnd, NULL, NULL, NULL);

        //myIcon = (HICON)LoadImage(hInstMain, _T("angery.ico"), IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
        myIcon = (HICON)LoadImage(hInstMain, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
        if (!myIcon) {
            MessageBox(NULL, _T("Icon fail"), _T("Icon fail"), MB_OK);
            return -1;
        }
        SendMessage(myButton, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)myIcon);

        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }
    return 0;
}



An icon, for your convenience (depicting my mood towards VS right now). https://drive.google.com/file/d/1HoPInZukIvAVkWs38l3MnfUkQ7HpLktR/view?usp=sharing I don't think the icon is corrupt because I've tried it with several icons from several different sources.

I would like to be able to load my own icon into a button while having it embedded in the exe so I don't have to send the image around as well.

Upvotes: 0

Views: 844

Answers (1)

rveerd
rveerd

Reputation: 4016

You do not set hInstMain. If it is zero, LoadImage loads OEM images. Also, why create controls on WM_PAINT?

Upvotes: 2

Related Questions