//
// GetMenuHctl
//
// this code demonstrates, how one can get a menu's control handle in a
// custom control for VB2. It can be used e.g. during the processing
// of WM_MENUSELECT to get the tag property of a menu entry.
//
// the code is taken (with some modifications) from the last version of my
// status bar control, where it is used to fire the SelectedTag event.
// I will upload the control within the next days.
//
// Input:      HWND hWndForm            window handle of the form
//             WORD wp                  see SDK documentation for WM_MENUSELECT
//             LONG lp                  ...
//
// Return:     hctlMenu                 control handle (or NULL)
//
// THIS CODE USES UNDOCUMENTED FEATURES OF VB2, AND THERE WILL BE CHANGES
// NEEDED FOR FUTURE VERSIONS. WE ALL SHOULD HOPE, THAT MS WILL MAKE THE
// CONTROL HANDLE OF MENU ITEMS AVAILABLE WITH AN API CALL.
//
// I had a similar routine working for VB1 (see version 1.x of StBar), but 
// it could not be ported to VB2, becaused it depended on assumptions on
// the messages, message ordering, and menu item ids.
//
// Any comment to this is welcome
// 
// Bernd Beekes, 100031,2063
// 

#include <windows.h>
#include <vbapi.h>

#define MENU_OFFSET             7
#define ITEM_OFFSET             8
#define MENU_CONTROL           "MENU"

HCTL NEAR GetMenuHctl(HWND hWndForm, WORD wp, LONG lp)

{
    HMENU       hMenu;
    SHORT       fwMenu;
    HCTL        hctl;
    HCTL        hctlMenu;
    SHORT       nMinItem;
    WORD        nItem;
    LPMODEL     lpModel;
    LPSHORT     lpMenuStruct;
    LPSTR       lpszName;
    
    // get menu handle and flags
      
    fwMenu = LOWORD(lp);
    hMenu  = (HMENU) HIWORD(lp);
            
    // ignore menu closing, separators, system menu, ...
            
    if (hMenu == 0)
        return NULL;
                               
    if (fwMenu & MF_SEPARATOR)
        return NULL;

    if (fwMenu & MF_SYSMENU)
        return NULL;
        
    // determine menu handle and item number
    
    if (fwMenu & MF_POPUP)
    {
        hMenu = (HMENU) wp;
        nItem = 0;
    }
    else
    {
        nItem = wp;
    }
    
    // initialize variables and walk thru control collection

    nMinItem = -1;
    hctlMenu = NULL;
    
    hctl     = VBGetHwndControl(hWndForm);
    hctl     = VBGetControl(hctl, GC_CHILD);
    hctl     = VBGetControl(hctl, GC_FIRSTCONTROL);
    
    while (hctl != NULL)
    {
        lpModel  = VBGetControlModel(hctl);
        lpszName = (LPSTR) MAKELONG(lpModel->npszClassName, (_segment) lpModel);

        if (lstrcmpi(lpszName, MENU_CONTROL) == 0)
        {
            lpMenuStruct = (LPSHORT) VBDerefControl(hctl);
            
            if ((HMENU) *(lpMenuStruct + MENU_OFFSET) == hMenu)
            {
            	// for menu items the item id is at lpMenuStruct + ITEM_OFFSET
            	
                if (nItem != 0 && (WORD) *(lpMenuStruct + ITEM_OFFSET) == nItem)
                {
                    hctlMenu = hctl;
                    break;
                }
                
                // for pop up entries, look for the entry with minimal id !!!
                
                if (nItem == 0)
                {
                    if (nMinItem == -1 || nMinItem > *(lpMenuStruct + ITEM_OFFSET))
                    {
                        nMinItem = *(lpMenuStruct + ITEM_OFFSET);
                        hctlMenu = hctl;
                    }
                }
            }
        }
        
        hctl = VBGetControl(hctl, GC_NEXTCONTROL);
    }

    return  hctlMenu;
}
