I want to insert a new menu into other process. But I get an error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
code for button:
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)
declare for 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
declare for 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
How do I fix this error?
The P/Invoke code is incorrect... It looks to be copied from a VB 6 source, and the data types of equivalent names have very different semantic meanings in VB 6 than they do in VB.NET.
In addition, handles/pointers are declared using fixed integer types, which will not work properly in 64-bit environments. These types of values should always be declared using the
IntPtr
type specifically designed for this purpose.And, pointers to structures need to be passed
ByRef
in VB.NET. You can't pass themByVal
.You need to use the tools found in the
System.Runtime.InteropServices
namespace and the .NET marshaller to help you out.This is yet another reason why you should never just copy and paste code that you find online without understanding what it means and what it does.
The declarations should look like this:
Then you can use the function like this (re-write your code to match):
Everything works as expected, at least within the same process. Note that P/Invoke is a fairly difficult topic, and you'll need to have a fairly thorough understanding of not only VB.NET but also the Win32 API to get it to work correctly. Copying and pasting code that you find online is an inherently risky proposition. Most of the time, it won't work. The rest of the time, it's a possible security risk. Unfortunately, you'll need more than an answer on Stack Overflow to explain to you how it all works.
Edit: Actually, the above code works just fine across processes, too. No special effort required. I tried monkeying with the menus in a running instance of Notepad, and everything worked fine. Not that I recommend doing this without a very good reason...