我有一个控制台应用程序,应该在MSPaint中绘制随机图片(鼠标向下->让光标随机绘制一些内容->鼠标向上。这就是我到目前为止(为了更好地理解我想要的内容,我在Main方法中添加了注释)实现):

[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, uint dx, uint dy, long cButtons, long dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x201;
private const int MOUSEEVENTF_LEFTUP = 0x202;
private const uint MK_LBUTTON = 0x0001;

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

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);

static IntPtr childWindow;

private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
    childWindow = handle;
    return false;
}

public static void Main(string[] args)
{
    OpenPaint(); // Method that opens MSPaint
    IntPtr hwndMain = FindWindow("mspaint", null);
    IntPtr hwndView = FindWindowEx(hwndMain, IntPtr.Zero, "MSPaintView", null);
    // Getting the child windows of MSPaintView because it seems that the class name of the child isn't constant
    EnumChildWindows(hwndView, new EnumWindowsProc(EnumWindow), IntPtr.Zero);
    Random random = new Random();
    Thread.Sleep(500);

    // Simulate a left click without releasing it
    SendMessage(childWindow, MOUSEEVENTF_LEFTDOWN, new IntPtr(MK_LBUTTON), CreateLParam(random.Next(10, 930), random.Next(150, 880)));
    for (int counter = 0; counter < 50; counter++)
    {
        // Change the cursor position to a random point in the paint area
        Cursor.Position = new Point(random.Next(10, 930), random.Next(150, 880));
        Thread.Sleep(100);
    }
    // Release the left click
    SendMessage(childWindow, MOUSEEVENTF_LEFTUP, new IntPtr(MK_LBUTTON), CreateLParam(random.Next(10, 930), random.Next(150, 880)));
}

我从here获得了用于点击模拟的代码。

该点击会被模拟,但不会显示任何内容。似乎该点击在MSPaint内部不起作用。光标变为MSPaint的“十字”,但是正如我提到的那样,单击似乎无效。
FindWindowhwndMain的值设置为0。将mspaint参数更改为MSPaintApp不会进行任何更改。 hwndMain的值保持为0。

如果有帮助,这是我的OpenPaint()方法:
private static void OpenPaint()
{
    Process.process = new Process();
    process.StartInfo.FileName = "mspaint.exe";
    process.StartInfo.WindowStyle = "ProcessWindowStyle.Maximized;
    process.Start();
}

我究竟做错了什么?

最佳答案

按照 promise ,我昨天自己进行了测试(说实话,我的光标刚刚移动了,但没有移动到窗口中,并且没有任何影响),正如我调试时所看到的那样,我看到var hwndMain = FindWindow("mspaint ", null);0值。我虽然这一定是个问题,所以我确实查看了另一个stackoverflow主题,您从那里得到了代码。我认识到解决方案使用的是他们在FindWindow()中负责的其他窗口名称-所以我确实尝试了。

var hwndMain = FindWindow("MSPaintApp", null);

更改方法调用后,它对我有用-但是-移动MsPaint之后,光标仍然位于原始的打开位置中-您可能需要考虑一下并询问窗口位置。
Win7/8/10可能会更改名称吗?

编辑:

在Windows 10上,paint的名称似乎已更改-因此我想您在获取正确的窗口句柄方面仍然存在问题-Hans Passant证明了这是错误的,他用处理程序很好地解释了问题(下面的链接)。解决此问题的一种方法是从流程本身获取处理程序,而不是从FindWindow()获取它

我建议您像这样更改OpenPaint():
 private IntPtr OpenPaint()
 {
    Process process = new Process();
    process.StartInfo.FileName = "mspaint.exe";
    process.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
    process.Start();
    // As suggested by Thread Owner Thread.Sleep so we get no probs with the handle not set yet
    //Thread.Sleep(500); - bad as suggested by @Hans Passant in his post below,
    // a much better approach would be WaitForInputIdle() as he describes it in his post.
    process.WaitForInputIdle();
    return process.MainWindowHandle;
 }

链接到Hans Passant decription来解释为什么Thread.Sleep()只是一个不好的主意。

依次致电:
IntPtr hwndMain = OpenPaint(); // Method that opens MSPaint

这样,无论微软如何在win10中调用它,您都应该可以正确地获得正确的windowhandle,并且代码也可以正常工作

09-20 07:44