Yes! I am proud to be able to announce victory over the terrible documentation on MSDN and the innate confusing-ness of the Windows API. But, I have included completely source code to draw a bitmap file on the right-hand corner of the menu bar of your application. Just make sure the bitmap is less than 20 pixels high (this may depend on your resolution; I use 1024x768 and used a handy tool called Meazure [yes it's spelled right--search Google if you want it] to measure the height of the menu bar.
Below is source code. If the included comments are inadequate, reply and I'll explain what I've done. When in doubt, search MSDN. (If you look at enough disparate pages on there, you can usually find what you need, although it took me about two hours of blundering just to find out how to make an owner-drawn menu item!) Note that this code compiles with Dev-C++ 4.9.9.2.
source file
#include "menudraw.h"
#include <windows.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
HBITMAP hbmp = NULL; //global variable, handle for the bitmap to draw in the menubar
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
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 */
hbmp = (HBITMAP)LoadImage(hThisInstance, "logo.bmp", IMAGE_BITMAP, 60, 20, LR_LOADFROMFILE); //load the bitmap. must be a file called "logo.bmp" in the same directory as this program. This can be changed, but remember to reflect that in the file name (and use "\\" for single backslash). See MSDN docs for LoadImage if you want to load the picture from a resource.
if (!hbmp) return 0; //if it failed, bail out. You probably want to display some kind of error message or quietly set some flag that gets rid of the menu item, but I was lazy and just had the program quit.
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = "MenuDrawClass__345";
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 (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = MAKEINTRESOURCE(1); /* 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) COLOR_BACKGROUND;
/* 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 */
"MenuDrawClass__345", /* Classname */
"Menu Drawing Demonstration", /* 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 */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
DeleteObject(hbmp);
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
{
MENUITEMINFO mii = { 0 }; //create structure
mii.cbSize = sizeof(MENUITEMINFO);
//if you are on Windows 95 (in theory, untested because I have XP):
//mii.fMask = MIIM_FTYPE; //tells Windows 95 we're gonna modify the fType member
//mii.fType = MFT_RIGHTJUSTIFY | MFT_OWNERDRAW; //set menu item to be aligned on the right side of the window (this also tells windows to take care of wrapping it onto the next line if the window is resized to be very narrow) and to be owner-drawn (so we can draw the bitmap)
//end Windows 95 specific
//below if you are on Windows >95
mii.fMask = MIIM_TYPE; //tell Windows >95 we're gonna modify the fType member
mii.fType = MFT_RIGHTJUSTIFY | MFT_OWNERDRAW; //set menu item to be aligned on the right side of the window (this also tells windows to take care of wrapping it onto the next line if the window is resized to be very narrow) and to be owner-drawn (so we can draw the bitmap)
//end Windows >95 specific
SetMenuItemInfo(GetMenu(hwnd), IDM_MENUBMP, false, &mii); //very important line. applies the changes laid out in the structure above to our image menu item.
}
break;
case WM_MEASUREITEM: //Windows is asking us for the size of our owner-drawn menu item
{
if (wParam != 0) break; //if the message isn't about a menu (although this condition should never be true in this sample program) then don't do the following
LPMEASUREITEMSTRUCT size = (LPMEASUREITEMSTRUCT)lParam; //for convenience and readability; I didn't want to have to type this huge cast every time I referred to the structure pointed to by lParam
size->CtlType = ODT_MENU; //it's a menu item
size->itemID = IDM_MENUBMP; //it's the bitmap menu item
size->itemWidth = 60; //it's 60 pixels wide
size->itemHeight = 20; //it's 20 pixels tall (this is the limit as I measured it; windows will clip any part of the picture that's outside the menubar)
return true; //tell windows we've processed the message
}
case WM_DRAWITEM: //Windows is asking us to draw the item
{
if (wParam != 0) break; //if the message isn't about the menu do nothing
LPDRAWITEMSTRUCT item = (LPDRAWITEMSTRUCT)lParam; //convenience, same as above
if (item->itemAction != ODA_DRAWENTIRE) break; //since this isn't really a menu, we only care if we have to draw the whole thing. this value can also tell us to draw selected or highlighted states, but we don't need to change anything on those states
HDC hTempDC = CreateCompatibleDC(NULL); //need source device context to use with BitBlt
SelectObject(hTempDC, hbmp); //select our bitmap into the temporary source device context
BitBlt(item->hDC, item->rcItem.left, item->rcItem.top, (item->rcItem.right - item->rcItem.left), (item->rcItem.bottom - item->rcItem.top), hTempDC, 0, 0, SRCCOPY); //most important line in the program here. copies the bitmap from the source device context into the rectangle provided for us in the menubar.
DeleteDC(hTempDC); //...and clean up after ourselves by releasing the device context
return true;
}
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
.rc (resource) file
#include <windows.h>
#include "menudraw.h"
IDM_MAINMENU MENU DISCARDABLE
BEGIN
POPUP "&Menu" //dummy menu
BEGIN
MENUITEM "&Item", IDM_MENUITEM //dummy menu item, never handled
END
MENUITEM "pic", IDM_MENUBMP //yes, you can create a menu item outside of a popup. will be replaced immediately by the logo.bmp; "pic" is never seen by the user
END
header file (referred to in source and resource file as "menudraw.h" but can be named anything, just remember to change the #include lines)
#ifndef _MENU_DRAWING_HEADER_INCLUDED_
#define _MENU_DRAWING_HEADER_INCLUDED_
#define IDM_MAINMENU 1 //menu constants
#define IDM_MENUITEM 2
#define IDM_MENUBMP 3
#ifndef RC_INVOKED //stuff below will just confuse the resource compiler
#include <windows.h>
extern HBITMAP hbmp;
#endif //RC_INVOKED
#endif //inclusion guard
|