c#进程间通信是否可以传递对象?

hpygzhx520 2014-08-01 11:07:26
进程间通信的方式有很多,比如管道,比如发送消息等,传递个字符串啥的好办些,但我要传递个对象呢?可以吗?怎么做?

具体描述如下:

一个项目生成一个EXE,里面包含两个窗体A、B。启动EXE的时候(比如不带参数运行这个EXE),显示窗体A。

窗体A上放个按钮,点击的时候带参数启动这个EXE的另一进程,进程启动的时候检测到参数,显示窗体B。

然后两个进程用某种途径实现通信。

现在问:B窗体能否得到A这个窗体对象?(当然是实现进程通信后)得到后,直接可以取得A的属性等。反过来也一样,A也要可以取得窗体B这个对象。

搜索了半天,好像可以序列化,但看得一头雾水,所以在此请教。COM类的可以CoMarshalInterface等实现,在.NET下就不知道怎么办了。
...全文
897 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
快乐起航2020 2015-12-29
  • 打赏
  • 举报
回复
xfroot_gmail 2014-08-11
  • 打赏
  • 举报
回复
特意上来回你 用json或者xml序列化 和反序列化 ,用文件 或者 memcached来管理序列化内容,还有要建立确定的命名机制
hpygzhx520 2014-08-04
  • 打赏
  • 举报
回复
感谢各位的回复和指点,我暂时不结贴,我仔细研究下各位的回复。
全栈极简 2014-08-03
  • 打赏
  • 举报
回复
你能传字符串,就能传对象。比如用xml或者JSON格式的字符串封装一下,然后再还原就是了。
kxyzjm62 2014-08-03
  • 打赏
  • 举报
回复
只要这个程序是你自己写的就好办,A、B窗体不断地将自己的属性等B窗体要求的东西作为消息作为应答发给另一个窗体就可以了。也可以通过文件进行。把自己找到改为提醒对方给出就可以了。
bu_ge 2014-08-03
  • 打赏
  • 举报
回复
gomoku 2014-08-03
  • 打赏
  • 举报
回复
引用 16 楼 hpygzhx520 的回复:
我实际使用中就是需要“窗体”这个对象,现在倒不是麻烦不麻烦的事情。比如窗体的public void Show(IWin32Window owner);,我想指定A进程的A窗体为B进程B窗体的owner
如果是要IWin32Window,那就简单的多了。就象贴创可贴一样,用不着进程通讯/RPC这些象试管婴儿的大动作。

class WindowWrapper : IWin32Window
{
    public IntPtr Handle {get; set;}
}
// 调用方法:
IntPtr intptr = FindWindow等等;
Show(new WindowWrapper (){Handle = intptr});
jointan 2014-08-02
  • 打赏
  • 举报
回复
至于楼主的需求,由于是同一个EXE,完全可以通过互斥锁禁止重复启动,然后把内部搞成多线程去解决性能问题.这类问题我也遇到过,一般是同一台主机上多身份登录共同请求一项资源时常遇到的需求,一般可以通过优化软件功能或客户业务逻辑去解决.如果是两个不同的Exe,可以尝试一下上面的方法.
jointan 2014-08-02
  • 打赏
  • 举报
回复
VB6中可以用ActiveX.Exe轻松实现 .Net中,用前几年的方法,可以对指定的窗口进行一下包装,用一个相对简单的方式提取出一个包含必要操作的类,设计为COM+组件(服务器应用程序,等同于进程外组件(作用相当于COM中以-embed为参数的exe )),进程中不直接操作Form类,而是操作COM+组件. 对于轻量级的,也可以通过普通的进程通讯方式完成同一窗口跨进程数据同步.我个人习惯使用CreateFileMapping+WM_USER 这几年这方面的需求好象越来越少,不太清楚是用什么方法解决此类需求
hpygzhx520 2014-08-02
  • 打赏
  • 举报
回复
我实际使用中就是需要“窗体”这个对象,现在倒不是麻烦不麻烦的事情。比如窗体的public void Show(IWin32Window owner);,我想指定A进程的A窗体为B进程B窗体的owner
  • 打赏
  • 举报
回复
如果你做点局域网内的程序,那么你可以使用 remoting。感受一下.net 框架中早期的 remoting 技术是个好事。其实 remoting 还是相当好用的,而且也非常强大的。但是绝对达不到你要求的那种程度。 从互联网爆发出来的各种应用需要互联互通,于是浅显的东西占了上风,而且这些东西显然就比沉重的 rpc 通讯框架更快更轻便。如果你要做自己的远程控制,那么你需要定义5、6个通讯信令(例如开启、关闭命令,某种业务事件通知),定义通讯实体模型(例如对象的“唯一标识id”、大小、相对位置)等属性。然后在两个进程中实现灵活的通讯网关。这个协议可以写成文本,然后发给各种各样的公司采用完全不同的技术平台去实现。但是使用 remoting,那么对技术上的限制就很“死”了。 如果你自己不会设计更好的远程操控技术框架,那么你当然还是可以首选 remoting。使用remoting其实可以省去考虑消息序列化、解析、对象自动跟踪等问题,是一个相当伟大的框架。它是简单而完善(但是不完备)的,不仅仅用于远程通讯,它往往也是系统级平台“横切注入”技术的一个标准研究对象。remoting 的问题就是与当今主流编程不协调,公司找到的使用 remoting 进行系统开发人员很容易是又不懂、又漫天要价的。但是你自己学习他很好。
  • 打赏
  • 举报
回复
引用 16 楼 hpygzhx520 的回复:
我实际使用中就是需要“窗体”这个对象,现在倒不是麻烦不麻烦的事情。比如窗体的public void Show(IWin32Window owner);,我想指定A进程的A窗体为B进程B窗体的owner
没有你想象的这种东西。 即使是2003年前就开始被淘汰的 remoting 技术,它也是“对象代理”机制。因此就有一堆复杂的通讯层,和一堆的编程限制你需要遵守。例如 remoting 根本不能直接支持远程对象事件通知,必须通过手动进行复杂的封装来模拟。 remoting 与另外两种技术,在上个世纪90年代是主要的三大进程通讯技术。然后到了互联网时代,这些全都烟消云散了。逐渐地,soap等等基于 xml 进行封装处理的轻量级通讯技术成为了主流。最近5、6年由于ajax技术兴起,json较多地取代 xml。
相思梦 2014-08-02
  • 打赏
  • 举报
回复
楼上虽然说的对象也是存于内存之中并没有错,但如果其他进程需要访问这就不太可能 即使你将那一块内存完全复制出也是不行的,正确的办法是通过进行通信编写特定机制 来实现A进程类与B进程进行交互,否则编写COM+使用MSAA也是可以的,前提是你必 必须清楚暴露出的IID与发送捕获的消息是什么一般取WM_GetObject
  • 打赏
  • 举报
回复
也可以传递对象,但是更建议通过json序列化反序列化的方式来传递信息, 简单,方便,跨一切
wwwww112233 2014-08-02
  • 打赏
  • 举报
回复
序列化传过去再反序列化就好了
hpygzhx520 2014-08-01
  • 打赏
  • 举报
回复
表示段位低,还需要仔细研究代码,非常敬佩+感谢。我先研究下8楼代码
gomoku 2014-08-01
  • 打赏
  • 举报
回复
可以用Remoting做。其中MarshalByRefObject表示可远程代理。 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; }
    }
}
// -- 结束添加
hpygzhx520 2014-08-01
  • 打赏
  • 举报
回复
这个板块就是好,提问后那么多人帮忙解答,很欣慰…… 在COM框架下,比如用VB6,列集IDispatch是可以成功的,在.NET很茫然。
gomoku 2014-08-01
  • 打赏
  • 举报
回复
引用 3 楼 mlqxj35674 的回复:
只要是内存中,什么都可以传递,
内存是可以传递,但对一个进程有意义的内存数据,在另外一个进程就可能是垃圾。
hpygzhx520 2014-08-01
  • 打赏
  • 举报
回复
引用 1 楼 bdmh 的回复:
对象也是在内存里,你把那块内存读出来,转换为对象就行了,传递内存地址(内存映射)
比如读出自身内存起始地址和长度,传递给另外一个进程?这个难度比较大吧
引用 2 楼 gomoku 的回复:
不可以传递窗体,因为窗体不可以系列化,本身也不支持代理。
如果无法实现,在需要做较多通信的时候,实在是有些麻烦啊。 感谢版主们回复。
加载更多回复(8)
什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式。从微软的产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下。Microsoft? .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这也正是我们使用Remoting的原因。为什么呢?在Windows操作系统中,是将应用程序分离为单独的进程。这个进程形成了应用程序代码和数据周围的一道边界。如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一进程。这是一种操作系统对应用程序的保护机制。然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。   在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。首先,客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象。这就提供一种可能性,即以服务的方式来发布服务器对象。远程对象代码可以运行在服务器上(如服务器激活的对象和客户端激活的对象),然后客户端再通过Remoting连接服务器,获得该服务对象并通过序列化在客户端运行。   在Remoting中,对于要传递对象,设计者除了需要了解通道的类型和端口号之外,无需再了解数据包的格式。但必须注意的是,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。这既保证了客户端和服务器端有关对象的松散耦合,同时也优化了通信的性能。

110,532

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧