2

I am developing a desktop app (C# 4.0 Winforms) where one of the requirements is that the program can be open more than one time. However, I don't want the users to be able to open a given document more than one time (bad things can happen).

Basically I want it to function similarly to MS Word (at least the newer versions) where if you try to open a doc that is already open it takes you to the instance of the program that already has that doc open.

I spend most of my time doing web development, so there might be some easy solution that I just don't know about.

So I really have two different needs.

1) Keep the file from being opened more than one time 2) If they attempt to open it again, bring the instance to the fore ground.

There are a couple of ways I can think of to handle #1, but I'm curious how other people have solved this issue.

I actually don't really have any idea where to even start trying to get #2 to work without making some master form/process that stays open and creates the child programs. IE create another form that actually controls the opening and closing of the current program's main forms, so it would be more of a "tabbed" experience than an actual multiple window experience. More like an old style MDI (which would still leave issue #1).

Any help here (sites to read, namespaces to look at, etc...) would be greatly appreciated.

Edit - I see that this has been marked as a duplicate and that the "duplicate" is at top of the page. One of my requirements is that the program HAS to be able to be open multiple times. Did you guys even read the post? Can some one else come in and vote to reopen the question.

Further Edit - I went with the Mutex idea for to keep the program from opening the same document multiple times. I never did find an easy way to figure out which instance of the program had the document open and bring it to the front, so I gave up for now and just pop a message box telling them it is already open. Named Pipes seemed a bit of overkill for this as it isn't exactly what I want to do and would involve a lot of overhead (and WCF is not the easiest thing in the world), so any further help would be appreciated.

Benji
  • 105
  • 8
  • @HansPassant, I don't think it is question about "how to create single instance application" - "the program can be open more than one time" which to me reads that multiple instances of EXE must be running at the same time for some reason. – Alexei Levenkov Dec 30 '12 at 01:57
  • Word is a single-instance app with all the behavior the OP describes. Not sure what you are talking about. – Hans Passant Dec 30 '12 at 02:01
  • It may be interesting/educational to read how Word actually does it by using [running objects table](http://msdn.microsoft.com/en-us/library/aa911889.aspx). There are some questions that talk about using it from C#, like - http://stackoverflow.com/questions/8215203/problems-accessing-the-running-object-table. To my knowledge there is no built in C#/CLR way of using it also it was designed ages ago to solve exactly this problem. – Alexei Levenkov Dec 30 '12 at 02:02
  • @HansPassant, it does appear that word is actually a single instance app, but it appears to the user to be a multi-instance app. Perhaps thinking of it more like Visual Studio is helpful. Definitely multiple instances there. – Benji Dec 30 '12 at 03:22
  • @AlexeiLevenkov - Thanks for the heads up. The running objects table looks interesting (the link you provided actually goes to windows CE). I'm not a huge fan of messing with COM objects from managed code. It seems like it might be simpler to just create a "master" form that spawns the others and can access their properties since I own the entire stack. – Benji Dec 30 '12 at 03:23
  • Yes, it was mostly for inspiration... Update to my comment: there is builtin [interop for IRunningObjectTable](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comtypes.irunningobjecttable.aspx). Correct link to COM [IRunningObjectsTable](http://msdn.microsoft.com/en-us/library/ms695276.aspx) – Alexei Levenkov Dec 30 '12 at 04:27

2 Answers2

1

You are asking about mutexes. In Windows you can create a MUTEX (mutually-exclusive flag) so even if second instance of the process opens it tries to create mutex and then fails. Mutexes are OS-wide global vars (sort of) for this purpose and used for IPC/coordination.

Another way would be this - create a window with class name (class as in windows API not as in C# or C++) that has document name embedded and use FindWindow() function to first see if such a window already open. Then you can SendMessage(HWND) to snd that window a message to bring it to front, so if user clicks in Explorer "myfile.doc" and it is already open - you just bring it to front. APIs to look at (from my brain ram, how do I remember this stuff?):

 CreateMutex() / OpenMutex()
 FindWindow() / CreateWindow()
 SendMessage() / PostMessage()
 ShowWindow()/ SetWindowPosition()/BringWinToTop()
itadapter DKh
  • 596
  • 3
  • 7
  • This seems promising, but if the program were to crash before the Mutex is released, then won't the file be un-openable until the user restarts their computer? – Benji Dec 30 '12 at 04:06
  • No, Mutex will be rolled back by OS. I recommend you use Window names/classes and use FindWindow/SendMessage approach. You can also prevent second instance of your EXE by using this p-code if ( hwnd =FindWindow("NameofYourAppmainwindowWhich is Unique")!=0) BringToFront(hwnd); return. In other words second instance starts finds the first one, brings it to front and exits the process. – itadapter DKh Dec 30 '12 at 17:35
  • This was definitely the way I wanted to go with preventing the file from being opened more than one time by my program, but I'm not really sure how I use any of the other things you suggested for the rest. I read the MSDN stuff on CreateWindow, but I'm really sure how I'd go about using them in my C# program. – Benji Jan 06 '13 at 02:55
1

I suspect that there are dozens of ways to approach this, but here is how I would approach it:

Only have a single instance of the application and open each of the requested documents in a new window within the application.

This will take a little coordination since subsequent documents that are opened will cause a new instance to be created, but you could setup an interprocess communication mechanism (such as a named pipe) that the first instance of the application creates and subsequent instances check for.

If they find that the IPC exists, they pass the requested file name to the first app instance (which opens the specified file), and then terminate.

Here is a good article on named pipe usage from Microsoft: How to: Use Named Pipes for Network Interprocess Communication

competent_tech
  • 44,465
  • 11
  • 90
  • 113
  • If I go with the idea of having a master form spawn the child forms then why would I need to communicate between the children? Wouldn't it be easier to actually have the master open and close the children and that way it can look at (or store) their properties? Wouldn't it be easier to just use events or public methods to accomplish it instead of named pipes? – Benji Dec 30 '12 at 03:34
  • The issue is that if you associate a file extension with the application and the user double-clicks on the application, I believe windows spawns a new instance of the application using the command line parameters (i.e. the name of the file the user selected). If all of the file opening is performed completely under the control of your application, then there is obviously no need for IPC. – competent_tech Dec 30 '12 at 03:46
  • Ahhh. I haven't yet actually registered the file extensions with windows to allow double clicking to open, but was thinking about it. Something to think about. – Benji Dec 30 '12 at 04:07