views:

1510

answers:

5

I have two exe running, c# console programs. From one, I need to tell the second exe to do something? How... ? I looked at

(Remotable.CommonAssembly)Activator.GetObject(typeof(Remotable.CommonAssembly)

but from here i can call a method of the CommonAssembly(referenced dll) not the exe one's.

+3  A: 

Look into WCF for inter-process communication in .NET. There are a variety of protocols available for same-machine or remote-machine communication. For same-machine, I would recommend checking out named pipes or the .NET TCP binding.

There is a slight learning curve for WCF, but there are plenty of tutorials out there, and it's something that's definitely worth learning.

Andy White
WCF can do the job for you.
Irwin
+2  A: 

I frequently use MSMQ for this.

http://www.csharphelp.com/archives3/archive581.html

cookre
I'd only use this if I had a requirement to use persistent storage, otherwise it would be overkill for interprocess communication.
RichardOD
+5  A: 

For simple scenarios a plain old windows event would be enough - a program waits to be signaled to do something.

Spawn a thread in the waiting program that waits for the event.

//Program 1

EventWaitHandle evt = OpenOrCreateEvent("Global\\MyEvent");
evt.WaitOne(); // this thread will block waiting without wasting CPU cycles, 
               // it will be be signaled from the kernel 
               // when the event is set
DoStuff();


//Program 2

EventWaitHandle evt = OpenOrCreateEvent("Global\\MyEvent");
evt.Set();

Take a look at the EventWaitHandle, ManualResetEvent, AutoResetEvent classes.

  • Consider which program is going to create the event - you could try to open the event from both programs, if it doesn't exist than create it.
  • Prefix the event name with 'Global\' if one of the programs is a service ( and/or running in other session/user). Otherwise it won't work on Vista or later.
  • When creating the event you may need to set security attributes so it can be opened from other processes from other sessions.

Advanced IPC mechanisms like WCF, Remoting, DCOM, CORBA, etc may be better if you have more complicated communication protocol with different actions to trigger, return values and so on. For simple cases (a couple) of windows events would be enough.

Notice If you need to transfer data between your processes consider memory mapped files. "Official" .NET classes for them will be available with .NET 4.0, currently you can use http://github.com/tomasr/filemap/tree/master

devdimi
Interesting, didn't know memory mapped files will be supported in .NET 4.0
RichardOD
You can check the documentation at:http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles(VS.100).aspx
devdimi
+1  A: 

You might consider IPC. NamedPipeClientStream and NamedPipeServerStream are pretty simple. Here's an example where IPC is used to pass command line arguments from one instance of an application to another. It's not exactly what you want to do, but pretty close.

JP Alioto
+1  A: 

This should do the trick for you...

[code] using System; using System.Collections.Generic; using System.Text; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.InteropServices; using System.Diagnostics;

namespace TestApp { public static class Messenger { public const uint WM_USER = 0x0400;

    public const int MyMessage = 0x00000001;;

    [DllImport("User32.dll")]
    private static extern int RegisterWindowMessage(string lpString);

    [DllImport("User32.dll", EntryPoint = "FindWindow")]
    internal static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

    //For use with WM_COPYDATA and COPYDATASTRUCT
    [DllImport("User32.dll", EntryPoint = "SendMessage")]
    internal static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

    //For use with WM_COPYDATA and COPYDATASTRUCT
    [DllImport("User32.dll", EntryPoint = "PostMessage")]
    internal static extern int PostMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

    [DllImport("User32.dll", EntryPoint = "SendMessage")]
    internal static extern uint SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, int lParam);

    [DllImport("User32.dll", EntryPoint = "PostMessage")]
    internal static extern int PostMessage(int hWnd, int Msg, int wParam, int lParam);

    [DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
    internal static extern bool SetForegroundWindow(int hWnd);


    //Used for WM_COPYDATA for string messages
    public struct COPYDATASTRUCT
    {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;
    }


    internal static int sendWindowsStringMessage(int hWnd, int wParam, string msg)
    {
        int result = 0;

        if (hWnd > 0)
        {
            byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);
            int len = sarr.Length;
            COPYDATASTRUCT cds;
            cds.dwData = (IntPtr)100;
            cds.lpData = msg;
            cds.cbData = len + 1;
            result = SendMessage(hWnd, (int)WM_USER, wParam, ref cds);
        }

        return result;
    }

    internal static uint sendWindowsMessage(IntPtr hWnd, uint Msg, IntPtr wParam, int lParam)
    {
        uint result = 0;

        if (hWnd != IntPtr.Zero)
        {
            result = SendMessage(hWnd, Msg, wParam, lParam);
        }

        return result;
    }

    internal static IntPtr getWindowId(string className, string windowName)
    {
        return FindWindow(className, windowName);
    }
}

}

In your calling method:

uint result = 0; IntPtr hWnd = Messenger.getWindowId(null, "MyOtherApp-Window_Title"); result = Messenger.sendWindowsMessage(hWnd, Messenger.WM_USER, Handle, Messenger.MyMessage); [/code]