FAQ (exmenu)
Exontrol.COM Software - Frequently Asked Questions - ExMenu Component
1:
The control's release notes can be found on our web site, looking for the Release Notes column in the control's main page. Click here for direct link.
2:
The ExMenu control allows hosting ActiveX controls to a sub menu. The SubControl value ( 3 ) allows adding an sub menu that hosts an ActiveX control. The SubControl property of Item object gets a Control object that holds information about ActiveX control such us control's identifier, width or height, runtime license key, and so on. The following sample adds a sub menu that hosts an MSCal.Calendar ActiveX control:
With ExMenu1
        .Debug = True
        With .Items.Add("<b>MSCAL</b>.Calendar", EXMENULibCtl.ItemTypeEnum.SubControl)
            .ID = 1212
            With .SubControl
                .ControlID = "MSCal.Calendar"
                .Create
            End With
        End With
        .Refresh
End With

 The Create method of the Control object creates the control identifies by ControlID property. If the ControlID property specifies a control that requires a runtime license key, the LicenseKey property should be set before calling Create method. You can use properties like Width and Height of the Control object to specify the size of the hosted ActiveX control. The Height and Width properties need to be called before Create method. Once that Create method was successfully called, you can use the Object property to access the created control's properties like in the following sample:

With ExMenu1
        With .Items.Add("<b>MSCAL</b>.Calendar", EXMENULibCtl.ItemTypeEnum.SubControl)
            .ID = 1212
            With .SubControl
                .Width = 256
                .Height = 196
                .ControlID = "MSCal.Calendar"
                .Create
                If Not .Object Is Nothing Then
                    With .Object
                        .ShowDateSelectors = False
                    End With
                End If
            End With
        End With
        .Refresh
End With

The type of the object gets by the Object property depends on the ControlID property.  For instance, in the above sample the type of the returned object is MSACAL.Calendar. If you have already a item that you want to host an ActiveX control you need to use a sample like follows:

With ExMenu1
        With .Items.Add("<b>MSCAL</b>.Calendar", EXMENULibCtl.ItemTypeEnum.Default)
            .ID = 1212
        End With
        
        With .Items(1212)
            .Control = True
            With .SubControl
                .Width = 256
                .Height = 196
                .ControlID = "MSCal.Calendar"
                .Create
                If Not .Object Is Nothing Then
                    With .Object
                        .ShowDateSelectors = False
                        .ShowTitle = False
                    End With
                End If
            End With
        End With
        .Refresh
End With
3:
The SubControl property of the Item object gets a Control object that holds information about ActiveX control, when Control property is True ( when the item hosts an ActiveX control ). The following sample adds two ActiveX controls ( Exontrol ExCalendar and Exontrol ExGrid ):
With ExMenu1
        With .Items.Add("<b>Exontrol</b>.Calendar ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            With .SubControl
                .Width = 184
                .Height = 256
                .ControlID = "Exontrol.Calendar"
                .CloseOn = exLButtonUp
                .Create
                If Not .Object Is Nothing Then
                    With .Object
                        .DrawGridLine = True
                        .ShowWeeks = True
                    End With
                End If
            End With
        End With
        With .Items.Add("<b>Exontrol</b>.Grid ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 1
            With .SubControl
                .Width = 184
                .Height = 224
                .CloseOn = exLButtonUp
                .ControlID = "Exontrol.Grid"
                .Create
                If Not .Object Is Nothing Then
                    With .Object
                        .BeginUpdate
                            .HeaderVisible = False
                            .ColumnAutoResize = True
                            .MarkSearchColumn = False
                            .LinesAtRoot = 1
                            .HasButtons = 1
                            .HasLines = 1
                            .Columns.Add ("Column 1")
                            With .Columns.Add("Color")
                                .Enabled = False
                                With .Editor
                                    .EditType = 17
                                End With
                            End With
                            Dim h As Long, hA As Long
                            With .Items
                                Dim i As Long
                                For i = 0 To 1
                                    h = .AddItem("Root 1")
                                    .ItemBold(h) = True
                                    .CellEditorVisible(h, 1) = False
                                    hA = .InsertItem(h, , "Color 1")
                                    .CellValue(hA, 1) = vbBlue
                                    hA = .InsertItem(h, , "Color 2")
                                    .CellValue(hA, 1) = vbRed
                                    hA = .InsertItem(h, , "Color 3")
                                    .CellValue(hA, 1) = vbWhite
                                    .ExpandItem(h) = True
                                Next
                            End With
                        .EndUpdate
                    End With
                End If
            End With
        End With
        .Refresh
    End With
4:
The CloseOn property of the Control object specify how the user closes the ActiveX control when clicking on it. You have the following options: left button down, left button up,  left button dbl click, right button up, right button down, right button dbl click, middle button down, middle button up and middle button dbl click. By default, the user can close the ActiveX control by dbl click on it. The following sample shows how to close an ActiveX control when left mouse button is up:
With ExMenu1
        With .Items.Add("<b>Exontrol</b>.Calendar ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            With .SubControl
                .ControlID = "Exontrol.Calendar"
                .CloseOn = exLButtonUp
                .Create
            End With
        End With
        .Refresh
End With
5:
The ExMenu control fires the OleEvent event when an hosted ActiveX control fires an event. The OleEvent object holds information about fired event. The following sample displays information about a fired event:
Private Sub ExMenu1_OleEvent(ByVal ID As Long, ByVal Ev As EXMENULibCtl.IOleEvent)
    With ExMenu1(ID)
        Debug.Print "The '" & .SubControl.ControlID & "' fires the following event:"
        With Ev
            Debug.Print "Event Name: " & .Name
            Dim i As Long
            For i = 0 To .CountParam - 1
                Dim p As OleEventParam
                Set p = .Param(i)
                With p
                    Debug.Print "Parameter Name: " & .Name
                    Debug.Print "Parameter Value: " & .Value
                End With
            Next
        End With
    End With
End Sub

Private Sub Form_Load()
    With ExMenu1
        With .Items.Add("<b>Exontrol</b>.Calendar ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            With .SubControl
                .ControlID = "Exontrol.Calendar"
                .CloseOn = exLButtonUp
                .Create
            End With
        End With
        .Refresh
    End With
End Sub
6:
  1. The ControlID property should contain a valid control's identifier.

    If you are using VB you can use the following code if yours control identifier is valid:

    Private Function check(ByVal controlID As String) As Boolean
        On Error Resume Next
        Dim o As Object
        Set o = CreateObject(controlID)
        check = IIf(o Is Nothing, False, True)
    End Function  

    If you are using C++ you can use the following function:

    BOOL check( LPCTSTR szControlID )
    {
    	USES_CONVERSION;
    	CoInitialize( NULL );
    	CLSID clsid = CLSID_NULL;
    	CComPtr<IDispatch> spObject;
    	if ( SUCCEEDED( CLSIDFromProgID( T2OLE( szControlID ), &clsid ) ) )
    		if ( SUCCEEDED( CoCreateInstance( clsid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID*)&spObject ) ) )
    			return TRUE;
    	CoUninitialize();
    	return FALSE;
    }
  2. If your control requires a runtime license key, you need to provide the runtime license key to LicenseKey property of Control object
  3. The Create method of control object needs to be called, after ControlID property is set. If you are not calling the .Create method the ActiveX control will not be created.
7:
Yes. You can use the "Shell.Explorer" control that allows you to browse for a HTML page, like in the following sample:
With ExMenu1
        With .Items.Add("<b>Shell</b>.Explorer ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            With .SubControl
                .Width = 448
                .Height = 256
                .ControlID = "Shell.Explorer"
                .CloseOn = exNone
                .Create
                With .Object
                    .Navigate2 "https://exontrol.com"
                End With
            End With
        End With
        .Refresh
End With
8:
The "Shell.Explorer" control fires the BeforeNavigate2 event when user clicks a hyperlink. The following sample shows how to prevent any further navigation into a HTML page:
Dim i As Long

Private Sub ExMenu1_OleEvent(ByVal ID As Long, ByVal Ev As EXMENULibCtl.IOleEvent)
    If (i = 0) Then
        If ID = 1234 Then
            If Ev.Name = "BeforeNavigate2" Then
                Ev("Cancel").Value = True
            End If
        End If
    End If
End Sub

Private Sub Form_Load()
    i = i + 1
    With ExMenu1
        With .Items.Add("<b>Shell</b>.Explorer ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .ID = 1234
            With .SubControl
                .Width = 448
                .Height = 256
                .ControlID = "Shell.Explorer"
                .CloseOn = exLButtonDown
                .Create
                With .Object
                    .Navigate2 "https://exontrol.com"
                End With
            End With
        End With
        .Refresh
    End With
    i = i - 1
End Sub
9:
Yes. You can use the "Shell.Explorer" control that allows you to browse for a drive like in the following sample:
With ExMenu1
        With .Items.Add("<b>Shell</b>.Explorer ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            With .SubControl
                .Width = 448
                .Height = 256
                .ControlID = "Shell.Explorer"
                .CloseOn = exNone
                .Create
                With .Object
                    .Navigate2 "C:\"
                End With
            End With
        End With
        .Refresh
End With 

The following sample displays a Word document:

With ExMenu1
        With .Items.Add("<b>Shell</b>.Explorer ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            With .SubControl
                .Width = 448
                .Height = 256
                .controlID = "Shell.Explorer"
                .CloseOn = exNone
                .Create
                With .Object
                    .Navigate2 "D:\Program Files\Microsoft Visual Studio .NET\Vc7\migration_guide.doc"
                End With
            End With
        End With
        .Refresh
End With
10:
In this case we would suggest using the Exontrol ExPropertiesList control that will help you to find a lot of interesting things about any ActiveX control that hosted by a sub menu. The following sample adds a Exontrol.Grid and browses the properties of created object once that it was created by Create method ( the sample requires a ExPropertiesList control in the form )
With ExMenu1
        With .Items.Add("<b>Shell</b>.Explorer ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .ID = 1212
            .Image = 0
            With .SubControl
                .Width = 448
                .Height = 256
                .ControlID = "Exontrol.Grid"
                .CloseOn = exNone
                .Create
                PropertiesList1.Select ExMenu1(1212).SubControl
            End With
        End With
        .Refresh
End With
11:
We have been asking many times how to make a word document read only, so we have decided to add it to control's faq page, even if it is related to a Word automation problem. The following sample adds a sub menu that hosts a read- only Word document:
With ExMenu1
        With .Items.Add("<b>Shell</b>.Explorer ", EXMENULibCtl.ItemTypeEnum.SubControl)
            .Image = 0
            .ID = 1212
            With .SubControl
                .Width = 448
                .Height = 256
                .ControlID = "Shell.Explorer"
                .CloseOn = exNone
                .Create
                With .Object
                    .Navigate2 "D:\Program Files\Microsoft Visual Studio .NET\Vc7\migration_guide.doc"
                    .Document.Protect 2
                End With
            End With
        End With
        .Refresh
End With

The whole idea is to call Protect method of object returned by the Document property. 

Here's few hints that should be followed in order to get information about returned object. We would suggest using the following snippet of code ( the sample requires an Exontrol ExPropertiesList control on the form ). The code needs to be called after ExMenu creates the ActiveX controls. 

MsgBox PropertiesList1.Interfaces(ExMenu1(XXX).SubControl.Object)

where XXX is the item's identifier that hosts an ActiveX control. PropertiesList1 is the name of the ExPropertiesList control into your form. The above snippet displays the list of interfaces implemented by the object passed to Interfaces property of the ExPropertiesList control. Once that we got the interfaces list, we should look for any interface that object implements. For instance, if we are using as ControlID the expression: "Shell.Explorer", the result of Interfaces property will include interfaces like: IWebBrowser and IWebBrowser2. Of course, you need to read more about each implemented interface depends on what are you trying to do with the hosted object. In our case, we have a Microsoft Web Browser control that hosts a Word document. Calling any property of IWebBrowser2 will affect only the WebBrowser control without affecting the inside document, so we need to go forward by looking at what Document property exposes using the following snippet of code:

MsgBox PropertiesList1.Interfaces(ExMenu1(XXX).SubControl.Object.Document) 
In this case the result is the list of interfaces exported by Document object. We will observe that it includes the _Document interface ( the main interface for Word automation ). Now how can I see the properties and methods that _Document interface exposes? There are plenty of tools that can browses the COM objects type libraries, we prefer using the  OLE/COM Object Viewer ( OLEVIEW.EXE ) tools. Usually it is located in the C:\Program Files\Microsoft Visual Studio\Common\Tools folder, it depends how you installed the MSDEV. So, in order to find out properties and methods that an IDispatch interface exposes you have to open the "Interfaces" item, and to look for the interface name. Once that we locate the interface we have to display its type library ( right click\View\View Type Info).
12:
Opens the control's Editor and click the Images panel. Press INSERT key and an open file dialog shows up.
13:
The Item.Tooltip and Item.TooltipTitle properties define the item's tooltip and its title. The tooltip may contain built-in HTML tags like follows:
  • <b>  bold </b>
  • <u> underline </u>
  • <s> strikeout </s>
  • <i> italic </i>
  • <fgcolor = FF0000> fgcolor </fgcolor>
  • <bgcolor = FF0000> bgcolor </bgcolor>
  • <br> breaks a line. 
  • <solidline> draws a solid line
  • <dotline> draws a dotted line
  • <upline> draws the line to the top of the text line
  • <r> aligns the rest of the text line to the right side.

The following sample defines the tooltip for the item with 2 as identifier:

ExMenu1.Debug = True
    With ExMenu1(2)
        .TooltipTitle = "Just a title"
        .Tooltip = "This is a bit of text that should appear when cursor is over the item.<br><dotline><upline><r><fgcolor=000080>Exontrol.<b>Menu</b></fgcolor>"
End With
The ToolTipDelay property specifies the time in ms that passes before the ToolTip appears. The ToolTipPopDelay specifies the period in ms of time the ToolTip remains visible if the mouse pointer is stationary within a control.
14:
The AddAcelerator method associates an accelerator key to the menu item. The following C++ sample adds the CTRL+S accelerator key to the menu with the ID 11:
m_menu.AddAcelerator( 11, 83, COleVariant( VARIANT_TRUE ), COleVariant( VARIANT_FALSE ), COleVariant( VARIANT_FALSE ) );
The 11 represents the ID of the menu item, 83 represents the key code for the 'S'.
15:
You can use the Visible property of the Item object to hide an item. By default, all items are visible.
16:
The MouseUp event occurs on your third control, because the control fires the Select event when the user presses the mouse button ( by default ), not when the user releases the mouse button. Use the SelectOn property on exMouseUp to specify whether the control selects an item if presses or releases the mouse button.
17:
The differences between exMenu and exPopupMenu components include:
  • the exPopupMenu displays a shortcut, vertical or context menu, since the exMenu displays a top level menu for a form or dialog.
  • the exPopupMenu uses the system context menu to display items, the exMenu doesn't subclass any window or system menu.
  • only one exPopupMenu can be shown at one time, since a form may display multiple exMenu instances in the same time.
  • the exMenu provides the ability to host ActiveX controls, the exPopup can't display ActiveX inside.
  • the exPopupMenu can be assigned to a button using the MenuButton object, since the exMenu has not such of an option.
  • At runtime, the exPopupMenu is a modal window and can't be a child window of a form or dialog, since the exMenu component is a child of a form or dialog.
  • the exMenu can use accelerator keys, the exPopupMenu doesn't use accelerator keys.
  • and more.
18:
Starting with the version 1.0.3.7, the Menu object includes a new property Width that allows you to truncate the long strings. Use the Width property to specify the exact width of the menu no matter what's the length for the items. 
  • The Width property has no effect if it is 0.
  • The Width property indicates the maximum width of the menu, if the value is positive.
  • The Width property indicates the exact width of the menu, if the value is negative.
19:
Yes. You have to insert a SubControl ( ActiveX ) item like in the following sample:
With ExMenu1
    With .Items.Add(" <b>HTML</b> Document ", EXMENULibCtl.SubControl, 1).SubControl
        .CloseOn = exClick
        .Width = 196
        .Height = 134
        .ControlID = "htmlfile"
        .Create
        With .Object()
            .write "<HTML><BODY>"
            .write "<p>This is a <b>HTML</b> page...</p>"
            .write "<ul>"
                .write "<li>1 issue</li>"
                .write "<li>2 issue</li>"
                .write "<li>3 issue</li>"
            .write "</ul>"
            .write "</BODY></HTML>"
        End With
    End With
    .Refresh
End With

The "htmlfile" identifier creates a Microsoft Web Browser object that exposes the IHTMLDocument, IHTMLDocument2, ... interfaces that help you to display HTML documents. The IHTMLDocument2::write method writes one or more HTML expressions to a document in the specified window.

20:
The VisibleItemsCount property specifies the number of items being visible without scroll option.
21:
The most probably thing is that you have installed a service pack for your Internet Explorer browser. The problem is that your web browser disables the ActiveX Inline Data Streaming Functionality described here. ( Microsoft Knowledge Base Article - 317599 ). There is only a value that should be added to your registry. The name of the key is EnableInlineData. You can download and import the registry file here. If you still want to do it manually here's what you need:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility] "EnableInlineData"=dword:00000001
22:
The following VB sample recursively enumerates all items in the menu:
Private Sub scan(ByVal e As EXMENULibCtl.Menu)
    If Not (e Is Nothing) Then
        Dim i As EXMENULibCtl.Item
        For Each i In e
            Debug.Print i.Caption
            scan i.SubMenu
        Next
    End If
End Sub

Or an alternative function without using for each statement will be:

Private Sub scan(ByVal e As EXMENULibCtl.Menu)
    If Not (e Is Nothing) Then
        Dim j As Long
        For j = 0 To e.Count - 1
            Debug.Print e.ItemByIndex(j).Caption
            scan e.ItemByIndex(j).SubMenu
        Next
    End If
End Sub
How-To Questions
General Questions