Изменил определение структуры по вашей рекомендации и добавил функции чтения памяти из другого процесса. В итоге структура заполняется, но к сожалению названия значков я так и не вижу :-( - поля "pszText" и "cchText" всегда равны нулю, остальные поля структуры успешно заполняются, а explorer больше не валится. Привожу полный код класса:
Код | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices;
namespace SingleInst2 { static class WinApi {
public const uint TBIF_IMAGE = 0x0001; public const uint TBIF_TEXT = 0x0002; public const uint TBIF_STATE = 0x0004; public const uint TBIF_STYLE = 0x0008; public const uint TBIF_LPARAM = 0x0010; public const uint TBIF_COMMAND = 0x0020; public const uint TBIF_SIZE = 0x0040; public const uint TBIF_BYINDEX = 0x80000000;
const uint WM_USER = 1024; const uint TB_HIDEBUTTON = (WM_USER + 4); const uint TB_BUTTONCOUNT = (WM_USER + 24); const uint TB_GETBUTTON = (WM_USER + 23); const uint TB_GETITEMRECT = (WM_USER + 29); const uint TB_DELETEBUTTON = (WM_USER + 22); const uint TB_GETBUTTONTEXT = (WM_USER + 45); const uint TBSTATE_HIDDEN = 0x08; const uint PROCESS_ALL_ACCESS = 0x1F0FFF; const uint MEM_COMMIT = 0x1000; const uint MEM_RELEASE = 0x8000; const uint PAGE_READWRITE = 0x04;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct TBBUTTONINFO { public int cbSize; public int dwMask; public int idCommand; public int iImage; public byte fsState; public byte fsStyle; public short cx; public IntPtr lParam; public IntPtr pszText; public int cchText; }
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
public static readonly int WM_SHOWFIRSTINSTANCE = RegisterWindowMessage("WM_SHOWFIRSTINSTANCE");
[DllImport("user32.dll")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, bool lParam);
[DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);
[DllImport("user32")] public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")] public static extern int RegisterWindowMessage(string message);
[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr OpenProcess(uint dwDesiredAccess, Int32 bInheritHandle, Int32 dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern Int32 VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, uint dwFreeType);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern Int32 CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] lpBuffer, Int32 nSize, out Int32 lpNumberOfBytesRead);
public static void ShowToFront(string windowName) { IntPtr window = FindWindow(null, windowName); ShowWindow(window, 1); SetForegroundWindow(window); }
public static void ShowTaskbarButtons(bool showButtons) { IntPtr hTrayWnd = GetNotifyWindow(); int count = (int)SendMessage(hTrayWnd, TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero);
Int32 dwTrayProcessID = -1; // получаем ID процесса таскбара GetWindowThreadProcessId(hTrayWnd, out dwTrayProcessID); if (dwTrayProcessID <= 0) { return; }
TBBUTTONINFO tbbi = new TBBUTTONINFO();
// открываем процесс на чтение\запись IntPtr hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID); if (hTrayProc == IntPtr.Zero) { return; }
Int32 dwBytesRead = -1; byte[] byteBuffer = new byte[Marshal.SizeOf(tbbi.GetType())];
// создаем переменную в другом процессе IntPtr lpData = VirtualAllocEx(hTrayProc, IntPtr.Zero, Marshal.SizeOf(tbbi.GetType()), MEM_COMMIT, PAGE_READWRITE); if (lpData == IntPtr.Zero) { CloseHandle(hTrayProc); return; }
for (int i = 0; i < count; i++) { SendMessage(hTrayWnd, TB_GETBUTTON, i, lpData);
// Читаем данные из другого процесса ReadProcessMemory(hTrayProc, lpData, byteBuffer, Marshal.SizeOf(tbbi.GetType()), out dwBytesRead);
if (dwBytesRead < Marshal.SizeOf(tbbi.GetType())) { continue; } IntPtr ptrOut = Marshal.AllocHGlobal(Marshal.SizeOf(tbbi.GetType())); Marshal.Copy(byteBuffer, 0, ptrOut, byteBuffer.Length);
// Получаем данные в структуру tbbi = (TBBUTTONINFO)Marshal.PtrToStructure(ptrOut, typeof(TBBUTTONINFO)); }
VirtualFreeEx(hTrayProc, lpData, 0, MEM_RELEASE); CloseHandle(hTrayProc); } } }
|
В отладчике на 142 строке у меня установлен breakpoint и я вижу что поля tbbi.pszText и tbbi.cchText в процессе прохождения цикла остаются неизменными. |