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
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...
<william....@gmail.com> wrote in message
news:1187788719.9...@e9g2000prf.googlegroups.com...