As I’ve said before, the Windows Vista system automatically reserves the Windows’ Logo + Number key combinations for the shortcuts on your Quick Launch bar, so that you can easily launch your Quick Launch applications. That is, to start the first shortcut on your Quick Launch bar, you just press Win+1, and to start the second, you press Win+2 … and so on.

The problem is that pressing this hotkey always runs a new copy of the application (although obviously some applications have their own system for making sure only a single app is running, so for instance, you won’t get multiple copies of Windows Media Player) ... so I wrote a little application called RunOnlyOne which solves this problem. RunOnlyOne allows you to call it with an executable as an argument and it will either run that application or switch to it if it’s already running, making sure you only have a single copy running. You can use it in shortcuts on your Quick Launch bar, but also in geoShell shortcuts and hotkeys, Start Menu shortcuts, or even explorer desktop shortcuts (did you know you can assign a “Shortcut Key” to any shortcut in your Start Menu or on your desktop?).

I’ve actually just posted a new version of it, so if you downloaded it earlier (after my first post) you should go ahead and get the new version: the main change is the addition of a new command-line argument: -proc: which allows you to specify the name of the process module to look for, in case you want to run a shortcut or “launcher” app, but check for something else to be running.

For instance, if you want to run PowerShell, you probably want to run it via the shortcut which has font settings, window sizes, etc. So if you want to make sure you only keep one instance running, you can just specify the command line as: RunOnlyOne.exe -proc:PowerShell.exe "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Windows PowerShell 1.0\Windows PowerShell.lnk" You might have to specify the full path to RunOnlyOne.exe, and if you’re not on Vista, the path to the PowerShell.lnk file is probably different.

At any rate, I thought I’d share the source code and a couple of pointers about how to do this sort of thing. The source code includes a copy of some Iterator classes (two files: EnumProc.cpp and EnumProc.h) which were part of an MSDN Article back in 2002 … and basically uses them to do it’s magic:

  1. Loop through all the processes
  2. Check the first module from each process against either the -proc argument, or the name of the executable in the command-line path …
  1. If we find a match, pick the first window in the process and call SwitchToThisWindow, the Windows’ API for activating application windows.

The only real trick — apart from using the iterators — is that this is a “Windows” application, not a command-line application, so I had to remember to make a call to get the command-line arguments: int argc; LPWSTR *argv = CommandLineToArgvW ( GetCommandLineW(), &argc );. If you run it with no arguments, it pops up a MessageBox which shows the parameters which it accepts:

  • -? to show help
  • -s to RunAs Administrator (still only runs a new copy if the application is not already running, but you can bypass this by using the -proc argument to pass something impossible, like -proc:???)
  • -proc to specify the process module name, like: -proc:Explorer.exe.
  • the first argument after the flags should be the path to what you want to run
  • any following arguments will be passed to that application as arguments

As a side note: despite what you might have thought from my previous article, this is not a Vista-only application, it should run fine all the way back to Windows 2000 at least. Also: I’m not 100% sure what would happen if you call this to try to ‘sudo’ a command line app or any other app which has no window — it may crash (the other application I announced yesterday (sudo) doesn’t check for windows, so it’s a better choice for that).

14 Responses to “Run only one copy of an application”

  • Hey, I remember…you’ve been trying to get this functionality in the taskbar for years in GS. Congrats…I’m thinking of trying this out on my XP system. Now, if we could just get it built in (or hooked into) the Explorer taskbar…

  • Arno says:

    I’ve been looking for an application that does exactly this, but without the automatic “switch to”. >> I am building a couple of antique gaming pc’s and would like users to be able to run only one instance of the game (ms-dos based games..) , but if they alt-tab to windows (to change volume or anything) and accidently click the icon again, they should not be auto-forced to switch back to the (fullscreen) game.

  • That would be simple … just comment out that one line of code ;)

  • K H says:

    For situation that the prog is being minimized, RunOnlyOne is not able to bring it to front. Can this be done ?

  • JF says:

    KH> I’m not really a C coder, but I think you would just need add these lines:

    ::ShowWindow(itw.First(), SW_SHOWNORMAL);
    ::BringWindowToTop(itw.First());

    right after the SwitchToWindow line…that would restore the window if it’s minimized, as well as bring the window to top if it’s open but behind some other window(s).

    Joel – do you think you could update the code & binary to include the changes?

  • JF says:

    Actually I just played around with this with VS 2008 Express (as in free). All that is needed is:

    ::ShowWindow(itw.First(), SW_SHOWNORMAL);

    works like a champ. Perfect for use with cygwin.

  • Yeah, absolutely… gimme a day or two and I’ll repost the new one

  • JF says:

    Actually, after a little more playing, I discovered what I think is the ‘right way’. Apparently SwitchToApplication messes with the Z-ordering of any applications between the currently focused app, and the app you wish to switch to – like the way Alt-Tab brings each window into focus as you tab through them. Furthermore, if the window is maximized and focused, and you RunOnlyOne again, it shouldn’t restore the window. Anyway, I think I’ve fixed all possible scenarios and have been running the new code and haven’t detected any bugs:

    //add these lines over the process iteration loop
    WINDOWPLACEMENT wp;
    wp.length = sizeof(wp);

    // replace SwitchToThisWindow() with:

    ::GetWindowPlacement( itw.First(), &wp);
    if( wp.showCmd == SW_SHOWMINIMIZED ) {
    ::ShowWindow( itw.First(), SW_RESTORE );
    } else {
    ::SetForegroundWindow( itw.First() );
    }

  • Daniel says:

    The program seems to get the error:
    “This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.”

    Is this a Vista only app? Did now know if there was a dll or such that xp does not have.

    Best Regards,
    -daniel

  • Actually, it should not be a Vista only app, but it probably does require the latest VC++ 8 runtime dlls… I’ll make sure I include them in the update…

  • Doug says:

    Joel, I was looking for something like this to be able to hotkey an Explorer window to open to a specific directory or to switch back to the explorer window if it was currently open (regardless of the directory I left it at). The problem with RunOnlyOne is that I believe explorer changes the name of the Window each time the directory changes. If this is the case, the only way I could see RunOnlyOne working is if it tracked the process id instead of the name?

    Does this sound like it could work, or maybe there’s just a better way to do what I’m wanting.

    Thanks
    -Doug

  • Sorry, did you even read the article? It matches based on process name, not window titles. That’s why it has a -proc parameter.

  • Doug says:

    Actually I did read the article (no need to be pissy). I also tried the proc parameter and it doesn’t work properly with “Explorer.exe” as there is always an instance running, so it will not bring up a window initially when used with “proc”.

    In order to make it work I had to change the code and have it store the process id in the registry. It will try to find that process id running and switch to it. If it’s not valid or another named process is in its place it spawns a new instance and updates the id in the registry.

    With that change and a change to how the focus is reset, it works fine.

  • Oh, I see what you mean … you’re trying to run … only two. Or rather, only one that you started. I didn’t understand what you meant at all.

    Obviously having RunOnlyOne track what it starts should work fine (or, I take it, does work fine for you) ... I mean, it’s hypothetically possible that you could get a coincidence with the process id on a subsequent boot or something, but it seems really unlikely.

    Sorry for the confusion.

Search
Similar Posts
    None Found
Recent Posts
    None Found