Article View: borland.public.cppbuilder.nativeapi
Article #4236Re: PostMessage not being received
From: JD
Date: Sat, 25 Feb 2006 06:37
Date: Sat, 25 Feb 2006 06:37
207 lines
8821 bytes
8821 bytes
Nate Lockwood <RNLockwoodREMOVE@attglobal.net> wrote:
>After determining that there is another instance of the application
>running I try to post a message but I'm not receiving it.
I wrote TSingleInstance which is a component that does all of
that for you. Just drop it on the main form or dynamically
allocate it in the main form's ctor.
The only thing that you need to do to make it work is to give
the main form a unique name (because that's how it finds the
first instance). Something like CompanyNameApplicationName:
//-------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//-------------------------------------------------------------
#include <Classes.hpp>
//-------------------------------------------------------------
class TSingleInstance : public TComponent
{
private:
bool FMinimized,
FMainWindowHooked;
HANDLE hMutex;
HWND FHandle;
HHOOK FMainThreadHook;
UINT SI_RESTORE,
SI_INITIALIZE;
TForm* FParentForm;
protected:
bool __fastcall MainWindowHook( TMessage &Message );
virtual void __fastcall WndProc( TMessage &Message );
static int __stdcall MainThreadWndProcRetHook( int Code, WPARAM WParam, LPARAM LParam );
public:
__fastcall TSingleInstance(TComponent* Owner);
__fastcall ~TSingleInstance();
__published:
};
//-------------------------------------------------------------
#endif
//-------------------------------------------------------------
#include <vcl.h>
#include <basepch.h>
//-------------------------------------------------------------
#pragma hdrstop
//-------------------------------------------------------------
#include "Unit2.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)
{
FParentForm = dynamic_cast<TForm*>(Owner);
if( !Owner )
{
throw Exception("TSingleInstance : You must assign an Owner.");
}
if( !FParentForm )
{
throw Exception("TSingleInstance : The Owner must be a TForm.");
}
if( ThisSingleInstance )
{
throw Exception("TSingleInstance : Only one instance of TSingleInstance is allowed per application.");
}
hMutex = NULL;
FHandle = NULL;
FMainThreadHook = NULL;
FMainWindowHooked = false;
ThisSingleInstance = this;
if( !ComponentState.Contains(csDesigning) )
{
char ThisClassName[ 256 ] = { 0 };
SI_RESTORE = ::RegisterWindowMessage( "TSingleInstanceRestoreMessage" );
SI_INITIALIZE = ::RegisterWindowMessage( "TSingleInstanceInitializeMessage" );
if( ! SI_RESTORE || ! SI_INITIALIZE )
{
throw Exception("TSingleInstance : RegisterWindowMessage failed.");
}
::GetClassName( FParentForm->Handle, ThisClassName, 255 );
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_RESTORE, 0, 0 );
::SetForegroundWindow( hFirstInstance );
Application->Terminate();
}
else
{
// Need to monitor main form window state
Application->HookMainWindow( MainWindowHook );
FMainWindowHooked = true;
// To catch messages sent to the HWND found by the above win32 API EnumWindows
FMainThreadHook = ::SetWindowsHookEx( WH_CALLWNDPROCRET, (int (__stdcall*)())MainThreadWndProcRetHook, HInstance, ::GetCurrentThreadId() );
if( !FMainThreadHook )
{
throw Exception("TSingleInstance : Hooking Main Thread failed.");
}
// Still need some final initialization but it needs to be delayed until Application::MainForm is valid.
FHandle = AllocateHWnd( WndProc );
if( !FHandle )
{
throw Exception("TSingleInstance : AllocateHWnd failed.");
}
::PostMessage( FHandle, SI_INITIALIZE, 0, 0 );
}
}
}
//-------------------------------------------------------------
__fastcall TSingleInstance::~TSingleInstance()
{
if( FHandle ) DeallocateHWnd( FHandle );
if( FMainWindowHooked ) Application->UnhookMainWindow( MainWindowHook );
if( FMainThreadHook ) ::UnhookWindowsHookEx( FMainThreadHook );
if( hMutex ) ::CloseHandle( hMutex );
ThisSingleInstance = NULL;
}
//-------------------------------------------------------------
void __fastcall TSingleInstance::WndProc( TMessage &Message )
{
if( Message.Msg == SI_INITIALIZE )
{
if( FParentForm != Application->MainForm )
{
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;
}
}
Message.Result = DefWindowProc( FHandle, Message.Msg, Message.WParam, Message.LParam );
}
//-------------------------------------------------------------
bool __fastcall TSingleInstance::MainWindowHook( TMessage &Message )
{
if( Message.Msg == WM_SYSCOMMAND )
{
switch( Message.WParam )
{
case SC_RESTORE:
case SC_MAXIMIZE: FMinimized = false; break;
case SC_MINIMIZE: FMinimized = true;
}
}
return false;
}
//-------------------------------------------------------------
int __stdcall TSingleInstance::MainThreadWndProcRetHook( int Code, WPARAM WParam, LPARAM LParam )
{
if( Code == HC_ACTION )
{
CWPRETSTRUCT* cwp = (CWPRETSTRUCT *) LParam;
if( cwp->message == ThisSingleInstance->SI_RESTORE )
{
if( ThisSingleInstance->FMinimized )
{
::SendMessage( Application->Handle, WM_SYSCOMMAND, SC_RESTORE, 0 );
}
}
}
return ::CallNextHookEx( ThisSingleInstance->FMainThreadHook, Code, WParam, LParam );
}
//-------------------------------------------------------------
~ JD
Technical Details
Message-ID:
<4400091f$1@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news4.google.com!news.glorb.com!newsgate.cistron.nl!feeder.enertel.nl!nntpfeed-01.ops.asmr-01.energis-idc.net!216.196.110.149.MISMATCH!border2.nntp.ams.giganews.com!nntp.giganews.com!newsfeeder.wxs.nl!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailReferences:
<43ff8a0d$1@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,3775f67446cfe781 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: PostMessage not being received Newsgroups: borland.public.cppbuilder.nativeapi X-User-Info: 205.188.116.136 X-Forwarded-For: 172.138.253.193 References: <43ff8a0d$1@newsgroups.borland.com> NNTP-Posting-Host: 207.105.83.66 Message-ID: <4400091f$1@newsgroups.borland.com> Date: 24 Feb 2006 23:37:03 -0700 X-Trace: newsgroups.borland.com 1140853023 207.105.83.66 (24 Feb 2006 23:37:03 -0700) Lines: 208 Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news4.google.com!news.glorb.com!newsgate.cistron.nl!feeder.enertel.nl!nntpfeed-01.ops.asmr-01.energis-idc.net!216.196.110.149.MISMATCH!border2.nntp.ams.giganews.com!nntp.giganews.com!newsfeeder.wxs.nl!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail