1

Situation:

My Application is designed to be SingleInstance -> Working
My Application is deployed via ClickOnce - > Working

New request is, that you can pass arguments to this Application. This is currently realized with ApplicationDeployment.CurrentDeployment.ActivationUri.Query;

Now the tricky part. The Argument, which should be passed is a FileName or a Path.

Parsing this is no problem.

But since my SingleInstance is realized with PostMessage, im in trouble getting the Argument passed to the running instance.

My Native's-Class:

internal static class NativeMethods {
    public const int HwndBroadcast = 0xffff;

    public static readonly int WmShowme = RegisterWindowMessage("WM_SHOWME");

    public static readonly int SendArg = RegisterWindowMessage("WM_SENDARG");

    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);

    [DllImport("user32")]
    private static extern int RegisterWindowMessage(string message);

  }

The MessageSender

 protected override void OnStartup(StartupEventArgs e) {
      // check that there is only one instance of the control panel running...
      bool createdNew;
      this._instanceMutex = new Mutex(true, @"{0D119AC4-0F2D-4986-B4AB-5CEC8E52D9F3}", out createdNew);
      if (!createdNew) {
        var ptr = Marshal.StringToHGlobalUni("Hello World");
        NativeMethods.PostMessage((IntPtr)NativeMethods.HwndBroadcast, NativeMethods.WmShowme, IntPtr.Zero, IntPtr.Zero);
        NativeMethods.PostMessage((IntPtr)NativeMethods.HwndBroadcast, NativeMethods.SendArg, ptr, IntPtr.Zero);
        Environment.Exit(0);
      }
}

The Receiver (In MainWindow):

protected override void OnSourceInitialized(EventArgs e) {
      base.OnSourceInitialized(e);
      var source = PresentationSource.FromVisual(this) as HwndSource;
      source.AddHook(this.WndProc);
    }


    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {

      if (msg == NativeMethods.SendArg) {
        var s = Marshal.PtrToStringUni(wParam);
        MessageBox.Show(s);
      }

      if (msg == NativeMethods.WmShowme) {
        this.ShowMe();
      }
      return IntPtr.Zero;
    }

Question / Issue:

Everything compiles and runs fine in the first instance. But after starting the second instance, i'm receiving an System.AccessViolationException.

Wierd thing: Sometimes im getting no exception, but the received string shows as for example :

䀊虐\u0090

Since im no expert with WindowMessages and Pointers, i'm a bit clueless now.

Solutions including 3rd-Party-Tools, IPC or WCF are not wanted to realize for this project

lokusking
  • 7,396
  • 13
  • 38
  • 57
  • Maybe you should try this : http://stackoverflow.com/questions/14506406/wpf-single-instance-best-practices – KANAX Jul 20 '16 at 10:00
  • Thanks for your afford, but that article is only handlig different ways to set up an SingleInstance Application, not how to pass parameters – lokusking Jul 20 '16 at 10:29

1 Answers1

1

I did a quick test (with WinForms, though). When you do PostMessage, you make receiving end access another process' memory, which is a no go, hence AccessViolationException. As you don't like IPC, here is another approach, using memory mapped files. Sorry for messy code, just to illustrate the approach.

sender part:

            mmf = MemoryMappedFile.CreateOrOpen("testmap", 10000);
        using (var stm = mmf.CreateViewStream())
        {
            new BinaryWriter(stm).Write("Hello World");
        }

        NativeMethods.PostMessage((IntPtr)NativeMethods.HwndBroadcast, NativeMethods.SendArg, IntPtr.Zero, IntPtr.Zero);

receiver part:

        if (m.Msg == NativeMethods.SendArg)
        {
            string s;

            using (var mmf = MemoryMappedFile.OpenExisting("testmap"))
            {
                using (var stm = mmf.CreateViewStream())
                {
                    s = new BinaryReader(stm).ReadString();
                }
            }


            listBox1.Items.Add(s);
        }
Alex Seleznyov
  • 905
  • 6
  • 18