更改窗口的粘滞便笺(StikyNot.exe)位置(多个实例)

时间:2015-09-13 00:49:06

标签: c# winapi

似乎StikyNot.exe下的所有笔记都是单个exes而不是多个。这也就是说它的位置坐标总是0,0,0,0。有没有办法移动它?我尝试使用Win32的MoveWindow功能但没有成功。

1 个答案:

答案 0 :(得分:1)

这是一个如何遍历所有Sticky Note窗口并移动每个窗口的示例。 (为简洁起见,已删除错误检查。另外,请务必阅读最后的注释,以获得有关此实现的一些注释。)

首先,我们必须定义RECT结构。

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public RECT(int l, int t, int r, int b)
    {
        Left = l;
        Top = t;
        Right = r;
        Bottom = b;
    }
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

然后是一些关键的p / Invokes。我们需要FindWindowExW来找到具有正确窗口类的窗口以获得便利贴。我们还需要GetWindowRect,所以我们可以计算窗口的大小,所以我们只移动它,而不是移动和调整大小。最后,我们需要SetWindowPos这是非常不言自明的。

[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr FindWindowExW(IntPtr hWndParent, IntPtr hWndAfter, 
                                          string lpszClass, string lpszWindow);

[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);

[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, 
                                       int Y, int cx, int cy, uint uFlags);

最后我们的算法。

IntPtr hWnd = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "Sticky_Notes_Note_Window", null);
if (hWnd == IntPtr.Zero)
{
    int error = Marshal.GetLastWin32Error();
    if (error > 0) throw new Win32Exception(error);
    else return;
}
IntPtr first = hWnd;
int currentX = 0;
while (hWnd != IntPtr.Zero)
{
    RECT r;
    bool result = GetWindowRect(hWnd, out r);
    if (!result)
    {
        int error = Marshal.GetLastWin32Error();
        if (error > 0) throw new Win32Exception(error);
        else return;
    }
    result = SetWindowPos(hWnd, 
                          IntPtr.Zero, 
                          currentX, 
                          0, 
                          r.Right - r.Left, 
                          r.Bottom - r.Top, 
                          0);
    if (!result)
    {
        int error = Marshal.GetLastWin32Error();
        if (error > 0) throw new Win32Exception(error);
        else return;
    }        

    currentX += r.Right - r.Left;
    hWnd = FindWindowExW(IntPtr.Zero, hWnd, "Sticky_Notes_Note_Window", null);
    if (hWnd == IntPtr.Zero)
    {
        int error = Marshal.GetLastWin32Error();
        if (error > 0) throw new Win32Exception(error);
        else return;
    }
    if (hWnd == first) hWnd = IntPtr.Zero;
}

它是如何工作的?首先,使用像Spy ++这样的工具,我找到了窗口类。在窗口的属性表中,我们可以看到窗口的类名是Sticky_Notes_Note_Window

Spy++ Property Sheet Screenshot

使用Spy ++中的信息,第一个窗口句柄是使用FindWindowExW获得的。缓存此值,以便在我们完成迭代所有窗口时确定。在循环内部,我们移动窗口,然后使用FindWindowEx再次找到具有相同类的下一个窗口,如果找不到,hWndIntPtr.Zero又称NULL 。我们还必须检查我们是否回到了迭代的开始。 (如果音符比屏幕宽,它们会向右溢出。将音符包装到另一行留作练习)

这个实现的问题是,如果第一个粘滞便笺被关闭,在我们遍历所有粘滞便笺之前,那么程序将永远不会终止。最好跟踪已经看到的所有窗口,如果再看到任何窗口,那么所有窗口都已被枚举。

另一种方法是使用EnumWindows并在回调电话GetClassName内查看它是否为Sticky_Notes_Note_Window,然后采取适当行动。上面的方法需要的工作量较少,所以我选择的方法就是这样。

参考文献:

编辑:根据@ DavidHeffernan的评论添加了错误检查。还添加了关于我如何找到Window类名称的说明。