是否有任何 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:
图像详细信息:应用程序高度为 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;
}
}
这是一个使用官方 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
}
}