How do I use LoadIcon and MAKEINTRESOURCE correctly when changing the title bar icon? [duplicate] - c++

This question already has an answer here:
How to change the title bar icon using winapi
(1 answer)
Closed 7 years ago.
I am working on a project in Code:Blocks c++ win32. I have read on this honorable page the use of LoadIcon and MAKEINTRESOURCE. However, it seems I am not using them correctly. I have created an icon with Greenfish and named it 'dvc icon'. It is in the format '.ico'.
When I execute the program I get an error code "can't open icon file 'dvc icon.ico': No such file or directory.
Below is the code.
#include <resource.h>
#define IDI_OWNERDRAW 103
#define IDI_BUTTON_ICO 201
#define IDI_dvc icon 205
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadImage (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_dvc icon));
wincl.hIconSm = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_dvc icon), IMAGE_ICON, 16, 16, 0);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No me u */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
What should I do next?
Any help is much appreciated. Thanks.

There are the fields hIcon and hIconSm of type HICON in the WNDCLASSEX struct used by RegisterClassEx. It specifies what icon to use in the task bar and in the title bar of the window respectively. You can use LoadImage to get a valid icon handle. Use it together with the MAKEINTRESOURCE to get the icon from an embedded resource.
See the LoadImage documentation for details.

Related

InsertMenu/AppendMenu - How to add Icons to menu and submenus using C++ and win32

I have written a shell extension dll context menu program using C++ and win32 programming. The development environment is Visual Studio 2008 and 2010. In the below sample code, I am trying to add menu icon for the main menu only. The menu icon is not showing for the main menu. (I need to add icons for all menu items.).
Please correct the below code.
QueryContextMenu(HMENU hmenu, UINT /*uInd*/, UINT idCmdFirst, UINT /*idCmdLast*/, UINT /*uFlags*/ )
{
int id = 1;
HBITMAP hBitmap = NULL;
hBitmap = (HBITMAP)LoadImage((HMODULE)_AtlBaseModule.m_hInst,MAKEINTRESOURCE(IDB_MYBITMAP), IMAGE_BITMAP, 12, 12, 0);
HMENU submenu = CreatePopupMenu();
AppendMenu(submenu, MF_STRING|MF_ENABLED, uidCmdFirst + id++, L"XP");
AppendMenu(submenu, MF_STRING|MF_ENABLED,uidCmdFirst + id++, L"VISTA");
AppendMenu(submenu, MF_STRING|MF_ENABLED,uidCmdFirst + id++, L"Win 7");
InsertMenu(hmenu, 4,MF_BYPOSITION|MF_POPUP, UINT(submenu), L"Windows");
SetMenuItemBitmaps(hmenu,id++, MF_BITMAP, hBitmap,hBitmap);
return id;
}
CreatePopUpMenu also works. You just had to use InsertMenu instead of AppendMenu.
Reading the definition of SetMenuItemBitmap https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setmenuitembitmaps there is not such a thing as a MF_BITMAP flag.
The options are MF_BYCOMMAND and MF_BYPOSITION. Seems like that you are trying to use MF_BYCOMMAND but have to use the same values already given to the MenuItens.
You have also to check for the format of the BITMAP. SetMenuItemBitmaps just acepts monochrome. I was googling to do the same and had success here. Thanks for showing the way.

DialogBoxIndirect creates dialog bigger than asked

For my application I need to create a Dialog Box without using resource.
I am trying to do it with DialogBoxInderect function.
The code is unbelievably ugly but somehow I succeeded to do it.
The problem is that dialog, for some reason, is much bigger than I asked with much bigger fonts.
Here is how the dialog looks like if I load it from resource:
And here is the dialog with the same size stated when I call DialogBoxInderect function.
Here is how it is defined in code:
HGLOBAL hGlobal;
LPDLGTEMPLATE wlsDialogTemplate;
LPDLGITEMTEMPLATE wlsDialogItemTemplate;
LPWORD nextItem;
LPWSTR itemString;
int32_t itemStringLength;
// Check for memory allocation errors
hGlobal = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hGlobal)
return -1;
wlsDialogTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
// Define a dialog box.
wlsDialogTemplate->style = WS_CAPTION;
wlsDialogTemplate->x = 0;
wlsDialogTemplate->y = 0;
wlsDialogTemplate->cx = 320;
wlsDialogTemplate->cy = 115;
GlobalUnlock(hGlobal);
retCode = DialogBoxIndirect(0, (LPDLGTEMPLATE)hGlobal, 0, ActivateWlsMsgDialog);
And here is how it is defined in RC file:
IDD_WLS_SMALL_MESSAGE_DLG DIALOGEX 0, 0, 320, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",ID_CUSTOM_OK,175,95,120,15
PUSHBUTTON "Cancel",ID_CUSTOM_CANCEL,45,95,120,15
CTEXT "Static",IDC_HEADER_TEXT,120,10,170,70
CONTROL "",IDC_LOGO,"Static",SS_BITMAP,16,10,83,70
END
As you can see, the second dialog is much bigger than defined. I tried to play with various style flags but without any success (That is why there is red cross on the bigger dialog).
Any help with that?
Thanks!
The larger size is easy to explain. Windows automatically sizes the dialog in accordance with its font, and the larger dialog uses a different font. In fact, it is using the default system font (more info on the confusing issue of Windows dialog fonts is found in my answer here).
So the real issue to focus on is why it's using a different font, and fixing that will solve the size problem.
In the dialog box resource file, you specify the DS_SETFONT flag as one of the dialog box styles. According to the documentation, this flag
[i]ndicates that the header of the dialog box template (either standard or extended) contains additional data specifying the font to use for text in the client area and controls of the dialog box. If possible, the system selects a font according to the specified font data. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message.
So that explains why that one is displaying with the expected font.
The next logical question is what's different about your dynamically-created dialog template, shown with the DialogBoxIndirect function. The culprit is, once again, the DS_SETFONT flag, but in this case, the flag is absent. That means that the dialog doesn't contain any information about which font to use to display its controls, and the system defaults to the default system font (which is the ugly Windows 2.0-era font that you see in the second screenshot).
Once we've come to this understanding, the solution should be obvious: you need to tell the dialog which font you want it to use. There are two possible ways of doing so that come to mind:
You can set the DS_SETFONT flag and provide the font information in the header of the dialog box template as described in the above-linked documentation.
Or you can simply create and set the dialog's font in response to the WM_INITDIALOG message.
The latter is probably what you really want to do, as it allows you to use the actual system font (which, confusingly, is different from what I've been calling the "default" system font), which is Segoe UI in Windows Vista and later. Note that even in your first screenshot, it's using MS Sans Serif and therefore sticks out like a sore thumb in the Aero interface. Again, see this answer for more about fonts than you ever wanted to know and sample code for making this work. You'll need to make sure that you set the font for the dialog itself and all of its child controls.
I had played with DialogBoxIndirect (actually with DialogBoxIndirectParam), and here's the part of the code that sets the font. Observe the DS_SHELLFONT option.
LPWORD lpwAlign(LPWORD lpIn, int nAlignment)
{
return (LPWORD)(((ULONG_PTR)lpIn + nAlignment - 1) & -nAlignment);
}
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPMYMESSAGEPARAMS pParams)
{
WORD mem[1024]; // Buffer for dialog resource
LPDLGTEMPLATEW lpdt; // Pointer to heading resource structure
LPDLGITEMTEMPLATEW lpdit; // Pointer to current control
LPWORD lpw; // Cursor to resource buffer
LPWSTR lpwsz; // Cursor to resource buffer (of type WCHAR)
LPCWSTR lpwszCaption; // Aux pointer for text copying
LRESULT ret; // Function's return value
lpdt = (LPDLGTEMPLATEW)lpwAlign( mem, 4 );
//-----------------------
// Define a dialog box.
//-----------------------
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION |
DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
lpdt->dwExtendedStyle = 0;
lpdt->cdit = 3; // number of controls
lpdt->x = 0; lpdt->y = 0;
lpdt->cx = 164; lpdt->cy = 49;
lpw = (LPWORD)(lpdt + 1);
// Dialog menu
*lpw++ = 0;
// Dialog class
*lpw++ = 0;
// Dialog title
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"Choose language";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
// Dialog font
if ( lpdt->style & (DS_SETFONT | DS_SHELLFONT) )
{
// Size
*lpw++ = 8;
// Typeface name
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"MS Shell Dlg";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
}
// Define the rest of the controls
...
ret = DialogBoxIndirectParamW( hinst, lpdt,
hwndOwner, MyMessageProc, (LPARAM)pParams );
return ret;
}
This can be solved in your dialog handler by looking for the WM_INITDIALOG message, and then setting the font for all the controls in the dialog.
int CALLBACK SetChildFont(HWND child, LPARAM font) {
SendMessage(child, WM_SETFONT, font, TRUE);
return TRUE;
}
static int CALLBACK MyMessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
/* Set font for dialog and all child controls */
EnumChildWindows(hwnd, (WNDENUMPROC)SetChildFont, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
break;
}
return 0;
}

How to use Windows ToolTip Control without bounding to a tool

I want to use the native windows tooltip control (pure Win32 API, no MFC stuff).
I read the doc, it seems that I have to send a TTM_ADDTOOL message to bond a tool to the tooltip control. Only after that can I send TTM_TRACKACTIVATE & TTM_TRACKPOSITION to show the tooltip.
But I want to display the tooltip anywhere I want it to be. For example, when the mouse hovers over a region of my window. This region is not a tool in the eye of Windows, it's just a region in my window.
Perhaps I can bond the window to the tooltip control, but, doesn't this mean that I have to bond every window I created to the tooltip control?
Is there an easy solution so that I don't have to send TTM_ADDTOOL messages for every window?
I actually have written some code, but the tooltip just doesn't appear. Anders' answer solves some questions actually. And after I poke around my code, I make it work.
In case someone wants to know how it work:
HWND toolTipWnd = ::CreateWindowExW(WS_EX_TOPMOST,
TOOLTIPS_CLASSW,0,WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
0,0,appHandle,0);
TOOLINFOW ti = {};
ti.cbSize = sizeof(TOOLINFOW);
ti.uFlags = TTF_ABSOLUTE | TTF_IDISHWND /* | TTF_TRACK */; // Don't specify TTF_TRACK here. Otherwise the tooltip won't show up.
ti.hwnd = toolTipWnd; // By doing this, you don't have to create another window.
ti.hinst = NULL;
ti.uId = (UINT)toolTipWnd;
ti.lpszText = L"";
::SendMessageW(toolTipWnd, TTM_ADDTOOLW, 0, (LPARAM)&ti);
::SendMessageW(toolTipWnd, TTM_SETMAXTIPWIDTH,0, (LPARAM)350);
This will create a tooltip window which is not bound to any other window.
So when you want to show the tooltip (e.g. in responds to WM_MOUSEHOVER message), call this:
TOOLINFOW ti = {};
ti.cbSize = sizeof(TOOLINFOW);
ti.hwnd = toolTipWnd;
ti.uId = (UINT)toolTipWnd;
ti.lpszText = L"Sample Tip Text";
::SendMessageW(toolTipWnd,TTM_UPDATETIPTEXTW,0,(LPARAM)&ti); // This will update the tooltip content.
::SendMessageW(toolTipWnd,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti);
::SendMessageW(toolTipWnd, TTM_TRACKPOSITION,0,(LPARAM)MAKELONG(x,y)); // Update the position of your tooltip. Screen coordinate.
//::SendMessageW(toolTipWnd,TTM_POPUP,0,0); // TTM_POPUP not working.. Don't know why.
You need to call TTM_ADDTOOL at least once, you can't call TTM_SETTOOLINFO or get TTN_GETDISPINFO without it AFAIK.
If your target it XP+ you can get away with using TTM_POPUP to display the tip at any position and at any time (But you need to handle the initial delay yourself unless you want a tracking tooltip)
Generally you call TTM_ADDTOOL and associate it with a rectangle (TOOLINFO.rect) or a child window, or you can set the text to LPSTR_TEXTCALLBACK and handle TTN_GETDISPINFO if everything has a tip. MSDN has some sample code you should take a look at...
Addition Windows 10 (Visual Studio 2015, Win32 Console Application)
#include "Commctrl.h"
#pragma comment (lib,"comctl32.lib")
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
TOOLINFOW ti = {};
ti.cbSize = sizeof(TOOLINFOW);
ti.uFlags = TTF_ABSOLUTE | TTF_IDISHWND | TTF_TRACK ; // WITH TTF_TRACK! Otherwise the tooltip doesn't follow TTM_TRACKPOSITION message!
ti.hwnd = toolTipWnd;
ti.hinst = 0;
ti.uId = (UINT)toolTipWnd;
ti.lpszText = L"";
LRESULT result;
int error;
if (!SendMessageW(toolTipWnd, TTM_ADDTOOLW, 0, (LPARAM)&ti)) {
MessageBox(NULL, L"Couldn't create the ToolTip control.", L"Error", MB_OK);
error = 0;
error = GetLastError();
}
if (!SendMessageW(toolTipWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)350)) {
MessageBox(NULL, L"Couldn't create the ToolTip control.", L"Error", MB_OK);
error = 0;
error = GetLastError();
}

Menu disappears after running program later

Okay, so at first when i run my win32 program the menu works fine, however when i open the application later the next day or such the menu is gone but the code never changed. im making the menu with a .rc file. is this the recommended way?
resource.rc
#include "resource.h"
IDR_MYMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", ID_FILE_EXIT
END
END
resource.h
#define IDR_MYMENU 101
#define IDI_MYICON 201
#define ID_FILE_EXIT 9001
#define ID_STUFF_GO 9002
main.cpp
#include "resource.h"
wincl.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);
also i noticed that MSVC++ has a very very complex windows templates, vs bloodshed. should i maybe give up on bloodshed and use MSVC++? I am use to blooshed, but i want to have an edge when i finally learn this stuff?
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON));
wincl.hIconSm = (HICON) LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON), IMAGE_ICON, 16, 16 ,0);
wincl.hCursor = LoadCursor (NULL, IDC_CROSS);
wincl.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU); /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
The content of your RC file looks fine, so I don't think the problem is there. I doubt the problem is in Bloodshed either -- while I'm not particularly fond of Dev-C++, I doubt it's causing anything like this. That leaves your code for the application as the most likely culprit for causing the problem. Unfortunately, you haven't shown enough of that to even guess at likely sources of the problem.

CDialog doesnt show in task bar

Im trying to get a CDialog that has no border or frame to show in the task bar.
It is created in the InitInstance of CWinApp (used to update the app) and i have tried setting the WS_EX_APPWINDOW flag but it still doesnt show in the task bar.
Any ideas?
Edit:
As defined in the resource:
IDD_UPDATEFORM_DIALOG DIALOGEX 0, 0, 246, 124
STYLE WS_POPUP
EXSTYLE WS_EX_APPWINDOW
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
As used:
UpdateForm *dlg = new UpdateForm(UPDATE_FILES, CWnd::GetDesktopWindow());
INT_PTR nResponse = dlg->DoModal();
UpdateForm::UpdateForm(int updateType, CWnd* pParent) : CDialog(IDD_UPDATEFORM_DIALOG, pParent)
{
m_bInit = false;
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON);
m_Progress = new DesuraProgress();
m_updateType = updateType;
}
Still Shows up like so:
http://update.goldeneyesource.net/lodle/noicon.jpg http://update.goldeneyesource.net/lodle/noicon.jpg
Edit #2:
To set the icon for this window (essentially a splash screen), you can send the window a WM_SETICON message along with a desired icon.
For a dialog, you can do this in OnInitDialog(). Here's a snippet that uses the default windows information icon as noted here: LoadIcon # MSDN.
// CHelperDlg message handlers
BOOL CHelperDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 32516 is also known as IDI_INFORMATION
HICON hIcon = LoadIcon(0, MAKEINTRESOURCE(32516));
// 0 in WPARAM is 'small version'
::SendMessage(GetSafeHwnd(), WM_SETICON, 0, (LPARAM)hIcon);
// 1 in WPARAM is 'large version'
::SendMessage(GetSafeHwnd(), WM_SETICON, 1, (LPARAM)hIcon);
// No cleanup as HICONs are free from disposal rules.
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
--
Edit:
I created a second project to mimic your update, but I don't see any differences except the inclusion of DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) in my .rc file. These dialog style definitions don't affect the display of the dialog.
I've uploaded key parts for my minimal example to http://gist.github.com/461057 for your reference, in case you'd like to try adding this dialog ahead of yours for testing.
Also, I'm using VS2010. I have VS2008 available if you'd like me to repeat this test in that version as well.
--
Original:
Try specifying the desktop window (via CWnd::GetDesktopWindow()) as the parent window when you create the dialog.
// Member Variable
CHelperDlg *dlg;
// Meanwhile, elsewhere...
dlg = new CHelperDlg();
dlg->Create(IDD_HELPERDLG, CWnd::GetDesktopWindow());
dlg->ShowWindow(SW_SHOW);
// or...
// dlg->DoModal();
Also, don't forget to destroy the dialog when you're done with it, either in the destructor of the class owner, or other convenient location.
I figured out a hack to get this to work. Instead of disabling the toolbar/caption bar styles to get no border, i used SetWindowRgn to clip the frame and title bar. Same affect, less issues.
RECT rect;
GetWindowRect(&rect);
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
HRGN region = CreateRoundRectRgn(5, 30, w-5, h-5-30, 5, 5);
SetWindowRgn(region, true);