![](/img/trans.png)
[英]Need Help Diagnosing a Failing P/Invoke Call Only on Windows XP
[英]need help in windows API InsertMenuItem
我想在其他過程中插入一個新菜單。 但是我得到一個錯誤:
嘗試讀取或寫入受保護的內存。 這通常表明其他內存已損壞。
按鈕代碼:
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
如何解決此錯誤?
P / Invoke代碼不正確 。它似乎是從VB 6源復制的,等效名稱的數據類型在VB 6中的含義與在VB.NET中的含義非常不同。
此外,句柄/指針使用固定的整數類型聲明,在64位環境中將無法正常使用。 這些類型的值應始終使用專門為此目的設計的IntPtr
類型聲明。
並且,結構的指針需要在VB.NET中傳遞ByRef
。 您不能通過他們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有一個相當透徹的理解,才能使其正常工作。 在線復制和粘貼代碼是一種固有的風險主張。 在大多數情況下,它是行不通的。 其余時間,這可能會帶來安全風險。 不幸的是,您不僅需要有關Stack Overflow的答案,還可以向您解釋它們的工作原理。
編輯:實際上,以上代碼在各個進程之間也可以正常工作。 無需特別的努力。 我嘗試在運行的記事本實例中瀏覽菜單,然后一切正常。 這並不是說我建議沒有一個很好的理由這樣做...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.