欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.Net程序间的通讯与控制

程序员文章站 2022-03-26 19:01:55
如果有一个需求,用一个程序控制另一个程序,最简单的,比如用程序a打开程序b,这个想必平时都会用到,可以使用process类及相关的方法。那么再打开b的时候发送一些参数,然后b根据这些参数做出一些反映...
如果有一个需求,用一个程序控制另一个程序,最简单的,比如用程序a打开程序b,这个想必平时都会用到,可以使用process类及相关的方法。那么再打开b的时候发送一些参数,然后b根据这些参数做出一些反映,这该怎么实现?其实还是用process。

 

发送端:

 

复制代码

     static void main(string[] args)

        {

            console.writeline("请输入接收器路径:");

            string path = console.readline();

            console.writeline("请输入接收器启动参数:");

            string para = console.readline();

            processstartinfo pi = new processstartinfo();

            pi.filename = @path;

            pi.arguments = para;

 

            try

            {

                process.start(pi);

            }

            catch

            {

                console.writeline("找不到接收器或出现错误!");

            }

            console.readkey();

        }

复制代码

 

 

接收端:

 

复制代码

        static void main(string[] args)

        {

            if (args.length == 0)

            {

                console.writeline("未接到信息!");

            }

            else

            {

                foreach (string s in args)

                {

                    console.writeline(s);

                }

            }

 

            console.readkey();

        }

复制代码

 

 

这样我们就可以用程序a启动程序b,根据a传入的参数,程序b做出相应的处理。不过在wpf中,就没法直接用main中的args参数了。对于wpf,可以用下面的方式处理:

 

1.在app.xaml 中删除 startupuri,并添加startup

 

复制代码

<application x:class="wpfapplication65.app"

             xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"

             startup="application_startup" >

    <application.resources>

         

    </application.resources>

</application>

复制代码

 

 

2.在app.xaml.cs中填写startup的内容

 

复制代码

   private void application_startup(object sender, startupeventargs e)

        {

            mainwindow mw = new mainwindow();

            foreach(string s in e.args)

            {

                mw.txtshow.text += s;

            }

            mw.show();

        }

复制代码

 

 

这样就可以获取传入的参数了。

 

但是再改一下需求,我们不仅仅通过程序启动的时候传入参数,而是需要给一个已经启动的程序传入参数,那么就需要用进程通信了ipc了。ipc需要用到windows api,下面将介绍一下wpf实现进程间的通信。

 

1.新建数据的结构体类库

 

新建一个类库,类库内容如下:

 

复制代码

using system;

using system.collections.generic;

using system.linq;

using system.runtime.interopservices;

using system.text;

using system.threading.tasks;

 

namespace datastruct

{

    [structlayout(layoutkind.sequential)]

    public struct datastruct

    {

        public intptr dwdata;

        public int cbdata;  // 字符串长度

        [marshalas(unmanagedtype.lpstr)]

        public string lpdata; // 字符串

    }

}

复制代码

 

 

2.新建信息帮助类库

 

新建一个类库,引用上一步的结构体类库,类库内容如下:

 

复制代码

using system;

using system.collections.generic;

using system.linq;

using system.runtime.interopservices;

using system.text;

using system.threading.tasks;

 

namespace messagehelper

{

    public class messagehelper

    {

        public const int wm_download_completed = 0x00aa;

        public const int wm_copydata = 0x004a;

 

        [dllimport("user32.dll", entrypoint = "findwindow")]

        public static extern intptr findwindow(string lpclassname, string lpwindowname);

 

        [dllimport("user32.dll", entrypoint = "sendmessage")]

        public static extern int sendmessage(intptr wnd, int msg, int wp, ref datastruct.datastruct cds);

    }

}

复制代码

 

 

3.发送端

 

首先引用前两部的类库

 

发送有两种方式:

 

a.通过进程名

 

复制代码

  var lstprocess = process.getprocessesbyname(txtprocess.text);

            if (lstprocess.length > 0)

            {

                process proc = lstprocess[0];

                datastruct.datastruct cds;

                cds.dwdata = intptr.zero;

                cds.lpdata = txtmsg.text;

                cds.cbdata = system.text.encoding.default.getbytes(txtmsg.text).length + 1;

 

                int fromwindowhandler = 0;

 

                messagehelper.messagehelper.sendmessage(proc.mainwindowhandle, messagehelper.messagehelper.wm_copydata, fromwindowhandler, ref cds);

            }

复制代码

 

 

注意:使用这种方法,如果窗体的showintaskbar=false,也就是不在任务栏显示的话,那么是没有办法通过mainwindowhandle获取窗口的。

 

b.通过窗口名

 

复制代码

  intptr hwnd = messagehelper.messagehelper.findwindow(null, txttitle.text);

 

            if (hwnd != intptr.zero)

            {

                datastruct.datastruct cds;

                cds.dwdata = intptr.zero;

                cds.lpdata = txtmsg.text;

                cds.cbdata = system.text.encoding.default.getbytes(txtmsg.text).length + 1;

                // 消息来源窗体

                int fromwindowhandler = 0;

                messagehelper.messagehelper.sendmessage(hwnd, messagehelper.messagehelper.wm_copydata, fromwindowhandler, ref cds);

            }

复制代码

 

 

注意:使用这种方法,如果有多个窗口的title是一样的,也是会有冲突的。

 

4.接收端

 

首先还是先引用前两步的类库。

 

复制代码

 public mainwindow()

        {

            initializecomponent();

            loaded += new routedeventhandler(window_loaded);

        }

        private void window_loaded(object sender, routedeventargs e)

        {

            (presentationsource.fromvisual(this) as hwndsource).addhook(new hwndsourcehook(this.wndproc));

        }

 

        intptr wndproc(intptr hwnd, int msg, intptr wparam, intptr lparam, ref bool handled)

        {

 

            if (msg == messagehelper.messagehelper.wm_copydata)

            {

 

                datastruct.datastruct cds = (datastruct.datastruct)system.runtime.interopservices.marshal.ptrtostructure(lparam, typeof(datastruct.datastruct));

 

                txtshow.text = cds.lpdata;

 

            }

 

            return hwnd;

 

        }