One instance of an application only- How to post the creatio
Ari Villaca -- villaca@correionet.com.br Sunday, January 12, 1997 Environment: MSVC 4.0/Win95 I have an application which is supposed to have only one instance running. I know how to activate the 1st instance of the application when a 2nd one is started by the user. But the solution I have just do it, ie, activates the 1st instance. If th= e user has used Explorer to click on a saved application document name in order to open that document, the document won't be opened. How can I post the 2nd instance creation message arguments ( maybe the CWinApp::m_lpCmdLine ) to the 1st instance already running?=20 The code for limiting the application to one instance is: Bool CMyApp::InitInstance() { .... .... .... SetRegistryKey( "MyCompanyName" ); csClassName =3D GetProfileString( "Initialization", "ClassName", "None" = ); //determines if another window with our class name exists HWND hWnd; hWnd =3D ::FindWindow( ( LPCSTR ) csClassName, NULL ); if ( hWnd ) { AfxMessageBox( "The application is already running..." ); SetForegroundWindow( hWnd ); CWnd* PrevWindow =3D CWnd::FromHandle( hWnd ); PrevWindow->SetForegroundWindow(); //does it have a popup? CWnd* ChildWnd =3D PrevWindow->GetLastActivePopup(); //bring the main window to the top PrevWindow->BringWindowToTop(); //if iconic, restore the main window if ( PrevWindow->IsIconic() ) PrevWindow->ShowWindow( SW_RESTORE ); //if there are popups, bring them along too if ( PrevWindow !=3D ChildWnd ) ChildWnd->BringWindowToTop(); //here seems to be the place to post the 2nd instance creation argument= s (maybe m_lpCmdLine ) //to the 1st instance, so they are processed //for now, send a File/New message PrevWindow->PostMessage( WM_COMMAND, ID_FILE_NEW ); =09 // return FALSE; } .... .... .... } Any pointer to related documentation or solution is greatelly appreciated= .=20 Regards, Ari -------------------------------------------------------------------------= --- --- Ari de Moura Villa=E7a e-Mail: villaca@correionet.com.br Av. Moraes Sales, 987 Apto.113 fone: +55 19 232-2440 13010-001 - Campinas, SP fax: +55 19 232-2440 Brasil -------------------------------------------------------------------------= --- ---
Mats Mеnhav -- manhav@connectum.skurup.se Tuesday, January 14, 1997 -- [ From: Mats Manhav * EMC.Ver #2.5.02 ] -- The way you use for determining if this is the second instance, will not work in all cases. Since NT and 95 are multitasking systems it may very well happen that both instances are started in such a way that neither of them have created the mainframe when you do the FindWindow(). Instead you should do like this: Use a mutex to make sure that you are not running more than one instance. Create the mutex in the beginning of InitInstance(). If the mutex already exists when you creat it, there is already another instance running. You than do findwindow to get the window handle. Note that it may not be present at first, so you may need to test several times. Delete the mutex in the CMainFrame class, when the window is closing down. This way there is less chance that the mutex exists and that the first instance is about to end. To be able to send the string of the file name over you need to create some shared memory since NT and 95 have protected memory. You can achive this using FileMappings. (Or maybe using the CSharedFile I am not sure, please update me someone who knows how to do пt using CSharedFile). CApp::InitInstance() { // create the mutex m_Mutex = new CMutex(FALSE, "OneInstanceOnly"); // check if you are first. BOOL First = (GetLastError() != ERROR_ALREADY_EXISTS); // if First just startup as usual. if (!First) { // wait for the other instance to startup hWnd Wnd; while (NULL == (Wnd = FindWindow()) { Sleep(SOMETIME); // don't try forever if (GiveUpWaiting) DoSomethingToHandleTimout(); // maybe assume you are the only instance } ActivateFirstInstance(); // sending the file given to you on the commandline I would do using a special message // note that the string is not sharable between processes since the memory is // protected. You need to find some way to send the string over. // Try CreateFileMapping() which can be used to create a memory shared file. // look in the Win32 reference at the article "Using Shared Memory in a Dynamic-Link Library" // create a named the file mapping in memory and send the CopyTheFileNameIntoAFileMappingView(); SendMessage(wm_OpenFile, lpCmdLine); CloseTheFileMapping(); ExitNicely(); } } Good Luck! Mats Mats -------- REPLY, Original message follows -------- > Date: Sunday, 12-Jan-97 11:25 PM > > From: Ari Villaca \ Internet: (villaca@correionet.com.br) > To: MFCList \ Internet: (mfc-l@netcom.com) > > Subject: One instance of an application only- How to post the creation message > from the > > Environment: MSVC 4.0/Win95 > > I have an application which is supposed to have only one instance running. > I know how to activate the 1st instance of the application when a 2nd one > is started by the user. > > But the solution I have just do it, ie, activates the 1st instance. If the > user has used Explorer to click on a saved application document name in > order to open that document, the document won't be opened. > > How can I post the 2nd instance creation message arguments ( maybe the > CWinApp::m_lpCmdLine ) to the 1st instance already running? > > The code for limiting the application to one instance is: > > Bool CMyApp::InitInstance() { > .... > .... > .... > SetRegistryKey( "MyCompanyName" ); > csClassName = GetProfileString( "Initialization", "ClassName", "None" > ); > > //determines if another window with our class name exists > HWND hWnd; > hWnd = ::FindWindow( ( LPCSTR ) csClassName, NULL ); > if ( hWnd ) > { > AfxMessageBox( "The application is already running..." ); > > SetForegroundWindow( hWnd ); > CWnd* PrevWindow = CWnd::FromHandle( hWnd ); > PrevWindow->SetForegroundWindow(); > > //does it have a popup? > CWnd* ChildWnd = PrevWindow->GetLastActivePopup(); > > //bring the main window to the top > PrevWindow->BringWindowToTop(); > > //if iconic, restore the main window > if ( PrevWindow->IsIconic() ) > PrevWindow->ShowWindow( SW_RESTORE ); > > //if there are popups, bring them along too > if ( PrevWindow != ChildWnd ) > ChildWnd->BringWindowToTop(); > > //here seems to be the place to post the 2nd instance creation > arguments > (maybe m_lpCmdLine ) > //to the 1st instance, so they are processed > //for now, send a File/New message > PrevWindow->PostMessage( WM_COMMAND, ID_FILE_NEW ); > > > // > return FALSE; > } > > .... > .... > .... > } > > Any pointer to related documentation or solution is greatelly appreciated. > > Regards, > > Ari > > -------------------------------------------------------------------------- -- > --- > Ari de Moura Villaзa > e-Mail: villaca@correionet.com.br > > Av. Moraes Sales, 987 Apto.113 fone: +55 19 232-2440 > 13010-001 - Campinas, SP fax: +55 19 232-2440 > Brasil > -------------------------------------------------------------------------- -- > --- > -------- REPLY, End of original message -------- -- ========================================================================== Mats Mеnhav (Mats Manhav for 7-bit people) email:manhav@connectum.skurup.se WWW: http://connectum.skurup.se/~manhav FAX: (int) 46 (0) 414 243 05 Phone: (int) 46 (0) 414 243 05 ==========================================================================
=?iso-8859-1?Q?Marko_K=F6nig?= -- koenig@Spiess.com Thursday, January 16, 1997 [Mini-digest: 3 responses] Hi Environment: VC++ 4.2, Win NT 4.2 I had some problems to determine the HWND of the mainwindow from the = first instance using the windowclass. Here is an example which is using = a memory mapped file instead of FindWindow(). CMyApp::InitInstance() { m_hFileMapping =3D CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, = 0, sizeof(DWORD), "StringToIdentTheMapFile"); ASSERT(m_hFileMapping);=20 BOOL bFirst =3D (GetLastError() !=3D ERROR_ALREADY_EXISTS);=20 if (!bFirst) { AfxMessageBox("There is one previsious instance!"); HANDLE hFileMap =3D OpenFileMapping(FILE_MAP_READ, FALSE, = FILEMAPIDENTIFIER); ASSERT(hFileMap); LPDWORD pDword =3D (LPDWORD)MapViewOfFile( hFileMap, FILE_MAP_READ, 0, 0, 0); ASSERT(pDword); HWND hWnd =3D (HWND) *pDword; ASSERT(IsWindow(hWnd)); ::SetForegroundWindow(hWnd); UnmapViewOfFile(pDword); CloseHandle(hFileMap); return FALSE; } ... do some other initialisation ... (create the mainwindow e.t.c.) ... LPDWORD pDword =3D (LPDWORD)MapViewOfFile(m_hFileMapping, FILE_MAP_WRITE, 0, 0, 0); if(pDword) { *pDword =3D (DWORD)m_pMainWnd->m_hWnd; VERIFY(UnmapViewOfFile(pDword)); } return TRUE; } Marko Koenig Spiess COMPUTERSYSTEMS, Munich, Germany koenig@spiess.com http://www.spiess.com ---------- From: Mats Manhav[SMTP:manhav@connectum.skurup.se] Sent: Mittwoch, 15. Januar 1997 05:46 To: Ari Villaca; MFCList Subject: Re: One instance of an application only- How to post the = creation message from t -- [ From: Mats Manhav * EMC.Ver #2.5.02 ] -- The way you use for determining if this is the second instance, will not work in all cases. Since NT and 95 are multitasking systems it may very well happen that = both instances are started in such a way that neither of them have created the mainframe = when you do the FindWindow(). Instead you should do like this: Use a mutex to make sure that you are not running more than one = instance. Create the mutex in the beginning of InitInstance(). If the mutex = already exists when you creat it, there is already another instance running. You than = do findwindow to get the window handle. Note that it may not be present at first, so = you may need to test=20 several times.=20 Delete the mutex in the CMainFrame class, when the window is closing = down. This way there is less chance that the mutex exists and that the first instance is=20 about to end. To be able to send the string of the file name over you need to create = some shared memory since NT and 95 have protected memory. You can achive this using FileMappings. (Or maybe using the CSharedFile I am not sure, please update me someone = who knows how to do =EFt using CSharedFile). CApp::InitInstance() { // create the mutex m_Mutex =3D new CMutex(FALSE, "OneInstanceOnly"); // check if you are first. BOOL First =3D (GetLastError() !=3D ERROR_ALREADY_EXISTS);=20 =20 // if First just startup as usual. if (!First) { // wait for the other instance to startup hWnd Wnd; while (NULL =3D=3D (Wnd =3D FindWindow()) { Sleep(SOMETIME); // don't try forever if (GiveUpWaiting) DoSomethingToHandleTimout(); // maybe assume you are the = only instance }=20 =20 ActivateFirstInstance(); // sending the file given to you on the commandline I would do = using a special message // note that the string is not sharable between processes since = the memory is // protected. You need to find some way to send the string over. // Try CreateFileMapping() which can be used to create a memory = shared file. // look in the Win32 reference at the article "Using Shared Memory = in a Dynamic-Link Library" // create a named the file mapping in memory and send the =20 CopyTheFileNameIntoAFileMappingView(); SendMessage(wm_OpenFile, lpCmdLine); CloseTheFileMapping(); ExitNicely(); } } Good Luck! Mats Mats -------- REPLY, Original message follows -------- > Date: Sunday, 12-Jan-97 11:25 PM >=20 > From: Ari Villaca \ Internet: = (villaca@correionet.com.br) > To: MFCList \ Internet: (mfc-l@netcom.com) >=20 > Subject: One instance of an application only- How to post the creation message > from the=20 >=20 > Environment: MSVC 4.0/Win95 >=20 > I have an application which is supposed to have only one instance = running. > I know how to activate the 1st instance of the application when a 2nd = one > is started by the user. >=20 > But the solution I have just do it, ie, activates the 1st instance. If = the > user has used Explorer to click on a saved application document name = in > order to open that document, the document won't be opened. >=20 > How can I post the 2nd instance creation message arguments ( maybe the > CWinApp::m_lpCmdLine ) to the 1st instance already running?=20 >=20 > The code for limiting the application to one instance is: >=20 > Bool CMyApp::InitInstance() { > .... > .... > .... > SetRegistryKey( "MyCompanyName" ); > csClassName =3D GetProfileString( "Initialization", = "ClassName", "None" > ); >=20 > //determines if another window with our class name exists > HWND hWnd; > hWnd =3D ::FindWindow( ( LPCSTR ) csClassName, NULL ); > if ( hWnd ) > { > AfxMessageBox( "The application is already running..." = ); >=20 > SetForegroundWindow( hWnd ); > CWnd* PrevWindow =3D CWnd::FromHandle( hWnd ); > PrevWindow->SetForegroundWindow(); >=20 > //does it have a popup? > CWnd* ChildWnd =3D PrevWindow->GetLastActivePopup(); >=20 > //bring the main window to the top > PrevWindow->BringWindowToTop(); >=20 > //if iconic, restore the main window > if ( PrevWindow->IsIconic() ) > PrevWindow->ShowWindow( SW_RESTORE ); >=20 > //if there are popups, bring them along too > if ( PrevWindow !=3D ChildWnd ) > ChildWnd->BringWindowToTop(); >=20 > //here seems to be the place to post the 2nd instance creation > arguments > (maybe m_lpCmdLine ) > //to the 1st instance, so they are processed > //for now, send a File/New message > PrevWindow->PostMessage( WM_COMMAND, ID_FILE_NEW ); > =20 >=20 > // > return FALSE; > } >=20 > .... > .... > .... > } >=20 > Any pointer to related documentation or solution is greatelly = appreciated. >=20 > Regards, >=20 > Ari >=20 > = -------------------------------------------------------------------------= - -- > --- > Ari de Moura Villa=E7a > e-Mail: = villaca@correionet.com.br >=20 > Av. Moraes Sales, 987 Apto.113 fone: +55 19 232-2440 > 13010-001 - Campinas, SP fax: +55 19 232-2440 > Brasil > = -------------------------------------------------------------------------= - -- > --- >=20 -------- REPLY, End of original message -------- -- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Mats M=E5nhav (Mats Manhav for 7-bit people) email:manhav@connectum.skurup.se WWW: = http://connectum.skurup.se/~manhav FAX: (int) 46 (0) 414 243 05 Phone: (int) 46 (0) 414 243 05 = =20 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -----From: Peter.Walker@ubs.com Item Subject: cc:Mail Text >CopyTheFileNameIntoAFileMappingView(); >SendMessage(wm_OpenFile, lpCmdLine); >CloseTheFileMapping(); Shared memory seems a bit elegant, why not use WM_COPYDATA to transfer to string and capture this in the targets Main Window? Peter Walker peter.walker@ubs.com -----From: Jim Lawson WilliamsAt 10:12 AM 15/01/97 -0800, Gforce wrote: > I have a similar problem, I have an app that should only have one >instance running at any time, >I send the command line to the first instance with no problems, Problem >arises if the >user double clicks on a file associated with my app and a second >instance tries to launch, sends >command line info (path and filename) to the first instances, the first >instances acts on the >command line but gets a sharing volation error attempting to open the >file... > > Any ideas ?, thanks in advance. > G'day! I can't see why try/catch won't allow you, on trapping the exception, to scan the documents in play and report "you already have this open" or "something else has this one". Regards, Jim LW >From the BBC's "Barchester Chronicles": "I know that ultimately we are not supposed to understand. But I also know that we must try." -- the Reverend Septimus Harding, crypt-analyst, clog-dancer, C++ programmer
| Вернуться в корень Архива |