Article View: borland.public.cppbuilder.nativeapi
Article #6017Re: kill process?
From: JD
Date: Sat, 18 Jun 2005 19:27
Date: Sat, 18 Jun 2005 19:27
192 lines
8967 bytes
8967 bytes
"Ron Eggler @ work" <nospam@hotmail.com> wrote:
>
> [...] I moved that code in the WinMain()
The problem with this implemetation, you have to edit the
WinMain and override the main form's WndProc method everytime
you want to use it.
Below is a class that you can convert into a component that
you drop onto the main form or you can simply add the class to
your project and dynamically allocate an instance of it at run
time.
The only thing that the class needs is that your main form
has a unique name so that it doesn't get confused with other
applications so name the main form something like
CompanyNameApplicationName.
If you don't like that idea, then examine the code and use it
to figure out how to modify the WinMain:
//-------------------------------------------------------------
#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 )
{
//::ShowWindow( Application->Handle, SW_HIDE );
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
Technical Details
Message-ID:
<42b4758c$1@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news.glorb.com!border1.nntp.dca.giganews.com!border2.nntp.dca.giganews.com!nntp.giganews.com!meganewsservers.com!feeder2.on.meganewsservers.com!news-out.newsgroups.com!propagator2-sterling.newsfeeds.com!in.nntp.be!caladan.landsraad.net!newsgroups.borland.com!not-for-mailReferences:
<42b02536$1@newsgroups.borland.com> <42b1635a@newsgroups.borland.com> <42b184e4@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,d9980975a6334c47 X-Google-Attributes: gid10cc67,public X-Google-Language: ENGLISH,ASCII-7-bit From: "JD" <nospam@nospam.com> Sender: "JD" <nospam@nospam.com> Reply-To: "JD" <nospam@nospam.com> Subject: Re: kill process? Newsgroups: borland.public.cppbuilder.nativeapi X-User-Info: 205.188.116.135 X-Forwarded-For: 172.135.47.49 References: <42b02536$1@newsgroups.borland.com> <42b1635a@newsgroups.borland.com> <42b184e4@newsgroups.borland.com> NNTP-Posting-Host: 207.105.83.66 Message-ID: <42b4758c$1@newsgroups.borland.com> Date: 18 Jun 2005 12:27:08 -0700 X-Trace: newsgroups.borland.com 1119122828 207.105.83.66 (18 Jun 2005 12:27:08 -0700) Lines: 193 Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news.glorb.com!border1.nntp.dca.giganews.com!border2.nntp.dca.giganews.com!nntp.giganews.com!meganewsservers.com!feeder2.on.meganewsservers.com!news-out.newsgroups.com!propagator2-sterling.newsfeeds.com!in.nntp.be!caladan.landsraad.net!newsgroups.borland.com!not-for-mail