2

デスクトップ上でアイコンを移動しようとしていますが、画像の回転があるテーマが選択されるまではすべてうまくいきます。基本的な Windows 7 テーマでは、 のSysListView32子が のSHELLDLL_DefView子になりProgmanます。

ただし、画像の回転デスクトップ テーマが選択されると、SysListView32が子になり、その子SHELLDLL_DefViewが の子になり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
}

main()の例では、次の呼び出しを行います。

IntPtr HWND = FindWindow("Progman",null);
HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD);
HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD);
4

2 に答える 2

3

これを自分のマシンで試してくれた Hans と、SysListView32 が親を "Progman" から "WorkerW" クラス名に変更することを教えてくれた Sertac に感謝します。私の解決策は、最初に Progman の子の中で SysListView32 を見つけようとすることでした:

       hwndIcon = NativeMethods.FindWindow("Progman", null);
       hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null);
       hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView");

hwndIcon が IntPtr.Zero を返す場合、デスクトップの下にあるすべてのウィンドウを列挙してみて、クラス名が「WorkerW」のウィンドウを見つけます (デリゲート GetSysListViewContainer(...) でこれを行います)。一つ」、つまり。子供がいる方。これは、デスクトップ上の各アイコンのハンドルを含む SysListView32 を含む SHELLDLL_DefView を含むものです。

       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");
        }

次のようにして、デスクトップ アイコンの数を取得します。

       int vItemCount = NativeMethods.SendMessage(hwndIcon, LVM_GETITEMCOUNT, 0, 0);
       string vText;
       int vProcessId = 0;

これで、すべてのアイコンをループします。

        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]);

要約すると、すべてのデスクトップ アイコンが Windows に格納されているリストビュー コンテナーのハンドルを取得できなかった理由を突き止める必要がありました。私が持っていた元のコードは、バックグラウンドの回転がない場合はうまく機能しましたが、ある場合は ListSysView32 のハンドルを取得できませんでした。

.Net からこれを行うより良い方法はありますか? kj

于 2011-01-29T20:21:30.830 に答える
0

SysListView32これは、 (C++ コード)へのハンドラーを取得するための見苦しく単純な方法です。

HWND hWndLV = ::GetShellWindow();
hWndLV = ::GetNextWindow( ::GetNextWindow(hWndLV, GW_HWNDPREV), GW_HWNDPREV);
hWndLV = ::GetFirstChild(hWndLV);
hWndLV = ::GetNextWindow(hWndLV, GW_HWNDNEXT);
hWndLV = ::GetFirstChild(hWndLV);
于 2013-01-30T09:21:51.270 に答える