Цель
Получение координат рабочего стола элемента / значка рабочего стола.
Попытка
Я получил дескриптор окна SysListView32, который содержит значки на рабочем столе, используя:
HWND hWnd_Progman = User32.INSTANCE.FindWindow("Progman", "Program Manager");
HWND hWnd_SHELLDLL_DefView = User32.INSTANCE.FindWindowEx(hWnd_Progman, null, "SHELLDLL_DefView", null);
HWND hWnd_SysListView32 = User32.INSTANCE.FindWindowEx(hWnd_SHELLDLL_DefView, null, "SysListView32", "FolderView");
Я получил количество элементов рабочего стола:
LRESULT result = User32.INSTANCE.SendMessage(hWnd_SysListView32, LVM_GETITEMCOUNT, new WPARAM(), new LPARAM());
long desktopIconCount = result.longValue();
У меня установлено положение элемента рабочего стола (проверка того, что SysListView32 является правильным списком для элементов рабочего стола).Переданные координаты x и y соответствуют смещению от левого верхнего края моего левого монитора до левого верхнего угла элемента рабочего стола.Код:
int itemIndex = 0; // Allows 0 to desktopIconCount - 1.
int x = ...;
int y = ...;
LRESULT res = User32.INSTANCE.SendMessage(hWnd_SysListView32, LVM_SETITEMPOSITION, new WPARAM(itemIndex), new LPARAM((x & 0xFFFF) | (y << 16)));
Теперь, чтобы получить позицию элемента рабочего стола, необходимо отправить LVM_GETITEMPOSITION
в SysListView32 и включить указатель на адрес, по которому он может записать позицию.Однако этот указатель должен быть действительным адресом в памяти процесса, принадлежащего SysListView32.Поэтому я попытался сделать следующее:
- Получить процесс, принадлежащий SysListView32.
- Выделить память в этом процессе.
- Записать объект
POINT
вэта память (используется для позиции элемента). - Отправка
LVM_GETITEMPOSITION
в SysListView32 с указателем на эту выделенную память. - Считывание этого
POINT
объекта из памяти.На этом этапе процесс должен был записать в него позицию элемента рабочего стола.
Я пробовал это со следующим кодом:
// Get the SysListView32 process handle.
IntByReference processIdRef = new IntByReference();
User32.INSTANCE.GetWindowThreadProcessId(hWnd_SysListView32, processIdRef);
HANDLE procHandle = Kernel32.INSTANCE.OpenProcess(
Kernel32.PROCESS_VM_OPERATION | Kernel32.PROCESS_VM_WRITE | Kernel32.PROCESS_VM_READ,
false, processIdRef.getValue());
// Allocate memory in the SysView32 process.
int pointSize = Native.getNativeSize(POINT.class)); // 8 bytes.
LPVOID pMem = MyKernel32.INSTANCE.VirtualAllocEx(procHandle, new LPVOID(), new SIZE_T(pointSize),
MyKernel32.MEM_COMMIT, MyKernel32.PAGE_READWRITE);
// Put some POINT-sized object in the process its memory.
boolean success = Kernel32.INSTANCE.WriteProcessMemory(
procHandle, pMem.getPointer(), pMem.getPointer(), pointSize, null);
if(!success) {
System.out.println("Write error = " + Kernel32.INSTANCE.GetLastError());
System.exit(1);
}
// Send the LVM_GETITEMPOSITION message to the SysListView32.
int itemIndex = 0; // Allows 0 to desktopIconCount - 1.
LRESULT res = MyUser32.INSTANCE.SendMessage(
hWnd_SysListView32, LVM_GETITEMPOSITION, new WPARAM(itemIndex), pMem.getPointer());
System.out.println("Message result = " + res.longValue());
// Read the earlier POINT-sized written memory.
POINT point = new POINT();
success = Kernel32.INSTANCE.ReadProcessMemory(
procHandle, pMem.getPointer(), point.getPointer(), pointSize, null);
if(!success) {
System.out.println("Read error = " + Kernel32.INSTANCE.GetLastError());
System.exit(1);
}
System.out.println("Point found: x=" + pos.x + ", y=" + pos.y);
Здесь, MyUser32
созданоследующим образом:
interface MyUser32 extends User32 {
static MyUser32 INSTANCE =
(MyUser32) Native.load("user32", MyUser32.class, W32APIOptions.DEFAULT_OPTIONS);
LRESULT SendMessage(HWND hWnd, int msg, WPARAM wParam, Pointer pointer);
}
и MyKernel32
создаются следующим образом:
interface MyKernel32 extends Kernel32 {
static final MyKernel32 INSTANCE =
(MyKernel32) Native.load("kernel32", MyKernel32.class, W32APIOptions.DEFAULT_OPTIONS);
static int MEM_COMMIT = 0x1000;
static int PAGE_READWRITE = 0x04;
LPVOID VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, int flAllocationType, int flProtect);
}
Для завершения используются следующие дополнительные статические значения:
static final int LVM_FIRST = 0x1000;
static final int LVM_GETITEMCOUNT = LVM_FIRST + 4;
static final int LVM_SETITEMPOSITION = LVM_FIRST + 15;
static final int LVM_GETITEMPOSITION = LVM_FIRST + 16;
Проблема
Вызов WriteProcessMemory
часто завершается ошибкой с кодом ошибки 299 ERROR_PARTIAL_COPY
, и даже если он не выходит из строя, возвращаемое значение POINT всегда равно (0,0).Я ожидаю, что проблема будет либо в объявлениях метода SendMessage
/ VirtualAllocEx
в MyUser32
или MyKernel32
, либо в том, что я неправильно понимаю, какой объект / указатель должен быть передан VirtualAllocEx
или WriteProcessMemory
.
Я провел много исследований и выяснил, как это должно работать в C / C ++, но я не смог найти ни одного примера рабочего кода, использующего JNA для моего случая.
Спасибо за проявленный интереси пытаюсь помочь, если ты прошел через мое сообщение.