windows 桌面图标操作 - 如何在启用带有图片旋转的主题时获取 SysListView32 的句柄
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4834788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Desktop Icon manipulation - how to get a handle to SysListView32 when themes with picture rotation are enabled
提问by user594650
I'm trying to move icons around the desktop, everything works well until a theme that has picture rotation is picked. With a basic Windows 7 theme, the SysListView32
is child of SHELLDLL_DefView
which is in turn child of Progman
.
我正在尝试在桌面上移动图标,一切正常,直到选择了具有图片旋转的主题。使用基本的 Windows 7 主题,SysListView32
is 的孩子SHELLDLL_DefView
又是Progman
.
But when a picture rotation desktop theme is picked, SysListView32
becomes child of SHELLDLL_DefView
which in turn becomes child of WorkerW
. There are more than 1. How should I go about finding the right HWND pointing to the right WorkerW
. Enumerate all desktop windows and check each one with a classname WorkerW?
But when a picture rotation desktop theme is picked, SysListView32
becomes child of SHELLDLL_DefView
which in turn becomes child of WorkerW
. 有不止 1 个。我应该如何找到指向右侧的正确 HWND WorkerW
。枚举所有桌面窗口并使用类名 WorkerW 检查每个窗口?
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
[DllImport("user32.DLL")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
In my main()
for example, I make the following calls:
在我main()
的示例中,我进行了以下调用:
IntPtr HWND = FindWindow("Progman",null);
HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD);
HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD);
回答by user594650
Big thanks to Hans for trying this on his machine, and for Sertac for clueing me that SysListView32 changes parents from "Progman" to the "WorkerW" classname. My solution was to first try to find the SysListView32 inside Progman's children:
非常感谢 Hans 在他的机器上尝试这个,也感谢 Sertac 告诉我 SysListView32 将父级从“Progman”更改为“WorkerW”类名。我的解决方案是首先尝试在 Progman 的孩子中找到 SysListView32:
hwndIcon = NativeMethods.FindWindow("Progman", null);
hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null);
hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView");
if hwndIcon returns IntPtr.Zero, I try enumerating all windows under the desktop, then find those whose classname is "WorkerW" (I do this in the delegate GetSysListViewContainer(...)) Amongst the latter, I find "The One And Only One," ie. the one that has a child. That is the one that contains SHELLDLL_DefView, which itself contains SysListView32, which itself contains the handle of each Icon on the desktop:
如果 hwndIcon 返回 IntPtr.Zero,我尝试枚举桌面下的所有窗口,然后找到那些类名为“WorkerW”的窗口(我在委托 GetSysListViewContainer(...) 中这样做)在后者中,我找到“The One And Only一个,”即。那个有孩子的。那就是包含SHELLDLL_DefView的那个,它本身包含SysListView32,它本身包含桌面上每个Icon的句柄:
hwndIcon = NativeMethods.FindWindow("Progman", null);
hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null);
hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView");
if (hwndIcon == IntPtr.Zero)
{
IntPtr hDesktop = NativeMethods.GetDesktopWindow();
IntPtr hwnd = IntPtr.Zero;
EnumWindowsProc ewp = new EnumWindowsProc(GetSysListViewContainer);
EnumWindows(ewp, 0);
hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null);
hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView");
}
With the following I get a desktop icon count:
通过以下我得到一个桌面图标计数:
int vItemCount = NativeMethods.SendMessage(hwndIcon, LVM_GETITEMCOUNT, 0, 0);
string vText;
int vProcessId = 0;
And with this I loop through all icons:
有了这个,我遍历所有图标:
NativeMethods.GetWindowThreadProcessId(hwndIcon, ref vProcessId);
IntPtr vProcess = NativeMethods.OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, vProcessId);
IntPtr foo = IntPtr.Zero;
IntPtr vPointer = NativeMethods.VirtualAllocEx(vProcess, IntPtr.Zero, sizeof(uint), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
for (int j = 0; j < vItemCount; j++)
{
byte[] vBuffer = new byte[256];
LVITEM[] vItem = new LVITEM[1];
vItem[0].mask = LVIF_TEXT;
vItem[0].iItem = j;
vItem[0].iSubItem = 0;
vItem[0].cchTextMax = vBuffer.Length;
vItem[0].pszText = (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(LVITEM)));
uint vNumberOfBytesRead = 0;
WriteProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0), Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead);
SendMessage(hwndIcon, LVM_GETITEMW, j, vPointer.ToInt32());
ReadProcessMemory(vProcess, (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(LVITEM))), Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer, 0), vBuffer.Length, out vNumberOfBytesRead);
// Get the name of the Icon
vText = Encoding.Unicode.GetString(vBuffer, 0, (int)vNumberOfBytesRead);
// Get Icon location
SendMessage(hwndIcon, LVM_GETITEMPOSITION, j, vPointer.ToInt32());
Point[] vPoint = new Point[1];
foo = Marshal.UnsafeAddrOfPinnedArrayElement(vPoint, 0);
ReadProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vPoint, 0), Marshal.SizeOf(typeof(Point)), out vNumberOfBytesRead);
//and ultimaely move icon.
SendMessage(hwndIcon, LVM_SETITEMPOSITION, j, lParam[0]);
So to recap, I needed to figure out why I couldn't get a handle for the listview container where all desktop icons are stored in Windows. The original code I had worked well when there was no background rotation, but failed to get the handle of ListSysView32 when there was.
总结一下,我需要弄清楚为什么我无法获得所有桌面图标都存储在 Windows 中的 listview 容器的句柄。当没有背景旋转时我运行良好的原始代码,但是当有时未能获得 ListSysView32 的句柄。
Is there any better way to do this from .Net? kj
有没有更好的方法可以从 .Net 做到这一点?千斤顶
回答by vSzemkel
This is the ugly and simple way to get a handler to a SysListView32
(C++ code)
这是将处理程序获取到SysListView32
(C++ 代码)的丑陋而简单的方法
HWND hWndLV = ::GetShellWindow();
hWndLV = ::GetNextWindow( ::GetNextWindow(hWndLV, GW_HWNDPREV), GW_HWNDPREV);
hWndLV = ::GetFirstChild(hWndLV);
hWndLV = ::GetNextWindow(hWndLV, GW_HWNDNEXT);
hWndLV = ::GetFirstChild(hWndLV);