0

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.

SyntaxVoid
  • 2,501
  • 2
  • 15
  • 23
  • you should not change id's in `reousrce.h` because that messes up thing, you change the id in properties window and let VS reassign ID, all you can do is delete old id, and `MAKEINTRESOURCE(107)` is wrong you should use `MAKEINTRESOURCE(IDI_ICON1)` –  Apr 12 '19 at 09:23
  • The IDS can be changed in the property window of the resource- Nice catch on the IDI_ICON1. I was changing it around to check the behavior and forgot to change it back before pasting here. – SyntaxVoid Apr 12 '19 at 09:27

1 Answers1

2

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

rveerd
  • 3,620
  • 1
  • 14
  • 30
  • Thank you. Adding "hInstMain = hInstance;" near the top of my WinMain function fixed it. Also you're right, I've moved my control creation to WM_CREATE. – SyntaxVoid Apr 12 '19 at 09:28