 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
N Bentley Guest
|
Posted: Sat Mar 05, 2005 11:34 am Post subject: IsIconic returns false when Application is minimised |
|
|
I am trying to prevent multiple instances of my application using C++
Builder 6.
I have done this before with C++ Builder 5 without problem. The code
template I am using is:
::CreateMutex(NULL, FALSE, "YourMutexName");
if ( GetlastError() == ERROR_ALREADY_EXISTS )
{
// Found another running application with the same mutex
// so one instance is already running.
Application->Title="Testing"; // prohibits finding this instance
HWND FirsthWnd, FirstChildhWnd;
FirsthWnd = ::FindWindow("TApplication", "YourApplicationTitle");
// see Application->Title or Options|Project|Application Tab|Title
if (::IsIconic(FirsthWnd))
::ShowWindow(FirsthWnd, SW_SHOWDEFAULT);
::SetForegroundWindow(FirsthWnd);
FirstChildhWnd = ::GetLastActivePopup(FirsthWnd);
if (FirsthWnd != FirstChildhWnd)
::BringWindowToTop(FirstChildhWnd); // A pop-up is active so
bring it to the top too.
}
else
{
Application->Initialize();
Application->Title = "YourApplicationTitle";
Application->CreateForm(__classid(TYourAppMainForm),&YourAppMainForm);
}
This works fine except when the first Instance is minimised. When loading a
second instance the code failes to restore the first instance because
IsIconic always returns false.
Does anyone know why this might be the case.
I'm running on WinXP SP2.
Out of interest if I run a second instance whilst my project is open in BCB6
with the Main Form's design Window minimised then the Forms design Window is
restored??
Thanks,
Neville.
|
|
| Back to top |
|
 |
JD Guest
|
Posted: Sun Mar 06, 2005 7:52 pm Post subject: Re: IsIconic returns false when Application is minimised |
|
|
"N Bentley" <nlb (AT) ntl (DOT) com> wrote:
| Quote: |
This works fine except when the first Instance is minimised.
When loading a second instance the code failes to restore
the first instance because IsIconic always returns false.
|
That's correct. You need to apply the WS_EX_APPWINDOW flag
to the form's exStyle by overriding it's CreateParams method
for IsIconic to return the correct status. Be aware however,
this flag will cause the main form to have 2 icons on the
taskbar.
This class solves your problem and it can easily be wrapped
into a component. All you need to do to make it work is give
your main form an unique name - something like CoNameAppName
and add a line to the main form's constructor where you
allocate the class:
//-------------------------------------------------------------
#ifndef SingleInstanceH
#define SingleInstanceH
//-------------------------------------------------------------
#include <Classes.hpp>
//-------------------------------------------------------------
class TSingleInstance : public TComponent
{
private:
bool FHooked;
bool FMinimized;
HANDLE hMutex;
HHOOK WndReturnHook;
unsigned int SI_CUSTOM_MESSAGE;
TForm* FParentForm;
protected:
bool __fastcall AppWndProcHook( TMessage &Message );
static int __stdcall CallWndRetCallBackProc( int Code, WPARAM WParam, LPARAM LParam );
public:
__fastcall TSingleInstance(TComponent* Owner);
__fastcall TSingleInstance::~TSingleInstance();
__published:
};
//-------------------------------------------------------------
#endif
//-------------------------------------------------------------
#include <vcl.h>
#include <basepch.h>
//-------------------------------------------------------------
#pragma hdrstop
//-------------------------------------------------------------
#include "SingleInstance.h"
#pragma package(smart_init)
//-------------------------------------------------------------
TSingleInstance* ThisSingleInstance = NULL;
HWND hFirstInstance, hSecondInstance;
//-------------------------------------------------------------
BOOL CALLBACK EnumWindowsCallBack( HWND hWnd, LPARAM lParam )
{
char WindowClassName[256] = {0};
if( ::GetClassName(hWnd, WindowClassName, 255) )
{
if( stricmp(WindowClassName, (char*)lParam) == 0)
{
if( hFirstInstance )
{
hSecondInstance = hWnd;
return FALSE;
}
else hFirstInstance = hWnd;
}
}
return TRUE;
}
//-------------------------------------------------------------
__fastcall TSingleInstance::TSingleInstance(TComponent* Owner) : TComponent(Owner)
{
if( ThisSingleInstance ) throw Exception("TSingleInstance : Only one instance of TSingleInstance is allowed per application.");
if( !Owner ) throw Exception("TSingleInstance : You must assign an Owner.");
FParentForm = dynamic_cast<TForm*>(Owner);
if( !FParentForm ) throw Exception("TSingleInstance : The Owner must be a TForm.");
ThisSingleInstance = this;
FHooked = false;
hMutex = NULL;
WndReturnHook = NULL;
if( !ComponentState.Contains(csDesigning) )
{
char ThisClassName[ 256 ] = { 0 };
::GetClassName( FParentForm->Handle, ThisClassName, 255 );
SI_CUSTOM_MESSAGE = ::RegisterWindowMessage( ThisClassName );
hMutex = ::CreateMutex( NULL, TRUE, ThisClassName );
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
Application->ShowMainForm = false;
hFirstInstance = hSecondInstance = NULL;
::EnumWindows( (WNDENUMPROC)EnumWindowsCallBack, (LPARAM)ThisClassName );
if( hFirstInstance == FParentForm->Handle ) hFirstInstance = hSecondInstance;
::SendMessage( hFirstInstance, SI_CUSTOM_MESSAGE, 0, 0 );
::SetForegroundWindow( hFirstInstance );
Application->Terminate();
}
else
{
Application->HookMainWindow( AppWndProcHook );
FHooked = true;
WndReturnHook = ::SetWindowsHookEx( WH_CALLWNDPROCRET, (int (__stdcall*)())CallWndRetCallBackProc, HInstance, ::GetCurrentThreadId() );
::PostMessage( Application->Handle, SI_CUSTOM_MESSAGE, 0, 0 );
}
}
}
//-------------------------------------------------------------
__fastcall TSingleInstance::~TSingleInstance()
{
if( FHooked ) Application->UnhookMainWindow( AppWndProcHook );
if( WndReturnHook ) ::UnhookWindowsHookEx( WndReturnHook );
if( hMutex ) ::CloseHandle( hMutex );
ThisSingleInstance = NULL;
}
//-------------------------------------------------------------
bool __fastcall TSingleInstance::AppWndProcHook( TMessage &Message )
{ /*
There is a problem with windows correctly recording the window state
when the form's exStyle does not include WS_EX_APPWINDOW. To be more
exact, without WS_EX_APPWINDOW, when the form is minimized, windows will
report the last state prior to minimizing so API's such as IsIconic will
fail to detect the correct window state. This is important because if
one blindly restores the first instance when it is already in a restored
state, it will exibit strange behavior when the user tries to minimize
the first instance.
The only way around this is to not manipulate the first instance's window
state directly and instead monitor the application's window state so that
the first instance can determine what it wants to do when it recieves a
custom restore message. */
if( Message.Msg == WM_SYSCOMMAND )
{
switch( Message.WParam )
{
case SC_RESTORE:
case SC_MAXIMIZE: FMinimized = false; break;
case SC_MINIMIZE: FMinimized = true;
}
}
else if( Message.Msg == SI_CUSTOM_MESSAGE )
{
// SI_CUSTOM_MESSAGE only reaches here once and is used to complete
// initialization. I could have used a seperate message but there was
// no need to register a seperate message.
if( FParentForm != Application->MainForm )
{
// The application is already running at this point. I had to wait
// to check if the object was owned by the main form and this is
// important because this hooks into the owner and it needs to be
// hooked into the main form.
MessageDlg("TSingleInstance : Object can only be placed on the Main Form.", mtError, TMsgDlgButtons() << mbOK, 0);
Application->Terminate();
}
else
{
if( Application->MainForm->WindowState == wsMinimized ) FMinimized = true;
else FMinimized = false;
}
}
return false;
}
//-------------------------------------------------------------
int __stdcall TSingleInstance::CallWndRetCallBackProc( int Code, WPARAM WParam, LPARAM LParam )
{
if( Code == HC_ACTION )
{
CWPRETSTRUCT* cwp = (CWPRETSTRUCT *) LParam;
if( cwp->message == ThisSingleInstance->SI_CUSTOM_MESSAGE )
{
if( ThisSingleInstance->FMinimized )
{
::SendMessage( Application->Handle, WM_SYSCOMMAND, SC_RESTORE, 0 );
}
}
}
return ::CallNextHookEx( ThisSingleInstance->WndReturnHook, Code, WParam, LParam );
}
//-------------------------------------------------------------
~ JD
|
|
| Back to top |
|
 |
N Bentley Guest
|
Posted: Fri Mar 11, 2005 4:38 pm Post subject: Re: IsIconic returns false when Application is minimised |
|
|
Many thanks,
I'll give that a try.
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|