views:

107

answers:

2

I use a Console Application in Windows Mobile to handle incoming message interception. In the same console application i accept parameters (string args[]) which based on the parameters, register the message interceptor.

InterceptorType is a enum

static void Main(string[] args)
        {                 

            if (args[0] == "Location")
            {               

                addInterception(InterceptorType.Location, args[1],args[2]);
            } 

        }


private static void addInterception(InterceptorType type, string Location, string Number )
    {

        if (type == InterceptorType.Location)
        {

           using (MessageInterceptor interceptor = new MessageInterceptor(InterceptionAction.NotifyAndDelete, false))
           {

               interceptor.MessageCondition = new MessageCondition(MessageProperty.Sender, MessagePropertyComparisonType.Contains, Number, false);

               string myAppPath = Assembly.GetExecutingAssembly().GetName().CodeBase;

               interceptor.EnableApplicationLauncher("Location", myAppPath);

               interceptor.MessageReceived += new MessageInterceptorEventHandler(interceptor_MessageReceived);


           }


        }


    }


static void interceptor_MessageReceived(object sender, MessageInterceptorEventArgs e)
    {

        //Do something



    }

I made this a console application because i want it keep running in the background and intercept incoming messages.

This works fine for the first time. But the problem is that I have to keep calling the addInterception method to add subsequent interception rules. This makes the console application start again and again for each time i add a rule. How do i make this run only once and add more message interceptor rules?

+2  A: 

EDIT

It seems that people are misunterstanding your question (or I am) so here's some clarification on how I'm seeing the problem.

You have an console app that takes in command-line parameters. These parameters are used for something (the what is irrelevant actually). You want to be able to add parameters after the app is already running by calling the app with new command line args.

What is happening is that when you call the app any time after teh first, a new instance of the process starts up instead of the command-line arguments going to the existing, already running application.

END EDIT

The solution is fairly straightforward and requires two pieces.

  1. You need a named mutex. For whatever (poor) reason, the CF doesn't expose a version of a mutex that takes a name, so you have to P/Invoke CreateMutex or use a library (like the SDF) that already has it. Your app needs to create the mutex at startup and check to see if it already exists. if it doesn't you're the first running instance and run as normal. If the mutex exists, you need to pass your command line args to the one that is already running via a P2P queue then simply exits.

  2. After checking the mutex, the first instance spawns a worker thread. This thread listens on a P2P queue for messages. When they come in, you handle them.

ctacke
Yes. You got it correct. I actually want to call the `addInterception` function to register another Message Interceptor event without starting another instance of the console application.
Ranhiru Cooray
EDIT mistake: He just needs to re-use the process instance and override the streams instead of creating a new process everytime. Combine this with some kind of looping logic and wala, no more multi-processes just to hook new events.
P.Brian.Mackey
+2  A: 

Since you already have a method in place to call the command prompt once, update your logic with some simple looping so you can pass N commands.

EDIT: I wrote it a fully compileable example to show you exactly what I am talking about. Note how the child process can be called any number of times without re-launching. This is not just a simple command line launch with arguments being passed because that idea will lead to X processes which is exactly what you do not want.

PARENT PROCESS: (The one with System.Diagnostics.Process)

/// <summary>
    /// This is the calling application.  The one where u currently have System.Diagnostics.Process
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Process p = new Process();
            p.StartInfo.CreateNoWindow = false;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.FileName = @"C:\AppfolderThing\ConsoleApplication1.exe";
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;


            p.Start();            
            p.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
            {
                Console.WriteLine("Output received from application: {0}", e.Data);
            };
            p.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e)
            {
                Console.WriteLine("Output received from application: {0}", e.Data);
            };
            p.BeginErrorReadLine();
            p.BeginOutputReadLine();
            StreamWriter inputStream = p.StandardInput;
            inputStream.WriteLine(1);
            inputStream.WriteLine(2);
            inputStream.WriteLine(-1);//tell it to exit
            p.WaitForExit();
        }

    }

CHILD PROCESS:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    enum InterceptorType
    {
        foo,
        bar,
        zee,
        brah
    } 
    /// <summary>
    /// This is the child process called by System.Diagnostics.Process
    /// </summary>
    class Program
    {
        public static void Main()
        {
            while (true)
            {
                int command = int.Parse(Console.ReadLine());
                if (command == -1)
                    Environment.Exit(0);
                else
                    addInterception((InterceptorType)command, "some location", "0");
            }
        }
        private static void addInterception(InterceptorType type, string Location, string Number)
        {
            switch (type)
            {
                case InterceptorType.foo: Console.WriteLine("bind foo"); break;
                case InterceptorType.bar: Console.WriteLine("bind bar"); break;
                default: Console.WriteLine("default bind zee"); break;
            }

        }


        static void interceptor_MessageReceived(object sender, EventArgs e)
        {
            //Do something  
        }  
    }
}

Note that codeplex has a managed service library.

P.Brian.Mackey
Would you be kind enough to explain what happens in the while(true) loop. Isn't that an infinite loop?
Ranhiru Cooray
The loop runs until you pass it an exit code. You could break and fall through to other logic. Its just a demonstration of what's possible in light of the fact that I don't know everything that your application does; note also the service library. You could look into an asynch thread as well, depending on your requirements. Just ensure the main thread doesn't fall through and die until you want it to.
P.Brian.Mackey
How does this prevent the multiple process problem he's having?
ctacke
"Since you already have a method in place to call the command prompt once" <-- Noted assumption of programmatic cmd line process call. Assumption is also made that user can hook into input/output stream similar to Process class available in full .NET framework.
P.Brian.Mackey
I am using System.Diagnostics.Process.Start() method to start the application.
Ranhiru Cooray
@Ranhiru, yep thats the one I'm referring to. You will need to get a reference to the process object instance in order to override the streams. I have a pretty long example on my blog, likely more powerful than you require. If you want something simpler I can update the post. http://brianmackey.net/Blog/?p=10
P.Brian.Mackey
@Ranhiru ok there you go full implementation.
P.Brian.Mackey