keyongtech


  keyongtech > dotnet.languages.* > dotnet.languages.csharp

 #1  
09-25-08, 07:58 PM
Peter Morris
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
 #2  
09-25-08, 08:09 PM
Peter Duniho
On Thu, 25 Sep 2008 11:58:02 -0700, Peter Morris
<mrpmorrisNO> wrote:

> 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
 #3  
09-25-08, 08:10 PM
Jon Skeet [C# MVP]
Peter Morris <mrpmorrisNO> wrote:
> 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.VisualBasic.ApplicationServices
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.*...
 #4  
09-25-08, 09:28 PM
Peter Morris
Yes. Unfortunately it threw a "NotImplemented" or "NotSupported" exception
(don't recall which) on a couple of machines at work, so I abandoned it.
 #5  
09-25-08, 10:18 PM
Jon Skeet [C# MVP]
Peter Morris <mrpmorrisNO> wrote:
> Yes. Unfortunately it threw a "NotImplemented" or "NotSupported" 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.
 #6  
09-25-08, 10:29 PM
Peter Duniho
On Thu, 25 Sep 2008 12:09:18 -0700, Peter Duniho
<NpOeStPeAdM> wrote:

> [...]
>> 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.


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
 #7  
09-26-08, 08:17 AM
Peter Morris
Hi Pete

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


Thanks for your time!


Pete



private void ButtonSelectSpeechAudioFileName_Click(object sender,
EventArgs e)
{
Invoke(new System.Threading.ThreadStart(
delegate()
{
OpenFileDialog ofd = GetOpenWavDialog(Composition.SpeechAudioFile);
if (ofd.ShowDialog() == DialogResult.OK)
Composition.SpeechAudioFile = ofd.FileName;
}));
}



System.Threading.ThreadStateException was unhandled by user code
Message="Current thread must be set to single thread apartment (STA) mode
before OLE calls can be made. Ensure that your Main function has
STAThreadAttribute 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.MarshaledInvoke(Contr ol caller,
Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
args)
at System.Windows.Forms.Control.Invoke(Delegate method)
at
AlterEgo.WizardStepControls.AudioAndScriptStepCont rol.ButtonSelectSpeechAudioFileName_Click(Object
sender, EventArgs e) in
C:\Data\CustomerProjects\Inteevo\Projects\AlterEgo \AlterEgo\WizardStepControls\AudioAndScriptStepCon trol.cs:line
77
at System.Windows.Forms.Control.OnClick(EventArgs e)
at DevExpress.XtraEditors.BaseButton.OnClick(EventArg s e)
at DevExpress.XtraEditors.BaseButton.OnMouseUp(MouseE ventArgs e)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons
button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at DevExpress.Utils.Controls.ControlBase.WndProc(Mess age& m)
at
System.Windows.Forms.Control.ControlNativeWindow.O nMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.W ndProc(Message&
m)
at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG&
msg)
at
System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at
System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32
reason, ApplicationContext context)
at
System.Windows.Forms.Application.ThreadContext.Run MessageLoop(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Inteevo.SingleInstanceApp.SingleInstance.Execute(S tring[] args) in
C:\Data\CustomerProjects\Inteevo\Libraries\Inteevo .SingleInstanceApp\SingleInstance.cs:line
26
at
System.Runtime.Remoting.Messaging.StackBuilderSink ._PrivateProcessMessage(IntPtr
md, Object[] args, Object server, Int32 methodPtr, Boolean
fExecuteInContext, Object[]& outArgs)
at
System.Runtime.Remoting.Messaging.StackBuilderSink .PrivateProcessMessage(RuntimeMethodHandle
md, Object[] args, Object server, Int32 methodPtr, Boolean
fExecuteInContext, Object[]& outArgs)
at
System.Runtime.Remoting.Messaging.StackBuilderSink .SyncProcessMessage(IMessage
msg, Int32 methodPtr, Boolean fExecuteInContext)
InnerException:
 #8  
09-26-08, 08:21 AM
Peter Morris
I did decompile it in the past, pretty deep stuff with use of lots of
classes/methods marked "internal".
 #9  
09-26-08, 08:31 AM
Peter Morris
PS: I am going to try named pipes instead of remoting, see if that helps.


Pete
 #10  
09-26-08, 12:25 PM
Peter Morris
I adapted this....
[url down]

So now I just write

new SingleInstanceApplication<MainForm>("MyCompany.MyA pp");

instead of

Application.Run(new MainForm());


Works a treat :-)


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




Pete
 #11  
09-26-08, 07:28 PM
Peter Duniho
On Fri, 26 Sep 2008 00:17:48 -0700, Peter Morris
<mrpmorrisNO> wrote:

> 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
Similar Threads
Thread Thread Starter
extract items from list in single field, revisited

Hi, Would this also apply to my situation: I need to parse a long text field (imported from a very old database format) which will contain 0 or more 13-character blocks of...

mary r
Single-instance app: how to force running instance window to foreground?

I've implemented single-instance functionality in my .exe by using the mutex method. Works great. But when the .exe detects that it is not the first instance I want to...

Jen
Creating a single flat record from a one to many query revisited

Hope everyone is well, I have been trying to create a flat file that can be saved as a fixed length file. This file is required to transmet claims over an edi...

Tim Jones
Custom Taglib problems - instead of a single instance per page, I have a single instance per application.

Hi, What is the correct expected behaviour when using a taglib regarding how many objects are created per page/application? More clearly, I created a custom tag (call it...

chris brat
Multi-instance vs single instance application

I have a general question. If I write a application using any language(C/C++/C#/VB). How to make sure it only has one instance running? What I need to write in source code?...

kathy

Privacy Policy | All times are GMT. The time now is 12:35 PM.

Merging Information Logo
[Deutschland] [Espaņa] [France] [Italia] [Nederland] [Polska] [United Kingdom]