我有一个控制台应用程序,应该在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的“十字”,但是正如我提到的那样,单击似乎无效。
FindWindow
将hwndMain
的值设置为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,并且代码也可以正常工作