Wine menu woes

Geoffrey Hausheer winedevel9605 at phracturedblue.com
Sat Apr 10 12:20:56 CDT 2004


I have an application that seems to work very well, except that the menus
don't work (in wine, they are fine in Windows)

The app is located here (free download):
http://www.acumeninc.com/download/tzmax50v3.21.exe

After some debugging, I found that the app creates a menu, then destroys
it and recreates it using different titles.

Something like:
hMenu = CreateMenu();
hSub1 = CreatePopupMenu();
...
hSub2 = CreatePopupMenu();
...
AppendMenu(hMenu, MF_STRING | MF_POPUP, hSub1, "&File");
AppendMenu(hMenu, MF_STRING | MF_POPUP, hSub2, "&Other");
...
SetMenu(hWnd,hMenu);

while(GetMenuItemCount(hMenu))
    RemoveMenu(hMenu,0, 0x400); //Note: this just detaches the menus

hOldMenu = hMenu;
DestroyMenu(hMenu);
hMenu=CreateMenu();

AppendMenu(hMenu, MF_STRING | MF_POPUP, hSub1, "[&File]");
AppendMenu(hMenu, MF_STRING | MF_POPUP, hSub2, "[&Other]");

if(hMenu != hOldMenu)
   SetMenu(hWnd, hMenu);

That last line is where wine and Windows differ.  In windows, the menuid
is always different, so hMenu never equals hOldMenu.  In wine, we reuse
the menuid, so hMenu always equals hOldMenu.  Since SetMenu didn't get
called after the last createMenu, the menus don't work.

I have no idea why the app implements its menus this way, but I removed
the 'USER_HEAP_FREE( hMenu );' in DestroyMenu() and the menus work fine,
as expected (obviously this isn't a fix, just a validation that the code
behaves this way).

I've included a test app that does the above if anyone is interested.

As a secondary issue, for some reason the 'Exit' item executes the
ID_DO_SOMETHING code instead of the ID_FILE_EXIT code.  It doesn't do
that in windows (it correctly exits instead).  I don't think it is
related, and i haven't looked into it, but I thought I'd mention it.

Thanks,
.Geoff

-------------- next part --------------
#define ID_FILE_OPEN          1001
#define ID_FILE_EXIT          1003
#define ID_DO_SOMETHING       1004
#define ID_DO_SOMETHING_ELSE  1005

#include <windows.h>

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

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

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

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        HMENU hMenu, hOldMenu, hSubMenu1, hSubMenu2;
        MENUITEMINFO mii;
	char str1a[] ="Open";
	char str1b[] ="Close";
	char str1[] ="File";
        switch(Message) {
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                case WM_CREATE:
                        hMenu = CreateMenu();

                        hSubMenu1 = CreatePopupMenu();
                        AppendMenu(hSubMenu1, MF_STRING, ID_FILE_OPEN, "&Open");
                        AppendMenu(hSubMenu1, MF_STRING, ID_FILE_EXIT, "E&xit");
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu1, "&File");

                        hSubMenu2 = CreatePopupMenu();
                        AppendMenu(hSubMenu2, MF_STRING, ID_DO_SOMETHING, "&Something");
                        AppendMenu(hSubMenu2, MF_STRING, ID_DO_SOMETHING_ELSE, "Something &Else");
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu2, "&Other");

                        SetMenu(hwnd, hMenu);
			while(GetMenuItemCount(hMenu))
				RemoveMenu(hMenu,0,0x400);
			hOldMenu=hMenu;
			DestroyMenu(hMenu);
			hMenu=CreateMenu();
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu1, "[&File]");
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu2, "[&Other]");
			if (hMenu != hOldMenu)
				SetMenu(hwnd, hMenu);
                        break;
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case ID_FILE_OPEN:
                                        MessageBox(hwnd, "Open File", "Menu", 0);
                                        break;
                                case ID_FILE_EXIT:
                                        PostQuitMessage(0);
                                case ID_DO_SOMETHING:
                                        MessageBox(hwnd, "Do Something", "Menu", 0);
                                        break;
                                case ID_DO_SOMETHING_ELSE:
                                        MessageBox(hwnd, "Do Something Else", "Menu", 0);
                                        break;
                        }
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
} 


More information about the wine-devel mailing list