具体描述如下:
一个项目生成一个EXE,里面包含两个窗体A、B。启动EXE的时候(比如不带参数运行这个EXE),显示窗体A。
窗体A上放个按钮,点击的时候带参数启动这个EXE的另一进程,进程启动的时候检测到参数,显示窗体B。
然后两个进程用某种途径实现通信。
现在问:B窗体能否得到A这个窗体对象?(当然是实现进程通信后)得到后,直接可以取得A的属性等。反过来也一样,A也要可以取得窗体B这个对象。
搜索了半天,好像可以序列化,但看得一头雾水,所以在此请教。COM类的可以CoMarshalInterface等实现,在.NET下就不知道怎么办了。
29 个解决方案
#1
对象也是在内存里,你把那块内存读出来,转换为对象就行了,传递内存地址(内存映射)
#2
不可以传递窗体,因为窗体不可以系列化,本身也不支持代理。
#3
只要是内存中,什么都可以传递,
#4
+1
#5
比如读出自身内存起始地址和长度,传递给另外一个进程?这个难度比较大吧
如果无法实现,在需要做较多通信的时候,实在是有些麻烦啊。
感谢版主们回复。
#6
内存是可以传递,但对一个进程有意义的内存数据,在另外一个进程就可能是垃圾。
#7
这个板块就是好,提问后那么多人帮忙解答,很欣慰……
在COM框架下,比如用VB6,列集IDispatch是可以成功的,在.NET很茫然。
在COM框架下,比如用VB6,列集IDispatch是可以成功的,在.NET很茫然。
#8
可以用Remoting做。其中MarshalByRefObject表示可远程代理。
1、新建一个WinForm项目作为服务方。
2、添加一个MyWindow.cs文件,并贴入内容(关键是接口不要有命名空间)。
3、打开WinForm项目的代码,在Form1.cs的构造函数中登记Remote Server。
4、再新建一个Winform项目作为客户。
5、拉一个PropertyGrid到窗体上。
6、打开该项目的Form1.cs
7、改成类似以下代码(关键是接口不要有任何命名空间,与Server保持一致)
8、记得要先运行server,再运行客户。
1、新建一个WinForm项目作为服务方。
2、添加一个MyWindow.cs文件,并贴入内容(关键是接口不要有命名空间)。
3、打开WinForm项目的代码,在Form1.cs的构造函数中登记Remote Server。
// MyWindow.cs
using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
public interface IMyWindow
{
Point Location { get; set; }
Size Size { get; set; }
}
public class MyWindow : MarshalByRefObject, IMyWindow
{
public Point Location
{
get
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
return form == null ? Point.Empty : form.Location;
}
set
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
if (form != null) form.Location = value;
}
}
public Size Size
{
get
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
return form == null ? Size.Empty : form.Size;
}
set
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
if (form != null) form.Size = value;
}
}
}
public Form1()
{
InitializeComponent();
// 登记Remote Server
try
{
ChannelServices.RegisterChannel(new TcpChannel(54322), false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyWindow), "MyWindow", WellKnownObjectMode.SingleCall);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
4、再新建一个Winform项目作为客户。
5、拉一个PropertyGrid到窗体上。
6、打开该项目的Form1.cs
7、改成类似以下代码(关键是接口不要有任何命名空间,与Server保持一致)
8、记得要先运行server,再运行客户。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.propertyGrid1.SelectedObject = new MyController(); // -- 添加
}
}
}
// -- 添加
public interface IMyWindow
{
Point Location { get; set; }
Size Size { get; set; }
}
public class MyController
{
IMyWindow remoteObject;
public MyController()
{
try
{
remoteObject = Activator.GetObject(typeof(IMyWindow), "tcp://localhost:54322/MyWindow") as IMyWindow;
}
catch (Exception ex)
{
this.Error = "Failed remote activation:" + ex.Message;
}
}
public string Error { get; private set; }
public Point Location
{
get { return remoteObject == null ? Point.Empty : remoteObject.Location; }
set { if (remoteObject != null) remoteObject.Location = value; }
}
public Size Size
{
get { return remoteObject == null ? Size.Empty : remoteObject.Size; }
set { if (remoteObject != null) remoteObject.Size = value; }
}
}
// -- 结束添加
#9
表示段位低,还需要仔细研究代码,非常敬佩+感谢。我先研究下8楼代码
#10
#11
可以 用窗体句柄 和进程ID 可以互相通讯
#12
保护模式中,两个进程的同一个内存地址完全是两回事。
楼主还是多了解一下序列化吧。
另外序列化的对象应该是数据描述性的,而不是窗体这种东西。
楼主还是多了解一下序列化吧。
另外序列化的对象应该是数据描述性的,而不是窗体这种东西。
#13
1.系统API。如:SendMessage与FindWindow
2.remoting。
3.WCF;
4.webService
等等。具体看你的应用。
2.remoting。
3.WCF;
4.webService
等等。具体看你的应用。
#14
你了解过xml或者json吗?
#15
楼上虽然说的对象也是存于内存之中并没有错,但如果其他进程需要访问这就不太可能
即使你将那一块内存完全复制出也是不行的,正确的办法是通过进行通信编写特定机制
来实现A进程类与B进程进行交互,否则编写COM+使用MSAA也是可以的,前提是你必
必须清楚暴露出的IID与发送捕获的消息是什么一般取WM_GetObject
#16
我实际使用中就是需要“窗体”这个对象,现在倒不是麻烦不麻烦的事情。比如窗体的public void Show(IWin32Window owner);,我想指定A进程的A窗体为B进程B窗体的owner
#17
序列化传过去再反序列化就好了
#18
也可以传递对象,但是更建议通过json序列化反序列化的方式来传递信息,
简单,方便,跨一切
简单,方便,跨一切
#19
没有你想象的这种东西。
即使是2003年前就开始被淘汰的 remoting 技术,它也是“对象代理”机制。因此就有一堆复杂的通讯层,和一堆的编程限制你需要遵守。例如 remoting 根本不能直接支持远程对象事件通知,必须通过手动进行复杂的封装来模拟。
remoting 与另外两种技术,在上个世纪90年代是主要的三大进程通讯技术。然后到了互联网时代,这些全都烟消云散了。逐渐地,soap等等基于 xml 进行封装处理的轻量级通讯技术成为了主流。最近5、6年由于ajax技术兴起,json较多地取代 xml。
#20
如果你做点局域网内的程序,那么你可以使用 remoting。感受一下.net 框架中早期的 remoting 技术是个好事。其实 remoting 还是相当好用的,而且也非常强大的。但是绝对达不到你要求的那种程度。
从互联网爆发出来的各种应用需要互联互通,于是浅显的东西占了上风,而且这些东西显然就比沉重的 rpc 通讯框架更快更轻便。如果你要做自己的远程控制,那么你需要定义5、6个通讯信令(例如开启、关闭命令,某种业务事件通知),定义通讯实体模型(例如对象的“唯一标识id”、大小、相对位置)等属性。然后在两个进程中实现灵活的通讯网关。这个协议可以写成文本,然后发给各种各样的公司采用完全不同的技术平台去实现。但是使用 remoting,那么对技术上的限制就很“死”了。
如果你自己不会设计更好的远程操控技术框架,那么你当然还是可以首选 remoting。使用remoting其实可以省去考虑消息序列化、解析、对象自动跟踪等问题,是一个相当伟大的框架。它是简单而完善(但是不完备)的,不仅仅用于远程通讯,它往往也是系统级平台“横切注入”技术的一个标准研究对象。remoting 的问题就是与当今主流编程不协调,公司找到的使用 remoting 进行系统开发人员很容易是又不懂、又漫天要价的。但是你自己学习他很好。
从互联网爆发出来的各种应用需要互联互通,于是浅显的东西占了上风,而且这些东西显然就比沉重的 rpc 通讯框架更快更轻便。如果你要做自己的远程控制,那么你需要定义5、6个通讯信令(例如开启、关闭命令,某种业务事件通知),定义通讯实体模型(例如对象的“唯一标识id”、大小、相对位置)等属性。然后在两个进程中实现灵活的通讯网关。这个协议可以写成文本,然后发给各种各样的公司采用完全不同的技术平台去实现。但是使用 remoting,那么对技术上的限制就很“死”了。
如果你自己不会设计更好的远程操控技术框架,那么你当然还是可以首选 remoting。使用remoting其实可以省去考虑消息序列化、解析、对象自动跟踪等问题,是一个相当伟大的框架。它是简单而完善(但是不完备)的,不仅仅用于远程通讯,它往往也是系统级平台“横切注入”技术的一个标准研究对象。remoting 的问题就是与当今主流编程不协调,公司找到的使用 remoting 进行系统开发人员很容易是又不懂、又漫天要价的。但是你自己学习他很好。
#21
VB6中可以用ActiveX.Exe轻松实现
.Net中,用前几年的方法,可以对指定的窗口进行一下包装,用一个相对简单的方式提取出一个包含必要操作的类,设计为COM+组件(服务器应用程序,等同于进程外组件(作用相当于COM中以-embed为参数的exe )),进程中不直接操作Form类,而是操作COM+组件.
对于轻量级的,也可以通过普通的进程通讯方式完成同一窗口跨进程数据同步.我个人习惯使用CreateFileMapping+WM_USER
这几年这方面的需求好象越来越少,不太清楚是用什么方法解决此类需求
.Net中,用前几年的方法,可以对指定的窗口进行一下包装,用一个相对简单的方式提取出一个包含必要操作的类,设计为COM+组件(服务器应用程序,等同于进程外组件(作用相当于COM中以-embed为参数的exe )),进程中不直接操作Form类,而是操作COM+组件.
对于轻量级的,也可以通过普通的进程通讯方式完成同一窗口跨进程数据同步.我个人习惯使用CreateFileMapping+WM_USER
这几年这方面的需求好象越来越少,不太清楚是用什么方法解决此类需求
#22
至于楼主的需求,由于是同一个EXE,完全可以通过互斥锁禁止重复启动,然后把内部搞成多线程去解决性能问题.这类问题我也遇到过,一般是同一台主机上多身份登录共同请求一项资源时常遇到的需求,一般可以通过优化软件功能或客户业务逻辑去解决.如果是两个不同的Exe,可以尝试一下上面的方法.
#23
如果是要IWin32Window,那就简单的多了。就象贴创可贴一样,用不着进程通讯/RPC这些象试管婴儿的大动作。
class WindowWrapper : IWin32Window
{
public IntPtr Handle {get; set;}
}
// 调用方法:
IntPtr intptr = FindWindow等等;
Show(new WindowWrapper (){Handle = intptr});
#25
只要这个程序是你自己写的就好办,A、B窗体不断地将自己的属性等B窗体要求的东西作为消息作为应答发给另一个窗体就可以了。也可以通过文件进行。把自己找到改为提醒对方给出就可以了。
#26
你能传字符串,就能传对象。比如用xml或者JSON格式的字符串封装一下,然后再还原就是了。
#27
感谢各位的回复和指点,我暂时不结贴,我仔细研究下各位的回复。
#28
特意上来回你 用json或者xml序列化 和反序列化 ,用文件 或者 memcached来管理序列化内容,还有要建立确定的命名机制
#29
#1
对象也是在内存里,你把那块内存读出来,转换为对象就行了,传递内存地址(内存映射)
#2
不可以传递窗体,因为窗体不可以系列化,本身也不支持代理。
#3
只要是内存中,什么都可以传递,
#4
+1
#5
比如读出自身内存起始地址和长度,传递给另外一个进程?这个难度比较大吧
如果无法实现,在需要做较多通信的时候,实在是有些麻烦啊。
感谢版主们回复。
#6
内存是可以传递,但对一个进程有意义的内存数据,在另外一个进程就可能是垃圾。
#7
这个板块就是好,提问后那么多人帮忙解答,很欣慰……
在COM框架下,比如用VB6,列集IDispatch是可以成功的,在.NET很茫然。
在COM框架下,比如用VB6,列集IDispatch是可以成功的,在.NET很茫然。
#8
可以用Remoting做。其中MarshalByRefObject表示可远程代理。
1、新建一个WinForm项目作为服务方。
2、添加一个MyWindow.cs文件,并贴入内容(关键是接口不要有命名空间)。
3、打开WinForm项目的代码,在Form1.cs的构造函数中登记Remote Server。
4、再新建一个Winform项目作为客户。
5、拉一个PropertyGrid到窗体上。
6、打开该项目的Form1.cs
7、改成类似以下代码(关键是接口不要有任何命名空间,与Server保持一致)
8、记得要先运行server,再运行客户。
1、新建一个WinForm项目作为服务方。
2、添加一个MyWindow.cs文件,并贴入内容(关键是接口不要有命名空间)。
3、打开WinForm项目的代码,在Form1.cs的构造函数中登记Remote Server。
// MyWindow.cs
using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
public interface IMyWindow
{
Point Location { get; set; }
Size Size { get; set; }
}
public class MyWindow : MarshalByRefObject, IMyWindow
{
public Point Location
{
get
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
return form == null ? Point.Empty : form.Location;
}
set
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
if (form != null) form.Location = value;
}
}
public Size Size
{
get
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
return form == null ? Size.Empty : form.Size;
}
set
{
Form form = Application.OpenForms.OfType<Form>().FirstOrDefault();
if (form != null) form.Size = value;
}
}
}
public Form1()
{
InitializeComponent();
// 登记Remote Server
try
{
ChannelServices.RegisterChannel(new TcpChannel(54322), false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyWindow), "MyWindow", WellKnownObjectMode.SingleCall);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
4、再新建一个Winform项目作为客户。
5、拉一个PropertyGrid到窗体上。
6、打开该项目的Form1.cs
7、改成类似以下代码(关键是接口不要有任何命名空间,与Server保持一致)
8、记得要先运行server,再运行客户。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.propertyGrid1.SelectedObject = new MyController(); // -- 添加
}
}
}
// -- 添加
public interface IMyWindow
{
Point Location { get; set; }
Size Size { get; set; }
}
public class MyController
{
IMyWindow remoteObject;
public MyController()
{
try
{
remoteObject = Activator.GetObject(typeof(IMyWindow), "tcp://localhost:54322/MyWindow") as IMyWindow;
}
catch (Exception ex)
{
this.Error = "Failed remote activation:" + ex.Message;
}
}
public string Error { get; private set; }
public Point Location
{
get { return remoteObject == null ? Point.Empty : remoteObject.Location; }
set { if (remoteObject != null) remoteObject.Location = value; }
}
public Size Size
{
get { return remoteObject == null ? Size.Empty : remoteObject.Size; }
set { if (remoteObject != null) remoteObject.Size = value; }
}
}
// -- 结束添加
#9
表示段位低,还需要仔细研究代码,非常敬佩+感谢。我先研究下8楼代码
#10
#11
可以 用窗体句柄 和进程ID 可以互相通讯
#12
保护模式中,两个进程的同一个内存地址完全是两回事。
楼主还是多了解一下序列化吧。
另外序列化的对象应该是数据描述性的,而不是窗体这种东西。
楼主还是多了解一下序列化吧。
另外序列化的对象应该是数据描述性的,而不是窗体这种东西。
#13
1.系统API。如:SendMessage与FindWindow
2.remoting。
3.WCF;
4.webService
等等。具体看你的应用。
2.remoting。
3.WCF;
4.webService
等等。具体看你的应用。
#14
你了解过xml或者json吗?
#15
楼上虽然说的对象也是存于内存之中并没有错,但如果其他进程需要访问这就不太可能
即使你将那一块内存完全复制出也是不行的,正确的办法是通过进行通信编写特定机制
来实现A进程类与B进程进行交互,否则编写COM+使用MSAA也是可以的,前提是你必
必须清楚暴露出的IID与发送捕获的消息是什么一般取WM_GetObject
#16
我实际使用中就是需要“窗体”这个对象,现在倒不是麻烦不麻烦的事情。比如窗体的public void Show(IWin32Window owner);,我想指定A进程的A窗体为B进程B窗体的owner
#17
序列化传过去再反序列化就好了
#18
也可以传递对象,但是更建议通过json序列化反序列化的方式来传递信息,
简单,方便,跨一切
简单,方便,跨一切
#19
没有你想象的这种东西。
即使是2003年前就开始被淘汰的 remoting 技术,它也是“对象代理”机制。因此就有一堆复杂的通讯层,和一堆的编程限制你需要遵守。例如 remoting 根本不能直接支持远程对象事件通知,必须通过手动进行复杂的封装来模拟。
remoting 与另外两种技术,在上个世纪90年代是主要的三大进程通讯技术。然后到了互联网时代,这些全都烟消云散了。逐渐地,soap等等基于 xml 进行封装处理的轻量级通讯技术成为了主流。最近5、6年由于ajax技术兴起,json较多地取代 xml。
#20
如果你做点局域网内的程序,那么你可以使用 remoting。感受一下.net 框架中早期的 remoting 技术是个好事。其实 remoting 还是相当好用的,而且也非常强大的。但是绝对达不到你要求的那种程度。
从互联网爆发出来的各种应用需要互联互通,于是浅显的东西占了上风,而且这些东西显然就比沉重的 rpc 通讯框架更快更轻便。如果你要做自己的远程控制,那么你需要定义5、6个通讯信令(例如开启、关闭命令,某种业务事件通知),定义通讯实体模型(例如对象的“唯一标识id”、大小、相对位置)等属性。然后在两个进程中实现灵活的通讯网关。这个协议可以写成文本,然后发给各种各样的公司采用完全不同的技术平台去实现。但是使用 remoting,那么对技术上的限制就很“死”了。
如果你自己不会设计更好的远程操控技术框架,那么你当然还是可以首选 remoting。使用remoting其实可以省去考虑消息序列化、解析、对象自动跟踪等问题,是一个相当伟大的框架。它是简单而完善(但是不完备)的,不仅仅用于远程通讯,它往往也是系统级平台“横切注入”技术的一个标准研究对象。remoting 的问题就是与当今主流编程不协调,公司找到的使用 remoting 进行系统开发人员很容易是又不懂、又漫天要价的。但是你自己学习他很好。
从互联网爆发出来的各种应用需要互联互通,于是浅显的东西占了上风,而且这些东西显然就比沉重的 rpc 通讯框架更快更轻便。如果你要做自己的远程控制,那么你需要定义5、6个通讯信令(例如开启、关闭命令,某种业务事件通知),定义通讯实体模型(例如对象的“唯一标识id”、大小、相对位置)等属性。然后在两个进程中实现灵活的通讯网关。这个协议可以写成文本,然后发给各种各样的公司采用完全不同的技术平台去实现。但是使用 remoting,那么对技术上的限制就很“死”了。
如果你自己不会设计更好的远程操控技术框架,那么你当然还是可以首选 remoting。使用remoting其实可以省去考虑消息序列化、解析、对象自动跟踪等问题,是一个相当伟大的框架。它是简单而完善(但是不完备)的,不仅仅用于远程通讯,它往往也是系统级平台“横切注入”技术的一个标准研究对象。remoting 的问题就是与当今主流编程不协调,公司找到的使用 remoting 进行系统开发人员很容易是又不懂、又漫天要价的。但是你自己学习他很好。
#21
VB6中可以用ActiveX.Exe轻松实现
.Net中,用前几年的方法,可以对指定的窗口进行一下包装,用一个相对简单的方式提取出一个包含必要操作的类,设计为COM+组件(服务器应用程序,等同于进程外组件(作用相当于COM中以-embed为参数的exe )),进程中不直接操作Form类,而是操作COM+组件.
对于轻量级的,也可以通过普通的进程通讯方式完成同一窗口跨进程数据同步.我个人习惯使用CreateFileMapping+WM_USER
这几年这方面的需求好象越来越少,不太清楚是用什么方法解决此类需求
.Net中,用前几年的方法,可以对指定的窗口进行一下包装,用一个相对简单的方式提取出一个包含必要操作的类,设计为COM+组件(服务器应用程序,等同于进程外组件(作用相当于COM中以-embed为参数的exe )),进程中不直接操作Form类,而是操作COM+组件.
对于轻量级的,也可以通过普通的进程通讯方式完成同一窗口跨进程数据同步.我个人习惯使用CreateFileMapping+WM_USER
这几年这方面的需求好象越来越少,不太清楚是用什么方法解决此类需求
#22
至于楼主的需求,由于是同一个EXE,完全可以通过互斥锁禁止重复启动,然后把内部搞成多线程去解决性能问题.这类问题我也遇到过,一般是同一台主机上多身份登录共同请求一项资源时常遇到的需求,一般可以通过优化软件功能或客户业务逻辑去解决.如果是两个不同的Exe,可以尝试一下上面的方法.
#23
如果是要IWin32Window,那就简单的多了。就象贴创可贴一样,用不着进程通讯/RPC这些象试管婴儿的大动作。
class WindowWrapper : IWin32Window
{
public IntPtr Handle {get; set;}
}
// 调用方法:
IntPtr intptr = FindWindow等等;
Show(new WindowWrapper (){Handle = intptr});
#24
#25
只要这个程序是你自己写的就好办,A、B窗体不断地将自己的属性等B窗体要求的东西作为消息作为应答发给另一个窗体就可以了。也可以通过文件进行。把自己找到改为提醒对方给出就可以了。
#26
你能传字符串,就能传对象。比如用xml或者JSON格式的字符串封装一下,然后再还原就是了。
#27
感谢各位的回复和指点,我暂时不结贴,我仔细研究下各位的回复。
#28
特意上来回你 用json或者xml序列化 和反序列化 ,用文件 或者 memcached来管理序列化内容,还有要建立确定的命名机制