Неверный код P / Invoke ... Он выглядит скопированным из источника VB 6, и типы данных эквивалентных имен имеют очень разные семантические значения в VB 6, чем в VB .NET.
Кроме того, дескрипторы / указатели объявляются с использованием фиксированных целочисленных типов, которые не будут работать должным образом в 64-разрядных средах. Эти типы значений всегда должны объявляться с использованием типа IntPtr
, специально разработанного для этой цели.
И, указатели на структуры нужно передавать ByRef
в VB.NET. Вы не можете передать их ByVal
.
Вам понадобятся инструменты, найденные в пространстве имен System.Runtime.InteropServices
и маршаллере .NET, чтобы помочь вам.
Это еще одна причина, по которой вам никогда не следует просто копировать и вставлять код, который вы найдете в Интернете, не понимая, что он означает и что он делает.
Декларации должны выглядеть следующим образом:
Imports System.Runtime.InteropServices
Public NotInheritable Class NativeMethods
Public Const MIIM_STATE As Integer = &H1
Public Const MIIM_ID As Integer = &H2
Public Const MIIM_STRING As Integer = &H40
Public Const MIIM_BITMAP As Integer = &H80
Public Const MIIM_FTYPE As Integer = &H100
Public Const MFT_STRING As Integer = &H0
Public Const MFS_ENABLED As Integer = &H0
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
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 IntPtr
Public hbmpChecked As IntPtr
Public hbmpUnchecked As IntPtr
Public dwItemData As IntPtr
<MarshalAs(UnmanagedType.LPTStr)> Public dwTypeData As String
Public cch As Integer
Public hbmpItem As IntPtr
End Structure
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Public Shared Function GetMenu(ByVal hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function GetMenuItemCount(ByVal hMenu As IntPtr) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Public Shared Function GetSubMenu(ByVal hMenu As IntPtr, ByVal nPos As Integer) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function InsertMenuItem(ByVal hMenu As IntPtr,
ByVal uItem As Integer,
<MarshalAs(UnmanagedType.Bool)> fByPosition As Boolean,
ByRef lpmii As MENUITEMINFO) _
As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function DrawMenuBar(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
End Class
Затем вы можете использовать такую функцию (переписать свой код для соответствия):
' Get a handle to the menu assigned to a window (in this case, your form)
Dim hMenu As IntPtr = NativeMethods.GetMenu(Me.Handle)
' Get a count of the total items in that menu
Dim menuItemCount As Integer = NativeMethods.GetMenuItemCount(hMenu)
' Get a handle to the sub-menu at index 0
Dim hSubMenu As IntPtr = NativeMethods.GetSubMenu(hMenu, 0)
' Get a count of the total items in that sub-menu
Dim subMenuItemCount As Integer = NativeMethods.GetMenuItemCount(hSubMenu)
' Create and fill in a MENUITEMINFO structure, describing the menu item to add
Dim mii As New NativeMethods.MENUITEMINFO
With mii
.cbSize = Marshal.SizeOf(mii) ' prefer Marshal.SizeOf over the VB 6 Len() function
.fMask = NativeMethods.MIIM_FTYPE Or NativeMethods.MIIM_STATE Or NativeMethods.MIIM_ID Or NativeMethods.MIIM_STRING
.fType = NativeMethods.MFT_STRING
.fState = NativeMethods.MFS_ENABLED
.wID = 0 ' your custom menu item ID here
.hSubMenu = IntPtr.Zero
.hbmpChecked = IntPtr.Zero
.hbmpUnchecked = IntPtr.Zero
.dwItemData = IntPtr.Zero
.dwTypeData = "My Menu Item" ' the name of your custom menu item
End With
' Insert the menu item described by the above structure
' (notice that we're passing the structure by reference in the P/Invoke definition!)
NativeMethods.InsertMenuItem(hSubMenu, subMenuItemCount + 1, True, mii)
' Force an update of the window's menu bar (again, in this case, your form)
NativeMethods.DrawMenuBar(Me.Handle)
Все работает как положено, по крайней мере, в одном и том же процессе. Обратите внимание, что P / Invoke - довольно сложная тема, и вам нужно иметь достаточно полное понимание не только VB.NET, но и Win32 API, чтобы заставить его работать правильно. Копирование и вставка кода, который вы находите в Интернете, является рискованным предложением. В большинстве случаев это не сработает. В остальное время это возможный риск для безопасности. К сожалению, вам понадобится не только ответ о переполнении стека, чтобы объяснить вам, как все это работает.
Редактировать: На самом деле, вышеприведенный код также отлично работает во всех процессах. Никаких особых усилий не требуется. Я попытался поработать с меню в работающем экземпляре Notepad, и все работало нормально. Не то чтобы я рекомендовал делать это без очень веских причин ...