Re: can't bring "single instance" tray app to foreground
On Thu, 5 Jul 2007 16:43:26 -0700 "David Ching" <dc@remove-this.dcsoft.com> wrote:
"Frank Cusack" <fcusack@fcusack.com> wrote in message
news:m2abuaig6h.fsf@sucksless.local...
CTrayApp::CTrayApp()
: CSingleInstanceApp(TEXT("{...}"))
{
// if this is the 2nd instance, allow the 1st instance to come to fg
if (!AllowSetForegroundWindow(ASFW_ANY))
throw 1;
}
CTrayApp theApp;
BOOL
CTrayApp::InitInstance()
{
if (!AmITheFirst()) {
// wait just a bit so ASFW() in 2nd instance works
// (don't exit before 2nd instance calls SFW())
Sleep(500);
return FALSE;
}
CMainFrame *pMainFrame = new CMainFrame;
m_pMainWnd = pMainFrame;
if (!pMainFrame->Create(NULL, "foo"))
return FALSE;
m_pMainWnd->ShowWindow(SW_HIDE);
m_pMainWnd->UpdateWindow();
return TRUE;
}
void CTrayApp::OnSecondInstance(UINT, LPARAM)
{
m_pMainWnd->SetForegroundWindow(); // no effect (but main wnd was hidden)
AfxMessageBox("hello world!", MB_OK|MB_SETFOREGROUND); // not in fg
}
====
OK, let's start from scratch:
//////////////////////////////////////////////////////////////////////////
// Shared global variables - visible to all instances of this .exe
#pragma data_seg(".sdata")
HWND sh_hwndMainFrame = NULL;
#pragma data_seg()
// This comment makes the above data segment shareable
// It replaces having to add a linker option to the project
#pragma comment(linker, "/SECTION:.sdata,rws")
CTrayApp::CTrayApp()
: CSingleInstanceApp(TEXT("{...}"))
{
}
CTrayApp theApp;
BOOL
CTrayApp::InitInstance()
{
if (!AmITheFirst()) {
// this instance (the second instance) has the focus and must explicity
give it away
AllowSetForegroundWindow(ASFW_ANY);
// Request the first instance to bring its window to foreground
// Post message to CMainFrame of first instance
// Assume CMainFrame::OnSecondInstance() is called when it receives a
UWM_SECOND_INSTANCE message
ASSERT (sh_hwndMainFrame != NULL);
::PostMessage ( sh_hwndMainFrame, UWM_SECOND_INSTANCE, 0, 0);
return FALSE;
}
// First instance - create mainframe window that is hidden
CMainFrame *pMainFrame = new CMainFrame;
m_pMainWnd = pMainFrame;
if (!pMainFrame->Create(NULL, "foo"))
return FALSE;
// No need to show or update the window, as it is hidden --- comment out
//m_pMainWnd->ShowWindow(SW_HIDE);
//m_pMainWnd->UpdateWindow();
// Save main window handle for use in second instance
sh_hwndMainFrame = m_pMainWnd->GetSafeHwnd();
return TRUE;
}
Does this make sense?
It makes sense, but seems to be the same as what I'm doing.
Using the CSingleInstanceApp class I found, AmITheFirst() sends the
notification to the 1st instance. Therefore, I call ASFW() in my
constructor, so that I know it is called before the 1st instance tries
to call SFW(). In your example, AmITheFirst() would (apparently) just
return the value of (sh_hwndMainFrame == NULL).
CSingleInstanceApp creates a shared file mapping for the purpose of
sharing data between the 2 (or more?) instances. The constructor
saves the thread id into the shared space if the shared mapping
doesn't already exist; if it did already exist, it posts a message to
the thread whose id was saved. This seems to be a common technique.
It does work, as far as only allowing a single instance goes.
Why did you move ASFW() from the constructor to InitInstance()? I
guess it's better that away since only the 2nd instance will allow
focus to be taken from it, but does it make any other difference?
-frank