🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #4236

Re: PostMessage not being received

#4236
From: JD
Date: Sat, 25 Feb 2006 06:37
207 lines
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-mail
References: <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