项目需要一个升级程序,这时候需要一个添加一个中间引导程序,实现两个程序互动,一个程序可以调用另外一个程序,本来程序是wpf实现,所以就还想都用wpf实现,但是试了几天各种办法都调试不过,只能找到窗体的句柄,但是找不到控件的句柄。所以最终失败,最后发现原因可能是:wpf的界面是画出来的,不是win32窗体,没法用api操作。
主要实现方式:利用API函数去找到进程窗口的句柄,然后用API去控制这个窗口
一:第一个程序引导第二个程序后,实现控制第二个程序的隐藏和实现等
WindowsFormsApp1中Form1窗体如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 控制执行文件
{
public partial class Form1 : Form
{
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
Process process = new Process();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process.StartInfo.FileName = @"E:\test\控制执行文件\测试程序\bin\Debug\测试程序.exe";
// process.StartInfo.FileName = ConfigurationManager.AppSettings["sb1"];
process.Start();
}
private void button3_Click(object sender, EventArgs e)
{
DisPlayWindow(process.MainWindowHandle,1);
}
public int DisPlayWindow(IntPtr hwnd, int nCmdshow) {
return ShowWindow(hwnd, nCmdshow);
}
private void button4_Click(object sender, EventArgs e)
{
DisPlayWindow(process.MainWindowHandle, 2);
}
private void button2_Click(object sender, EventArgs e)
{
process.Kill();
}
}
}
出现的问题:如果被控制程序自己隐藏后,再从控制程序去显示被控制程序就会有问题,程序会黑屏
二:被控制程序来操作控制程序,主要实现方式
导入“User32.dll”中的FindWindow、FindWindowEx函数查找窗口,并获取窗口句柄。也可直接利用C#中的Process类来启动程序,并获取这个进程的主窗口的句柄,等等
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
//[DllImport("user32.dll")]
//public static extern bool SendMessage(int hWnd, int msg, Boolean wParam, int lParam);
/// <summary>
/// 第一个参数是窗体的类名、第二个参数是窗体的标题,二者必须要有一个。这里推荐vs自带的 spy++ 工具查看窗体参数
/// </summary>
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
///
/// 参数说明:
hwndParent
主窗体句柄、第一步调用 FindWindow 函数返回的值
hwndChildAfter
子窗体的句柄,可空
lpClassName
要寻找的控件的类名
lpWindowName
要寻找的控件的标题
然后我们调用此函数寻找窗体里的 “button1” 按钮。
///
[DllImport("User32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
const int WM_SHOWWINDOW = 0x18;
const int BM_CLICK = 0xF5;
IntPtr WINDOW_HANDLER = FindWindow(null, "FormLead");//发送消息窗口句柄this.Handle.ToInt32(
//IntPtr WINDOW_HANDLER = FindWindow(null, "layoutPnlUpdate");//发送消息窗口句柄this.Handle.ToInt32(
IntPtr childHwnd = FindWindowEx(WINDOW_HANDLER, 0, null, "button1"); //获得按钮的句柄,此按钮父控件必须是上面搜索的窗体
if (childHwnd != IntPtr.Zero)
{
SendMessage(childHwnd, BM_CLICK, 0, 0);
}
}
注意事项:FindWindowEx(WINDOW_HANDLER, 0, null, "button1"); //获得按钮的句柄,此按钮父控件必须是上面搜索的窗体,要不搜索不到
wMsg常量值:因为字数限制,请看另一篇