Passing command line parameters between instances

W

william.w.oneill

I have an application that takes a few command line parameters. As
recommended by others in this group, I'm using a named mutex to ensure
that only one instance of the application is running. My question is
how to elegantly pass a command line parameter from Instance_B to
Instance_A where Instance_A was running prior to Instance_B.

For example, the user can launch the program by passing a file name as
a command line argument. The program will display the file after the
program launches. If a second instance is launched, I want the first
instance to display the file and the second instance to close.

How I'm doing it now is clumsy. When Instance_B starts and notices
Instance_A is already running, I write a temp file to the user's area
that contains the name of the user's file to open. Instance_A polls
the temp file and opens the user's file when temp file is created.
Ugly, but it works.

Have any of you done something like this before? I can think of a few
other solutions but they are overly complex.

Thank you,
Bill
 
P

pedrito

There are a few ways to do this. The problem of course, is each process has
its own address space, so you can't directly pass data between them

You can use sockets or some other IPC mechanism. But that seems like a lot
of trouble for passing some arguments.

The way I normally do it is to actually use the WM_COPYDATA message. It
requires some marshalling of the data, but I think it's a lot easier than
setting up sockets and all the error handlign and stuff that come with doing
that.

Basically, what you do is figure out a way to pack your arguments into a
byte[] array. Lay them out however you want.

You'll need these two definitions:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam,
IntPtr lParam);

[StructLayout(LayoutKind.Sequential)]
public struct COPYDATA
{
public uint dwData;
public uint cbData;
public IntPtr lpData;
}


Then for sending from the second app to the first, I first go through the
process list (Process.GetProcesses()) and find the first instance and get
its main window handle.

I also have a class calld ArgumentInfo which simply contains my parsed
arguments in properties and fields and has two methods, CreateByteArray()
and ParseByteArray(). CreateByteArray() simply creates a byte array from the
arguments in the fields and a constructor override that takes byte[] and
populates the fields based on that.

So to send the message from the second app to the first, I do:

private static void SendWMData(IntPtr hwnd, ArgumentInfo argInfo)
{
COPYDATA cd = new COPYDATA();
cd.dwData = 0;
cd.cbData = (uint) (argData.Length + 1);
cd.lpData = Marshal.StringToHGlobalAnsi(argData.CreateByteArray());
IntPtr lpPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cd));

Marshal.StructureToPtr(cd, lpPtr, true);

// Send WM_COPYDATA
SendMessage(hwnd, 0x004A, 0, lpPtr);

Marshal.FreeHGlobal(lpPtr);
}


Then to receive the message in the second app, in the second app's main
window, I override WndProc. You can do a switch/case, but in my case, it's
the only message I handle so it's like this:

protected override void WndProc(ref Message m)
{
if (m.HWnd == Handle && m.Msg == 0x004A)
{
COPYDATA cd = (MainApp.COPYDATA) Marshal.PtrToStructure(m.LParam,
typeof(MainApp.COPYDATA));
string data = Marshal.PtrToStringAnsi(cd.lpData);
string[] jobData = DataSplit(data);
ArgumentInfo newArgs = new ArgumentInfo(jobData);
ProcessArguments(newArgs)
}
base.WndProc (ref m);
}

Anyway, this works pretty well for me and saves me from having to deal with
sockets any more than I already have to...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top