2011-08-05 162 views
0

我想在其他進程中插入一個新的菜單。但是,我得到一個錯誤:爲按鈕在windows API中需要幫助InsertMenuItem

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

代碼:

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 

我該如何解決THI錯誤?

+0

你使用一個鉤子執行到其他進程的上下文嗎? –

+0

是我的初學者 – sozai

回答

3

P/Invoke代碼不正確 ...它看起來是從VB 6源複製的,並且VB 6中的等效名稱的數據類型與VB.NET中的語義含義有很大不同。

另外,句柄/指針是使用固定整數類型聲明的,它在64位環境下無法正常工作。應始終使用專門爲此目的設計的IntPtr類型聲明這些類型的值。

而且,指向結構的指針需要在VB.NET中傳遞ByRef。你不能通過他們ByVal。您需要使用System.Runtime.InteropServices namespace和.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才能使其正常工作。複製並粘貼您在網上找到的代碼是一個固有風險的提議。大多數時候,這是行不通的。其餘時間,這是一個可能的安全風險。不幸的是,你需要的不僅僅是堆棧溢出的答案,以向你解釋它是如何工作的。

編輯:實際上,上面的代碼也適用於跨進程。無需特別努力。我嘗試用記事本運行實例中的菜單進行操作,並且一切正常。不,我建議這樣做,沒有非常很好的理由...