Beispiel #1
0
int
menubar_init_module(void)
{
    WNDCLASS wc = { 0 };

    if(MC_ERR(mc_init_comctl32(ICC_BAR_CLASSES | ICC_COOL_CLASSES) != 0)) {
        MC_TRACE("menubar_init_module: mc_init_comctl32() failed.");
        return -1;
    }

    if(MC_ERR(!GetClassInfo(NULL, _T("ToolbarWindow32"), &wc))) {
        MC_TRACE_ERR("menubar_init_module: GetClassInfo() failed");
        return -1;
    }

    /* Remember needed values of standard toolbar window class */
    orig_toolbar_proc = wc.lpfnWndProc;
    extra_offset = wc.cbWndExtra;

    /* Create our subclass. */
    wc.lpfnWndProc = menubar_proc;
    wc.cbWndExtra += sizeof(menubar_t*);
    wc.style |= CS_GLOBALCLASS;
    wc.hInstance = NULL;
    wc.lpszClassName = menubar_wc;
    if(MC_ERR(!RegisterClass(&wc))) {
        MC_TRACE_ERR("menubar_init_module: RegisterClass() failed");
        return -1;
    }

    InitializeCriticalSection(&menubar_ht_lock);

    return 0;
}
Beispiel #2
0
int
button_init_module(void)
{
    WNDCLASS wc;

    mc_init_common_controls(ICC_STANDARD_CLASSES);

    if(MC_ERR(!GetClassInfo(NULL, _T("BUTTON"), &wc))) {
        MC_TRACE_ERR("button_init_module: GetClassInfo() failed");
        return -1;
    }

    /* Remember needed values of standard "button" window class */
    orig_button_proc = wc.lpfnWndProc;
    extra_offset = wc.cbWndExtra;

    /* On Win7 we do not need to emulate anzthing, so we are just alias class
     * of the standard button. */
    if(mc_win_version < MC_WIN_7  ||  mc_comctl32_version < MC_DLL_VER(6, 0)) {
        wc.lpfnWndProc = button_proc;
        wc.cbWndExtra += sizeof(button_t*);
    }
    wc.style |= CS_GLOBALCLASS;
    wc.hInstance = NULL;
    wc.lpszClassName = button_wc;
    if(MC_ERR(!RegisterClass(&wc))) {
        MC_TRACE_ERR("button_init_module: RegisterClass() failed");
        return -1;
    }

    return 0;
}
Beispiel #3
0
int
html_init_module(void)
{
    WNDCLASS wc = { 0 };

    /* Load OLEAUT32.DLL and OLE32.DLL */
    oleaut32_dll = LoadLibrary(_T("OLEAUT32.DLL"));
    if(MC_ERR(oleaut32_dll == NULL)) {
        MC_TRACE_ERR("html_init_module: LoadLibrary(OLEAUT32.DLL) failed.");
        goto err_oleaut32;
    }
    ole32_dll = LoadLibrary(_T("OLE32.DLL"));
    if(MC_ERR(oleaut32_dll == NULL)) {
        MC_TRACE_ERR("html_init_module: LoadLibrary(OLE32.DLL) failed.");
        goto err_ole32;
    }
    html_SysAllocString = (BSTR (WINAPI*)(const OLECHAR*)) GetProcAddress(oleaut32_dll, "SysAllocString");
    html_SysFreeString = (INT (WINAPI*)(BSTR)) GetProcAddress(oleaut32_dll, "SysFreeString");
    html_OleInitialize = (HRESULT (WINAPI*)(void*)) GetProcAddress(ole32_dll, "OleInitialize");
    html_OleUninitialize = (void (WINAPI*)(void)) GetProcAddress(ole32_dll, "OleUninitialize");
    html_CoCreateInstance = (HRESULT (WINAPI*)(REFCLSID,IUnknown*,DWORD,REFIID,void**)) GetProcAddress(ole32_dll, "CoCreateInstance");
    if(MC_ERR(html_SysAllocString == NULL  ||  html_SysFreeString == NULL  ||
              html_OleInitialize == NULL  ||  html_OleUninitialize == NULL  ||
              html_CoCreateInstance == NULL)) {
        MC_TRACE_ERR("html_init_module: GetProcAddress() failed.");
        goto err_procaddr;
    }

    /* Register window class */
    mc_init_common_controls(ICC_STANDARD_CLASSES);
    wc.style = CS_GLOBALCLASS | CS_PARENTDC;
    wc.lpfnWndProc = html_proc;
    wc.cbWndExtra = sizeof(html_t*);
    wc.lpszClassName = html_wc;
    if(MC_ERR(!RegisterClass(&wc))) {
        MC_TRACE_ERR("html_init_module: RegisterClass() failed");
        goto err_register;
    }

    /* Success */
    return 0;

    /* Error path unwinding */
err_register:
err_procaddr:
    FreeLibrary(ole32_dll);
err_ole32:
    FreeLibrary(oleaut32_dll);
err_oleaut32:
    return -1;
}
Beispiel #4
0
static void
menubar_ht_enable(menubar_t* mb)
{
    MENUBAR_TRACE("menubar_ht_enable(%p)", mb);

    EnterCriticalSection(&menubar_ht_lock);

    if(MC_ERR(menubar_ht_hook != NULL)) {
        MC_TRACE("menubar_ht_enable: Another menubar hot tracks???");
        menubar_ht_perform_disable();
    }

    menubar_ht_hook = SetWindowsHookEx(WH_MSGFILTER, menubar_ht_proc, mc_instance, GetCurrentThreadId());
    if(MC_ERR(menubar_ht_hook == NULL)) {
        MC_TRACE_ERR("menubar_ht_enable: SetWindowsHookEx() failed");
        goto err_hook;
    }

    menubar_ht_mb = mb;
    GetCursorPos(&menubar_ht_last_pos);
    MapWindowPoints(NULL, mb->win, &menubar_ht_last_pos, 1);

err_hook:
    LeaveCriticalSection(&menubar_ht_lock);
}
Beispiel #5
0
static int
menubar_create(menubar_t* mb, CREATESTRUCT *cs)
{
    MENUBAR_TRACE("menubar_create(%p, %p)", mb, cs);

    if(MC_ERR(MENUBAR_SENDMSG(mb->win, WM_CREATE, 0, cs) != 0)) {
        MC_TRACE_ERR("menubar_create: CallWindowProc() failed");
        return -1;
    }

    MENUBAR_SENDMSG(mb->win, TB_SETPARENT, mb->win, 0);
    MENUBAR_SENDMSG(mb->win, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
    MENUBAR_SENDMSG(mb->win, TB_SETBITMAPSIZE, 0, MAKELONG(0, -2));
    MENUBAR_SENDMSG(mb->win, TB_SETPADDING, 0, MAKELONG(10, 6));
    MENUBAR_SENDMSG(mb->win, TB_SETDRAWTEXTFLAGS, MENUBAR_DTFLAGS, MENUBAR_DTFLAGS);

    /* Add some styles we consider default */
    SetWindowLongPtr(mb->win, GWL_STYLE, cs->style | TBSTYLE_FLAT |
                     TBSTYLE_TRANSPARENT | CCS_NODIVIDER);

    if(cs->lpCreateParams != NULL) {
        if(MC_ERR(menubar_set_menu(mb, (HMENU) cs->lpCreateParams, FALSE) != 0)) {
            MC_TRACE("menubar_create: menubar_set_menu() failed.");
            return -1;
        }
    }

    menubar_update_ui_state(mb, FALSE);
    return 0;
}
Beispiel #6
0
int
imgview_init_module(void)
{
    WNDCLASS wc = { 0 };

    wc.style = CS_GLOBALCLASS | CS_PARENTDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = imgview_proc;
    wc.cbWndExtra = sizeof(imgview_t*);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = imgview_wc;
    if(MC_ERR(RegisterClass(&wc) == 0)) {
        MC_TRACE_ERR("imgview_init_module: RegisterClass() failed");
        return -1;
    }

    return 0;
}
Beispiel #7
0
int
grid_init_module(void)
{
    WNDCLASS wc = { 0 };

    wc.style = CS_GLOBALCLASS | CS_PARENTDC;
    wc.lpfnWndProc = grid_proc;
    wc.cbWndExtra = sizeof(grid_t*);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszClassName = grid_wc;
    if(MC_ERR(RegisterClass(&wc) == 0)) {
        MC_TRACE_ERR("grid_init_module: RegisterClass() failed");
        return -1;
    }

    return 0;
}
Beispiel #8
0
static LRESULT CALLBACK
button_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp)
{
    button_t* button = (button_t*) GetWindowLongPtr(win, extra_offset);

    /* Window procedure for our subclassed BUTTON does some logic if
     * either [1] the control is split button and system does not support it
     *            (i.e. Windows is older then Vista).
     *     or [2] the control is BS_ICON and theming is in use, as std.
     *            control draws in the old unthemed style this kind of button.
     * In all other cases all messages are just forwarded to the standard
     * Microsoft button procedure.
     */

    switch(msg) {
        case WM_PAINT:
        case WM_PRINTCLIENT:
        {
            BOOL fake_split;
            BOOL fake_icon;
            PAINTSTRUCT ps;
            HDC dc;

            fake_split = button_is_fake_split(button);
            fake_icon = button_is_fake_icon(button);
            if(!fake_split  &&  !fake_icon) {
                /* Keep it on original proc */
                break;
            }

            if(msg == WM_PAINT)
                dc = BeginPaint(win, &ps);
            else
                dc = (HDC) wp;

            if(!button->no_redraw) {
                if(fake_split)
                    button_paint_split(win, button, dc);
                else
                    button_paint_icon(win, button, dc);
            }

            if(msg == WM_PAINT)
                EndPaint(win, &ps);
            return 0;
        }

        case WM_LBUTTONDOWN:
            if(button_is_fake_split(button)) {
                POINT pt = { GET_X_LPARAM(lp), GET_Y_LPARAM(lp) };
                RECT rect;

                SetFocus(win);
                GetClientRect(win, &rect);
                rect.left = rect.right - DROPDOWN_W;

                if(mc_rect_contains_pt(&rect, &pt)) {
                    /* Handle the click in the drop-down part */
                    MC_NMBCDROPDOWN notify;

                    button->is_dropdown_pushed = 1;
                    InvalidateRect(win, &rect, TRUE);

                    notify.hdr.hwndFrom = win;
                    notify.hdr.idFrom = GetWindowLong(win, GWL_ID);
                    notify.hdr.code = MC_BCN_DROPDOWN;
                    mc_rect_copy(&notify.rcButton, &rect);
                    MC_SEND(GetAncestor(win, GA_PARENT), WM_NOTIFY, notify.hdr.idFrom, &notify);
                    /* We unpush immediately after the parent handles the
                     * notification. Usually it takes some time - parent
                     * typically shows some popup-menu or other stuff
                     * which includes a modal eventloop and/or mouse capture.
                     */
                    button->is_dropdown_pushed = 0;
                    InvalidateRect(win, NULL, TRUE);
                    return 0;
                }
            }
            break;

        case WM_LBUTTONDBLCLK:
            if(button_is_fake_split(button)) {
                RECT rect;

                GetClientRect(win, &rect);
                rect.left = rect.right - DROPDOWN_W;
                if(mc_rect_contains_pos(&rect, lp)) {
                    /* We ignore duble-click in the drop-down part. */
                    return 0;
                }
            }
            break;

        case WM_GETDLGCODE:
            /* Handling this message allows the dialogs to set the button
             * as default, as it is done for normal push buttons. Unfortunately
             * it causes other problems. See the comment in WM_STYLECHANGING.
             */
            if(button_is_fake_split(button)) {
                if((button->style & BS_TYPEMASK) == MC_BS_DEFSPLITBUTTON) {
                    BUTTON_TRACE("button_proc(WM_GETDLGCODE): -> DLGC_DEFPUSHBUTTON");
                    return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
                }
                if((button->style & BS_TYPEMASK) == MC_BS_SPLITBUTTON) {
                    BUTTON_TRACE("button_proc(WM_GETDLGCODE): -> DLGC_UNDEFPUSHBUTTON");
                    return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
                }
            }
            break;

        case BM_SETSTATE:
            if(button_is_fake_split(button)) {
                CallWindowProc(orig_button_proc, win, msg, wp, lp);
                /* USER32.DLL does some painting in BM_SETSTATE. Repaint
                 * the split button. */
                InvalidateRect(win, NULL, TRUE);
                return 0;
            }
            break;

        case BM_GETSTATE:
            if(button_is_fake_split(button)) {
                DWORD s = CallWindowProc(orig_button_proc, win, msg, wp, lp);
                if(button->is_dropdown_pushed)
                    s |= MC_BST_DROPDOWNPUSHED;
                return s;
            }
            break;

        case BM_SETSTYLE:
            if(button_is_fake_split(button)) {
                BUTTON_TRACE("button_proc(BM_SETSTYLE): split style fixup");
                wp &= ~(BS_TYPEMASK & ~BS_DEFPUSHBUTTON);
                wp |= MC_BS_SPLITBUTTON;
                CallWindowProc(orig_button_proc, win, msg, wp, lp);
                button->style = GetWindowLong(win, GWL_STYLE);
                return 0;
            }
            break;

        case WM_SETREDRAW:
            button->no_redraw = !wp;
            break;

        case WM_STYLECHANGING:
            if(button_is_fake_split(button)) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lp;
                if((ss->styleOld & BS_TYPEMASK) == MC_BS_SPLITBUTTON  ||
                   (ss->styleOld & BS_TYPEMASK) == MC_BS_DEFSPLITBUTTON) {
                    /* On older system which do not support split buttons
                     * (i.e. 2000, XP), the dialog procedure does not handle
                     * moving the default state correctly: It accidentaly
                     * removes our split button button type. Hence we perform
                     * this fixup.
                     *
                     * Unfortunately this means that app. cannot freely change
                     * BS_SPLITBUTTON to BS_BUTTON with SetWindowLong(GWL_STYLE)
                     * as this will prevent that too... */
                    BUTTON_TRACE("button_proc(WM_STYLECHANGING): split style fixup");
                    ss->styleNew &= ~(BS_TYPEMASK & ~BS_DEFPUSHBUTTON);
                    ss->styleNew |= MC_BS_SPLITBUTTON;
                }
            }
            break;

        case WM_STYLECHANGED:
            if(wp == GWL_STYLE) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lp;
                button->style = ss->styleNew;
            }
            break;

        case WM_THEMECHANGED:
            if(button->theme)
                mcCloseThemeData(button->theme);
            button->theme = mcOpenThemeData(win, button_tc);
            InvalidateRect(win, NULL, FALSE);
            break;

        case WM_SYSCOLORCHANGE:
            InvalidateRect(win, NULL, FALSE);
            break;

        case WM_UPDATEUISTATE:
            button_update_ui_state(button, LOWORD(wp), HIWORD(wp));
            InvalidateRect(win, NULL, FALSE);
            break;

        case WM_NCCREATE:
            if(MC_ERR(!CallWindowProc(orig_button_proc, win, WM_NCCREATE, wp, lp))) {
                MC_TRACE_ERR("button_proc(WM_NCCREATE): orig_button_proc() failed");
                return FALSE;
            }
            button = (button_t*) malloc(sizeof(button_t));
            if(MC_ERR(button == NULL)) {
                MC_TRACE("button_proc(WM_CREATE): malloc() failed.");
                return FALSE;
            }
            memset(button, 0, sizeof(button_t));
            button->style = ((CREATESTRUCT*)lp)->style;
            SetWindowLongPtr(win, extra_offset, (LONG_PTR) button);
            return TRUE;

        case WM_CREATE:
            if(MC_ERR(CallWindowProc(orig_button_proc, win, WM_CREATE, wp, lp) != 0)) {
                MC_TRACE_ERR("button_proc(WM_CREATE): orig_button_proc() failed");
                return -1;
            }
            button->theme = mcOpenThemeData(win, button_tc);

            {
                WORD ui_state = MC_SEND(win, WM_QUERYUISTATE, 0, 0);
                button->hide_focus = (ui_state & UISF_HIDEFOCUS) ? 1 : 0;
                button->hide_accel = (ui_state & UISF_HIDEACCEL) ? 1 : 0;
            }
            return 0;

        case WM_DESTROY:
            if(button->theme) {
                mcCloseThemeData(button->theme);
                button->theme = NULL;
            }
            break;

        case WM_NCDESTROY:
            if(button)
                free(button);
            break;
    }

    return CallWindowProc(orig_button_proc, win, msg, wp, lp);
}
Beispiel #9
0
static gdix_Image*
imgview_load_image_from_resource(HINSTANCE instance, const TCHAR* name)
{
    static TCHAR* allowed_res_types[] = {
        RT_RCDATA, _T("PNG"), RT_BITMAP, RT_HTML
    };

    int i;
    HRSRC res;
    DWORD res_size;
    HGLOBAL res_global;
    void* res_data;
    imgview_stream_t* stream;
    gdix_Image* img;
    gdix_Status status;

    /* See http://blogs.msdn.com/b/oldnewthing/archive/2011/03/07/10137456.aspx
     * We rely on the fact UnlockResource() and FreeResource() do nothing.
     * It is a bit ugly, but it simplifies things a lot, as our IStream
     * implementation would have to "own" the resource and free it in
     * destructor, complicating the IStream::Clone() even further.
     */

    for(i = 0; i < MC_ARRAY_SIZE(allowed_res_types); i++) {
        res = FindResource(instance, name, allowed_res_types[i]);
        if(res != NULL)
            break;
    }
    if(MC_ERR(res == NULL)) {
        MC_TRACE_ERR("imgview_load_image_from_resource: FindResource() failed");
        return NULL;
    }

    res_size = SizeofResource(instance, res);
    res_global = LoadResource(instance, res);
    if(MC_ERR(res_global == NULL)) {
        MC_TRACE_ERR("imgview_load_image_from_resource: LoadResource() failed");
        return NULL;
    }
    res_data = LockResource(res_global);
    if(MC_ERR(res_data == NULL)) {
        MC_TRACE_ERR("imgview_load_image_from_resource: LockResource() failed");
        return NULL;
    }

    stream = imgview_stream_create(res_data, res_size);
    if(MC_ERR(stream == NULL)) {
        MC_TRACE("imgview_load_image_from_resource: imgview_stream_create() failed");
        return NULL;
    }

    status = gdix_LoadImageFromStream(&stream->stream, &img);
    if(MC_ERR(status != gdix_Ok)) {
        MC_TRACE("imgview_load_image_from_resource: "
                 "GdipLoadImageFromStream() failed [%lu]", status);
        img = NULL;
    }

    stream->stream.lpVtbl->Release(&stream->stream);
    return img;
}
Beispiel #10
0
BOOL MCTRL_API
mcMenubar_HandleRebarChevronPushed(HWND hwndMenubar,
                                   NMREBARCHEVRON* lpRebarChevron)
{
    REBARBANDINFO band_info;
    menubar_t* mb;
    RECT rect;
    HMENU menu;
    MENUITEMINFO mii;
    TCHAR buffer[MENUBAR_ITEM_LABEL_MAXSIZE];
    int i, n;
    TPMPARAMS params;

    /* Verify lpRebarChevron is from notification we assume. */
    if(MC_ERR(lpRebarChevron->hdr.code != RBN_CHEVRONPUSHED)) {
        MC_TRACE("mcMenubar_HandleRebarChevronPushed: Not RBN_CHEVRONPUSHED");
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    /* Verify/get the menubar handle */
    band_info.cbSize = REBARBANDINFO_V3_SIZE;
    band_info.fMask = RBBIM_CHILD;
    MC_SEND(lpRebarChevron->hdr.hwndFrom, RB_GETBANDINFO, lpRebarChevron->uBand, &band_info);
    if(hwndMenubar != NULL) {
        if(MC_ERR(hwndMenubar != band_info.hwndChild)) {
            MC_TRACE("mcMenubar_HandleRebarChevronPushed: "
                     "Notification not about band with the specified menubar.");
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }
    } else {
        hwndMenubar = band_info.hwndChild;
        if(MC_ERR(hwndMenubar == NULL)) {
            MC_TRACE("mcMenubar_HandleRebarChevronPushed: "
                     "The band does not host any child window");
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }
    }

    /* Create popup menu for not completely visible menu items */
    mb = (menubar_t*) GetWindowLongPtr(hwndMenubar, extra_offset);
    GetClientRect(hwndMenubar, &rect);
    menu = CreatePopupMenu();
    if(MC_ERR(menu == NULL)) {
        MC_TRACE_ERR("mcMenubar_HandleRebarChevronPushed: CreatePopupMenu() failed.");
        return FALSE;
    }
    mii.cbSize = sizeof(MENUITEMINFO);
    mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID | MIIM_SUBMENU;
    mii.dwTypeData = buffer;
    mii.cch = MC_SIZEOF_ARRAY(buffer);
    n = MENUBAR_SENDMSG(hwndMenubar, TB_BUTTONCOUNT, 0, 0);
    for(i = n-1; i >= 0; i--) {
        RECT item_rect;

        MENUBAR_SENDMSG(hwndMenubar, TB_GETITEMRECT, i, &item_rect);
        if(item_rect.right < rect.right)
            break;

        mii.cch = MC_SIZEOF_ARRAY(buffer);
        GetMenuItemInfo(mb->menu, i, TRUE, &mii);
        InsertMenuItem(menu, 0, TRUE, &mii);
    }
    params.cbSize = sizeof(TPMPARAMS);
    mc_rect_copy(&params.rcExclude, &lpRebarChevron->rc);

    /* Run the menu */
    MapWindowPoints(hwndMenubar, NULL, (POINT*) &params.rcExclude, 2);
    TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
                     params.rcExclude.left, params.rcExclude.bottom, mb->win, &params);

    /* Destroy the popup menu. Note submenus have to survive as they are shared
     * with the menubar itself. */
    n = GetMenuItemCount(menu);
    for(i = 0; i < n; i++)
        RemoveMenu(menu, 0, MF_BYPOSITION);
    DestroyMenu(menu);

    return TRUE;
}
Beispiel #11
0
static LRESULT CALLBACK
menubar_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp)
{
    menubar_t* mb = (menubar_t*) GetWindowLongPtr(win, extra_offset);

    switch(msg) {
        case MC_MBM_REFRESH:
            lp = (LPARAM)mb->menu;
            /* no break */
        case MC_MBM_SETMENU:
            return (menubar_set_menu(mb, (HMENU)lp, (msg == MC_MBM_REFRESH)) == 0 ? TRUE : FALSE);

        case TB_SETPARENT:
        case CCM_SETNOTIFYWINDOW:
        {
            HWND old = mb->notify_win;
            mb->notify_win = (wp ? (HWND) wp : GetAncestor(win, GA_PARENT));
            return (LRESULT) old;
        }

        case WM_COMMAND:
            MENUBAR_TRACE("menubar_proc(WM_COMMAND): code=%d; wid=%d; control=%p",
                          (int)HIWORD(wp), (int)LOWORD(wp), (HWND)lp);
            if(lp == 0  &&  HIWORD(wp) == 0)  /* msg came from the menu */
                return MC_SEND(mb->notify_win, msg, wp, lp);
            break;

        case WM_NOTIFY:
        {
            NMHDR* hdr = (NMHDR*) lp;
            if(hdr->hwndFrom == win)
                return menubar_notify(mb, hdr);
            break;
        }

        case WM_ENTERMENULOOP:
        case WM_EXITMENULOOP:
        case WM_CONTEXTMENU:
        case WM_INITMENU:
        case WM_INITMENUPOPUP:
        case WM_UNINITMENUPOPUP:
        case WM_MENUSELECT:
        case WM_MENUCHAR:
        case WM_MENURBUTTONUP:
        case WM_MENUCOMMAND:
        case WM_MENUDRAG:
        case WM_MENUGETOBJECT:
        case WM_MEASUREITEM:
        case WM_DRAWITEM:
            return MC_SEND(mb->notify_win, msg, wp, lp);

        case WM_KEYDOWN:
        case WM_SYSKEYDOWN:
            if(menubar_key_down(mb, wp, lp))
                return 0;
            break;

        case WM_GETDLGCODE:
            return MENUBAR_SENDMSG(win, msg, wp, lp) | DLGC_WANTALLKEYS | DLGC_WANTARROWS;

        case WM_NCCREATE:
            if(MC_ERR(MENUBAR_SENDMSG(win, msg, wp, lp) == FALSE)) {
                MC_TRACE_ERR("menubar_proc: MENUBAR_SENDMSG(WM_NCCREATE) failed");
                return FALSE;
            }
            mb = menubar_nccreate(win, (CREATESTRUCT*) lp);
            if(MC_ERR(mb == NULL))
                return FALSE;
            SetWindowLongPtr(win, extra_offset, (LONG_PTR)mb);
            return TRUE;

        case WM_SETFOCUS:
            MENUBAR_TRACE("menubar_proc(WM_SETFOCUS): old focus %p", (HWND) wp);
            if(win != (HWND) wp)
                mb->old_focus = (HWND) wp;
            active_menubar = mb;
            break;

        case WM_KILLFOCUS:
            MENUBAR_TRACE("menubar_proc: WM_KILLFOCUS");
            mb->old_focus = NULL;
            MENUBAR_SENDMSG(mb->win, TB_SETHOTITEM, -1, 0);
            menubar_update_ui_state(mb, FALSE);
            active_menubar = NULL;
            break;

        case WM_CREATE:
            return menubar_create(mb, (CREATESTRUCT*) lp);

        case WM_DESTROY:
            menubar_destroy(mb);
            break;

        case WM_NCDESTROY:
            if(mb) {
                menubar_ncdestroy(mb);
                mb = NULL;
            }
            break;

        /* Disable those standard toolbar messages, which modify contents of
         * the toolbar, as it is our internal responsibility to set it
         * according to the menu. */
        case TB_ADDBITMAP:
        case TB_ADDSTRING:
            MC_TRACE("menubar_proc: Suppressing message TB_xxxx (%d)", msg);
            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
            return -1;
        case TB_ADDBUTTONS:
        case TB_BUTTONSTRUCTSIZE:
        case TB_CHANGEBITMAP:
        case TB_DELETEBUTTON:
        case TB_ENABLEBUTTON:
        case TB_HIDEBUTTON:
        case TB_INDETERMINATE:
        case TB_INSERTBUTTON:
        case TB_LOADIMAGES:
        case TB_MARKBUTTON:
        case TB_MOVEBUTTON:
        case TB_PRESSBUTTON:
        case TB_REPLACEBITMAP:
        case TB_SAVERESTORE:
        case TB_SETANCHORHIGHLIGHT:
        case TB_SETBITMAPSIZE:
        case TB_SETBOUNDINGSIZE:
        case TB_SETCMDID:
        case TB_SETDISABLEDIMAGELIST:
        case TB_SETHOTIMAGELIST:
        case TB_SETIMAGELIST:
        case TB_SETINSERTMARK:
        case TB_SETPRESSEDIMAGELIST:
        case TB_SETSTATE:
            MC_TRACE("menubar_proc: Suppressing message TB_xxxx (%d)", msg);
            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
            return 0;  /* FALSE == NULL == 0 */

        case TB_CUSTOMIZE:
            /* Actually we suppress TB_CUSTOMIZE as the message above (i.e.
             * not passing it into the original proc), but we also misuse
             * is for our internal purpose of showing the popup menu. */
            menubar_perform_dropdown(mb);
            return 0;
    }

    return MENUBAR_SENDMSG(win, msg, wp, lp);
}