views:

69

answers:

1

I have two assemblies that I'm trying to link together. One is a sort of background process that's built with WinForms and will be designed to run as a Windows Service. I have a second project that will act as a UI for the background process whenever a user launches it. I've never tried attempting something like this with managed code before, so I've started trying to use windows messages to communicate between the two processes. I'm struggling when it comes to passing more than just IntPtrs back and forth, however.

Here's the code from a control in my UI project that registers itself with the background process:

public void Init()
    {
        IntPtr hwnd = IntPtr.Zero;
        Process[] ps = Process.GetProcessesByName("BGServiceApp");
        Process mainProcess = null;
        if(ps == null || ps.GetLength(0) == 0)
        {
            mainProcess = LaunchApp();
        }
        else
        {
            mainProcess = ps[0];
        }
        SendMessage(mainProcess.MainWindowHandle, INIT_CONNECTION, this.Handle, IntPtr.Zero);
    } 
protected override void  WndProc(ref Message m)
    {
        if(m.Msg == INIT_CONFIRMED && InitComplete != null)
        {
            string message = Marshal.PtrToStringAuto(m.WParam);
            Marshal.FreeHGlobal(m.WParam);

            InitComplete(message, EventArgs.Empty);

        }
        base.WndProc(ref m);
    }

This is the code from the background process that's supposed to receive a request from the UI process to register for status updates and send a confirmation message.

 protected override void WndProc(ref Message m)
    {

        if(m.Msg == INIT_CONNECTION)
        {
            RegisterUIDispatcher(m.WParam);
            Respond(m.WParam);
        }

        if(m.Msg == UNINIT_CONNECTION)
        {
            UnregisterUIDispatcher(m.WParam);
            if(m_RegisteredDispatchers.Count == 0)
            {
                this.Close();
            }
        }
        base.WndProc(ref m);
    }

    private void Respond(IntPtr caller)
    {
        string test = "Registration confirmed!";
        IntPtr ptr = Marshal.StringToHGlobalAuto(test);

        SendMessage(caller, INIT_CONFIRMED, ptr, IntPtr.Zero);
        }
    }

The UI process receives the INIT_CONFIRMED message from my background process, but when I try to marshal the IntPtr back into a string, I get an empty string. Is the area of heap I'm using out of scope to the other process or am I missing some security attribute maybe? Is there a better and cleaner way to go about something like this using an event driven model?

+1  A: 

Not sure if you want to go this route, but you might have an easier time using WCF as the IPC layer, rather than low-level Windows IPC stuff. You'll need to build and expose interfaces for the service, then connect to them using your UI appklication.

There are a lot of good WCF tutorials out there, if you want to give it a shot.

Andy White
That would work rather well, unfortunately one of the other uses for the UI project is that the class that interfaces with the background process I would eventually like to use for exposing an API to other users. Using unmanaged code for IPC is definitely more involved, but it would allow me to market to a greater audience of end users.
Dennis P