如何将桌面图标网格从顶部 150 像素移至下方

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

是否有任何 WinAPI 方法可以将桌面图标网格从屏幕顶部移动,例如下方 150 像素?

我正在使用 此 Github 代码 将图标从屏幕顶部移动到下方,但其不起作用的图标再次重置为默认位置:

internal class Desktop
{
    private readonly IntPtr _desktopHandle;
    private readonly List<string> _currentIconsOrder;

    public Desktop()
    {
        _desktopHandle = Win32.GetDesktopWindow(Win32.DesktopWindow.SysListView32);

        AutomationElement el = AutomationElement.FromHandle(_desktopHandle);

        TreeWalker walker = TreeWalker.ContentViewWalker;
        _currentIconsOrder = new List<string>();
        for (AutomationElement child = walker.GetFirstChild(el);
            child != null;
            child = walker.GetNextSibling(child))
        {
            _currentIconsOrder.Add(child.Current.Name);
        }
    }

    private int GetIconsNumber()
    {
        return (int)Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    }

    public NamedDesktopPoint[] GetIconsPositions()
    {
        uint desktopProcessId;
        Win32.GetWindowThreadProcessId(_desktopHandle, out desktopProcessId);

        IntPtr desktopProcessHandle = IntPtr.Zero;
        try
        {
            desktopProcessHandle = Win32.OpenProcess(Win32.ProcessAccess.VmOperation | Win32.ProcessAccess.VmRead |
                Win32.ProcessAccess.VmWrite, false, desktopProcessId);

            return GetIconsPositions(desktopProcessHandle);
        }
        finally
        {
            if (desktopProcessHandle != IntPtr.Zero)
            { Win32.CloseHandle(desktopProcessHandle); }
        }
    }

    private NamedDesktopPoint[] GetIconsPositions(IntPtr desktopProcessHandle)
    {
        IntPtr sharedMemoryPointer = IntPtr.Zero;

        try
        {
            sharedMemoryPointer = Win32.VirtualAllocEx(desktopProcessHandle, IntPtr.Zero, 4096, Win32.AllocationType.Reserve | Win32.AllocationType.Commit, Win32.MemoryProtection.ReadWrite);

            return GetIconsPositions(desktopProcessHandle, sharedMemoryPointer);
        }
        finally
        {
            if (sharedMemoryPointer != IntPtr.Zero)
            {
                Win32.VirtualFreeEx(desktopProcessHandle, sharedMemoryPointer, 0, Win32.FreeType.Release);
            }
        }

    }

    private NamedDesktopPoint[] GetIconsPositions(IntPtr desktopProcessHandle, IntPtr sharedMemoryPointer)
    {
        var listOfPoints = new LinkedList<NamedDesktopPoint>();

        var numberOfIcons = GetIconsNumber();

        for (int itemIndex = 0; itemIndex < numberOfIcons; itemIndex++)
        {
            uint numberOfBytes = 0;
            DesktopPoint[] points = new DesktopPoint[1];

            Win32.WriteProcessMemory(desktopProcessHandle, sharedMemoryPointer,
                Marshal.UnsafeAddrOfPinnedArrayElement(points, 0),
                Marshal.SizeOf(typeof(DesktopPoint)),
                ref numberOfBytes);

            Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMPOSITION, itemIndex, sharedMemoryPointer);

            Win32.ReadProcessMemory(desktopProcessHandle, sharedMemoryPointer,
                Marshal.UnsafeAddrOfPinnedArrayElement(points, 0),
                Marshal.SizeOf(typeof(DesktopPoint)),
                ref numberOfBytes);

            var point = points[0];
            listOfPoints.AddLast(new NamedDesktopPoint(_currentIconsOrder[itemIndex], point.X, point.Y));
        }

        return listOfPoints.ToArray();
    }

    public void SetIconPositions(IEnumerable<NamedDesktopPoint> iconPositions)
    {
        foreach (var position in iconPositions)
        {
            var iconIndex = _currentIconsOrder.IndexOf(position.Name);
            if (iconIndex == -1)
            { continue; }

            Win32.SendMessage(_desktopHandle, Win32.LVM_SETITEMPOSITION, iconIndex, Win32.MakeLParam(position.X, position.Y));
        }
    }

    public void SetDefaultIconPositions(IEnumerable<NamedDesktopPoint> iconPositions)
    {
        foreach (var position in iconPositions)
        {
            var iconIndex = _currentIconsOrder.IndexOf(position.Name);
            if (iconIndex == -1)
            { continue; }

            Win32.SendMessage(_desktopHandle, Win32.LVM_SETITEMPOSITION, iconIndex, Win32.MakeLParam(position.X, position.Y));
        }
    }

    public void Refresh()
    {
        Win32.PostMessage(_desktopHandle, Win32.WM_KEYDOWN, Win32.VK_F5, 0);

        Win32.SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
    }
}

我想实现这个GUI:

I would like to achieve this GUI

图像详细信息:应用程序高度为 150 像素,我尝试将图标移动到该应用程序下方。

这可以实现吗?


问题编辑:

不知道为什么不清楚!虽然它明确指出我正在尝试移动桌面图标网格(不是桌面图标)。

我们都知道Windows桌面有一个ListView(

SysListView32
)来将其图标存储在桌面上,我正在尝试将此ListView(或桌面网格)从屏幕顶部移动到150像素以下。而且,我的应用程序(高度为 150 像素)放置在屏幕顶部(参见上图)。

我可以使用此代码获取桌面 ListView (

SysListView32
):

[DllImport("user32.dll")]
public static extern IntPtr GetShellWindow();

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);        

public static IntPtr GetDesktopWindow(DesktopWindow desktopWindow)
{
    IntPtr _ProgMan = GetShellWindow();
    IntPtr _SHELLDLL_DefViewParent = _ProgMan;
    IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
    IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");

    if (_SHELLDLL_DefView == IntPtr.Zero)
    {
        EnumWindows((hwnd, lParam) =>
        {
            var sb = new StringBuilder(256);
            GetClassName(hwnd, sb, sb.Capacity);

            if (sb.ToString() == "WorkerW")
            {
                IntPtr child = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);
                if (child != IntPtr.Zero)
                {
                    _SHELLDLL_DefViewParent = hwnd;
                    _SHELLDLL_DefView = child;
                    _SysListView32 = FindWindowEx(child, IntPtr.Zero, "SysListView32", "FolderView"); ;
                    return false;
                }
            }
            return true;
        }, IntPtr.Zero);
    }

    switch (desktopWindow)
    {
        case DesktopWindow.ProgMan:
            return _ProgMan;
        case DesktopWindow.SHELLDLL_DefViewParent:
            return _SHELLDLL_DefViewParent;
        case DesktopWindow.SHELLDLL_DefView:
            return _SHELLDLL_DefView;
        case DesktopWindow.SysListView32:
            return _SysListView32;
        default:
            return IntPtr.Zero;
    }
}
c# winapi pinvoke
1个回答
0
投票

这是一个使用官方 API IFolderView::SelectAndPositionItems 方法 的示例 C# 控制台应用程序,可用于此目的:

using System;
using System.Runtime.InteropServices;

namespace MyConsoleApp;

public class Program
{
    public static void Main()
    {
        // we basically follow https://devblogs.microsoft.com/oldnewthing/20130318-00/?p=4933
        dynamic app = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
        var windows = app.Windows;

        const int SWC_DESKTOP = 8;
        const int SWFO_NEEDDISPATCH = 1;
        var hwnd = 0;
        var disp = windows.FindWindowSW(Type.Missing, Type.Missing, SWC_DESKTOP, ref hwnd, SWFO_NEEDDISPATCH);

        var sp = (IServiceProvider)disp;
        var SID_STopLevelBrowser = new Guid("4c96be40-915c-11cf-99d3-00aa004ae837");

        var browser = (IShellBrowser)sp.QueryService(SID_STopLevelBrowser, typeof(IShellBrowser).GUID);
        var view = (IFolderView)browser.QueryActiveShellView();
        var view2 = (IFolderView2)view;

        // get all items, dump & sets their position (here y+= 150)
        for (var i = 0; i < view.ItemCount(); i++)
        {
            // get some item's info to be able to determine if we want to move it or not
            var item = view2.GetItem(i, typeof(IShellItem).GUID);
            Console.WriteLine(item.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING));

            var pidl = view.Item(i);
            view.GetItemPosition(pidl, out var pt);
            Console.WriteLine("Current position: " + pt.x + ", " + pt.y);

            pt.y += 150;
            view.SelectAndPositionItems(1, new IntPtr[] { pidl }, new POINT[] { pt }, SVSIF.SVSI_POSITIONITEM);
            Console.WriteLine();
        }
    }

    [ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IServiceProvider
    {
        [return: MarshalAs(UnmanagedType.IUnknown)]
        object QueryService([MarshalAs(UnmanagedType.LPStruct)] Guid service, [MarshalAs(UnmanagedType.LPStruct)] Guid riid);
    }

    // note: for the following interfaces, not all methods are defined as we don't use them here
    [ComImport, Guid("000214E2-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IShellBrowser
    {
        void _VtblGap1_12(); // skip 12 methods https://stackoverflow.com/a/47567206/403671

        [return: MarshalAs(UnmanagedType.IUnknown)]
        object QueryActiveShellView();
    }

    [ComImport, Guid("cde725b0-ccc9-4519-917e-325d72fab4ce"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IFolderView
    {
        void _VtblGap1_3(); // skip 3 methods

        IntPtr Item(int iItemIndex);
        int ItemCount(uint uFlags = 0);

        void _VtblGap2_3(); // skip 2 methods

        void GetItemPosition(IntPtr pidl, out POINT ppt);

        void _VtblGap1_4(); // skip 4 methods

        void SelectAndPositionItems(int cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] apidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] POINT[] apt, SVSIF dwFlags);

        // more undefined methods
    }

    [ComImport, Guid("1af3a467-214f-4298-908e-06b03e0b39f9"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IFolderView2
    {
        void _VtblGap1_26(); // skip 14 (IFolderView) + 12 methods

        IShellItem GetItem(int iItemIndex, [MarshalAs(UnmanagedType.LPStruct)] Guid riid);

        // more undefined methods
    }

    [ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IShellItem
    {
        [return: MarshalAs(UnmanagedType.IUnknown)]
        object BindToHandler(System.Runtime.InteropServices.ComTypes.IBindCtx pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid);

        IShellItem GetParent();

        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetDisplayName(SIGDN sigdnName);

        // more undefined methods
    }

    public struct POINT
    {
        public int x;
        public int y;
    }

    public enum SIGDN
    {
        SIGDN_NORMALDISPLAY,
        SIGDN_PARENTRELATIVEPARSING,
        SIGDN_DESKTOPABSOLUTEPARSING,
        SIGDN_PARENTRELATIVEEDITING,
        SIGDN_DESKTOPABSOLUTEEDITING,
        SIGDN_FILESYSPATH,
        SIGDN_URL,
        SIGDN_PARENTRELATIVEFORADDRESSBAR,
        SIGDN_PARENTRELATIVE,
        SIGDN_PARENTRELATIVEFORUI
    }

    [Flags]
    public enum SVSIF
    {
        SVSI_DESELECT = 0,
        SVSI_SELECT = 0x1,
        SVSI_EDIT = 0x3,
        SVSI_DESELECTOTHERS = 0x4,
        SVSI_ENSUREVISIBLE = 0x8,
        SVSI_FOCUSED = 0x10,
        SVSI_TRANSLATEPT = 0x20,
        SVSI_SELECTIONMARK = 0x40,
        SVSI_POSITIONITEM = 0x80,
        SVSI_CHECK = 0x100,
        SVSI_CHECK2 = 0x200,
        SVSI_KEYBOARDSELECT = 0x401,
        SVSI_NOTAKEFOCUS = 0x40000000
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.