当你写了一个c# 程序,而又不得不使用c++ 例如MFC或者qt等来做高效率的编解码等等工作的时候,问题来了,怎么通信,怎么解决两个界面的问题,这里介绍一个终极技巧,那就是c# 直接嵌入c++窗口。
这里下载源代码
设置父窗体函数,这是个API函数,可以设置窗体为另外一个窗体的父亲
public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
namespace cnc
{
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
public class cncfunc
{
Process p = null;
private const int WM_COPYDATA = 0x004A;
const int SWP_NOMOVE = 0x02, SWP_NOSIZE = 0x01, SWP_NOZORDER = 0x04, SWP_FRAMECHANGED = 0x20;
[DllImport("user32.dll", EntryPoint = "SetParent")]
public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern int GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndlnsertAfter, int X, int Y, int cx, int cy, uint Flags);
[DllImport("user32.dll ", EntryPoint = "ShowWindow")]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("User32.dll")]
public static extern int SendMessage(int hwnd, int msg, int wParam, ref COPYDATASTRUCT IParam);
[DllImport("User32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
///
/// 向C++程序 CshapMessage发送消息
///
///
///
///
public int SndMessage(int nMessgeId, String strSend)
{
if (p == null)
return -1;
// WINDOW_HANDLE = p.MainWindowHandle;
IntPtr hWnd = p.MainWindowHandle;
int handle = hWnd.ToInt32();
if (handle != 0)
{
COPYDATASTRUCT cdata;
cdata.dwData = (IntPtr)nMessgeId;//这里可以传入一些自定义的数据,但只能是4字节整数
cdata.lpData = strSend;//消息字符串
cdata.cData = System.Text.Encoding.Default.GetBytes(strSend).Length + 1;//注意,这里的长度是按字节来算的
return SendMessage(handle, WM_COPYDATA, 0, ref cdata);
}
else
{
return -1;
}
return 0;
}
public int connect(string name,int time,IntPtr parent)
{
if (p != null)
return -1;
p = new Process();
p.StartInfo.FileName = name; //"MFCApplication1.exe";
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;//加上这句效果更好
p.Start();
System.Threading.Thread.Sleep(time);
SetParent(p.MainWindowHandle, parent/*pictureBox1.Handle*/);
//panel1.Handle为要显示外部程序的容器
ShowWindow(p.MainWindowHandle, 3);
return 0;
}
}
}
窗口程序叫做rcxsharp
c# 窗体中包含两个按钮,一个打开,一个发送消息,打开负责打开MFC程序,发送消息负责向c++ MFC发送信息,以便于控制
public partial class Form1 : Form
{
cncfunc m_cncfunc = new cncfunc();
//IntPtr hwnd;
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
m_cncfunc.connect("rcx.exe", 200, pictureBox1.Handle);
}
private void button1_Click(object sender, EventArgs e)
{
m_cncfunc.SndMessage(100, "hello world");
}
}
代码很简单:
打开按钮:cncfunc 对象负责打开本目录下的rcx.exe程序,并把这个程序放到pictureBox1 里面。
发送消息按钮,发送一个hello world 消息给打开的rcx.exe程序
点击打开按钮,MFC 窗体被放进了c# 窗体里面。
点击按钮,MFC 窗口里的事件被如期执行
点击发送消息,MFC窗体中的cmd 被修改成了hello world
头文件定义消息
afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);
OnCopyData 消息接收代码如下:
BOOL CMFCApplication1Dlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
USES_CONVERSION;
switch (pCopyDataStruct->dwData)
{
case 98:
break;
case 99:
{
char * wname = (char*)pCopyDataStruct->lpData;
m_windowname = A2W(wname);
break;
}
case 100:
{
char * d = (char*)pCopyDataStruct->lpData;
CWnd *wnd = GetDlgItem(IDC_S_SHOW);
wnd->SetWindowTextW(A2W(d));
break;
}
default:
{
break;
}
}
return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
很好用吧,免去了很多麻烦的事情。
这里下载源代码