[VB.NET] Cross-Process Data Extraction: How?

Have you looked at www.pinvoke.net - there are an awful lot of P/Invoke declarations there.

Other than that the common conversions from VB6 are normally Longs become Integers or IntPtrs and Integers become Shorts. In fact if you are using VS 2005 it even gives you a menu entry under the Tools menu to convert VB6 code that might help in converting simple Declare statements.

Other than that which parts of the post are relevant as there may be an easier or an alternate way that wont involve interop and P/Invoke.
 
Have you looked at www.pinvoke.net - there are an awful lot of P/Invoke declarations there.

No I havent, cause I dont know exactly how to look for what I want... I know that the above code will work, cause the example used is almost what I want to do...

Other than that the common conversions from VB6 are normally Longs become Integers or IntPtrs and Integers become Shorts. In fact if you are using VS 2005 it even gives you a menu entry under the Tools menu to convert VB6 code that might help in converting simple Declare statements.

Ill try to convert it again and post the results here...
 
This is the code from DrMemory converted to VB.NET:

DrMemory.vb
[VBNET]=======================================================================

drMemory - Cross-Process Memory Buffer support

(c) 2003 "Dr Memory" ==> Jim White
MathImagics
Uki, NSW, Australia
Puttenham, Surrey, UK

This module contains functions that provide both WinNT and Win9x
style cross-process memory buffer allocation, read and write
functions.

These functions are typically required when trying to use
SendMessage to exchange data with windows in another process.


=======================================================================
Usage guide:

1. Allocate buffer(s) in the target process

xpWindow& = <<target control window handle>>
xpBuffer& = drMemoryAlloc(xpWindow, nBytes)

2. Prepare the data to be passed to the control
and copy it into the buffer

drMemoryWrite xpBuffer, myBuffer, nBytes

3. SendMessage xpWindow, MSG_CODE, wParam, ByVal xpBuffer
==============

4. Extract return data

drMemoryRead xpBuffer, myBuffer, nBytes

(repeat 3/4 as necessary)

5. Release the buffer

drMemoryFree xpBuffer

=======================================================================

Imports System.Runtime.InteropServices

Module DrMemory

Private PlatformKnown As Boolean have we identified the platform?
Private NTflag As Boolean if so, are we NT family (NT, 2K,XP) or non-NT (9x)?

Private fpHandle As Integer the foreign-process instance handle. When we want
memory on NT platforms, this is returned to us by
OpenProcess, and we pass it in to VirtualAllocEx.

We must preserve it, as we need it for read/write
operations, and to release the memory when weve
finished with it.

For this reason, on NT/2K/XP platforms this module should only be used to
interface with ONE TARGET PROCESS at a time. In the future Ill rewrite
this as a class, which can handle multiple-targets, automatic allocation
de-allocation, etc


Private WIN As OperatingSystem = Environment.OSVersion

================== Win95/98 Process Memory functions
Private Declare Function CreateFileMapping Lib "kernel32" (ByVal hFile As Integer, ByVal lpFileMappigAttributes As Integer, ByVal flProtect As Integer, ByVal dwMaximumSizeHigh As Integer, ByVal dwMaximumSizeLow As Integer, ByVal lpName As String) As Integer
Private Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMappingObject As Integer, ByVal dwDesiredAccess As Integer, ByVal dwFileOffsetHigh As Integer, ByVal dwFileOffsetLow As Integer, ByVal dwNumberOfBytesToMap As Integer) As Integer
Private Declare Function UnmapViewOfFile Lib "kernel32" (ByRef lpBaseAddress As Integer) As Integer
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer

================== WinNT/2000 Process Memory functions
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal dwProcId As Integer) As Integer
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Integer, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal flAllocationType As Integer, ByVal flProtect As Integer) As Integer
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Integer, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal dwFreeType As Integer) As Integer
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer

================== Common Platform
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Integer, ByRef lpdwProcessId As Integer) As Integer
Private Declare Sub CopyMemory Lib "kernel32" (ByVal lpDest As Integer, ByVal lpSource As Integer, ByVal cBytes As Integer)
Private Declare Function lstrlenA Lib "kernel32" (ByVal lpsz As Integer) As Integer
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Integer) As Integer
Private Declare Function GetClassName Lib "user32" (ByVal hwnd As Integer, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
Public Declare Function GetParent Lib "user32" (ByVal hwnd As Integer) As Integer


----------
Const PAGE_READWRITE As Short = &H4S
Const MEM_RESERVE As Integer = &H2000
Const MEM_RELEASE As Integer = &H8000
Const MEM_COMMIT As Integer = &H1000
Const PROCESS_VM_OPERATION As Short = &H8S
Const PROCESS_VM_READ As Short = &H10S
Const PROCESS_VM_WRITE As Short = &H20S
Const STANDARD_RIGHTS_REQUIRED As Integer = &HF0000
Const SECTION_QUERY As Short = &H1S
Const SECTION_MAP_WRITE As Short = &H2S
Const SECTION_MAP_READ As Short = &H4S
Const SECTION_MAP_EXECUTE As Short = &H8S
Const SECTION_EXTEND_SIZE As Short = &H10S
Const SECTION_ALL_ACCESS As Boolean = CBool(STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE)
Const FILE_MAP_ALL_ACCESS As Boolean = SECTION_ALL_ACCESS


Public Function drMemoryAlloc(ByVal xpWindow As Integer, ByVal nBytes As Integer) As Integer

Returns pointer to a share-able buffer (size nBytes) in target process
that owns xpWindow

Dim xpThread As Integer target controls thread id
Dim xpID As Integer process id
If WindowsNT() Then
xpThread = GetWindowThreadProcessId(xpWindow, xpID)
drMemoryAlloc = VirtualAllocNT(xpID, nBytes)
Else
drMemoryAlloc = VirtualAlloc9X(nBytes)
End If
End Function

Public Sub drMemoryFree(ByVal mPointer As Integer)
If WindowsNT() Then
VirtualFreeNT(mPointer)
Else
VirtualFree9X(mPointer)
End If
End Sub

Public Sub drMemoryRead(ByVal xpBuffer As Integer, ByVal myBuffer As Integer, ByVal nBytes As Integer)
If WindowsNT() Then
ReadProcessMemory(fpHandle, xpBuffer, myBuffer, nBytes, 0)
Else
CopyMemory(myBuffer, xpBuffer, nBytes)
End If
End Sub

Public Sub drMemoryWrite(ByVal xpBuffer As Integer, ByVal myBuffer As Integer, ByVal nBytes As Integer)
If WindowsNT() Then
WriteProcessMemory(fpHandle, xpBuffer, myBuffer, nBytes, 0)
Else
CopyMemory(xpBuffer, myBuffer, nBytes)
End If
End Sub

Public Function WindowsNT() As Boolean
return TRUE if NT-like platform (NT, 2000, XP, etc)
If Not PlatformKnown Then GetWindowsVersion()
WindowsNT = NTflag
End Function

Public Function WindowsXP() As Boolean
return TRUE only if XP
If Not PlatformKnown Then GetWindowsVersion()
WindowsXP = NTflag And (WIN.Version.MinorRevision <> 0)
End Function

Public Sub GetWindowsVersion()
If WIN.Platform = PlatformID.Win32NT Then
NTflag = True
PlatformKnown = True
ElseIf WIN.Platform = PlatformID.Win32Windows Then
PlatformKnown = True
End If
End Sub

============================================
The NT/2000 Allocate and Release functions
============================================

Private Function VirtualAllocNT(ByVal fpID As Integer, ByVal memSize As Integer) As Integer
fpHandle = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, CInt(False), fpID)
VirtualAllocNT = VirtualAllocEx(fpHandle, 0, memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
End Function

Private Sub VirtualFreeNT(ByVal MemAddress As Integer)
Call VirtualFreeEx(fpHandle, MemAddress, 0, MEM_RELEASE)
CloseHandle(fpHandle)
End Sub

============================================
The 95/98 Allocate and Release functions
============================================

Private Function VirtualAlloc9X(ByVal memSize As Integer) As Integer
fpHandle = CreateFileMapping(&HFFFFFFFF, 0, PAGE_READWRITE, 0, memSize, vbNullString)
VirtualAlloc9X = MapViewOfFile(fpHandle, CInt(FILE_MAP_ALL_ACCESS), 0, 0, 0)
End Function

Private Sub VirtualFree9X(ByVal lpMem As Integer)
UnmapViewOfFile(lpMem)
CloseHandle(fpHandle)
End Sub

Public Function dmWindowClass(ByVal hWindow As Integer) As String
Dim className As String
Dim cLen As Integer
className = New String(Chr(0), 64)
cLen = GetClassName(hWindow, className, 63)
If cLen > 0 Then className = Left(className, cLen)
dmWindowClass = className
End Function

End Module[/VBNET]
 
And the rest of the code is the following. The program compiles and runs but it doesnt work as expected.

Program.vb
[VBNET]Imports System.Runtime.InteropServices
Imports TrayTest.Common

Module Program
Public Const WM_USER As Short = &H400S
Public Const TB_GETBUTTON As Integer = (WM_USER + 23)
Public Const TB_BUTTONCOUNT As Integer = (WM_USER + 24)
Public Const TB_COMMANDTOINDEX As Integer = (WM_USER + 25)
Public Const TB_GETBUTTONTEXTA As Integer = (WM_USER + 45)

Public Sub Main()
Dim hWndTray As IntPtr = GetToolbarWindowHandle()
GetToolbarButtons(hWndTray)
End Sub

Private Function GetToolbarWindowHandle() As IntPtr
Dim hWnd As IntPtr

hWnd = User32.FindWindow("Shell_TrayWnd", Nothing)
hWnd = User32.FindWindowEx(hWnd, Nothing, "TrayNotifyWnd", Nothing)
hWnd = User32.FindWindowEx(hWnd, Nothing, "SysPager", Nothing)
hWnd = User32.FindWindowEx(hWnd, Nothing, "ToolbarWindow32", Nothing)

Return hWnd
End Function

Private Sub GetToolbarButtons(ByVal hWndTray As IntPtr)
Dim bInfo As TBBUTTON

Dim xpBuffer As Integer
Dim bText As String

Dim tbCount As Integer
Dim lret As Integer

Get button count
tbCount = User32.SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0)

If tbCount <= 0 Then Exit Sub

Need a buffer? Ask Dr Memory!
xpBuffer = drMemoryAlloc(CInt(hWndTray), 4096)

For tbIndex As Integer = 0 To tbCount - 1
TB_GETBUTTON
User32.SendMessage(hWndTray, TB_GETBUTTON, tbIndex, xpBuffer)
drMemoryRead(xpBuffer, VarPtr(bInfo), Len(bInfo))

lret = User32.SendMessage(hWndTray, TB_GETBUTTONTEXTA, bInfo.idCommand, xpBuffer)

If lret > 0 Then
bText = New String(Chr(0), lret + 1)
drMemoryRead(xpBuffer, VarPtr(bText), lret)
Else
bText = ""
End If
Next

drMemoryFree(xpBuffer)
End Sub

Private Function VarPtr(ByVal o As Object) As Integer
Dim GC As GCHandle = GCHandle.Alloc(o, GCHandleType.Pinned)
Dim vAddress As IntPtr = GC.AddrOfPinnedObject

GC.Free()

Return Marshal.ReadInt32(vAddress)
End Function

End Module[/VBNET]

User32.vb
[VBNET]Imports System.Runtime.InteropServices

Namespace Common

#Region " Strcuture Declarations "

<StructLayout(LayoutKind.Sequential)> _
Friend Structure TBBUTTON
Public iBitmap As Integer
Public idCommand As Integer
Public fsState As Byte
Public fsStyle As Byte
Public bReserved1 As Byte
Public bReserved2 As Byte
Public dwData As Integer
Public iString As Integer
End Structure

#End Region

#Region " API Declarations "

Friend Class User32
<DllImport("user32.dll")> _
Public Shared Function SendMessage( _
ByVal hWnd As IntPtr, _
ByVal msg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Public Shared Function FindWindow( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
End Function

<DllImport("user32.dll", CharSet:=CharSet.Unicode)> _
Public Shared Function FindWindowEx( _
ByVal hwndParent As IntPtr, _
ByVal hwndChildAfter As IntPtr, _
ByVal lpszClass As String, _
ByVal lpszWindow As String) As IntPtr
End Function
End Class

#End Region

End Namespace[/VBNET]

What code program do and whats supposed to do:
First, it will find the systray (notification area) window handler, count all the toolbar buttons (icons in the systray) and then get the text (tooltip) from each button and store it in bText. The tooltip value isnt saved, the code just loops through every button, gets the text and does nothing with it. This is what the code is supposed to do. Everything works except the part to get the tooltip text from the button. I dont understand why but bInfo is always "empty" (zeros in most values).

Any suggestions?
 
Here it is... The variable bText is supposed to get the tooltip from each systray icon (doesnt do anything with it, but while debugging I checked and there was only an empty string). Also bInfo values should have some values in each structure element but they are all the same through the button loop and almost all zeros.

Hope you find a way to sort it out, I must be doing something wrong...
 

Attachments

Back
Top