"François Charton" <
XXXX@XXXXX.COM >wrote:
Quote
I have a program which has to have only one instance running.
You're going to run into problems restoring the first instance
because of the way that windows works. It incorrectly record
the window state unless the window's exStyle includes the
WS_EX_APPWINDOW flag. However, applying the WS_EX_APPWINDOW
flag is problematic because it causes 2 icons to appear on the
taskbar - one for the application and one for the form.
Now you *can* get it restored from within the second instance
*but* the window state will be messed up. The form will look
as if it's been restored but when the user tries to minimize
it, they won't be able to because windows thinks that the
state is already minimized.
The solution is to override the form's WndProc method and keep
track of the window state yourself when ever the window state
changes:
protected: // User declarations
virtual void __fastcall WndProc(TMessage &Message);
void __fastcall TForm1::WndProc(TMessage &Message)
{
static bool IsMinimized = false;
if( Message.Msg == WM_SYSCOMMAND )
{
if( Message.WParam == SC_MINIMIZE )
{
IsMinimized = true;
}
else
{
IsMinimized = false;
}
}
else if( Message.Msg == UWM_MYCUSTOMMESSAGE )
{
if( IsMinimized )
{
Application->Restore();
}
}
TForm::WndProc(Message);
}
Quote
[...] To cure it, I could change my application title to
something that has a better chance of being unique
Your best choice is to change the main form's class name from
TForm1 or TMainForm to something like TMyCompanyNameAppName
which should make that unique.
Then if the mutex already exists, use the win32 api EnumWindows
to find the handle to the first instance. I wrote a component
that works off of the unique main form class name but for it
to be a component, it had to hook backwards (upwards) into
it's parent's WndProc which is different:
groups.google.com/groups
The only thing left is for you to modify the component to
account for passing data to the first instance - which BTW you
couldn't do from within the WinMain which is where all of your
code is now.
I think that the easiest solution is to send the first instance
a WM_COPYDATA message just before you send it the
SINGLE_INSTANCE_RESTORE_MESSAGE.
That way the component will still be generic enough to work
with other apps and all you have to do in your app is
something like:
protected: // User declarations
virtual void __fastcall WndProc( TMessage &Message );
private: // User declarations
char *Buffer;
void __fastcall AppActivate( TObject* );
public: // User declarations
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
Buffer = NULL;
Application->OnActivate = AppActivate;
}
//-------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
if( Buffer )
{
delete [] Buffer;
}
}
//-------------------------------------------------------------
void __fastcall TForm1::AppActivate(TObject *Sender)
{
if( Buffer )
{
// do something with Buffer
delete [] Buffer;
Buffer = NULL;
}
}
//-------------------------------------------------------------
void __fastcall TForm1::WndProc(TMessage &Message)
{
if( Message.Msg == WM_COPYDATA )
{
COPYDATASTRUCT *CDS = reinterpret_cast<COPYDATASTRUCT*>( Message.LParam );
if( CDS->lpData )
{
Buffer = new char[ CDS->cbData + 1 ];
strncpy( Buffer, CDS->lpData, CDS->cbData );
}
}
}
//-------------------------------------------------------------
~ JD
{smallsort}