C#可以通过windows API,将第三方程序嵌入到panel中,并且可以隐藏程序边框。
问题:
焦点在内部程序时,主窗口失去焦点;
通讯解决方案
使用 User32.dll SendMessage 发送窗口级的 WM_COPYDATA 消息;使用 DefWndProc 处理消息;
来实现两个独立C#程序之间的通讯。
主程序代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms; namespace CallMain
{
public partial class Form1 : Form
{
#region 外部DLL定义 [DllImport("User32.dll", EntryPoint = "SetParent")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", EntryPoint = "ShowWindow")]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); [DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint); [DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); const int WS_THICKFRAME = ;
const int WS_BORDER = ;
const int GWL_STYLE = -; [DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref COPYDATASTRUCT IParam); public const int WM_COPYDATA = 0x004A; public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
} // 发送 windows 消息
public void SendMsg(IntPtr hwnd, string str)
{
byte[] arr = Encoding.Default.GetBytes(str);
int len = arr.Length;
COPYDATASTRUCT cdata;
cdata.dwData = (IntPtr);
cdata.lpData = str;
cdata.cbData = len + ;
SendMessage(hwnd, WM_COPYDATA, this.Handle, ref cdata);
} public delegate void EventMsg(object sender, IntPtr wnd, string str);
public event EventMsg OnMsg; // 进程间消息通讯
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT cdata = new COPYDATASTRUCT();
Type mytype = cdata.GetType();
cdata = (COPYDATASTRUCT)m.GetLParam(mytype);
OnMsg(this, m.WParam, cdata.lpData);
break;
default:
base.DefWndProc(ref m);
break;
}
} #endregion public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
this.OnMsg += Form1_OnMsg; ;
} private void Form1_OnMsg(object sender, IntPtr wnd, string str)
{
// 接收消息处理
SendMsg(wnd, "收到了子窗口消息:" + str);
} private void button1_Click(object sender, EventArgs e)
{
Process proApp = new Process();
proApp.StartInfo.FileName = Application.StartupPath + "\\CallTest.exe";
proApp.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
proApp.Start();
proApp.WaitForInputIdle(); while (proApp.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep();
proApp.Refresh();
}
IntPtr wnd = proApp.MainWindowHandle; Int32 wndStyle = GetWindowLong(wnd, GWL_STYLE);
wndStyle &= ~WS_BORDER;
wndStyle &= ~WS_THICKFRAME;
SetWindowLong(wnd, GWL_STYLE, wndStyle); SetParent(wnd, panel1.Handle);
ShowWindow(wnd, (int)ProcessWindowStyle.Maximized); panel1.Tag = proApp; SendMsg(wnd, "hi");
} private void button2_Click(object sender, EventArgs e)
{
// 给子窗口发消息
Process proApp = (Process)panel1.Tag;
SendMsg(proApp.MainWindowHandle, "hello 子窗口");
}
}
}
子程序通讯代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms; namespace CallTest
{
public partial class Form1 : Form
{
#region 消息通讯 [DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref COPYDATASTRUCT IParam); const int WM_COPYDATA = 0x004A; public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
} private IntPtr MainWnd = IntPtr.Zero; public delegate void EventMsg(object sender, string str);
public event EventMsg OnMsg; //发送消息
private void SendMsg(string str)
{
if (MainWnd == IntPtr.Zero)
{
return;
} byte[] arr = Encoding.Default.GetBytes(str);
int len = arr.Length;
COPYDATASTRUCT cdata;
cdata.dwData = (IntPtr);
cdata.lpData = str;
cdata.cbData = len + ;
SendMessage(MainWnd, WM_COPYDATA, this.Handle, ref cdata);
} protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT cdata = new COPYDATASTRUCT();
Type mytype = cdata.GetType();
cdata = (COPYDATASTRUCT)m.GetLParam(mytype);
MainWnd = m.WParam; OnMsg(this, cdata.lpData);
break;
default:
base.DefWndProc(ref m);
break;
}
}
#endregion public Form1()
{
InitializeComponent();
} private int index = ;
private void button1_Click(object sender, EventArgs e)
{
// 发送消息
index++;
SendMsg("收到啦!" + index);
} private void Form1_Load(object sender, EventArgs e)
{
this.OnMsg += Form1_OnMsg;
} private void Form1_OnMsg(object sender, string str)
{
// 接收消息
if (str == "hi")
{
SendMsg("hi");
return;
} label1.Text = str;
label2.Text = MainWnd.ToString("x");
}
}
}