Single-instance app revisited

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Peter Morris

    Single-instance app revisited

    Some time ago I needed to write a single-instance app. That's an easy task
    but I also needed duplicate instances to pass their command line parameters
    to the first instance so that it can act upon them.

    I ended up achieving this using Remoting to start my first app, and then
    call into that Singleton remoted object from secondary instances. I thought
    I was pretty clever until today when I tried to show an OpenFileDialog and
    received an error telling me I have to use my app's main thread.

    It's proving to be a real pain :-) Does anyone have a solution they have
    tried?



    Pete

  • Peter Duniho

    #2
    Re: Single-instance app revisited

    On Thu, 25 Sep 2008 11:58:02 -0700, Peter Morris
    <mrpmorrisNO@sp amgmail.comwrot e:
    Some time ago I needed to write a single-instance app. That's an easy
    task but I also needed duplicate instances to pass their command line
    parameters to the first instance so that it can act upon them.
    >
    I ended up achieving this using Remoting to start my first app, and then
    call into that Singleton remoted object from secondary instances. I
    thought I was pretty clever until today when I tried to show an
    OpenFileDialog and received an error telling me I have to use my app's
    main thread. [...]
    Really? That surprises me. Granted, I haven't tried it, and presumably
    it'd be trivial for me to reproduce the behavior. But dialogs, having
    their own message loops, usually work okay on any arbitrary thread.

    That said, given that requirement, why doesn't the standard technique
    apply? That is, just use Control.Invoke( ) or similar to execute the code
    to show the dialog on the correct thread?

    Pete

    Comment

    • Jon Skeet [C# MVP]

      #3
      Re: Single-instance app revisited

      Peter Morris <mrpmorrisNO@SP AMgmail.comwrot e:
      Some time ago I needed to write a single-instance app. That's an easy task
      but I also needed duplicate instances to pass their command line parameters
      to the first instance so that it can act upon them.
      >
      I ended up achieving this using Remoting to start my first app, and then
      call into that Singleton remoted object from secondary instances. I thought
      I was pretty clever until today when I tried to show an OpenFileDialog and
      received an error telling me I have to use my app's main thread.
      >
      It's proving to be a real pain :-) Does anyone have a solution they have
      tried?
      Have you tried using the Microsoft.Visua lBasic.Applicat ionServices
      classes?

      Read http://msdn.microsoft.com/en-us/libr...wx(VS.80).aspx and
      see if it helps you. Personally I think it would be nice to have this
      sort of functionality in System.*...

      --
      Jon Skeet - <skeet@pobox.co m>
      Web site: http://www.pobox.com/~skeet
      Blog: http://www.msmvps.com/jon.skeet
      C# in Depth: http://csharpindepth.com

      Comment

      • Peter Morris

        #4
        Re: Single-instance app revisited

        Yes. Unfortunately it threw a "NotImplemented " or "NotSupport ed" exception
        (don't recall which) on a couple of machines at work, so I abandoned it.


        Comment

        • Jon Skeet [C# MVP]

          #5
          Re: Single-instance app revisited

          Peter Morris <mrpmorrisNO@SP AMgmail.comwrot e:
          Yes. Unfortunately it threw a "NotImplemented " or "NotSupport ed" exception
          (don't recall which) on a couple of machines at work, so I abandoned it.
          I suspect it's worth digging into a bit further, as VB.NET uses it
          pretty easily. It may be worth coming up with a quick VB.NET app then
          decompiling it to see what it's doing.

          --
          Jon Skeet - <skeet@pobox.co m>
          Web site: http://www.pobox.com/~skeet
          Blog: http://www.msmvps.com/jon.skeet
          C# in Depth: http://csharpindepth.com

          Comment

          • Peter Duniho

            #6
            Re: Single-instance app revisited

            On Thu, 25 Sep 2008 12:09:18 -0700, Peter Duniho
            <NpOeStPeAdM@nn owslpianmk.comw rote:
            [...]
            >I ended up achieving this using Remoting to start my first app, and
            >then call into that Singleton remoted object from secondary instances.
            >I thought I was pretty clever until today when I tried to show an
            >OpenFileDial og and received an error telling me I have to use my app's
            >main thread. [...]
            >
            Really? That surprises me. Granted, I haven't tried it, and presumably
            it'd be trivial for me to reproduce the behavior. But dialogs, having
            their own message loops, usually work okay on any arbitrary thread.
            By the way, I took another look at this, and I can confirm that it's not
            actually a problem for the OpenFileDialog to be shown on other than the
            main GUI thread per se.

            However, the OpenFileDialog does require that the thread be initialized as
            a COM single-threaded-apartment. Since you're using remoting, you
            probably don't have control over the nature of the thread itself, and so
            it might be difficult for you to ensure that.

            Given that, I still think that my follow-up question still applies:
            That said, given that requirement, why doesn't the standard technique
            apply? That is, just use Control.Invoke( ) or similar to execute the
            code to show the dialog on the correct thread?
            Pete

            Comment

            • Peter Morris

              #7
              Re: Single-instance app revisited

              Hi Pete

              Using Invoke doesn't work either.....


              Thanks for your time!


              Pete



              private void ButtonSelectSpe echAudioFileNam e_Click(object sender,
              EventArgs e)
              {
              Invoke(new System.Threadin g.ThreadStart(
              delegate()
              {
              OpenFileDialog ofd = GetOpenWavDialo g(Composition.S peechAudioFile) ;
              if (ofd.ShowDialog () == DialogResult.OK )
              Composition.Spe echAudioFile = ofd.FileName;
              }));
              }



              System.Threadin g.ThreadStateEx ception was unhandled by user code
              Message="Curren t thread must be set to single thread apartment (STA) mode
              before OLE calls can be made. Ensure that your Main function has
              STAThreadAttrib ute marked on it. This exception is only raised if a debugger
              is attached to the process."
              Source="System. Windows.Forms"
              StackTrace:
              at System.Windows. Forms.Control.M arshaledInvoke( Control caller,
              Delegate method, Object[] args, Boolean synchronous)
              at System.Windows. Forms.Control.I nvoke(Delegate method, Object[]
              args)
              at System.Windows. Forms.Control.I nvoke(Delegate method)
              at
              AlterEgo.Wizard StepControls.Au dioAndScriptSte pControl.Button SelectSpeechAud ioFileName_Clic k(Object
              sender, EventArgs e) in
              C:\Data\Custome rProjects\Intee vo\Projects\Alt erEgo\AlterEgo\ WizardStepContr ols\AudioAndScr iptStepControl. cs:line
              77
              at System.Windows. Forms.Control.O nClick(EventArg s e)
              at DevExpress.Xtra Editors.BaseBut ton.OnClick(Eve ntArgs e)
              at DevExpress.Xtra Editors.BaseBut ton.OnMouseUp(M ouseEventArgs e)
              at System.Windows. Forms.Control.W mMouseUp(Messag e& m, MouseButtons
              button, Int32 clicks)
              at System.Windows. Forms.Control.W ndProc(Message& m)
              at DevExpress.Util s.Controls.Cont rolBase.WndProc (Message& m)
              at
              System.Windows. Forms.Control.C ontrolNativeWin dow.OnMessage(M essage& m)
              at System.Windows. Forms.Control.C ontrolNativeWin dow.WndProc(Mes sage&
              m)
              at System.Windows. Forms.NativeWin dow.DebuggableC allback(IntPtr hWnd,
              Int32 msg, IntPtr wparam, IntPtr lparam)
              at System.Windows. Forms.UnsafeNat iveMethods.Disp atchMessageW(MS G&
              msg)
              at
              System.Windows. Forms.Applicati on.ComponentMan ager.System.Win dows.Forms.Unsa feNativeMethods .IMsoComponentM anager.FPushMes sageLoop(Int32
              dwComponentID, Int32 reason, Int32 pvLoopData)
              at
              System.Windows. Forms.Applicati on.ThreadContex t.RunMessageLoo pInner(Int32
              reason, ApplicationCont ext context)
              at
              System.Windows. Forms.Applicati on.ThreadContex t.RunMessageLoo p(Int32 reason,
              ApplicationCont ext context)
              at System.Windows. Forms.Applicati on.Run(Form mainForm)
              at Inteevo.SingleI nstanceApp.Sing leInstance.Exec ute(String[] args) in
              C:\Data\Custome rProjects\Intee vo\Libraries\In teevo.SingleIns tanceApp\Single Instance.cs:lin e
              26
              at
              System.Runtime. Remoting.Messag ing.StackBuilde rSink._PrivateP rocessMessage(I ntPtr
              md, Object[] args, Object server, Int32 methodPtr, Boolean
              fExecuteInConte xt, Object[]& outArgs)
              at
              System.Runtime. Remoting.Messag ing.StackBuilde rSink.PrivatePr ocessMessage(Ru ntimeMethodHand le
              md, Object[] args, Object server, Int32 methodPtr, Boolean
              fExecuteInConte xt, Object[]& outArgs)
              at
              System.Runtime. Remoting.Messag ing.StackBuilde rSink.SyncProce ssMessage(IMess age
              msg, Int32 methodPtr, Boolean fExecuteInConte xt)
              InnerException:

              Comment

              • Peter Morris

                #8
                Re: Single-instance app revisited

                I did decompile it in the past, pretty deep stuff with use of lots of
                classes/methods marked "internal".

                Comment

                • Peter Morris

                  #9
                  Re: Single-instance app revisited

                  PS: I am going to try named pipes instead of remoting, see if that helps.


                  Pete

                  Comment

                  • Peter Morris

                    #10
                    Re: Single-instance app revisited

                    I adapted this....
                    Get this domain name before someone else does. Quick and painless shopping. Affordable payment options available.


                    So now I just write

                    new SingleInstanceA pplication<Main Form>("MyCompan y.MyApp");

                    instead of

                    Application.Run (new MainForm());


                    Works a treat :-)


                    Thanks for your input guys, I appreciate it as always!




                    Pete

                    Comment

                    • Peter Duniho

                      #11
                      Re: Single-instance app revisited

                      On Fri, 26 Sep 2008 00:17:48 -0700, Peter Morris
                      <mrpmorrisNO@sp amgmail.comwrot e:
                      Hi Pete
                      >
                      Using Invoke doesn't work either.....
                      Your stack trace looks odd. In particular, you seem to be executing your
                      Application.Run () call on a thread without [STAThread]. This will, as the
                      exception implies, cause all sorts of problems. If this is in fact the
                      difficulty you're running into, then I'd say it's a good thing you're
                      running into this problem, because it's one you need to address regardless.

                      Without a concise-but-complete code sample, it's hard to comment on the
                      specific technique you're using to ensure a single-instance application
                      here, but I really don't see any reason that you should have a call to
                      Application.Run () in the same call stack with any of the remoting stuff.
                      By definition, the stuff coming in from remoting should never wind up
                      calling Application.Run ()...that's the point of making your application
                      single-instance.

                      Pete

                      Comment

                      Working...