c# 与 c++ 界面同框终极技巧

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# 与 c++ 界面同框终极技巧相关的知识,希望对你有一定的参考价值。

1、界面编程,需要同框

当你写了一个c# 程序,而又不得不使用c++ 例如MFC或者qt等来做高效率的编解码等等工作的时候,问题来了,怎么通信,怎么解决两个界面的问题,这里介绍一个终极技巧,那就是c# 直接嵌入c++窗口。

这里下载源代码

2、制作c# 调用api dll

2.1 setparent 函数

设置父窗体函数,这是个API函数,可以设置窗体为另外一个窗体的父亲

 public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

2.2 c# 调用API dll 封装

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);
        /// <summary>
        /// 向C++程序 CshapMessage发送消息
        /// </summary>
        /// <param name="nMessgeId"></param>
        /// <param name="strSend"></param>
        /// <returns></returns>
        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;
        }
    }
}

3 建立一个c# 窗口程序

窗口程序叫做rcxsharp
c# 窗体
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程序

4 、MFC 窗口

制作一个MFC程序,名称叫做rcx
MFC 窗体

5、开始执行

点击打开按钮,MFC 窗体被放进了c# 窗体里面。
点击打开
点击按钮,MFC 窗口里的事件被如期执行
点击按钮
点击发送消息,MFC窗体中的cmd 被修改成了hello world
发送消息

6、MFC窗体接受copydata 消息代码

头文件定义消息

	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);
}

很好用吧,免去了很多麻烦的事情。
这里下载源代码

以上是关于c# 与 c++ 界面同框终极技巧的主要内容,如果未能解决你的问题,请参考以下文章

此 Canon SDK C++ 代码片段的等效 C# 代码是啥?

性能提升:使用c#调用c++(核心代码优化)

C# 开发技巧 c#窗体关于调试界面和运行界面不一样的原因之一

C#_技巧:.net下C++调用C#的dll

C# winform 界面美化技巧(扁平化设计) (转)

当王自如和刘翔同框,人工智能能识别吗?