Winform 程序嵌入WPF程序 并发送消息
废话不多说,先看解决方案目录

WindowsFormsDemo是主程序,WpfApp是嵌入的WPF程序,先看WPF程序,程序默认启动的页面是MainWindow.xaml,这里注释掉App.xaml里的StartupUri="MainWindow.xaml",后台设置启动的Uri,将原来的空的App类改成一些内容(也可以不改)
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
public App()
{
Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
} void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
// 这里通常需要给用户一些较为友好的提示,并且后续可能的操作
MessageBox.Show(e.Exception.Message, "意外的操作", MessageBoxButton.OK, MessageBoxImage.Information); e.Handled = true;//我们很抱歉,当前应用程序遇到一些问题,该操作已经终止,请进行重试,如果问题继续存在,请联系管理员.
}
}
添加Program启动类并加入主方法Main,尽管修改了但是启动程序仍然会报错,需要右键设置工程属性设置启动对象

下面看看启动类里的东西
class Program
{
[STAThread]
static void Main(string[] args)
{
// 校验启动的参数,未设置参数为非法启动
if (null == args || args.Length <= )
{
MessageBox.Show("非法启动!");
return;
}
// 获取参数,在WindowsFormsDemo里启动的时候设置,参数的规则自己设置
string activeParameter = args[];
string[] parameters = activeParameter.Split(','); try
{
App app = new App();
string activeName = parameters[];
if (activeName == "UploadFile")
{
MainWindow mainWindow = new MainWindow();
// 获取主界面的句柄(最后一个参数),向主窗体发送消息需要根据主窗体的句柄来发送
// 在启动这个WpfApp 进程的时候设置最后一个参数为主窗体句柄
OperationContainer.ContainerPlayPtr = new IntPtr(Convert.ToInt32(parameters[parameters.Length - ]));
app.MainWindow = mainWindow;
app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
}
// 参数就是拼接的字符串,看WindowsFormsDemo主窗体的拼接方式
GetParameters(parameters[]);
app.Run();
App.Main();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
} /// <summary>
/// 分割参数(参数规则看WindowsFormsDemo启动时设置的参数字符串)
/// </summary>
/// <param name="param"></param>
static void GetParameters(string param)
{
string[] strs = param.Split('&'); ;
Dictionary<string, string> dic = new Dictionary<string, string>();
foreach (var item in strs)
{
string[] key = item.Split('=');
dic.Add(key[], key[]);
} // 静态来存放参数值
OperationContainer.ServerIP = dic["ServerIP"];
OperationContainer.Type = dic["Type"];
OperationContainer.UserID = dic["UserID"];
OperationContainer.CaseID = dic["CaseID"];
}
这个地方要注意的是,我开始设置参数值的时候是给MainWindow.xaml.cs里的MainWindow设置属性的方式传的,在启动App并对MainWindow对象实例化,取得参数赋给MainWindow的属性,但是程序启动之后过了一会儿才会赋值过去,不知道是不是窗体渲染的次序问题
操作容器缓存类OperationContainer
/// <summary>
/// 常见操作缓存类
/// </summary>
public class OperationContainer
{
/// <summary>
/// 主容器窗口句柄
/// </summary>
public static IntPtr ContainerPlayPtr = IntPtr.Zero; #region 长连接属性
public static string ServerIP = ""; public static string Type = ""; public static string UserID = ""; public static string UserName = "admin"; public static string CaseID = "";
#endregion
}
MainWindow.xaml里的内容,一个按钮和按钮的点击事件,点击的时候向主窗体发送消息
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid Background="#FFA1E5DB">
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="btn_Upload" />
</Grid>
</Window>
MainWindow.xaml里的后台代码,消息发送
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// 当前进程句柄
/// </summary>
//public IntPtr CurWindows { get; set; } /// <summary>
/// 主进程句柄
/// </summary>
public IntPtr ContainerPlayPtr { get; set; } public int UploadType { get; set; } public string CaseID { get; set; } #region 进程消息处理 [DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); /// <summary>
/// 向主窗体发送消息
/// </summary>
/// <param name="success">标识是否操作成功,可根据自己使用情况来定</param>
private void Send(int success)
{
// 需要根据主窗体的句柄来发送,OperationContainer.ContainerPlayPtr在App程序初始化的时候已经取得的主窗体的句柄
SendMessage(OperationContainer.ContainerPlayPtr, Message.WM_MSG, success, );
} #endregion public MainWindow()
{
InitializeComponent();
} private void Window_Loaded(object sender, RoutedEventArgs e)
{
//MsgForm form = new MsgForm();
//CurWindows = form.Handle;
//ContainerPlayPtr = OperationContainer.ContainerPlayPtr;
//MessageBox.Show("容器窗体句柄:" + ContainerPlayPtr.ToInt32());
// 取得参数
UploadType = Convert.ToInt32(OperationContainer.Type);
CaseID = OperationContainer.CaseID;
} private void btn_Upload(object sender, RoutedEventArgs e)
{
MessageBox.Show(CaseID);
// 向主窗体发送消息
Send();
}
}
其中的消息枚举
/// <summary>
/// 消息枚举
/// </summary>
public class Message
{
public const int USER = 0x0400;
public const int WM_MSG = USER + ;
}
至于Controls里的内容暂时还没用到
有了上面的内容,这个时候启动WpfApp应该会提示非法启动,给启动参数赋初始值 args = new string[] { "UploadFile,ServerIP=127.0.0.1&Type=2&UserID=xx&CaseID=604dffdd-0f8f-430d-8ca4-1d9714ba7609,11202" };即可成功启动
下面看看主窗体里的内容,先看下容器类AppContainer
public class AppContainer
{
#region 注册API函数
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
private static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
internal static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
private static extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetParent(IntPtr hwnd);
[DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); private const int SWP_NOOWNERZORDER = 0x200;
private const int SWP_NOREDRAW = 0x8;
private const int SWP_NOZORDER = 0x4;
private const int SWP_SHOWWINDOW = 0x0040;
private const int WS_EX_MDICHILD = 0x40;
private const int SWP_FRAMECHANGED = 0x20;
private const int SWP_NOACTIVATE = 0x10;
private const int SWP_ASYNCWINDOWPOS = 0x4000;
private const int SWP_NOMOVE = 0x2;
private const int SWP_NOSIZE = 0x1;
private const int GWL_STYLE = (-);
private const int WS_VISIBLE = 0x10000000;
private const int WM_CLOSE = 0x10;
private const int WS_CHILD = 0x40000000; private const int SW_HIDE = ; //{隐藏, 并且任务栏也没有最小化图标}
private const int SW_SHOWNORMAL = ; //{用最近的大小和位置显示, 激活}
private const int SW_NORMAL = ; //{同 SW_SHOWNORMAL}
private const int SW_SHOWMINIMIZED = ; //{最小化, 激活}
private const int SW_SHOWMAXIMIZED = ; //{最大化, 激活}
private const int SW_MAXIMIZE = ; //{同 SW_SHOWMAXIMIZED}
private const int SW_SHOWNOACTIVATE = ; //{用最近的大小和位置显示, 不激活}
private const int SW_SHOW = ; //{同 SW_SHOWNORMAL}
private const int SW_MINIMIZE = ; //{最小化, 不激活}
private const int SW_SHOWMINNOACTIVE = ; //{同 SW_MINIMIZE}
private const int SW_SHOWNA = ; //{同 SW_SHOWNOACTIVATE}
private const int SW_RESTORE = ; //{同 SW_SHOWNORMAL}
private const int SW_SHOWDEFAULT = ; //{同 SW_SHOWNORMAL}
private const int SW_MAX = ; //{同 SW_SHOWNORMAL}
private const int HWND_TOP = 0x0;
private const int WM_COMMAND = 0x0112;
private const int WM_QT_PAINT = 0xC2DC;
private const int WM_PAINT = 0x0001;
private const int WM_SIZE = 0x0001; #endregion [SecuritySafeCritical]
internal static void MoveWindow(Process app, Control control)
{
if (app != null)
{
MoveWindow(app.MainWindowHandle, , , control.Width, control.Height, true);
}
} [SecuritySafeCritical]
internal static void SetWindowLong(HandleRef handleRef)
{
SetWindowLong(handleRef, GWL_STYLE, WS_VISIBLE);
} [SecuritySafeCritical]
internal static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
{
if (IntPtr.Size == )
{
return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
} return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
}
这段代码是一同事写的,拿来直接用就可以了,其中上半段是windows的函数,下面的三个方法是拖动主窗体改变主窗体大小时,设置嵌套的窗体内容
看下主窗体里的代码
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
} Process _process;
bool isFirst = false; private void MainForm_Load(object sender, EventArgs e)
{
Process[] processs = Process.GetProcessesByName("WpfApp.exe");
foreach (var item in processs)
{
item.Kill();
} //string strPath = this.GetType().Assembly.Location;
//string baseDir = Path.Combine(strPath.Substring(0, strPath.LastIndexOf("\\")), "");
string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WpfApp.exe"); if (File.Exists(fileName))
{
// 设置消息参数
string param = "ServerIP=127.0.0.1&Type=2&UserID=xx&CaseID=604dffdd-0f8f-430d-8ca4-1d9714ba7609";
ProcessStartInfo startInfo = new ProcessStartInfo(fileName); startInfo.Arguments = "UploadFile," + param + "," + this.Handle;
startInfo.UseShellExecute = true;
startInfo.CreateNoWindow = true;
startInfo.WorkingDirectory = "";
startInfo.WindowStyle = ProcessWindowStyle.Hidden; _process = Process.Start(startInfo);
_process.EnableRaisingEvents = true;
WaitForInputIdle();
EmbedProcess(_process);
}
else
MessageBox.Show("未找到需要启动的exe文件");
isFirst = true;
} private void WaitForInputIdle()
{
while (_process.MainWindowHandle == IntPtr.Zero)
{
_process.Refresh();
_process.MainWindowHandle.ToInt32();
}
} /// <summary>
/// 嵌入程序
/// </summary>
private void EmbedProcess(Process process)
{
if (process != null && !(process.MainWindowHandle == IntPtr.Zero))
{
try
{
// Put it into this form
AppContainer.SetParent(process.MainWindowHandle, panel1.Handle);
// Remove border and whatnot
AppContainer.SetWindowLong(new HandleRef(this, process.MainWindowHandle));
// Move the window to overlay it on this window
AppContainer.MoveWindow(_process, panel1);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
} private void MainForm_Resize(object sender, EventArgs e)
{
// 设置窗体填充主窗体
if (isFirst)
AppContainer.MoveWindow(_process, this);
} public string Prams { get; set; } [DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int msg, uint wParam, uint lParam); // 响应和处理自定义消息
protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch (m.Msg)
{
case Message.WM_MSG://处理接收到的消息
int success = m.WParam.ToInt32();
if (success == )
MessageBox.Show("成功");
break;
default:
base.DefWndProc(ref m);
break;
}
} public class Message
{
public const int USER = 0x0400;
public const int WM_MSG = USER + ;
}
}
以上就是所有的代码,这个主要是最近开发ActiveX控件,考虑Winform 实现特效比较麻烦,所以用嵌入WPF的方式实现
demo 代码 http://download.csdn.net/detail/huayun1010/9609988
Winform 程序嵌入WPF程序 并发送消息的更多相关文章
- WPF向系统发送消息 并传递结构体
场景 :需要开发一个通讯组件 流程为:界面-开启接收服务-通过发送组件发送信息到 其他客户端和服务端 接受服务接收其他客户端发送的消息 需要传递给对应组件或者界面 因此会出现类库重复引用问题.因为采用 ...
- 在WinForm里嵌入WPF模拟公交运行状态
公司有个公交项目,模拟公交运行的时候使用的纯WinForm技术,5秒钟刷新一次,不仅看起来感觉很丑,而且性能上很有问题,听说一段时间后就会因为内存问题崩溃(估计是没释放非托管资源吧,不断重绘,非托管资 ...
- 在WinForm应用程序中嵌入WPF控件
我们知道,在WPF界面上添加WinForm的控件需要使用WindowsFormHost类.而在WinForm界面上添加WPF控件该如何做呢?有没有类似的类呢?明显是有的,ElementHost就是为了 ...
- WPF程序将DLL嵌入到EXE的两种方法
WPF程序将DLL嵌入到EXE的两种方法 这一篇可以看作是<Visual Studio 版本转换工具WPF版开源了>的续,关于<Visual Studio 版本转换工具WPF版开源了 ...
- C#将exe运行程序嵌入到自己的winform窗体中
以下例子是将Word打开,然后将它嵌入到winform窗体中,效果如下图:C将exe运行程序嵌入到自己的winform窗体中 - kingmax_res - iSport注意:该方法只适用于com的e ...
- winform/wpf 程序部署
(1):一些发布方式 ClickOnce是什么玩意儿,这个问题嘛,在21世纪的互联网严重发达的时代,估计也没有必要大费奏章去介绍了,弄不好的话,还有抄袭之嫌.因此,有关ClickOnce的介绍,各位朋 ...
- 关于 使用python向qq好友发送消息(对爬虫的作用----当程序执行完毕或者报错无限给自己qq发送消息,直到关闭)
以前看到网上一些小程序,在处理完事物后会自动发送qq消息,但是一直搞不懂是说明原理.也在网上找过一些python登陆qq发送消息的文字,但是都太复杂了.今天偶然看到一篇文章,是用python调用win ...
- exe程序嵌入Winform窗体
1.新建winform程序,添加一个Panel控件和一个button控件,winform窗体命名为:Mainform: 2.新建一个类文件,方便引用,命名为:exetowinform: 3.Mainf ...
- C#实现在应用程序间发送消息的方法示例
本文实例讲述了C#实现在应用程序间发送消息的方法.分享给大家供大家参考,具体如下: 首先建立两个C#应用程序项目. 第一个项目包含一个Windows Form(Form1),在Form1上有一个But ...
随机推荐
- 第7章 桥接模式(Bridge Pattern)
原文 第7章 桥接模式(Bridge Pattern) 定义: 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能 ...
- oracle_五千万数据插入测试
--创建表 tab_a -- create table tab_a (id int primary key not null,pid int); --创建序列 /** create sequence ...
- GDI+学问------ 绘制可变角度的色彩渐变效果
GDI+ 它是GDI(Windows 图形设备接口提供的早期版本)也许是版本号,它是Microsoft Windows XP作系统即兴许版本号的图形显示技术. 它已经集成到了.Net开发环境中.所以无 ...
- zoj 3822 Domination(dp)
题目链接:zoj 3822 Domination 题目大意:给定一个N∗M的棋盘,每次任选一个位置放置一枚棋子,直到每行每列上都至少有一枚棋子,问放置棋子个数的期望. 解题思路:大白书上概率那一张有一 ...
- asp.net mvc3 的数据验证(一)
原文:asp.net mvc3 的数据验证(一) 对于web开发人员来说,对用户输入的信息进行验证是一个重要但是繁琐的工作,而且很多开发者都会忽略.asp.net mvc3框架使用的是叫做“ ...
- Web API-属性路由
路由(Routing)就是Web API如何将一个URI匹配到一个action的过程.Web API 2 支持一个新的路由方式-属性路由(attribute routing).顾名思义,属性路由使用标 ...
- 关于jquery mobile 页面闪烁与抖动问题
1.闪烁:在用a链接跳转到另一个页面的时候,页面总会抖动几下,其实就是页面切换时的transition特效,jqm貌似默认了这项. 解决方案:在a链接添加transition:none; 属性就可以啦 ...
- Java多线程详解
Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...
- 使用.NET REACTOR制作软件许可证
原文:使用.NET REACTOR制作软件许可证 软件下载地址:http://www.eziriz.com/downloads.htm 做一个简单的许可证系统,下面是具体步骤: 1, OPEN AS ...
- 超酷的jQuery百叶窗图片滑块实现教程
原文:超酷的jQuery百叶窗图片滑块实现教程 今天我们要来分享一款基于jQuery的百叶窗焦点图插件,也可以说是图片滑块插件.这种jQuery焦点图插件的应用非常广泛,在早些年前,我们需要用flas ...