PDA

Click to See Complete Forum and Search --> : Forms System Menu..? [done] fell like i've been talking to myself in here


Magiaus
Apr 7th, 2002, 11:31 PM
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?

Magiaus
Apr 8th, 2002, 05:57 PM
is that it GetSystemMenu and AppendMenuItem..? I figured there would be a easier way now..?

Magiaus
Apr 9th, 2002, 11:04 AM
here is how i would do what i want to do in vb6 this code is right off vbapi.com


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

Bananafish
Apr 9th, 2002, 11:47 AM
or you could do something like this...


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

Magiaus
Apr 9th, 2002, 12:25 PM
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...

Magiaus
Apr 9th, 2002, 01:39 PM
the code generates an exeption it is being cause by MENUITEMINFO but i am unsure of how to fix it

module


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


form

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

Magiaus
Apr 10th, 2002, 08:57 AM
cander... anybody bill gates... corned bee oh wait wrong forum

Magiaus
Apr 11th, 2002, 04:29 PM
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

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 Module

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

Magiaus
Apr 11th, 2002, 04:33 PM
the code i took from vbapi.com had the error in it to begin with

Magiaus
Apr 11th, 2002, 05:43 PM
The finished product. Complete with WindowProc. say ewww subclassing really weak subclassing
module:
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

form:
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.