在 C# 中使用 LVM_GETITEMRECT 查询桌面图标仅产生位置,而不产生边界。怎么办?

问题描述 投票:0回答:1

我通过

LVM_GETITEMRECT
查询桌面图标,只得到图标的位置。但我还需要界限。

Docu在这里:https://learn.microsoft.com/en-us/windows/win32/controls/lvm-getitemrect

这部分我无法实现:

发送消息时,该结构体的左成员用于 指定要从中检索列表视图项的部分 边界矩形。它必须设置为以下值之一....

这里的代码正在运行,但只获取位置 x/y。宽度/高度值始终为 0。备注:完整代码“释放”

finally
中的内存。

genericPtr = VirtualAllocEx(
    processHandle,
    IntPtr.Zero,
    (uint)Marshal.SizeOf(typeof(Rectangle)),
    // Rectangle ist the maximum
    // sizeof(uint), ??? SIZE HERE ???
    AllocationType.Commit,
    MemoryProtection.ReadWrite);

CWindow.SendMessage(listViewPtr, (uint)LVM_Message.LVM_GETITEMRECT, itemId, genericPtr.ToInt32());
Rectangle[] vRectangle = new Rectangle[1];
int rectSize = Marshal.SizeOf(typeof(Rectangle));
ReadProcessMemory(processHandle, genericPtr, 
                        Marshal.UnsafeAddrOfPinnedArrayElement(vRectangle, 0),
                        rectSize, out vNumberOfBytes);

我知道我必须为

LVIR_Message
设置
SendMessage
值,但我该怎么做?

private enum LVIR_Message : uint
{
    LVIR_BOUNDS = 0,
    LVIR_ICON = 1,
    LVIR_LABEL = 2,
    LVIR_SELECTBOUNDS = 3
}

参考相关问题:如何在 C# 中禁用桌面视图的“自动排列图标”?

c# winapi
1个回答
0
投票

您需要先用

GCHandle
固定矩形,然后才能获取其地址。

并且您需要将

Rectangle
的内容写入目标进程,然后再发送消息。

如果您将应用程序编译为 64 位,则无法使用

IntPtr.ToInt32()
,您将需要
IntPtr.ToInt64()
,因为
LPARAM
会根据您运行的平台而改变大小。

试试这个:

Rectangle vRectangle = new Rectangle;
vRectangle.left = LVIR_Message.LVIR_BOUNDS;

GCHandle gch = GCHandle.Alloc(vRectangle, GCHandleType.Pinned);
try 
{
    uint rectSize = (uint)Marshal.SizeOf(typeof(Rectangle)); // make sure this is actually 16!

    IntPtr rectPtr = gch.AddrOfPinnedObject();

    processAllocPtr = VirtualAllocEx(
        processHandle,
        IntPtr.Zero,
        rectSize,
        AllocationType.Commit,
        MemoryProtection.ReadWrite);
    if (processAllocPtr == IntPtr.Zero)
    {
        throw new Win32Exception();
    }

    try
    {
        if (!WriteProcessMemory(
            processHandle,
            processAllocPtr,
            rectPtr,
            rectSize,
            out vNumberOfBytesWritten))
        {
            throw new Win32Exception();
        }

        if (IntPtr.Size() == 8) {
            CWindow.SendMessage(listViewPtr, (uint)LVM_Message.LVM_GETITEMRECT, itemId, processAllocPtr.ToInt64());
        } else {
            CWindow.SendMessage(listViewPtr, (uint)LVM_Message.LVM_GETITEMRECT, itemId, processAllocPtr.ToInt32());
        }

        if (!ReadProcessMemory(
            processHandle,
            processAllocPtr,
            rectPtr,
            rectSize,
            out vNumberOfBytes))
        {
            throw new Win32Exception();
        }
    }
    finally
    {
        VirtualFreeEx(
          processHandle,
          processAllocPtr,
          0,
          MEM_RELEASE
        );
    }
}
finally
{
    gch.Free();
}

// use vRectangle as needed...
© www.soinside.com 2019 - 2024. All rights reserved.