簡體   English   中英

在Windows API InsertMenuItem中需要幫助

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM