Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Objective-C

VB .NET/WinForms: Create Form's MainMenu by Load Menu from Resource-Only DLL

5.00/5 (10 votes)
5 Jan 2023CPOL2 min read 27.6K   314  
Load Menu from Resource-Only DLL (created by VC++) and Set for Form As MainMenu by API Functions.
Load Dynamic Link Library Created by VC++ as Resource-Only DLL by 'LoadLibrary' API Function, load Menu from Resource DLL by 'LoadMenu' API Function, Set Resource Menu as MainMenu of the Form by 'SetMenu' API Function. Frees the loaded dynamic-link library (DLL) module by 'FreeLibrary' API Function.

Introduction

Why do we need to load Menu from Resource-only DLL?
Resource Menus can be shared in several applications.

Use a resource-only DLL to Load Menu from that by Resource ID.

You need to know how to Create a resource-only DLL at first to make your own resource DLL and also Resource Menu.

  • After Make Resource-Only DLL Project to create Resource Menu:
    1. Choose Add->Resource Menu Item by Right-Click on the Project.

      Image 1

    2. Choose Menu Resource Type From Add Resource Dialog and Click on the New Button.

      Image 2

    3. Modify your New Resource Menu:

      Image 3

Background

Using API Functions:

  • Load Resource DLL by LoadLibrary API Function.
    VB.NET
    Private Declare Function LoadLibrary Lib "kernel32" _
    Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
    
  • Load Resource Menu by LoadMenu API Function.
    VB.NET
    Private Declare Function LoadMenu Lib "user32" Alias "LoadMenuA" (
    ByVal hInstance As Long,
    ByVal lpString As String) As Long
    
  • Use SetMenu API Function to set Form's MainMenu.
    VB.NET
    Public Declare Function SetMenu Lib "user32" (
    ByVal hwnd As Long,
    ByVal hMenu As Long) As Boolean
    
  • Create Select and Click Events and Raise those for Resource MenuItems by WndProc overridable method of the Form:
    VB.NET
    Protected Overrides Sub WndProc(ByRef m As Message)
        Static MenuID As Long = 0
        If (m.Msg = WM_MENUSELECT) And m.LParam <> hMenu Then
            If CBool(m.LParam) Then
                MenuID = m.WParam.ToInt64 And &HFFFF&
                RaiseEvent MenuItemSelected(MenuID)
            Else
                If MenuID > 0 Then
                    RaiseEvent MenuItemClicked(MenuID)
                    MenuID = 0
                End If
            End If
        ElseIf m.Msg = WM_MENUSELECT Then
            MenuID = 0
        End If
        MyBase.WndProc(m)
    End Sub
    
  • Use FreeLibrary API Function, when form is closing.
    VB.NET
    Private Declare Function FreeLibrary Lib "kernel32.dll" (
    ByVal hLibModule As Long) As Boolean
    

Using the Code

You need to Define the above API Functions at Form General Declaration Section, and also these two variables: hMenu and hInstance.

VB.NET
Dim hMenu As Long
Dim hInstance As Long

And also needs to copy the Created Resource-Only DLL in the root(Startup) Application Directory:

Image 4

Then Load that Resource DLL by using LoadLibrary API Function to set hInstance General Variable at Form Load Event:

VB.NET
hInstance = LoadLibrary("Resources")

And also call resource Menu by using LoadMenu API Function via Resource ID to set hMenu General Variable:

VB
hMenu = LoadMenu(hInstance, "#101")

Finally, to create Form MainMenu by Resource Menu using SetMenu API Function:

VB.NET
Me.Text = SetMenu(Me.Handle.ToInt64, hMenu)
Quote:
VB.NET
Private Sub ResourceMenu_Load(sender As Object, e As EventArgs) Handles Me.Load
    hInstance = LoadLibrary("Resources")
    hMenu = LoadMenu(hInstance, "#101")
    Me.Text = SetMenu(Me.Handle.ToInt64, hMenu)
End Sub

To know when user Select MenuItem or clicked need to use WndProc method of the Form:

  • Define this Constant at Form General Declaration Section:
    VB.NET
    Public Const WM_MENUSELECT = &H11F
    
  • Create Events for Select and Click Resource MenuItems:
    VB.NET
    Event MenuItemSelected(ID As Integer)
    Event MenuItemClicked(ID As Integer)
    
  • Type Overrides Keyword and press Space key to choose WndProc Method:

    Image 5

  • and use these below statements at this method:
    VB.NET
    Protected Overrides Sub WndProc(ByRef m As Message)
        Static MenuID As Long = 0
        If (m.Msg = WM_MENUSELECT) And m.LParam <> hMenu Then
            If CBool(m.LParam) Then
                MenuID = m.WParam.ToInt64 And &HFFFF&
                RaiseEvent MenuItemSelected(MenuID)
            Else
                If MenuID > 0 Then
                    RaiseEvent MenuItemClicked(MenuID)
                    MenuID = 0
                End If
            End If
        ElseIf m.Msg = WM_MENUSELECT Then
            MenuID = 0
        End If
        MyBase.WndProc(m)
    End Sub
    

But for Write and Invoke your Commands by clicking on each MenuItem, you need to know MenuItem IDs:

Go to Resource-Only DLL project and double-click on the Resources.rc to view Resources and Select Created Resource Menu, Right-click and choose Resource Symbols MenuItem:

Image 6

And use each statement you want with any ID at MenuItemClicked Event Procedure:

VB.NET
Private Sub ResourceMenu_MenuItemClicked(ID As Integer) Handles Me.MenuItemClicked
    Select Case ID
        Case 40001 'New
        Case 40002 'Open
        Case 40003 'Import
        Case 40004 'Export
        Case 40005 'Exit
            Application.Exit()
    End Select
End Sub

Use FreeLibrary API Function at Form Closed Event to free the loaded dynamic-link library (DLL) module:

VB.NET
Private Sub ResourceMenu_Closed(sender As Object, e As EventArgs) Handles Me.Closed
    FreeLibrary(hInstance)
End Sub

History

  • 15th December, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)