Questions similar to this appear on the Bentley Discussion Groups. These questions, or something like them, appeared in the MDL discussion group.

Q Questions about menus pop up occasionally …

A It's easy to include a menu in your own MDL dialog: the menu is part of the resource (.r) file that defines your dialog. Adding a custom menu to MicroStation's menu is a more complex task.

FlexiMenu™

Our application FlexiMenu lets you define your menu hierarchy in a FlexiFile (XML text file). FlexiMenu uses the FlexiFile to build a menu structure and attach it to MicroStation's main menu bar. You don't have to do any programming to use FlexiMenu.

Menus and VBA

It's not easy to add a custom menu using VBA. In fact, it seems to be impossible. However, FlexiMenu offers a simple solution.

MFC Menus

Microsoft Foundation Class (MFC) menus are one of the tools provided by Visual Studio when writing a C++ application. It's not straightforward using an MFC menu with an MFC dialog in MicroStation XM. The reason for the complexity is not revealed to us. Bentley appear to wrap a dialog in several layers of invisible frames, and any menu must attach to the outermost frame. Although we have dialog and menu classes that work with Bentley MFC dialogs, we don't publish those.

MFC Menu and Tooltip attached to Bentley MFC dialog

Contact us to discuss how to use MFC menus with Bentley MFC dialogs.

Menus and MDL

A menu item can be defined in a resource (.r) file or in memory. If you want to add a single menu item to an existing menu, then construct a menu item in your MDL code. If you want to add a complex menu to an existing menu, it's easier to define your submenu in a resource file, then attach that submenu to the existing menu.

Menu Terminology

First, some terminology. Menus have a hierarchy. MicroStation has menus, submenus, and menu items. Menus and submenus are navigation elements. A menu item holds details of the action to be performed when a user selects that menu.

Menu Hierarchy

Find a Menu Bar

Before you insert a menu, you must first find an insertion location. You must identify an existing menu bar. If the menu bar is in your own dialog, then it's easy. If the menu bar is MicroStation's main menu, then you need to find it. Here's a function to find MicroStation's menu bar …

#include <dlogids.h>
#include <msdialog.fdf>

RawItemHdr*         mainMenuBarGet
(
void
)
{
    DialogBox*      db      = mdlDialog_overallTitleBarGet ();
    RawItemHdr*     menuBar = NULL;

    if (db)
    {
        DialogItem* item    = mdlDialog_itemGetByTypeAndId (db, RTYPE_MenuBar, MENUBARID_Main, 0);
        if (item)
        {
            menuBar = item->rawItemP;
        }
    }
    return menuBar;
}

Find an Insertion Location

Before you insert a menu, you must first find an insertion location. You must identify an existing menu or menu item on a given menu bar. Use the identified menu to tell MicroStation where to insert your menu. Use mdlDialog_menuBarFindItem to locate an existing menu.

Define Menu In Memory

You can define a menu item in your MDL code by filling in two structs, TextPDM_Item and TextPDM_ItemModify. You should #include <dlogitem.h> to obtain those definitions. Use mdlDialog_textPDMItemIns to insert the memory at the specified location. When you want to remove your menu (e.g. when your MDL program is unloaded), use mdlDialog_menuBarDeleteItem.

Define Menu In a Resource File

You can define a menu structure with multiple menu items in your application's resource (.r) file.

#include <rscdefs.h>
#include <dlogbox.h>
#include <dlogids.h>

DItem_PulldownMenuRsc PULLDOWNMENUID_Help =
{
    NOHELP, MHELP, NOHOOK, ON | ALIGN_LEFT, "Help",
    {
    {"About Your Application",  NOACCEL, ON, NOMARK, NOSUBMENU,
                    0, NOHELP, MHELP,
                    NOHOOK, 0,
                    CMD_YOURAPP_HELP_ABOUT, OTASKID, ""},
    {"Help Contents",  NOACCEL, ON, NOMARK, NOSUBMENU,
                    0, NOHELP, MHELP,
                    NOHOOK, 0,
                    CMD_YOURAPP_HELP_WINHELP, OTASKID, ""},
    }
};

Insert a Menu

Here some functions that insert your menu into MicroStation's main menu bar. First, fill in the structs that define your menu, then call the insert function

BoolInt             menu_attachMenu
(
BoolInt             insert   //   =>   TRUE to attach menu, FALSE to detach
)
{
    RawItemHdr*     menuBarP = mainMenuBarGet ();
    DItem_PulldownMenu*     menuP       = NULL;
    DItem_PulldownMenuItem  targetItem, item;
    TextPDM_Item            textInfo;
    TextPDM_ItemModify      textModify;
    char                    label       [40];
    BoolInt                 present      = FALSE;

    menuP = mdlDialog_menuBarFindMenu (menuBarP, RTYPE_PulldownMenu, PULLDOWNMENUID_Utilities);

    if (mdlDialog_menuBarFindItem (&targetItem,
                                    &menuP,
                                    menuBarP,
                                    NULL,
                                    PULLDOWNMENUID_Utilities,
                                    MENUSEARCHID_User_MDLApps))
    {
	     return FALSE;
    }

    present = !mdlDialog_menuBarFindItem (&item,
                                    &menuP,
                                    menuBarP,
                                    NULL,
                                    PULLDOWNMENUID_Utilities,
                                    MENUSEARCHID_YourUniqueID);

    if (insert && !present)
    {
        memset (&textInfo,   0, sizeof (TextPDM_Item));
        memset (&textModify, 0, sizeof (TextPDM_ItemModify));
        //	Populate text item with stuff
        textInfo.enabled	      	= TRUE;
        //	Command to start up your application dialog etc.
        textInfo.commandNumber    	= CMD_YOUR_COMMAND_HERE;
        //	Application taskId (will reload if app is unloaded)
        textInfo.commandTaskIdP   	= mdlSystem_getCurrTaskID();
        //	Text to appear on Command Window pulldown menu
        strcpy (label, "Your Menu Label");
        textInfo.labelP				= label;
        textInfo.pulldownSearchId 	= MENUSEARCHID_YourUniqueID;
        textModify.enabled        	= TRUE;
        textModify.commandNumber  	= TRUE;
        textModify.commandTaskIdP 	= TRUE;
        textModify.labelP	      	= TRUE;
        textModify.pulldownSearchId	= TRUE;
        textModify.unparsedP      	= TRUE;
        menu_insertMenuItem (menuBarP, &textInfo, &textModify, &targetItem);
    }

    if (!insert && present)
    {	//	Delete items from menu
        menu_deleteMenuItem (menuBarP, PULLDOWNMENUID_Utilities,
           MENUSEARCHID_YourUniqueID);
    }
    return TRUE;
}
//	Insert a menu item
BoolInt                 menu_insertMenuItem
(
RawItemHdr*             menuBarP,
TextPDM_Item*           textInfoP,
TextPDM_ItemModify*     textModifyP,
DItem_PulldownMenuItem* menuItemP
)
{
    DItem_PulldownMenuItem checkItem;
    //	Check to see if our items are already inserted
    BoolInt             present = !mdlDialog_menuBarFindItem (&checkItem,
                                        NULL,
                                        menuBarP,
                                        NULL,
                                        PULLDOWNMENUID_File,
                                        textInfoP->pulldownSearchId);

    if (present)
        return FALSE;

    mdlDialog_textPDMItemIns (&checkItem, NULL, menuItemP,
        textInfoP, textModifyP);
    return TRUE;
}

Add a Menu to MicroStation's Menu Automatically

If you want to add your menu to MicroStation's menu bar automatically, then you'll have to do a little more work. First, some background information about MicroStation, how it starts, how it opens a file, and event handlers.

When MicroStation starts it initialises numerous internal data structures. If you have specified a file to open, MicroStation starts its graphical user interface (GUI). At some stage, MicroStation opens its main window and adds its GUI components, including the main menu bar.

Similarly, when you close MicroStation and open a new file, MicroStation shuts down its GUI (as a user, you see the MicroStation Manager window). Then, MicroStation restarts its graphical user interface (GUI). At some stage, MicroStation opens its main window and adds its GUI components, including the main menu bar.

To accommodate your menu to MicroStation, you need an event handler. The event you want to handle occurs when MicroStation opens its main command window. In your event handler you can add your menu to MicroStation's main menu. Here's how you set an event handler (also known as a callback function) for MicroStation's main window …

#include    <mssystem.fdf>
//	Event handler setup in your main() function
mdlSystem_setFunction (SYSTEM_CMD_WINDOW_OPEN, OnCommandWindowOpen);

The event handler is straightforward …

void    OnCommandWindowOpen
(
void
)
{
    menu_attachMenu (TRUE);
}

Feedback

We hope you find this article useful. Let us know! If you don't want to write code to add your menus to MicroStation, then consider FlexiMenu™. FlexiMenu makes it easy to define custom menus, including help documentation, and add them to MicroStation's menu bar.

Return to MDL articles index.