How would I go about appending an item to a window forms system menu. In VB6 I would do this with the Win32 API does anyone know if it is easier now or if I will still need to bust out the API?
How would I go about appending an item to a window forms system menu. In VB6 I would do this with the Win32 API does anyone know if it is easier now or if I will still need to bust out the API?
is that it GetSystemMenu and AppendMenuItem..? I figured there would be a easier way now..?
here is how i would do what i want to do in vb6 this code is right off vbapi.com
VB Code:
Public Declare Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Long, ByVal bRevert _ As Long) As Long Public Declare Function GetMenuItemCount Lib "user32.dll" (ByVal hMenu As Long) As Long Public Type MENUITEMINFO cbSize As Long fMask As Long fType As Long fState As Long wID As Long hSubMenu As Long hbmpChecked As Long hbmpUnchecked As Long dwItemData As Long dwTypeData As String cch As Long End Type Public Const MIIM_STATE = &H1 Public Const MIIM_ID = &H2 Public Const MIIM_TYPE = &H10 Public Const MFT_SEPARATOR = &H800 Public Const MFT_STRING = &H0 Public Const MFS_ENABLED = &H0 Public Const MFS_CHECKED = &H8 Public Declare Function InsertMenuItem Lib "user32.dll" Alias "InsertMenuItemA" (ByVal _ hMenu As Long, ByVal uItem As Long, ByVal fByPosition As Long, lpmii _ As MENUITEMINFO) As Long Public Declare Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal _ hMenu As Long, ByVal uItem As Long, ByVal fByPosition As Long, lpmii _ As MENUITEMINFO) As Long Public Declare Function SetWindowPos Lib "user32.dll" (ByVal hWnd As Long, ByVal _ hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal _ cy As Long, ByVal wFlags As Long) As Long Public Const HWND_TOPMOST = -1 Public Const HWND_NOTOPMOST = -2 Public Const SWP_NOMOVE = &H2 Public Const SWP_NOSIZE = &H1 Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd _ As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Const GWL_WNDPROC = -4 Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal _ lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam _ As Long, ByVal lParam As Long) As Long Public Const WM_SYSCOMMAND = &H112 Public Const WM_INITMENU = &H116 ' Add an option to make window Form1 "Always On Top" to the bottom of its system ' menu. A check mark appears next to this option when active. The menu item acts as a toggle. ' Note how subclassing the window is necessary to process the two messages needed ' to give the added system menu item its full functionality. ' *** Place the following code in a module. *** Public pOldProc As Long ' pointer to Form1's previous window procedure Public ontop As Boolean ' identifies if Form1 is always on top or not ' The following function acts as Form1's window procedure to process messages. Public Function WindowProc (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam _ As Long, ByVal lParam As Long) As Long Dim hSysMenu As Long ' handle to Form1's system menu Dim mii As MENUITEMINFO ' menu item information for Always On Top Dim retval As Long ' return value Select Case uMsg Case WM_INITMENU ' Before displaying the system menu, make sure that the Always On Top ' option is properly checked. hSysMenu = GetSystemMenu(hwnd, 0) With mii ' Size of the structure. .cbSize = Len(mii) ' Only use what needs to be changed. .fMask = MIIM_STATE ' If Form1 is now always on top, check the item. .fState = MFS_ENABLED Or IIf(ontop, MFS_CHECKED, 0) End With retval = SetMenuItemInfo(hSysMenu, 1, 0, mii) WindowProc = 0 Case WM_SYSCOMMAND ' If Always On Top (ID = 1) was selected, change the on top/not on top ' setting of Form1 to match. If wParam = 1 Then ' Reverse the setting and make it the current one. ontop = Not ontop retval = SetWindowPos(hwnd, IIf(ontop, HWND_TOPMOST, HWND_NOTOPMOST), _ 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE) WindowProc = 0 Else ' Some other item was selected. Let the previous window procedure ' process it. WindowProc = CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam) End If Case Else ' If this is some other message, let the previous procedure handle it. WindowProc = CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam) End Select End Function ' *** Place the following code inside Form1. *** ' When Form1 loads, add Always On Top to the system menu and set up the ' new window procedure. Private Sub Form_Load() Dim hSysMenu As Long ' handle to the system menu Dim count As Long ' the number of items initially on the menu Dim mii As MENUITEMINFO ' describes a menu item to add Dim retval As Long ' return value ' Get a handle to the system menu. hSysMenu = GetSystemMenu(Form1.hWnd, 0) ' See how many items are currently in it. count = GetMenuItemCount(hSysMenu) ' Add a separator bar and then Always On Top to the system menu. With mii ' The size of the structure. .cbSize = Len(mii) ' What parts of the structure to use. .fMask = MIIM_ID Or MIIM_TYPE ' This is a separator. .fType = MFT_SEPARATOR ' It has an ID of 0. .wID = 0 End With ' Add the separator to the end of the system menu. retval = InsertMenuItem(hSysMenu, count, 1, mii) ' Likewise, add the Always On Top command. With mii .fMask = MIIM_STATE Or MIIM_ID Or MIIM_TYPE ' This is a regular text item. .fType = MFT_STRING ' The option is enabled. .fState = MFS_ENABLED ' It has an ID of 1 (this identifies it in the window procedure). .wID = 1 ' The text to place in the menu item. .dwTypeData = "&Always On Top" .cch = Len(.dwTypeData) End With ' Add this to the bottom of the system menu. retval = InsertMenuItem(hSysMenu, count + 1, 1, mii) ' Set the custom window procedure to process Form1's messages. ontop = False pOldProc = SetWindowLong(Form1.hWnd, GWL_WNDPROC, AddressOf WindowProc) End Sub ' Before unloading, restore the default system menu and remove the ' custom window procedure. Private Sub Form_Unload(Cancel As Integer) Dim retval As Long ' return value ' Replace the previous window procedure to prevent crashing. retval = SetWindowLong(Form1.hWnd, GWL_WNDPROC, pOldProc) ' Remove the modifications made to the system menu. retval = GetSystemMenu(Form1.hWnd, 1) End Sub
does anybody know of an easier or "new" way to do this? I already know i don't need SetWindowPos() but I can't find anything on the system menu .....
if i find the answer or decided this is the only way i will post it
thanks
or you could do something like this...
VB Code:
MainMenu1.MenuItems.Add("NewItem") ' Wire up Click event to the NewItem_Click procedure AddHandler MainMenu1.MenuItems(MainMenu1.MenuItems.Count - 1).Click, AddressOf Me.NewItem_Click ...... Public Sub NewItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'whatever End Sub
the menu i am speaking of is the one that comes up when you click the form's icom or it's taskbar button with Minimize, maximixe, restore and close in it
i am convering the code right now i will post it in about an hr if my son will let me work...
the code generates an exeption it is being cause by MENUITEMINFO but i am unsure of how to fix it
module
formCode:
Public Module Magiaus
Public Declare Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Long, ByVal bRevert As Integer) As Integer
Public Declare Function GetMenuItemCount Lib "user32.dll" (ByVal hMenu As Integer) As Integer
Public Declare Function InsertMenuItem Lib "user32.dll" Alias "InsertMenuItemA" (ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Integer, lpmii As MENUITEMINFO) As Integer
Public Declare Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Integer, lpmii As MENUITEMINFO) As Integer
Public Structure MENUITEMINFO
Public cbSize As Integer
Public fMask As Integer
Public fType As Integer
Public fState As Integer
Public wID As Integer
Public hSubMenu As Integer
Public hbmpChecked As Integer
Public hbmpUnchecked As Integer
Public dwItemData As Integer
Public dwTypeData As String
Public cch As Integer
Public Sub New(cbSize As Integer, fMask As Integer, fType As Integer, fState As Integer, wID As Integer, hSubMenu As Integer, hbmpChecked As Integer, hbmpUnchecked As Integer, dwItemData As Integer, dwTypeData As String, cch As Integer )
Me.cbSize = cbSize
Me.fMask = fMask
Me.fType = fType
Me.fState = fState
Me.wID = wID
Me.hSubMenu = hSubMenu
Me.hbmpChecked = hbmpChecked
Me.hbmpUnchecked = hbmpUnchecked
Me.dwItemData = dwItemData
Me.dwTypeData = dwTypeData
Me.cch = cch
End Sub
End Structure
Public Const MIIM_STATE As Integer = &H1
Public Const MIIM_ID As Integer = &H2
Public Const MIIM_TYPE As Integer = &H10
Public Const MFT_SEPARATOR As Integer = &H800
Public Const MFT_STRING As Integer = &H0
Public Const MFS_ENABLED As Integer = &H0
Public Const MFS_CHECKED As Integer = &H8
End Module
Code:Option Explicit On
Option Strict On
Option Compare Binary
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Public Class SysMenu : Inherits Form
<STAThread()> _
Shared Sub Main()
System.Windows.Forms.Application.Run(New SysMenu())
End Sub
Public Sub New()
MyBase.New()
Dim hMenu As Integer = GetSystemMenu(Me.Handle.ToInt32, 0)
Dim ic As Integer = GetMenuItemCount(hMenu)
Dim mii As MENUITEMINFO
Dim iRet As Integer = 0
With mii
.cbsize = Len(mii)
.fMask = MIIM_ID Or MIIM_TYPE
.fType = MFT_SEPARATOR
.wID = 0
End With
iRet = InsertMenuItem(hMenu, ic, 1, mii) 'Add a seperator
With mii
.fMask = MIIM_STATE Or MIIM_ID Or MIIM_TYPE
.fType = MFT_STRING
.fState = MFS_ENABLED
.wID = 1
.dwTypeData = "&New Menu Item"
.cch = Len(.dwTypeData)
End With
iRet = InsertMenuItem(hMenu, ic + 1, 2, mii)
Me.Text = "Click Icon"
End Sub
End Class
cander... anybody bill gates... corned bee oh wait wrong forum
I fixed it. Now all I have to do is add the MsgProc but AHHHHHHHHHHHHHH I want an inline debugger @#$% notepad
it wasn't even the Struct it was a error on my part.
ok so you guys who didn't know what i meant give this a run and click the form icon or its taskbar button
VB Code:
Imports System.Runtime.InteropServices Public Module Magiaus Public Declare Ansi Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Integer, ByVal bRevert As Integer) As Integer Public Declare Ansi Function GetMenuItemCount Lib "user32.dll" (ByVal hMenu As Integer) As Integer Public Declare Ansi Function InsertMenuItem Lib "user32.dll" Alias "InsertMenuItemA" (ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Integer,ByRef lpmii As MENUITEMINFO) As Integer Public Declare Ansi Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Integer,ByRef lpmii As MENUITEMINFO) As Integer < StructLayout( LayoutKind.Sequential, CharSet := CharSet.Ansi )> _ Public Structure MENUITEMINFO Public cbSize As Integer Public fMask As Integer Public fType As Integer Public fState As Integer Public wID As Integer Public hSubMenu As Integer Public hbmpChecked As Integer Public hbmpUnchecked As Integer Public dwItemData As Integer Public dwTypeData As String Public cch As Integer Public hbmpItem As Integer End Structure Public Const MIIM_STATE As Integer = &H1 Public Const MIIM_ID As Integer = &H2 Public Const MIIM_TYPE As Integer = &H10 Public Const MFT_SEPARATOR As Integer = &H800 Public Const MFT_STRING As Integer = &H0 Public Const MFS_ENABLED As Integer = &H0 Public Const MFS_CHECKED As Integer = &H8 End ModuleVB Code:
Option Explicit On Option Strict On Option Compare Binary Imports Microsoft.VisualBasic Imports System Imports System.Windows.Forms Public Class SysMenu : Inherits Form <STAThread()> _ Shared Sub Main() System.Windows.Forms.Application.Run(New SysMenu()) End Sub Public Sub New() MyBase.New() Dim hMenu As Integer = GetSystemMenu(Me.Handle.ToInt32, 0) 'should really check this value Dim ic As Integer = GetMenuItemCount(hMenu) 'same here Dim mii As MENUITEMINFO Dim iRet As Integer = 0 With mii .cbsize = Len(mii) .fMask = MIIM_ID Or MIIM_TYPE .fType = MFT_SEPARATOR .wID = 0 End With iRet = InsertMenuItem(hMenu, ic + 1, 1, mii) 'Add a seperator With mii .fMask = MIIM_STATE Or MIIM_ID Or MIIM_TYPE .fType = MFT_STRING .fState = MFS_ENABLED .wID = 1 .dwTypeData = "&New Menu Item" .cch = Len(.dwTypeData) End With iRet = InsertMenuItem(hMenu, ic + 2, 1, mii) Me.Text = "Click Icon" End Sub End Class
if you look close you will see a major change and 2 minor changes
the code i took from vbapi.com had the error in it to begin with
The finished product. Complete with WindowProc. say ewww subclassing really weak subclassing
module:
form:VB Code:
Imports System.Runtime.InteropServices Public Module Magiaus Public Declare Ansi Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Integer, ByVal bRevert As Integer) As Integer Public Declare Ansi Function GetMenuItemCount Lib "user32.dll" (ByVal hMenu As Integer) As Integer Public Declare Ansi Function InsertMenuItem Lib "user32.dll" Alias "InsertMenuItemA" (ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Integer,ByRef lpmii As MENUITEMINFO) As Integer Public Declare Ansi Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Integer,ByRef lpmii As MENUITEMINFO) As Integer Public Declare Ansi Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Integer, ByVal hWnd As Integer, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer Public Declare Ansi Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As ipWindowProc) As Integer < StructLayout( LayoutKind.Sequential, CharSet := CharSet.Ansi )> _ Public Structure MENUITEMINFO Public cbSize As Integer Public fMask As Integer Public fType As Integer Public fState As Integer Public wID As Integer Public hSubMenu As Integer Public hbmpChecked As Integer Public hbmpUnchecked As Integer Public dwItemData As Integer Public dwTypeData As String Public cch As Integer Public hbmpItem As Integer End Structure Public Const MIIM_STATE As Integer = &H1 Public Const MIIM_ID As Integer = &H2 Public Const MIIM_TYPE As Integer = &H10 Public Const MFT_SEPARATOR As Integer = &H800 Public Const MFT_STRING As Integer = &H0 Public Const MFS_ENABLED As Integer = &H0 Public Const MFS_CHECKED As Integer = &H8 Public Const GWL_WNDPROC As Integer = -4 Public Const WM_INITMENU As Integer = &H116 Public Const WM_SYSCOMMAND As Integer = &H112 End Module
VB Code:
Option Explicit On Option Strict On Option Compare Binary Imports Microsoft.VisualBasic Imports System Imports System.Windows.Forms Public Delegate Function ipWindowProc(ByVal hwnd As Integer, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer Public Class SysMenu : Inherits Form Dim ioProc As Integer = 0 <STAThread()> _ Shared Sub Main() System.Windows.Forms.Application.Run(New SysMenu()) End Sub Public Sub New() MyBase.New() Dim hMenu As Integer = GetSystemMenu(Me.Handle.ToInt32, 0) 'should really check this value Dim ic As Integer = GetMenuItemCount(hMenu) 'same here Dim mii As MENUITEMINFO Dim iRet As Integer = 0 With mii .cbsize = Len(mii) .fMask = MIIM_ID Or MIIM_TYPE .fType = MFT_SEPARATOR .wID = 0 End With iRet = InsertMenuItem(hMenu, ic + 1, 1, mii) 'Add a seperator With mii .fMask = MIIM_STATE Or MIIM_ID Or MIIM_TYPE .fType = MFT_STRING .fState = MFS_ENABLED .wID = 1 .dwTypeData = "&Alway On Top" .cch = Len(.dwTypeData) End With iRet = InsertMenuItem(hMenu, ic + 2, 1, mii) Me.Text = "Click Icon" Me.TopMost = True Dim ip As ipWindowProc = AddressOf Me.WindowProc ioProc = SetWindowLong(Me.Handle.ToInt32, GWL_WNDPROC, ip) End Sub Public Function WindowProc(ByVal hwnd As Integer, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer ) As Integer Dim bTopMost As Boolean = Me.TopMost Dim hMenu As Integer = 0 Dim iRet As Integer = 0 Dim mii As MENUITEMINFO Select Case uMsg Case WM_INITMENU hMenu = GetSystemMenu(hwnd, 0) mii.cbSize = Len(mii) mii.fMask = MIIM_STATE If bTopMost = True Then mii.fState = MFS_ENABLED Or MFS_CHECKED Else mii.fState = MFS_ENABLED Or 0 End If iRet = SetMenuItemInfo(hMenu, 1, 0, mii) WindowProc = 0 Case WM_SYSCOMMAND If wParam = 1 Then mii.cbSize = Len(mii) mii.fMask = MIIM_STATE If bTopMost = True mii.fState = MFS_ENABLED Or 0 iRet = SetMenuItemInfo(hMenu, 1, 0, mii) Me.TopMost = False Else mii.fState = MFS_ENABLED Or MFS_CHECKED iRet = SetMenuItemInfo(hMenu, 1, 0, mii) Me.TopMost = True End If WindowProc = 0 Else WindowProc = CallWindowProc(ioProc, hwnd, uMsg, wParam, lParam) End If Case Else WindowProc = CallWindowProc(ioProc, hwnd, uMsg, wParam, lParam) End Select End Function End Class
Ok thats it. Source files and exe attached.
Please comment.