Dmitry Karneyev said:
Another one.
http://www.codeproject.com/csharp/singleinstance.asp
P.S. All code I've found uses user32.dll to bring main window of app to
front.
Is it possible to do the same thing using framework?
Dmitry
Dmitry
I've seen nothing in the framework "yet" that will bring the window in
another process to the foreground. That will certainly change in coming
release versions!
One would have to also consider the case of the original instance being in a
minimized state, not just hidden by another window.
The case in the work you cited has one minor problem - if the program is
executed from two different locations, both copies will run - the most
obvious case is a Release version and a Debug version (the cited work sees
that as two distinct executions).
Additionally, the use of the Mutex is exactly the right way to do it, but
the WaitOne is an unnecessary step, and there is no need to establish the
mutex as a static variable, the only requirement is that the life of the
mutex object be exactly that of the object it is trying to protect. The
mutex is a kernel object, so if the name is unique, then subsequent attempts
to create it will be seen in the Mutex(bool, string, bool) constructor (that
third param return true if this call is the first for the named object).
Here is a quick hack (no error checking, no comments, etc...) that I did
some time ago (my apologies, it is in MC++, but the xlate to C# should be
straightforward). Most of the work is done inline in the derived Form
object constructor - and it throws an exception if a multiple instance
condition is discovered. You can use the guidgen utilitiy to create the
seed for a unique name for each appliction. Then wrap the creation of the
main app form in WinMain in an exception handler, and exit without running
the form...
What you do when the second instance is discovered is very much up to you
and the requirments levied thereon. The message box that announces the
discovery of the first instance was included for demo purposes only (one
would likely remove that from a production release). I was playing with
someother things when I did this one - so I stuffed the HWND of the form
into the registry upon first successful invocation. Enumerating the windows
to find the initial instance did not seem to appealing to me at the time. In
the duplicate instance handler, I retreive the stored HWND value from the
registry, and then do a ShowWindow to bring the original form out of a
(potentially) minimized state. Next I pinned the original instance to TOP -
placing it above all other windows in the z-order, notwithstanding any that
have TOPMOST status. Be careful to not use TOPMOST, because that will force
the original window to the highest position in the z-order at that time. To
do this is almost never a user-friendly approach..
regards
roy fine
/* ******************* */
namespace SysWin32{
[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = Unicode)]
int MessageBox(IntPtr hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned
int uType);
[DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = Unicode)]
int ShowWindow(IntPtr hWnd, unsigned int uType);
[DllImport("user32.dll", EntryPoint = "SetWindowPos", CharSet = Unicode)]
int SetWindowPos(IntPtr, IntPtr,int x, int y, int sx, int sy, unsigned int
flags );
}
/* ******************* */
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE,LPTSTR,int ){
Thread *curThread = System::Threading::Thread::CurrentThread;
curThread->set_Name(S"UNIQUE_THREAD_3A2B4DE1_8F68_4647_9E84_5FD4B126696A");
curThread->set_ApartmentState(System::Threading::ApartmentState::STA);
Form1 *frm = 0;
try{
frm = new Form1();
String __gc *regKeyName = S"Software\\RLFine_Testing\\MC_Singleton";
RegistryKey __gc *regKey =
Registry::CurrentUser->CreateSubKey(regKeyName);
String __gc *iVal = frm->get_Handle().ToString();
regKey->SetValue(S"AppHWND",iVal);
regKey->Close();
regKey = NULL;
Application::Run(frm);
}
catch(int /* a */){
frm = NULL;
}
return 0;
}
/* ******************* */
public __gc class Form1 : public System::Windows::Forms::Form{
private:
Mutex *mtxInstance;
....
public:
Form1(void) {
InitializeComponent();
String *tstr = S"UNIQUE_INSTANCE_DF26B334_08A0_4ae5_9260_BBD975FB6E9E";
mtxInstance = new Mutex(true,tstr,&blMutexOwner);
if(!blMutexOwner) {
SysWin32::MessageBox( 0, L"YIKES!\nhere is already an instance of this
app running!",
L"Multiple Instance Monitor", MB_OK|MB_ICONWARNING);
RegistryKey *regKey =
Registry::CurrentUser->CreateSubKey(S"Software\\RLFine_Testing\\MC_Singleton
");
Object *obj = regKey->GetValue(S"AppHWND");
String *tstr = obj->ToString();
IntPtr hwnd = IntPtr(System::Convert::ToInt64(tstr));
SysWin32::ShowWindow(hwnd,SW_RESTORE);
SysWin32::SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
regKey->Close();
regKey = NULL;
throw 1;
}
}