我想在其他进程中插入新菜单。但是我收到了一个错误:
尝试读取或写入受保护的内存。这通常表明其他内存已损坏。
按钮代码:
Mmenuhandle = GetMenu(mainhandle)
Mmenucount = GetMenuItemCount(Mmenuhandle)
Smenuhandle = GetSubMenu(Mmenuhandle, 0)
Smenucount = GetMenuItemCount(Smenuhandle)
With mii
.cbSize = Len(mii)
.fMask = MIIM_STATE Or MIIM_ID Or MIIM_STRING Or MIIM_FTYPE
.fType = MFT_STRING
.fState = MFS_ENABLED
.wID = MENUID
.dwTypeData = "My Menu"
.cch = Len(.dwTypeData)
End With
InsertMenuItem(Smenuhandle, Smenucount + 1, True, mii) ' ERROR here
DrawMenuBar(mainhandle)
声明InsertMenuItem
:
Private Declare Function InsertMenuItem Lib "user32" Alias "InsertMenuItemA" _
(ByVal hMenu As Integer, ByVal uItem As Integer, ByVal fByPosition As Boolean, ByVal lpmii As MENUITEMINFO) As Integer
声明MENUITEMINFO
:
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 a As Integer
End Structure
如何解决此错误?
答案 0 :(得分:3)
P / Invoke代码不正确 ...它看起来是从VB 6源复制的,并且等效名称的数据类型在VB 6中的语义含义与它们在VB.NET。
此外,句柄/指针使用固定的整数类型声明,这在64位环境中无法正常工作。应始终使用专门为此目的设计的IntPtr
类型声明这些类型的值。
并且,需要在VB.NET中传递指向结构的指针ByRef
。你不能传递它们ByVal
。
您需要使用System.Runtime.InteropServices
namespace和.NET marshaller中的工具来帮助您。
这是另一个原因,你不应该只是复制和粘贴你在网上找到的代码而不了解它的意义和作用。
声明应如下所示:
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进行相当透彻的了解才能使其正常工作。复制和粘贴您在网上找到的代码是一个固有的风险主张。大多数时候,它都行不通。其余时间,这可能存在安全风险。不幸的是,你需要的不只是Stack Overflow的答案,要向你解释它是如何工作的。
编辑:实际上,上述代码也适用于各个流程。无需特别的努力。我尝试在记事本的运行实例中使用菜单进行修改,一切正常。不是我建议在没有非常充分理由的情况下这样做......