Board index » delphi » 'nother little window-question (One Instance)

'nother little window-question (One Instance)

I'm using the TMainInstance component to make sure only one instance of my
program is running, if a second was to be started it would send the main
instance a message with the params the user started the second instance
with. This works fine. Only when the main instances mainform is hidden (I
hide it OnMinimize) the second instance doesn't start (which is good!), but
the message isn't sent (or the maininstance doesn't receive, I'm not
sure)...now first I thought the problem was that the mainwindow was hidden,
so I removed the 'Form1.Hide (OnMinimize)', but still, no message was
received by the maininstance when the window was minimized, but it was when
the maininstance was in 'normal' mode...can anyone help me with this? This
is the components source code, its freeware:

//   original system: PBJustOne by Patrick Brisacier
(PBrisac...@mail.dotcom.fr)
//   using of Atom: Ken Hale and Coda Hale (kenh...@dcalcoda.com)
//   DCR contained bitmap: Troels S Eriksen (TSEri...@post8.tele.dk)
//   assembler: Paul Sitkei(sit...@elender.hu)

unit MainInstance;

interface

uses
  Windows, Messages, SysUtils, Classes, Forms;

type
  TMainInstance = class(TComponent)
  public
    constructor Create(aOwner: TComponent); override;
  end;

const wmMainInstanceOpenFile = WM_USER+ 101;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TMainInstance]);
end;

var
  MyAppName, MyClassName: array[0..255] of Char;
  NumFound: Integer;
  LastFound, MyPopup: HWND;

function LookAtAllWindows(Handle: HWND; Temp: LongInt): BOOL; stdcall;
var
  WindowName, ClassName: Array[0..255] of Char;
begin
  if (GetClassName(Handle, ClassName, SizeOf(ClassName)) > 0) and
     (StrComp(ClassName, MyClassName) = 0) and
     (GetWindowText(Handle, WindowName, SizeOf(WindowName)) > 0) and
     (StrComp(WindowName, MyAppName) = 0) then
  begin
    Inc(NumFound);
    if Handle <> Application.Handle then LastFound := Handle;
  end;
  Result:= True;
end;

function SendParam(aHandle: hWND): Boolean;
var S: String;
    i: Integer;
    Atom: tAtom;
begin
  Result:= False;
  S:= '';
  for i:= 1 to ParamCount do
  begin
    S:= S+ ParamStr(i)+ ' ';
    if Pos('.EXE', UpperCase(S))<>0 then S:= '';
  end;
  if S='' then Exit;
  Atom := GlobalAddAtom(PChar(S));
  SendMessage(aHandle, wmMainInstanceOpenFile, Atom, 0);
  GlobalDeleteAtom(Atom);
  Result:= True;
end;

constructor TMainInstance.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  NumFound := 0;
  LastFound := 0;
  GetWindowText(Application.Handle, MyAppName, SizeOf(MyAppName));
  GetClassName(Application.Handle, MyClassName, SizeOf(MyClassName));
  EnumWindows(@LookAtAllWindows, 0);
  if NumFound> 1 then
  begin
    MyPopup := GetLastActivePopup(LastFound);
    SendParam(MyPopup);
    BringWindowToTop(LastFound);
    if IsIconic(MyPopup)
      then ShowWindow(MyPopup, SW_RESTORE) // this part IS working when the
maininstance is minimized or hidden even
      else SetForegroundWindow(MyPopup);
    Halt;
  end
end;

end.

 

Re:'nother little window-question (One Instance)


This seems a slightly iffy way of doing things
- also the code seems incomplete

Notice how the 'parameters' are not sent if they contain '.EXE' or
nothing - bizarre

Also using WM_USER + 101 is a bit lax, when it could use
RegisterWindowMessage

Mutexes are also handy for determining whether something else is alive

In addition it should be the responsibility of the original instance
to make itself visible - not the second instance

Realistically a couple of ShowMessage statements should show you what
is going on

Some time ago I wrote something with similar functionality, but a
rather different approach, if you decide not to go with this, I can
post the code.

Quote
On Fri, 27 Jun 2003 13:00:34 +0200, "Jonathan" <a...@b.com> wrote:
>I'm using the TMainInstance component to make sure only one instance of my
>program is running, if a second was to be started it would send the main
>instance a message with the params the user started the second instance
>with. This works fine. Only when the main instances mainform is hidden (I
>hide it OnMinimize) the second instance doesn't start (which is good!), but
>the message isn't sent (or the maininstance doesn't receive, I'm not
>sure)...now first I thought the problem was that the mainwindow was hidden,
>so I removed the 'Form1.Hide (OnMinimize)', but still, no message was
>received by the maininstance when the window was minimized, but it was when
>the maininstance was in 'normal' mode...can anyone help me with this? This
>is the components source code, its freeware:

>//   original system: PBJustOne by Patrick Brisacier
>(PBrisac...@mail.dotcom.fr)
>//   using of Atom: Ken Hale and Coda Hale (kenh...@dcalcoda.com)
>//   DCR contained bitmap: Troels S Eriksen (TSEri...@post8.tele.dk)
>//   assembler: Paul Sitkei(sit...@elender.hu)

>unit MainInstance;

>interface

>uses
>  Windows, Messages, SysUtils, Classes, Forms;

>type
>  TMainInstance = class(TComponent)
>  public
>    constructor Create(aOwner: TComponent); override;
>  end;

>const wmMainInstanceOpenFile = WM_USER+ 101;

>procedure Register;

>implementation

>procedure Register;
>begin
>  RegisterComponents('Samples', [TMainInstance]);
>end;

>var
>  MyAppName, MyClassName: array[0..255] of Char;
>  NumFound: Integer;
>  LastFound, MyPopup: HWND;

>function LookAtAllWindows(Handle: HWND; Temp: LongInt): BOOL; stdcall;
>var
>  WindowName, ClassName: Array[0..255] of Char;
>begin
>  if (GetClassName(Handle, ClassName, SizeOf(ClassName)) > 0) and
>     (StrComp(ClassName, MyClassName) = 0) and
>     (GetWindowText(Handle, WindowName, SizeOf(WindowName)) > 0) and
>     (StrComp(WindowName, MyAppName) = 0) then
>  begin
>    Inc(NumFound);
>    if Handle <> Application.Handle then LastFound := Handle;
>  end;
>  Result:= True;
>end;

>function SendParam(aHandle: hWND): Boolean;
>var S: String;
>    i: Integer;
>    Atom: tAtom;
>begin
>  Result:= False;
>  S:= '';
>  for i:= 1 to ParamCount do
>  begin
>    S:= S+ ParamStr(i)+ ' ';
>    if Pos('.EXE', UpperCase(S))<>0 then S:= '';
>  end;
>  if S='' then Exit;
>  Atom := GlobalAddAtom(PChar(S));
>  SendMessage(aHandle, wmMainInstanceOpenFile, Atom, 0);
>  GlobalDeleteAtom(Atom);
>  Result:= True;
>end;

>constructor TMainInstance.Create(aOwner: TComponent);
>begin
>  inherited Create(aOwner);
>  NumFound := 0;
>  LastFound := 0;
>  GetWindowText(Application.Handle, MyAppName, SizeOf(MyAppName));
>  GetClassName(Application.Handle, MyClassName, SizeOf(MyClassName));
>  EnumWindows(@LookAtAllWindows, 0);
>  if NumFound> 1 then
>  begin
>    MyPopup := GetLastActivePopup(LastFound);
>    SendParam(MyPopup);
>    BringWindowToTop(LastFound);
>    if IsIconic(MyPopup)
>      then ShowWindow(MyPopup, SW_RESTORE) // this part IS working when the
>maininstance is minimized or hidden even
>      else SetForegroundWindow(MyPopup);
>    Halt;
>  end
>end;

>end.

Re:'nother little window-question (One Instance)


hey thanks for your input,
although I don't think I know as much about it as do you, I noticed it was a
weird (and maybe imcomplete) source code; I tried the Mutex thing but it
didn't work, so I'm gonna now try to find the problem myself, if that
doesn't work, I'd really like your code...!

Quote
"J French" <Bounce_It_je...@iss.u-net.com_.bin> wrote in message

news:3efc343d.17059671@news.btclick.com...
Quote
> This seems a slightly iffy way of doing things
> - also the code seems incomplete

> Notice how the 'parameters' are not sent if they contain '.EXE' or
> nothing - bizarre

> Also using WM_USER + 101 is a bit lax, when it could use
> RegisterWindowMessage

> Mutexes are also handy for determining whether something else is alive

> In addition it should be the responsibility of the original instance
> to make itself visible - not the second instance

> Realistically a couple of ShowMessage statements should show you what
> is going on

> Some time ago I wrote something with similar functionality, but a
> rather different approach, if you decide not to go with this, I can
> post the code.

> On Fri, 27 Jun 2003 13:00:34 +0200, "Jonathan" <a...@b.com> wrote:

> >I'm using the TMainInstance component to make sure only one instance of
my
> >program is running, if a second was to be started it would send the main
> >instance a message with the params the user started the second instance
> >with. This works fine. Only when the main instances mainform is hidden (I
> >hide it OnMinimize) the second instance doesn't start (which is good!),
but
> >the message isn't sent (or the maininstance doesn't receive, I'm not
> >sure)...now first I thought the problem was that the mainwindow was
hidden,
> >so I removed the 'Form1.Hide (OnMinimize)', but still, no message was
> >received by the maininstance when the window was minimized, but it was
when
> >the maininstance was in 'normal' mode...can anyone help me with this?
This
> >is the components source code, its freeware:

> >//   original system: PBJustOne by Patrick Brisacier
> >(PBrisac...@mail.dotcom.fr)
> >//   using of Atom: Ken Hale and Coda Hale (kenh...@dcalcoda.com)
> >//   DCR contained bitmap: Troels S Eriksen (TSEri...@post8.tele.dk)
> >//   assembler: Paul Sitkei(sit...@elender.hu)

> >unit MainInstance;

> >interface

> >uses
> >  Windows, Messages, SysUtils, Classes, Forms;

> >type
> >  TMainInstance = class(TComponent)
> >  public
> >    constructor Create(aOwner: TComponent); override;
> >  end;

> >const wmMainInstanceOpenFile = WM_USER+ 101;

> >procedure Register;

> >implementation

> >procedure Register;
> >begin
> >  RegisterComponents('Samples', [TMainInstance]);
> >end;

> >var
> >  MyAppName, MyClassName: array[0..255] of Char;
> >  NumFound: Integer;
> >  LastFound, MyPopup: HWND;

> >function LookAtAllWindows(Handle: HWND; Temp: LongInt): BOOL; stdcall;
> >var
> >  WindowName, ClassName: Array[0..255] of Char;
> >begin
> >  if (GetClassName(Handle, ClassName, SizeOf(ClassName)) > 0) and
> >     (StrComp(ClassName, MyClassName) = 0) and
> >     (GetWindowText(Handle, WindowName, SizeOf(WindowName)) > 0) and
> >     (StrComp(WindowName, MyAppName) = 0) then
> >  begin
> >    Inc(NumFound);
> >    if Handle <> Application.Handle then LastFound := Handle;
> >  end;
> >  Result:= True;
> >end;

> >function SendParam(aHandle: hWND): Boolean;
> >var S: String;
> >    i: Integer;
> >    Atom: tAtom;
> >begin
> >  Result:= False;
> >  S:= '';
> >  for i:= 1 to ParamCount do
> >  begin
> >    S:= S+ ParamStr(i)+ ' ';
> >    if Pos('.EXE', UpperCase(S))<>0 then S:= '';
> >  end;
> >  if S='' then Exit;
> >  Atom := GlobalAddAtom(PChar(S));
> >  SendMessage(aHandle, wmMainInstanceOpenFile, Atom, 0);
> >  GlobalDeleteAtom(Atom);
> >  Result:= True;
> >end;

> >constructor TMainInstance.Create(aOwner: TComponent);
> >begin
> >  inherited Create(aOwner);
> >  NumFound := 0;
> >  LastFound := 0;
> >  GetWindowText(Application.Handle, MyAppName, SizeOf(MyAppName));
> >  GetClassName(Application.Handle, MyClassName, SizeOf(MyClassName));
> >  EnumWindows(@LookAtAllWindows, 0);
> >  if NumFound> 1 then
> >  begin
> >    MyPopup := GetLastActivePopup(LastFound);
> >    SendParam(MyPopup);
> >    BringWindowToTop(LastFound);
> >    if IsIconic(MyPopup)
> >      then ShowWindow(MyPopup, SW_RESTORE) // this part IS working when
the
> >maininstance is minimized or hidden even
> >      else SetForegroundWindow(MyPopup);
> >    Halt;
> >  end
> >end;

> >end.

Re:'nother little window-question (One Instance)


Quote
On Fri, 27 Jun 2003 14:46:34 +0200, "Jonathan" <a...@b.com> wrote:
>hey thanks for your input,
>although I don't think I know as much about it as do you, I noticed it was a
>weird (and maybe imcomplete) source code; I tried the Mutex thing but it
>didn't work, so I'm gonna now try to find the problem myself, if that
>doesn't work, I'd really like your code...!

Maybe this will give you some ideas :-

unit BroadCast;

interface
(*   10/3/01  JF
     Usage:
         BroadCast.Install( Self.Handle,
                           'UNIQUE_ID',
                           @Notify )

         RecipientCount := BroadCast.SendString( 'Hullo' )

         If Notify is Called :-
            StringReceived := Broadcast.ReceiveString

*)

Uses Windows, Messages, Classes;

Type
  TNotify = Procedure;StdCall;
  TAppWinHook = Function( Var WindowHandle:hWnd;
                          Var TheMessage,
                          ParamW,
                          ParamL:Integer ):Integer;StdCall;

// Exposed Procedures
Procedure Install( Const App_HandleIn:Integer;
                   Const AppID_StringIn:String;
                   Const Address:TNotify );
Procedure SetAppWinHook( Const Address:TAppWinHook );
Function SendString( Const SendString:String ):Integer ;
Procedure UnInstall ;

// Exposed Variables
Var
ReceiveString : String ; // Public - The String from Another App

implementation

Const DEMAND_REPLY = 1 ;
Const NOTIFY_STRING_READY = 2 ;
Const REQUEST_DATA = 4 ;

Const STRING_FLAG = 140956 ;         // A rather unique number

var
  WM_ID : Integer = 0 ;              // Unique Windows Message ID
  App_Handle : Integer ;             // Form.hWnd or
Application.Handle
  AppID_String : String ;            // Application.ExeName is Ok
  FNotify : TNotify = Nil ;          // The Callback Notification
Address

  AppWinHook : TAppWinHook = Nil;    // Users Hook Callback

  HookedFlag : Boolean = False ;
  OldWindowProc : Pointer;
  Prev_HandleCount : Integer ;
  LocalSendString : String ;

  DebugFlag : Boolean = False ;

Procedure HookWindows;Forward;
Procedure UnHookWindows;Forward;
Procedure LS_ErrorMsg( Msg:String );Forward;

{
########################################################################

Quote
}

Procedure Install( Const App_HandleIn:Integer;
                   Const AppID_StringIn:String;
                   Const Address:TNotify );
  Begin

  If HookedFlag Then
     Begin
     LS_ErrorMsg( 'BroadCast.Install Error - Already Installed' ) ;
  End;

  AppID_String := AppID_StringIn ;
  App_Handle := App_HandleIn ;
  FNotify := @Address ;
  HookWindows ;
End;

{
########################################################################

Quote
}

Procedure SetAppWinHook( Const Address:TAppWinHook );
  Begin
  AppWinHook := @Address ;
End; {SetAppWinHook}

{
########################################################################

  Public Routine for Despatch

Quote
}

Function SendString( Const SendString:String ):Integer ;
  Begin

  LocalSendString := SendString ;  // We MUST make a Local Copy

  Prev_HandleCount := 0 ;
  SendMessage( HWND_BROADCAST, WM_ID, App_Handle, DEMAND_REPLY ) ;
  Result := Prev_HandleCount

End; {SendString}

{
########################################################################

Quote
}

Procedure UnInstall;
  Begin
  If HookedFlag = False Then
     Begin
     LS_ErrorMsg( 'BroadCast.InInstall Error - Not Installed' ) ;
     Exit;
  End;
  UnHookWindows ;
End; {UnInstall}

{
########################################################################

  Despatch Data to a Target App - in response to a REQUEST_DATA

Quote
}

Procedure LS_DespatchData( Const ParamW:Integer );
  Var
  P : Integer ;
  Packet : COPYDATASTRUCT ;
  Begin

  Packet.dwData := STRING_FLAG ;
  Packet.cbData := Length( LocalSendString ) ;
  Packet.lpData := @LocalSendString[1] ;

  P := Integer( ( @Packet ) ) ;
  {Send the Data - this blocks our thread}
  SendMessage( ParamW, WM_COPYDATA, App_Handle, P ) ;

  {Now notify the recipient - this is non-blocking}
  PostMessage( ParamW, WM_ID, App_Handle, NOTIFY_STRING_READY )

End; {LS_DespatchData}

{
########################################################################

  Read Data from another App  in response to a  WM_COPYDATA  message

Quote
}

Procedure LS_ReceiveData( Const ParamL:Integer );
  Type Packet = COPYDATASTRUCT ;
  Var
  P : ^Packet ;
  L9 : Integer ;
  Begin

  P := Pointer( ParamL ) ;
  // Sanity Checks
  If P^.dwData <> STRING_FLAG Then
     Begin
     LS_ErrorMsg( 'WM_COPYDATA - Bad Packet Type' ) ;
     Exit;
  End;

  If Integer( P^.cbData ) < 0 Then
     Begin
     LS_ErrorMsg( 'WM_COPYDATA - Bad Packet String Length' ) ;
     Exit;
  End;

  // So we are able to Get the Data
  SetLength( ReceiveString, P^.cbData ) ;

  For L9 := 1 To P^.cbData Do
      ReceiveString[L9] := PChar( P^.lpData )[L9-1]  ;

End; {LS_ReceiveData}

{
########################################################################

Quote
}

Procedure LS_ErrorMsg( Msg:String );
  Begin
  MessageBox( App_Handle,
                  PChar( ParamStr(0) + #13
                  + Msg ) ,
                  'Unit SendStrA', 0 ) ;

End; {LS_ErrorMsg}

{
########################################################################

  Windows Hook

Quote
}

function NewWindowProc(WindowHandle : hWnd;
                       TheMessage   : Integer;
                       ParamW       : Integer;
                       ParamL       : Integer  ) : Integer ; StdCall;
Export;
  begin

  { Message Handler -  WindowHandle is Target ID - Us or Broadcast
                       WM_ID        is Unique to this App
                       ParamW       is Possibly Callers ID / Maybe Our
Own
                       ParamL       our User Message
   }
  If Assigned( AppWinHook ) Then
     Begin
     If AppWinHook( WindowHandle, TheMessage, ParamW, ParamL ) <> 0
Then
        Begin
        Result := 0 ;  // The Caller decided to handle it
        Exit;
     End;
  End;

  If TheMessage = WM_ID then
     Begin

     {Message 1 - a Broadcast message - get out if it is from us }
     If ParamW = Integer( App_Handle ) Then   // It is Ourselves
        Begin
        Result := 0 ;
        Exit;
     End;

     {Message 2 - a Broadcast Message - from new instance OR Demanding
a reply}
     If ( ParamL = DEMAND_REPLY ) Then   // A new Notifier
        Begin
        SendMessage( ParamW, WM_ID, App_Handle, REQUEST_DATA ) ;
        Result := 0 ;
        Exit;
     End;

     {Message 3 - we have already got a string - notify our App}
     If ParamL = NOTIFY_STRING_READY Then       // the sender has sent
us a string
        Begin
        If Assigned( FNotify ) Then
           FNotify ;
        Result := 0 ;
        Exit;
     End;

     {Message 4 - Another Instance Requests the Data }
     If ( ParamL = REQUEST_DATA ) Then
        Begin
        Prev_HandleCount := Prev_HandleCount + 1 ;      // Remember
and reply
        LS_DespatchData( ParamW );
        Result := 0 ;
        Exit;
     End;

  End;

  { Copy Data Handler - Receive the Data }
  If TheMessage = WM_COPYDATA then
     Begin
     LS_ReceiveData( ParamL );
     Result := 0 ;
     Exit;
  End;

  { Exit here and return zero if you want     }
  { to stop further processing of the message }

  { Call the old Window procedure to }
  { allow processing of the message. }
  NewWindowProc := CallWindowProc(OldWindowProc,
                                  WindowHandle,
                                  TheMessage,
                                  ParamW,
                                  ParamL);

End; {NewWindowProc}

{
########################################################################

Quote
}

Procedure HookWindows;
  Begin
  If HookedFlag Then
     Exit;
  If App_Handle = 0 Then
     Exit;

  WM_ID := RegisterWindowMessage( PChar( AppID_String ) );
  SetLastError( 0 ) ;                   // Clear Last Error
  OldWindowProc := Pointer(SetWindowLong( App_Handle,
                                          GWL_WNDPROC,
                                          Integer(@NewWindowProc)));
  If Integer( OldWindowProc ) = 0 Then  // Maybe no prior hook or
Error
     Begin
     If GetLastError <> 0 Then          // Was it really an Error
        Begin
        LS_ErrorMsg( 'SetWindowLong Failed' ) ;
        Exit;
     End;
  End;
  HookedFlag := True ;
End; {HookWindows}

{
########################################################################

Quote
}

Procedure UnHookWindows;
  Begin
  If HookedFlag Then
     Begin
     SetWindowLong( App_Handle,
                    GWL_WNDPROC,
                    LongInt(OldWindowProc));
     App_Handle := 0 ;
     HookedFlag := False ;
  End;
End; {UnHookWindows}

{
########################################################################

Quote
}

Initialization
  If DebugFlag Then
     LS_ErrorMsg( 'DLL Initialization' ) ;

  HookWindows ;      // This will do nothing

Finalization
  UnHookWindows ;
  If DebugFlag Then
     LS_ErrorMsg( 'DLL Finalization' ) ;

end.

Re:'nother little window-question (One Instance)


thanks for the code,
could you help me with it?
how exactly should I set up my application so that only on instance can run
and the second instance will send its parameters to the first?

Quote
"J French" <Bounce_It_je...@iss.u-net.com_.bin> wrote in message

news:3efc3e51.19639856@news.btclick.com...
Quote
> On Fri, 27 Jun 2003 14:46:34 +0200, "Jonathan" <a...@b.com> wrote:

> >hey thanks for your input,
> >although I don't think I know as much about it as do you, I noticed it
was a
> >weird (and maybe imcomplete) source code; I tried the Mutex thing but it
> >didn't work, so I'm gonna now try to find the problem myself, if that
> >doesn't work, I'd really like your code...!

> Maybe this will give you some ideas :-

> unit BroadCast;

> interface
> (*   10/3/01  JF
>      Usage:
>          BroadCast.Install( Self.Handle,
>                            'UNIQUE_ID',
>                            @Notify )

>          RecipientCount := BroadCast.SendString( 'Hullo' )

>          If Notify is Called :-
>             StringReceived := Broadcast.ReceiveString

> *)

> Uses Windows, Messages, Classes;

> Type
>   TNotify = Procedure;StdCall;
>   TAppWinHook = Function( Var WindowHandle:hWnd;
>                           Var TheMessage,
>                           ParamW,
>                           ParamL:Integer ):Integer;StdCall;

> // Exposed Procedures
> Procedure Install( Const App_HandleIn:Integer;
>                    Const AppID_StringIn:String;
>                    Const Address:TNotify );
> Procedure SetAppWinHook( Const Address:TAppWinHook );
> Function SendString( Const SendString:String ):Integer ;
> Procedure UnInstall ;

> // Exposed Variables
> Var
> ReceiveString : String ; // Public - The String from Another App

> implementation

> Const DEMAND_REPLY = 1 ;
> Const NOTIFY_STRING_READY = 2 ;
> Const REQUEST_DATA = 4 ;

> Const STRING_FLAG = 140956 ;         // A rather unique number

> var
>   WM_ID : Integer = 0 ;              // Unique Windows Message ID
>   App_Handle : Integer ;             // Form.hWnd or
> Application.Handle
>   AppID_String : String ;            // Application.ExeName is Ok
>   FNotify : TNotify = Nil ;          // The Callback Notification
> Address

>   AppWinHook : TAppWinHook = Nil;    // Users Hook Callback

>   HookedFlag : Boolean = False ;
>   OldWindowProc : Pointer;
>   Prev_HandleCount : Integer ;
>   LocalSendString : String ;

>   DebugFlag : Boolean = False ;

> Procedure HookWindows;Forward;
> Procedure UnHookWindows;Forward;
> Procedure LS_ErrorMsg( Msg:String );Forward;

> {
> ########################################################################

> }
> Procedure Install( Const App_HandleIn:Integer;
>                    Const AppID_StringIn:String;
>                    Const Address:TNotify );
>   Begin

>   If HookedFlag Then
>      Begin
>      LS_ErrorMsg( 'BroadCast.Install Error - Already Installed' ) ;
>   End;

>   AppID_String := AppID_StringIn ;
>   App_Handle := App_HandleIn ;
>   FNotify := @Address ;
>   HookWindows ;
> End;

> {
> ########################################################################

> }
> Procedure SetAppWinHook( Const Address:TAppWinHook );
>   Begin
>   AppWinHook := @Address ;
> End; {SetAppWinHook}

> {
> ########################################################################

>   Public Routine for Despatch
> }
> Function SendString( Const SendString:String ):Integer ;
>   Begin

>   LocalSendString := SendString ;  // We MUST make a Local Copy

>   Prev_HandleCount := 0 ;
>   SendMessage( HWND_BROADCAST, WM_ID, App_Handle, DEMAND_REPLY ) ;
>   Result := Prev_HandleCount

> End; {SendString}

> {
> ########################################################################

> }
> Procedure UnInstall;
>   Begin
>   If HookedFlag = False Then
>      Begin
>      LS_ErrorMsg( 'BroadCast.InInstall Error - Not Installed' ) ;
>      Exit;
>   End;
>   UnHookWindows ;
> End; {UnInstall}

> {
> ########################################################################

>   Despatch Data to a Target App - in response to a REQUEST_DATA
> }
> Procedure LS_DespatchData( Const ParamW:Integer );
>   Var
>   P : Integer ;
>   Packet : COPYDATASTRUCT ;
>   Begin

>   Packet.dwData := STRING_FLAG ;
>   Packet.cbData := Length( LocalSendString ) ;
>   Packet.lpData := @LocalSendString[1] ;

>   P := Integer( ( @Packet ) ) ;
>   {Send the Data - this blocks our thread}
>   SendMessage( ParamW, WM_COPYDATA, App_Handle, P ) ;

>   {Now notify the recipient - this is non-blocking}
>   PostMessage( ParamW, WM_ID, App_Handle, NOTIFY_STRING_READY )

> End; {LS_DespatchData}

> {
> ########################################################################

>   Read Data from another App  in response to a  WM_COPYDATA  message
> }
> Procedure LS_ReceiveData( Const ParamL:Integer );
>   Type Packet = COPYDATASTRUCT ;
>   Var
>   P : ^Packet ;
>   L9 : Integer ;
>   Begin

>   P := Pointer( ParamL ) ;
>   // Sanity Checks
>   If P^.dwData <> STRING_FLAG Then
>      Begin
>      LS_ErrorMsg( 'WM_COPYDATA - Bad Packet Type' ) ;
>      Exit;
>   End;

>   If Integer( P^.cbData ) < 0 Then
>      Begin
>      LS_ErrorMsg( 'WM_COPYDATA - Bad Packet String Length' ) ;
>      Exit;
>   End;

>   // So we are able to Get the Data
>   SetLength( ReceiveString, P^.cbData ) ;

>   For L9 := 1 To P^.cbData Do
>       ReceiveString[L9] := PChar( P^.lpData )[L9-1]  ;

> End; {LS_ReceiveData}

> {
> ########################################################################

> }
> Procedure LS_ErrorMsg( Msg:String );
>   Begin
>   MessageBox( App_Handle,
>                   PChar( ParamStr(0) + #13
>                   + Msg ) ,
>                   'Unit SendStrA', 0 ) ;

> End; {LS_ErrorMsg}

> {
> ########################################################################

>   Windows Hook
> }
> function NewWindowProc(WindowHandle : hWnd;
>                        TheMessage   : Integer;
>                        ParamW       : Integer;
>                        ParamL       : Integer  ) : Integer ; StdCall;
> Export;
>   begin

>   { Message Handler -  WindowHandle is Target ID - Us or Broadcast
>                        WM_ID        is Unique to this App
>                        ParamW       is Possibly Callers ID / Maybe Our
> Own
>                        ParamL       our User Message
>    }
>   If Assigned( AppWinHook ) Then
>      Begin
>      If AppWinHook( WindowHandle, TheMessage, ParamW, ParamL ) <> 0
> Then
>         Begin
>         Result := 0 ;  // The Caller decided to handle it
>         Exit;
>      End;
>   End;

>   If TheMessage = WM_ID then
>      Begin

>      {Message 1 - a Broadcast message - get out if it is from us }
>      If ParamW = Integer( App_Handle ) Then   // It is Ourselves
>         Begin
>         Result := 0 ;
>         Exit;
>      End;

>      {Message 2 - a Broadcast Message - from new instance OR Demanding
> a reply}
>      If ( ParamL = DEMAND_REPLY ) Then   // A new Notifier
>         Begin
>         SendMessage( ParamW, WM_ID, App_Handle, REQUEST_DATA ) ;
>         Result := 0 ;
>         Exit;
>      End;

>      {Message 3 - we have already got a string - notify our App}
>      If ParamL = NOTIFY_STRING_READY Then       // the sender has sent
> us a string
>         Begin
>         If Assigned( FNotify ) Then
>            FNotify ;
>         Result := 0 ;
>         Exit;
>      End;

>      {Message 4 - Another Instance Requests the Data }
>      If ( ParamL = REQUEST_DATA ) Then
>         Begin
>         Prev_HandleCount := Prev_HandleCount + 1 ;      // Remember
> and reply
>         LS_DespatchData( ParamW );
>         Result := 0 ;
>         Exit;
>      End;

>   End;

>   { Copy Data Handler - Receive the Data }
>   If TheMessage = WM_COPYDATA then
>      Begin
>      LS_ReceiveData( ParamL );
>      Result := 0 ;
>      Exit;
>   End;

>   { Exit here and return zero if you want     }
>   { to stop further processing of the message }

>   { Call the old Window procedure to }
>   { allow processing of the message. }
>   NewWindowProc := CallWindowProc(OldWindowProc,
>                                   WindowHandle,
>                                   TheMessage,
>                                   ParamW,
>                                   ParamL);

> End; {NewWindowProc}

> {
> ########################################################################

> }
> Procedure HookWindows;
>   Begin
>   If HookedFlag Then
>      Exit;
>   If App_Handle = 0 Then
>      Exit;

>   WM_ID := RegisterWindowMessage( PChar( AppID_String ) );
>   SetLastError( 0 ) ;                   // Clear Last Error
>   OldWindowProc := Pointer(SetWindowLong( App_Handle,
>                                           GWL_WNDPROC,
>                                           Integer(@NewWindowProc)));
>   If Integer( OldWindowProc ) = 0 Then  // Maybe no prior hook or
> Error
>      Begin
>      If GetLastError <> 0 Then          // Was it really an Error
>         Begin
>         LS_ErrorMsg( 'SetWindowLong Failed' ) ;
>         Exit;
>      End;
>   End;
>   HookedFlag := True ;
> End; {HookWindows}

> {
> ########################################################################

> }
> Procedure UnHookWindows;
>   Begin
>   If HookedFlag Then
>      Begin
>      SetWindowLong( App_Handle,
>                     GWL_WNDPROC,
>                     LongInt(OldWindowProc));
>      App_Handle := 0 ;
>      HookedFlag := False ;
>   End;
> End; {UnHookWindows}

> {
> ########################################################################

> }
> Initialization
>   If DebugFlag Then
>      LS_ErrorMsg( 'DLL Initialization' ) ;

>   HookWindows ;      // This will do nothing

> Finalization
>   UnHookWindows ;
>   If DebugFlag Then
>      LS_ErrorMsg( 'DLL Finalization' ) ;

> end.

Re:'nother little window-question (One Instance)


Quote
In article <bdh84f$n6...@news2.tilbu1.nb.home.nl>, "Jonathan" <a...@b.com> writes:
>I'm using the TMainInstance component to make sure only one instance of my
>program is running, if a second was to be started it would send the main
>instance a message with the params the user started the second instance
>with. This works fine. Only when the main instances mainform is hidden (I
>hide it OnMinimize) the second instance doesn't start (which is good!), but
>the message isn't sent (or the maininstance doesn't receive, I'm not
>sure)...now first I thought the problem was that the mainwindow was hidden,
>so I removed the 'Form1.Hide (OnMinimize)', but still, no message was
>received by the maininstance when the window was minimized, but it was when
>the maininstance was in 'normal' mode...can anyone help me with this? This
>is the components source code, its freeware:

This project source code (in .dpr) works for me ...

var
  hWndTalk : THandle;

begin
  hWndTalk := FindWindow('TDictForm', nil);  // main form class name
  if (hWndTalk <> 0)
     and (FindWindow('TApplication', 'Delphi 3') = 0) then begin  // allows
running in IDE
    ShowWindow(hWndTalk, SW_RESTORE);  // restore first instance
    SetForegroundWindow(hWndTalk);    // make it foreground window
    end
  else begin
    {normal Delphi written project code}
    Application.Initialize;
    Application.Title := 'Lexacom Talk';
    Application.CreateForm(TDictForm, DictForm);
  Application.Run;
  end;
end.

Alan Lloyd
alangll...@aol.com

Other Threads