mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-23 22:52:13 +02:00
# revisions: 32859,32989,32994,32997,32999
git-svn-id: branches/fixes_3_0@33765 -
This commit is contained in:
parent
26fb374730
commit
99a9e1fd62
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -2574,9 +2574,8 @@ packages/fcl-process/src/unix/process.inc svneol=native#text/plain
|
|||||||
packages/fcl-process/src/unix/simpleipc.inc svneol=native#text/plain
|
packages/fcl-process/src/unix/simpleipc.inc svneol=native#text/plain
|
||||||
packages/fcl-process/src/win/pipes.inc svneol=native#text/plain
|
packages/fcl-process/src/win/pipes.inc svneol=native#text/plain
|
||||||
packages/fcl-process/src/win/process.inc svneol=native#text/plain
|
packages/fcl-process/src/win/process.inc svneol=native#text/plain
|
||||||
packages/fcl-process/src/win/simpleipc.inc svneol=native#text/plain
|
packages/fcl-process/src/winall/simpleipc.inc svneol=native#text/plain
|
||||||
packages/fcl-process/src/wince/process.inc svneol=native#text/plain
|
packages/fcl-process/src/wince/process.inc svneol=native#text/plain
|
||||||
packages/fcl-process/src/wince/simpleipc.inc svneol=native#text/plain
|
|
||||||
packages/fcl-registry/Makefile svneol=native#text/plain
|
packages/fcl-registry/Makefile svneol=native#text/plain
|
||||||
packages/fcl-registry/Makefile.fpc svneol=native#text/plain
|
packages/fcl-registry/Makefile.fpc svneol=native#text/plain
|
||||||
packages/fcl-registry/Makefile.fpc.fpcmake svneol=native#text/plain
|
packages/fcl-registry/Makefile.fpc.fpcmake svneol=native#text/plain
|
||||||
|
@ -29,6 +29,7 @@ begin
|
|||||||
|
|
||||||
P.SourcePath.Add('src');
|
P.SourcePath.Add('src');
|
||||||
P.IncludePath.Add('src/unix',AllUnixOSes);
|
P.IncludePath.Add('src/unix',AllUnixOSes);
|
||||||
|
P.IncludePath.Add('src/winall',AllWindowsOSes);
|
||||||
P.IncludePath.Add('src/win',[win32,win64]);
|
P.IncludePath.Add('src/win',[win32,win64]);
|
||||||
P.IncludePath.Add('src/amicommon',AllAmigaLikeOSes);
|
P.IncludePath.Add('src/amicommon',AllAmigaLikeOSes);
|
||||||
P.IncludePath.Add('src/$(OS)',AllOSes-[win32,win64]-AllUnixOSes-AllAmigaLikeOSes);
|
P.IncludePath.Add('src/$(OS)',AllOSes-[win32,win64]-AllUnixOSes-AllAmigaLikeOSes);
|
||||||
@ -37,6 +38,7 @@ begin
|
|||||||
P.Dependencies.add('morphunits',[morphos]);
|
P.Dependencies.add('morphunits',[morphos]);
|
||||||
P.Dependencies.add('arosunits',[aros]);
|
P.Dependencies.add('arosunits',[aros]);
|
||||||
P.Dependencies.add('amunits',[amiga]);
|
P.Dependencies.add('amunits',[amiga]);
|
||||||
|
P.Dependencies.add('fcl-base');
|
||||||
|
|
||||||
T:=P.Targets.AddUnit('pipes.pp');
|
T:=P.Targets.AddUnit('pipes.pp');
|
||||||
T.Dependencies.AddInclude('pipes.inc');
|
T.Dependencies.AddInclude('pipes.inc');
|
||||||
|
@ -28,7 +28,15 @@ Const
|
|||||||
//Message types
|
//Message types
|
||||||
mtUnknown = 0;
|
mtUnknown = 0;
|
||||||
mtString = 1;
|
mtString = 1;
|
||||||
|
|
||||||
|
type
|
||||||
|
TIPCMessageOverflowAction = (ipcmoaNone, ipcmoaDiscardOld, ipcmoaDiscardNew, ipcmoaError);
|
||||||
|
|
||||||
|
var
|
||||||
|
// Currently implemented only for Windows platform!
|
||||||
|
DefaultIPCMessageOverflowAction: TIPCMessageOverflowAction = ipcmoaNone;
|
||||||
|
DefaultIPCMessageQueueLimit: Integer = 0;
|
||||||
|
|
||||||
Type
|
Type
|
||||||
|
|
||||||
TMessageType = LongInt;
|
TMessageType = LongInt;
|
||||||
@ -48,7 +56,7 @@ Type
|
|||||||
FOwner : TSimpleIPCServer;
|
FOwner : TSimpleIPCServer;
|
||||||
Protected
|
Protected
|
||||||
Function GetInstanceID : String; virtual; abstract;
|
Function GetInstanceID : String; virtual; abstract;
|
||||||
Procedure DoError(Msg : String; Args : Array of const);
|
Procedure DoError(const Msg : String; const Args : Array of const);
|
||||||
Procedure SetMsgType(AMsgType: TMessageType);
|
Procedure SetMsgType(AMsgType: TMessageType);
|
||||||
Function MsgData : TStream;
|
Function MsgData : TStream;
|
||||||
Public
|
Public
|
||||||
@ -71,7 +79,7 @@ Type
|
|||||||
FBusy: Boolean;
|
FBusy: Boolean;
|
||||||
FActive : Boolean;
|
FActive : Boolean;
|
||||||
FServerID : String;
|
FServerID : String;
|
||||||
Procedure DoError(Msg : String; Args : Array of const);
|
Procedure DoError(const Msg: String; const Args: array of const);
|
||||||
Procedure CheckInactive;
|
Procedure CheckInactive;
|
||||||
Procedure CheckActive;
|
Procedure CheckActive;
|
||||||
Procedure Activate; virtual; abstract;
|
Procedure Activate; virtual; abstract;
|
||||||
@ -99,13 +107,13 @@ Type
|
|||||||
Function CommClass : TIPCServerCommClass; virtual;
|
Function CommClass : TIPCServerCommClass; virtual;
|
||||||
Procedure Activate; override;
|
Procedure Activate; override;
|
||||||
Procedure Deactivate; override;
|
Procedure Deactivate; override;
|
||||||
Procedure ReadMessage;
|
|
||||||
Public
|
Public
|
||||||
Constructor Create(AOwner : TComponent); override;
|
Constructor Create(AOwner : TComponent); override;
|
||||||
Destructor Destroy; override;
|
Destructor Destroy; override;
|
||||||
Procedure StartServer;
|
Procedure StartServer;
|
||||||
Procedure StopServer;
|
Procedure StopServer;
|
||||||
Function PeekMessage(TimeOut : Integer; DoReadMessage : Boolean): Boolean;
|
Function PeekMessage(TimeOut : Integer; DoReadMessage : Boolean): Boolean;
|
||||||
|
Procedure ReadMessage;
|
||||||
Property StringMessage : String Read GetStringMessage;
|
Property StringMessage : String Read GetStringMessage;
|
||||||
Procedure GetMessageData(Stream : TStream);
|
Procedure GetMessageData(Stream : TStream);
|
||||||
Property MsgType: TMessageType Read FMsgType;
|
Property MsgType: TMessageType Read FMsgType;
|
||||||
@ -122,7 +130,7 @@ Type
|
|||||||
private
|
private
|
||||||
FOwner: TSimpleIPCClient;
|
FOwner: TSimpleIPCClient;
|
||||||
protected
|
protected
|
||||||
Procedure DoError(Msg : String; Args : Array of const);
|
Procedure DoError(const Msg : String; const Args : Array of const);
|
||||||
Public
|
Public
|
||||||
Constructor Create(AOwner : TSimpleIPCClient); virtual;
|
Constructor Create(AOwner : TSimpleIPCClient); virtual;
|
||||||
Property Owner : TSimpleIPCClient read FOwner;
|
Property Owner : TSimpleIPCClient read FOwner;
|
||||||
@ -195,7 +203,7 @@ begin
|
|||||||
FOwner:=AOWner;
|
FOwner:=AOWner;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure TIPCServerComm.DoError(Msg : String; Args : Array of const);
|
Procedure TIPCServerComm.DoError(const Msg : String; const Args : Array of const);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
FOwner.DoError(Msg,Args);
|
FOwner.DoError(Msg,Args);
|
||||||
@ -222,7 +230,7 @@ begin
|
|||||||
FOwner:=AOwner;
|
FOwner:=AOwner;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure TIPCClientComm.DoError(Msg : String; Args : Array of const);
|
Procedure TIPCClientComm.DoError(const Msg : String; const Args : Array of const);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
FOwner.DoError(Msg,Args);
|
FOwner.DoError(Msg,Args);
|
||||||
@ -232,9 +240,15 @@ end;
|
|||||||
TSimpleIPC
|
TSimpleIPC
|
||||||
---------------------------------------------------------------------}
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
procedure TSimpleIPC.DoError(Msg: String; Args: array of const);
|
Procedure TSimpleIPC.DoError(const Msg: String; const Args: array of const);
|
||||||
|
var
|
||||||
|
FullMsg: String;
|
||||||
begin
|
begin
|
||||||
Raise EIPCError.Create(Name+': '+Format(Msg,Args));
|
if Length(Name) > 0
|
||||||
|
then FullMsg := Name + ': '
|
||||||
|
else FullMsg := '';
|
||||||
|
FullMsg := FullMsg + Format(Msg, Args);
|
||||||
|
raise EIPCError.Create(FullMsg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSimpleIPC.CheckInactive;
|
procedure TSimpleIPC.CheckInactive;
|
||||||
@ -351,10 +365,16 @@ begin
|
|||||||
FActive:=False;
|
FActive:=False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSimpleIPCServer.PeekMessage(TimeOut: Integer; DoReadMessage: Boolean
|
// TimeOut values:
|
||||||
): Boolean;
|
// > 0 -- number of milliseconds to wait
|
||||||
|
// = 0 -- return immediately
|
||||||
|
// = -1 -- wait infinitely
|
||||||
|
// < -1 -- wait infinitely (force to -1)
|
||||||
|
function TSimpleIPCServer.PeekMessage(TimeOut: Integer; DoReadMessage: Boolean): Boolean;
|
||||||
begin
|
begin
|
||||||
CheckActive;
|
CheckActive;
|
||||||
|
if TimeOut < -1 then
|
||||||
|
TimeOut := -1;
|
||||||
FBusy:=True;
|
FBusy:=True;
|
||||||
Try
|
Try
|
||||||
Result:=FIPCComm.PeekMessage(Timeout);
|
Result:=FIPCComm.PeekMessage(Timeout);
|
||||||
|
@ -1,294 +0,0 @@
|
|||||||
{
|
|
||||||
This file is part of the Free Component library.
|
|
||||||
Copyright (c) 2005 by Michael Van Canneyt, member of
|
|
||||||
the Free Pascal development team
|
|
||||||
|
|
||||||
Windows implementation of one-way IPC between 2 processes
|
|
||||||
|
|
||||||
See the file COPYING.FPC, included in this distribution,
|
|
||||||
for details about the copyright.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
**********************************************************************}
|
|
||||||
|
|
||||||
uses Windows,messages;
|
|
||||||
|
|
||||||
Const
|
|
||||||
MsgWndClassName : pchar = 'FPCMsgWindowCls';
|
|
||||||
|
|
||||||
Resourcestring
|
|
||||||
SErrFailedToRegisterWindowClass = 'Failed to register message window class';
|
|
||||||
SErrFailedToCreateWindow = 'Failed to create message window %s';
|
|
||||||
|
|
||||||
var
|
|
||||||
MsgWindowClass: TWndClassA = (
|
|
||||||
style: 0;
|
|
||||||
lpfnWndProc: Nil;
|
|
||||||
cbClsExtra: 0;
|
|
||||||
cbWndExtra: 0;
|
|
||||||
hInstance: 0;
|
|
||||||
hIcon: 0;
|
|
||||||
hCursor: 0;
|
|
||||||
hbrBackground: 0;
|
|
||||||
lpszMenuName: nil;
|
|
||||||
lpszClassName: Nil);
|
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
|
||||||
TWinMsgServerComm
|
|
||||||
---------------------------------------------------------------------}
|
|
||||||
|
|
||||||
Type
|
|
||||||
TWinMsgServerComm = Class(TIPCServerComm)
|
|
||||||
Private
|
|
||||||
FHWND : HWND;
|
|
||||||
FWindowName : String;
|
|
||||||
FDataPushed : Boolean;
|
|
||||||
FUnction AllocateHWnd(Const aWindowName : String) : HWND;
|
|
||||||
Public
|
|
||||||
Constructor Create(AOWner : TSimpleIPCServer); override;
|
|
||||||
procedure ReadMsgData(var Msg: TMsg);
|
|
||||||
Procedure StartServer; override;
|
|
||||||
Procedure StopServer; override;
|
|
||||||
Function PeekMessage(TimeOut : Integer) : Boolean; override;
|
|
||||||
Procedure ReadMessage ; override;
|
|
||||||
Function GetInstanceID : String;override;
|
|
||||||
Property WindowName : String Read FWindowName;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function MsgWndProc(HWindow: HWnd; Message, WParam, LParam: Longint): Longint;stdcall;
|
|
||||||
|
|
||||||
Var
|
|
||||||
I : TWinMsgServerComm;
|
|
||||||
Msg : TMsg;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Result:=0;
|
|
||||||
If (Message=WM_COPYDATA) then
|
|
||||||
begin
|
|
||||||
I:=TWinMsgServerComm(GetWindowLongPtr(HWindow,GWL_USERDATA));
|
|
||||||
If (I<>NIl) then
|
|
||||||
begin
|
|
||||||
Msg.Message:=Message;
|
|
||||||
Msg.WParam:=WParam;
|
|
||||||
Msg.LParam:=LParam;
|
|
||||||
I.ReadMsgData(Msg);
|
|
||||||
I.FDataPushed:=True;
|
|
||||||
If Assigned(I.Owner.OnMessage) then
|
|
||||||
I.Owner.ReadMessage;
|
|
||||||
Result:=1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result:=DefWindowProc(HWindow,Message,WParam,LParam);
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function TWinMsgServerComm.AllocateHWnd(const aWindowName: String): HWND;
|
|
||||||
|
|
||||||
var
|
|
||||||
cls: TWndClassA;
|
|
||||||
isreg : Boolean;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Pointer(MsgWindowClass.lpfnWndProc):=@MsgWndProc;
|
|
||||||
MsgWindowClass.hInstance := HInstance;
|
|
||||||
MsgWindowClass.lpszClassName:=MsgWndClassName;
|
|
||||||
isreg:=GetClassInfoA(HInstance,MsgWndClassName,cls);
|
|
||||||
if not isreg then
|
|
||||||
if (Windows.RegisterClassA(MsgWindowClass)=0) then
|
|
||||||
Owner.DoError(SErrFailedToRegisterWindowClass,[]);
|
|
||||||
Result:=CreateWindowExA(WS_EX_TOOLWINDOW, MsgWndClassName,
|
|
||||||
PChar(aWindowName), WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
|
|
||||||
if (Result=0) then
|
|
||||||
Owner.DoError(SErrFailedToCreateWindow,[aWindowName]);
|
|
||||||
SetWindowLongPtr(Result,GWL_USERDATA,PtrInt(Self));
|
|
||||||
end;
|
|
||||||
|
|
||||||
constructor TWinMsgServerComm.Create(AOWner: TSimpleIPCServer);
|
|
||||||
begin
|
|
||||||
inherited Create(AOWner);
|
|
||||||
FWindowName:=Owner.ServerID;
|
|
||||||
If not Owner.Global then
|
|
||||||
FWindowName:=FWindowName+'_'+InstanceID;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.StartServer;
|
|
||||||
|
|
||||||
begin
|
|
||||||
FHWND:=AllocateHWND(FWindowName);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.StopServer;
|
|
||||||
begin
|
|
||||||
DestroyWindow(FHWND);
|
|
||||||
FHWND:=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TWinMsgServerComm.PeekMessage(TimeOut: Integer): Boolean;
|
|
||||||
|
|
||||||
Var
|
|
||||||
Msg : Tmsg;
|
|
||||||
B : Boolean;
|
|
||||||
R : DWORD;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Result:=FDataPushed;
|
|
||||||
If Result then
|
|
||||||
Exit;
|
|
||||||
B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE);
|
|
||||||
If not B then
|
|
||||||
// No message yet. Wait for a message to arrive available within specified time.
|
|
||||||
begin
|
|
||||||
if (TimeOut=0) then
|
|
||||||
TimeOut:=Integer(INFINITE);
|
|
||||||
R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE);
|
|
||||||
B:=(R<>WAIT_TIMEOUT);
|
|
||||||
end;
|
|
||||||
If B then
|
|
||||||
Repeat
|
|
||||||
B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE);
|
|
||||||
if B then
|
|
||||||
begin
|
|
||||||
Result:=(Msg.Message=WM_COPYDATA);
|
|
||||||
// Remove non WM_COPY messages from Queue
|
|
||||||
if not Result then
|
|
||||||
GetMessage(Msg,FHWND,0,0);
|
|
||||||
end;
|
|
||||||
Until Result or (not B);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.ReadMsgData(var Msg: TMsg);
|
|
||||||
|
|
||||||
Var
|
|
||||||
CDS : PCopyDataStruct;
|
|
||||||
|
|
||||||
begin
|
|
||||||
CDS:=PCopyDataStruct(Msg.Lparam);
|
|
||||||
Owner.FMsgType:=CDS^.dwData;
|
|
||||||
Owner.FMsgData.Size:=0;
|
|
||||||
Owner.FMsgData.Seek(0,soFrombeginning);
|
|
||||||
Owner.FMsgData.WriteBuffer(CDS^.lpData^,CDS^.cbData);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.ReadMessage;
|
|
||||||
|
|
||||||
Var
|
|
||||||
Msg : TMsg;
|
|
||||||
|
|
||||||
begin
|
|
||||||
If FDataPushed then
|
|
||||||
FDataPushed:=False
|
|
||||||
else
|
|
||||||
If Windows.PeekMessage(Msg, FHWND, 0, 0, PM_REMOVE) then
|
|
||||||
if (Msg.Message=WM_COPYDATA) then
|
|
||||||
ReadMsgData(Msg);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TWinMsgServerComm.GetInstanceID: String;
|
|
||||||
begin
|
|
||||||
Result:=IntToStr(HInstance);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
|
||||||
TWinMsgClientComm
|
|
||||||
---------------------------------------------------------------------}
|
|
||||||
|
|
||||||
Type
|
|
||||||
TWinMsgClientComm = Class(TIPCClientComm)
|
|
||||||
Private
|
|
||||||
FWindowName: String;
|
|
||||||
FHWND : HWnd;
|
|
||||||
Public
|
|
||||||
Constructor Create(AOWner : TSimpleIPCClient); override;
|
|
||||||
Procedure Connect; override;
|
|
||||||
Procedure Disconnect; override;
|
|
||||||
Procedure SendMessage(MsgType : TMessageType; Stream : TStream); override;
|
|
||||||
Function ServerRunning : Boolean; override;
|
|
||||||
Property WindowName : String Read FWindowName;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
constructor TWinMsgClientComm.Create(AOWner: TSimpleIPCClient);
|
|
||||||
begin
|
|
||||||
inherited Create(AOWner);
|
|
||||||
FWindowName:=Owner.ServerID;
|
|
||||||
If (Owner.ServerInstance<>'') then
|
|
||||||
FWindowName:=FWindowName+'_'+Owner.ServerInstance;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgClientComm.Connect;
|
|
||||||
begin
|
|
||||||
FHWND:=FindWindowA(MsgWndClassName,PChar(FWindowName));
|
|
||||||
If (FHWND=0) then
|
|
||||||
Owner.DoError(SErrServerNotActive,[Owner.ServerID]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgClientComm.Disconnect;
|
|
||||||
begin
|
|
||||||
FHWND:=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgClientComm.SendMessage(MsgType: TMessageType; Stream: TStream
|
|
||||||
);
|
|
||||||
Var
|
|
||||||
CDS : TCopyDataStruct;
|
|
||||||
Data,FMemstr : TMemorySTream;
|
|
||||||
|
|
||||||
begin
|
|
||||||
If Stream is TMemoryStream then
|
|
||||||
begin
|
|
||||||
Data:=TMemoryStream(Stream);
|
|
||||||
FMemStr:=Nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
FMemStr:=TMemoryStream.Create;
|
|
||||||
Data:=FMemstr;
|
|
||||||
end;
|
|
||||||
Try
|
|
||||||
If Assigned(FMemStr) then
|
|
||||||
begin
|
|
||||||
FMemStr.CopyFrom(Stream,0);
|
|
||||||
FMemStr.Seek(0,soFromBeginning);
|
|
||||||
end;
|
|
||||||
CDS.dwData:=MsgType;
|
|
||||||
CDS.lpData:=Data.Memory;
|
|
||||||
CDS.cbData:=Data.Size;
|
|
||||||
Windows.SendMessage(FHWnd,WM_COPYDATA,0,PtrInt(@CDS));
|
|
||||||
Finally
|
|
||||||
FreeAndNil(FMemStr);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TWinMsgClientComm.ServerRunning: Boolean;
|
|
||||||
begin
|
|
||||||
Result:=FindWindowA(MsgWndClassName,PChar(FWindowName))<>0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
|
||||||
Set TSimpleIPCClient / TSimpleIPCServer defaults.
|
|
||||||
---------------------------------------------------------------------}
|
|
||||||
|
|
||||||
|
|
||||||
Function TSimpleIPCServer.CommClass : TIPCServerCommClass;
|
|
||||||
|
|
||||||
begin
|
|
||||||
if (DefaultIPCServerClass<>Nil) then
|
|
||||||
Result:=DefaultIPCServerClass
|
|
||||||
else
|
|
||||||
Result:=TWinMsgServerComm;
|
|
||||||
end;
|
|
||||||
|
|
||||||
Function TSimpleIPCClient.CommClass : TIPCClientCommClass;
|
|
||||||
|
|
||||||
begin
|
|
||||||
if (DefaultIPCClientClass<>Nil) then
|
|
||||||
Result:=DefaultIPCClientClass
|
|
||||||
else
|
|
||||||
Result:=TWinMsgClientComm;
|
|
||||||
end;
|
|
||||||
|
|
559
packages/fcl-process/src/winall/simpleipc.inc
Normal file
559
packages/fcl-process/src/winall/simpleipc.inc
Normal file
@ -0,0 +1,559 @@
|
|||||||
|
{
|
||||||
|
This file is part of the Free Component library.
|
||||||
|
Copyright (c) 2005 by Michael Van Canneyt, member of
|
||||||
|
the Free Pascal development team
|
||||||
|
|
||||||
|
Windows implementation of one-way IPC between 2 processes
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
**********************************************************************}
|
||||||
|
|
||||||
|
uses Windows,messages,contnrs;
|
||||||
|
|
||||||
|
const
|
||||||
|
MsgWndClassName: WideString = 'FPCMsgWindowCls';
|
||||||
|
|
||||||
|
resourcestring
|
||||||
|
SErrFailedToRegisterWindowClass = 'Failed to register message window class';
|
||||||
|
SErrFailedToCreateWindow = 'Failed to create message window %s';
|
||||||
|
SErrMessageQueueOverflow = 'Message queue overflow (limit %s)';
|
||||||
|
|
||||||
|
var
|
||||||
|
MsgWindowClass: TWndClassW = (
|
||||||
|
style: 0;
|
||||||
|
lpfnWndProc: nil;
|
||||||
|
cbClsExtra: 0;
|
||||||
|
cbWndExtra: 0;
|
||||||
|
hInstance: 0;
|
||||||
|
hIcon: 0;
|
||||||
|
hCursor: 0;
|
||||||
|
hbrBackground: 0;
|
||||||
|
lpszMenuName: nil;
|
||||||
|
lpszClassName: nil);
|
||||||
|
|
||||||
|
type
|
||||||
|
TWinMsgServerMsg = class
|
||||||
|
strict private
|
||||||
|
FStream: TStream;
|
||||||
|
FMsgType: TMessageType;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
property Stream: TStream read FStream;
|
||||||
|
property MsgType: TMessageType read FMsgType write FMsgType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TWinMsgServerMsgQueue = class
|
||||||
|
strict private
|
||||||
|
FList: TFPObjectList;
|
||||||
|
FMaxCount: Integer;
|
||||||
|
FMaxAction: TIPCMessageOverflowAction;
|
||||||
|
function GetCount: Integer;
|
||||||
|
procedure DeleteAndFree(Index: Integer);
|
||||||
|
function PrepareToPush: Boolean;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure Clear;
|
||||||
|
procedure Push(AItem: TWinMsgServerMsg);
|
||||||
|
function Pop: TWinMsgServerMsg;
|
||||||
|
property Count: Integer read GetCount;
|
||||||
|
property MaxCount: Integer read FMaxCount write FMaxCount;
|
||||||
|
property MaxAction: TIPCMessageOverflowAction read FMaxAction write FMaxAction;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TWinMsgServerComm = Class(TIPCServerComm)
|
||||||
|
strict private
|
||||||
|
FHWND : HWND;
|
||||||
|
FWindowName : String;
|
||||||
|
FWndProcException: Boolean;
|
||||||
|
FWndProcExceptionMsg: String;
|
||||||
|
FMsgQueue: TWinMsgServerMsgQueue;
|
||||||
|
function AllocateHWnd(const aWindowName: WideString) : HWND;
|
||||||
|
procedure ProcessMessages;
|
||||||
|
procedure ProcessMessagesWait(TimeOut: Integer);
|
||||||
|
procedure HandlePostedMessage(const Msg: TMsg); inline;
|
||||||
|
function HaveQueuedMessages: Boolean; inline;
|
||||||
|
function CountQueuedMessages: Integer; inline;
|
||||||
|
procedure CheckWndProcException; inline;
|
||||||
|
private
|
||||||
|
procedure ReadMsgData(var Msg: TMsg);
|
||||||
|
function TryReadMsgData(var Msg: TMsg; out Error: String): Boolean;
|
||||||
|
procedure SetWndProcException(const ErrorMsg: String); inline;
|
||||||
|
public
|
||||||
|
constructor Create(AOwner : TSimpleIPCServer); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
Procedure StartServer; override;
|
||||||
|
Procedure StopServer; override;
|
||||||
|
Function PeekMessage(TimeOut : Integer) : Boolean; override;
|
||||||
|
Procedure ReadMessage ; override;
|
||||||
|
Function GetInstanceID : String;override;
|
||||||
|
Property WindowName : String Read FWindowName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
TWinMsgServerMsg / TWinMsgServerMsgQueue
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
constructor TWinMsgServerMsg.Create;
|
||||||
|
begin
|
||||||
|
FMsgType := 0;
|
||||||
|
FStream := TMemoryStream.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TWinMsgServerMsg.Destroy;
|
||||||
|
begin
|
||||||
|
FStream.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
constructor TWinMsgServerMsgQueue.Create;
|
||||||
|
begin
|
||||||
|
FMaxCount := DefaultIPCMessageQueueLimit;
|
||||||
|
FMaxAction := DefaultIPCMessageOverflowAction;
|
||||||
|
FList := TFPObjectList.Create(False); // FreeObjects = False!
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TWinMsgServerMsgQueue.Destroy;
|
||||||
|
begin
|
||||||
|
Clear;
|
||||||
|
FList.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerMsgQueue.Clear;
|
||||||
|
begin
|
||||||
|
while FList.Count > 0 do
|
||||||
|
DeleteAndFree(FList.Count - 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerMsgQueue.DeleteAndFree(Index: Integer);
|
||||||
|
begin
|
||||||
|
FList[Index].Free; // Free objects manually!
|
||||||
|
FList.Delete(Index);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerMsgQueue.GetCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FList.Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerMsgQueue.PrepareToPush: Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
case FMaxAction of
|
||||||
|
ipcmoaDiscardOld:
|
||||||
|
begin
|
||||||
|
while (FList.Count >= FMaxCount) do
|
||||||
|
DeleteAndFree(FList.Count - 1);
|
||||||
|
end;
|
||||||
|
ipcmoaDiscardNew:
|
||||||
|
begin
|
||||||
|
Result := (FList.Count < FMaxCount);
|
||||||
|
end;
|
||||||
|
ipcmoaError:
|
||||||
|
begin
|
||||||
|
if (FList.Count >= FMaxCount) then
|
||||||
|
// Caller is expected to catch this exception, so not using Owner.DoError()
|
||||||
|
raise EIPCError.CreateFmt(SErrMessageQueueOverflow, [IntToStr(FMaxCount)]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerMsgQueue.Push(AItem: TWinMsgServerMsg);
|
||||||
|
begin
|
||||||
|
if PrepareToPush then
|
||||||
|
FList.Insert(0, AItem);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerMsgQueue.Pop: TWinMsgServerMsg;
|
||||||
|
var
|
||||||
|
Index: Integer;
|
||||||
|
begin
|
||||||
|
Index := FList.Count - 1;
|
||||||
|
if Index >= 0 then
|
||||||
|
begin
|
||||||
|
// Caller is responsible for freeing the object.
|
||||||
|
Result := TWinMsgServerMsg(FList[Index]);
|
||||||
|
FList.Delete(Index);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
MsgWndProc
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
function MsgWndProc(Window: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
|
||||||
|
Var
|
||||||
|
Server: TWinMsgServerComm;
|
||||||
|
Msg: TMsg;
|
||||||
|
MsgError: String;
|
||||||
|
begin
|
||||||
|
Result:=0;
|
||||||
|
if (uMsg=WM_COPYDATA) then
|
||||||
|
begin
|
||||||
|
// Post WM_USER to wake up GetMessage call.
|
||||||
|
PostMessage(Window, WM_USER, 0, 0);
|
||||||
|
// Read message data and add to message queue.
|
||||||
|
Server:=TWinMsgServerComm(GetWindowLongPtr(Window,GWL_USERDATA));
|
||||||
|
if Assigned(Server) then
|
||||||
|
begin
|
||||||
|
Msg.Message:=uMsg;
|
||||||
|
Msg.wParam:=wParam;
|
||||||
|
Msg.lParam:=lParam;
|
||||||
|
// Exceptions thrown inside WindowProc may not propagate back
|
||||||
|
// to the caller in some circumstances (according to MSDN),
|
||||||
|
// so capture it and raise it outside of WindowProc!
|
||||||
|
if Server.TryReadMsgData(Msg, MsgError) then
|
||||||
|
Result:=1 // True
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result:=0; // False
|
||||||
|
Server.SetWndProcException(MsgError);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result:=DefWindowProcW(Window,uMsg,wParam,lParam);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
TWinMsgServerComm
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
function TWinMsgServerComm.AllocateHWnd(const aWindowName: WideString): HWND;
|
||||||
|
var
|
||||||
|
cls: TWndClassW;
|
||||||
|
isreg : Boolean;
|
||||||
|
begin
|
||||||
|
MsgWindowClass.lpfnWndProc:=@MsgWndProc;
|
||||||
|
MsgWindowClass.hInstance := HInstance;
|
||||||
|
MsgWindowClass.lpszClassName:=PWideChar(MsgWndClassName);
|
||||||
|
isreg:=GetClassInfoW(HInstance,PWideChar(MsgWndClassName),@cls);
|
||||||
|
if not isreg then
|
||||||
|
if (Windows.RegisterClassW(MsgWindowClass)=0) then
|
||||||
|
Owner.DoError(SErrFailedToRegisterWindowClass,[]);
|
||||||
|
Result:=CreateWindowExW(WS_EX_TOOLWINDOW, PWideChar(MsgWndClassName),
|
||||||
|
PWideChar(aWindowName), WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
|
||||||
|
if (Result=0) then
|
||||||
|
Owner.DoError(SErrFailedToCreateWindow,[aWindowName]);
|
||||||
|
SetWindowLongPtr(Result,GWL_USERDATA,PtrInt(Self));
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TWinMsgServerComm.Create(AOwner: TSimpleIPCServer);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
FWindowName := Owner.ServerID;
|
||||||
|
If not Owner.Global then
|
||||||
|
FWindowName := FWindowName+'_'+InstanceID;
|
||||||
|
FWndProcException := False;
|
||||||
|
FWndProcExceptionMsg := '';
|
||||||
|
FMsgQueue := TWinMsgServerMsgQueue.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TWinMsgServerComm.Destroy;
|
||||||
|
begin
|
||||||
|
StopServer;
|
||||||
|
FMsgQueue.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.StartServer;
|
||||||
|
begin
|
||||||
|
StopServer;
|
||||||
|
FHWND := AllocateHWND(WideString(FWindowName));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.StopServer;
|
||||||
|
begin
|
||||||
|
FMsgQueue.Clear;
|
||||||
|
if FHWND <> 0 then
|
||||||
|
begin
|
||||||
|
DestroyWindow(FHWND);
|
||||||
|
FHWND := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.SetWndProcException(const ErrorMsg: String); inline;
|
||||||
|
begin
|
||||||
|
FWndProcException := True;
|
||||||
|
FWndProcExceptionMsg := ErrorMsg;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.CheckWndProcException; inline;
|
||||||
|
var
|
||||||
|
Msg: String;
|
||||||
|
begin
|
||||||
|
if FWndProcException then
|
||||||
|
begin
|
||||||
|
Msg := FWndProcExceptionMsg;
|
||||||
|
FWndProcException := False;
|
||||||
|
FWndProcExceptionMsg := '';
|
||||||
|
Owner.DoError(Msg, []);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerComm.HaveQueuedMessages: Boolean; inline;
|
||||||
|
begin
|
||||||
|
Result := (FMsgQueue.Count > 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerComm.CountQueuedMessages: Integer; inline;
|
||||||
|
begin
|
||||||
|
Result := FMsgQueue.Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.HandlePostedMessage(const Msg: TMsg); inline;
|
||||||
|
begin
|
||||||
|
if Msg.message <> WM_USER then
|
||||||
|
begin
|
||||||
|
TranslateMessage(Msg);
|
||||||
|
DispatchMessage(Msg);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.ProcessMessages;
|
||||||
|
var
|
||||||
|
Msg: TMsg;
|
||||||
|
begin
|
||||||
|
// Windows.PeekMessage dispatches incoming sent messages by directly
|
||||||
|
// calling associated WindowProc, and then checks the thread message queue
|
||||||
|
// for posted messages and retrieves a message if any available.
|
||||||
|
// Note: WM_COPYDATA is a sent message, not posted, so it will be processed
|
||||||
|
// directly via WindowProc inside of Windows.PeekMessage call.
|
||||||
|
while Windows.PeekMessage(Msg, FHWND, 0, 0, PM_REMOVE) do
|
||||||
|
begin
|
||||||
|
// Empty the message queue by processing all posted messages.
|
||||||
|
HandlePostedMessage(Msg);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.ProcessMessagesWait(TimeOut: Integer);
|
||||||
|
var
|
||||||
|
Msg: TMsg;
|
||||||
|
TimerID: UINT_PTR;
|
||||||
|
GetMessageResult: BOOL;
|
||||||
|
begin
|
||||||
|
// Not allowed to wait.
|
||||||
|
if TimeOut = 0 then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
// Setup a timer to post WM_TIMER to wake up GetMessage call.
|
||||||
|
if TimeOut > 0 then
|
||||||
|
TimerID := SetTimer(FHWND, 0, TimeOut, nil)
|
||||||
|
else
|
||||||
|
TimerID := 0;
|
||||||
|
|
||||||
|
// Wait until a message arrives.
|
||||||
|
try
|
||||||
|
// We either need to wait infinitely or we have a timer.
|
||||||
|
if (TimeOut < 0) or (TimerID <> 0) then
|
||||||
|
begin
|
||||||
|
// Windows.GetMessage dispatches incoming sent messages until a posted
|
||||||
|
// message is available for retrieval. Note: WM_COPYDATA will not actually
|
||||||
|
// wake up Windows.GetMessage, so we must post a dummy message when
|
||||||
|
// we receive WM_COPYDATA inside of WindowProc.
|
||||||
|
GetMessageResult := Windows.GetMessage(Msg, FHWND, 0, 0);
|
||||||
|
case LongInt(GetMessageResult) of
|
||||||
|
-1, 0: ;
|
||||||
|
else HandlePostedMessage(Msg);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
// Destroy timer.
|
||||||
|
if TimerID <> 0 then
|
||||||
|
KillTimer(FHWND, TimerID);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerComm.PeekMessage(TimeOut: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
// Process incoming messages.
|
||||||
|
ProcessMessages;
|
||||||
|
|
||||||
|
// Do we have queued messages?
|
||||||
|
Result := HaveQueuedMessages;
|
||||||
|
|
||||||
|
// Wait for incoming messages.
|
||||||
|
if (not Result) and (TimeOut <> 0) then
|
||||||
|
begin
|
||||||
|
ProcessMessagesWait(TimeOut);
|
||||||
|
Result := HaveQueuedMessages;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Check for exception raised inside WindowProc.
|
||||||
|
CheckWndProcException;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.ReadMsgData(var Msg: TMsg);
|
||||||
|
var
|
||||||
|
CDS: PCopyDataStruct;
|
||||||
|
MsgItem: TWinMsgServerMsg;
|
||||||
|
begin
|
||||||
|
CDS := PCopyDataStruct(Msg.lParam);
|
||||||
|
MsgItem := TWinMsgServerMsg.Create;
|
||||||
|
try
|
||||||
|
MsgItem.MsgType := CDS^.dwData;
|
||||||
|
MsgItem.Stream.WriteBuffer(CDS^.lpData^,CDS^.cbData);
|
||||||
|
except
|
||||||
|
FreeAndNil(MsgItem);
|
||||||
|
// Caller is expected to catch this exception, so not using Owner.DoError()
|
||||||
|
raise;
|
||||||
|
end;
|
||||||
|
FMsgQueue.Push(MsgItem);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerComm.TryReadMsgData(var Msg: TMsg; out Error: String): Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
try
|
||||||
|
ReadMsgData(Msg);
|
||||||
|
except on E: Exception do
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
Error := E.Message;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgServerComm.ReadMessage;
|
||||||
|
var
|
||||||
|
MsgItem: TWinMsgServerMsg;
|
||||||
|
begin
|
||||||
|
MsgItem := FMsgQueue.Pop;
|
||||||
|
if Assigned(MsgItem) then
|
||||||
|
try
|
||||||
|
// Load message from the queue into the owner's message data.
|
||||||
|
MsgItem.Stream.Position := 0;
|
||||||
|
Owner.FMsgData.Size := 0;
|
||||||
|
Owner.FMsgType := MsgItem.MsgType;
|
||||||
|
Owner.FMsgData.CopyFrom(MsgItem.Stream, MsgItem.Stream.Size);
|
||||||
|
finally
|
||||||
|
// We are responsible for freeing the message from the queue.
|
||||||
|
MsgItem.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgServerComm.GetInstanceID: String;
|
||||||
|
begin
|
||||||
|
Result:=IntToStr(HInstance);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
TWinMsgClientComm
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
Type
|
||||||
|
TWinMsgClientComm = Class(TIPCClientComm)
|
||||||
|
Private
|
||||||
|
FWindowName: String;
|
||||||
|
FHWND : HWND;
|
||||||
|
function FindServerWindow: HWND;
|
||||||
|
function FindServerWindow(const aWindowName: WideString): HWND;
|
||||||
|
Public
|
||||||
|
Constructor Create(AOWner : TSimpleIPCClient); override;
|
||||||
|
Procedure Connect; override;
|
||||||
|
Procedure Disconnect; override;
|
||||||
|
Procedure SendMessage(MsgType : TMessageType; Stream : TStream); override;
|
||||||
|
Function ServerRunning : Boolean; override;
|
||||||
|
Property WindowName : String Read FWindowName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
constructor TWinMsgClientComm.Create(AOWner: TSimpleIPCClient);
|
||||||
|
begin
|
||||||
|
inherited Create(AOWner);
|
||||||
|
FWindowName:=Owner.ServerID;
|
||||||
|
If (Owner.ServerInstance<>'') then
|
||||||
|
FWindowName:=FWindowName+'_'+Owner.ServerInstance;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgClientComm.FindServerWindow: HWND;
|
||||||
|
begin
|
||||||
|
Result := FindServerWindow(WideString(FWindowName));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgClientComm.FindServerWindow(const aWindowName: WideString): HWND;
|
||||||
|
begin
|
||||||
|
Result := FindWindowW(PWideChar(MsgWndClassName), PWideChar(aWindowName));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgClientComm.Connect;
|
||||||
|
begin
|
||||||
|
FHWND:=FindServerWindow;
|
||||||
|
If (FHWND=0) then
|
||||||
|
Owner.DoError(SErrServerNotActive,[Owner.ServerID]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgClientComm.Disconnect;
|
||||||
|
begin
|
||||||
|
FHWND:=0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TWinMsgClientComm.SendMessage(MsgType: TMessageType; Stream: TStream);
|
||||||
|
var
|
||||||
|
CDS : TCopyDataStruct;
|
||||||
|
Data,FMemstr : TMemorySTream;
|
||||||
|
begin
|
||||||
|
if Stream is TMemoryStream then
|
||||||
|
begin
|
||||||
|
Data:=TMemoryStream(Stream);
|
||||||
|
FMemStr:=nil;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
FMemStr:=TMemoryStream.Create;
|
||||||
|
Data:=FMemstr;
|
||||||
|
end;
|
||||||
|
try
|
||||||
|
if Assigned(FMemStr) then
|
||||||
|
begin
|
||||||
|
FMemStr.CopyFrom(Stream,0);
|
||||||
|
FMemStr.Seek(0,soFromBeginning);
|
||||||
|
end;
|
||||||
|
CDS.dwData:=MsgType;
|
||||||
|
CDS.lpData:=Data.Memory;
|
||||||
|
CDS.cbData:=Data.Size;
|
||||||
|
Windows.SendMessage(FHWND,WM_COPYDATA,0,PtrInt(@CDS));
|
||||||
|
finally
|
||||||
|
FreeAndNil(FMemStr);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWinMsgClientComm.ServerRunning: Boolean;
|
||||||
|
begin
|
||||||
|
Result:=FindServerWindow<>0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
Set TSimpleIPCClient / TSimpleIPCServer defaults.
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
|
||||||
|
Function TSimpleIPCServer.CommClass : TIPCServerCommClass;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if (DefaultIPCServerClass<>Nil) then
|
||||||
|
Result:=DefaultIPCServerClass
|
||||||
|
else
|
||||||
|
Result:=TWinMsgServerComm;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Function TSimpleIPCClient.CommClass : TIPCClientCommClass;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if (DefaultIPCClientClass<>Nil) then
|
||||||
|
Result:=DefaultIPCClientClass
|
||||||
|
else
|
||||||
|
Result:=TWinMsgClientComm;
|
||||||
|
end;
|
||||||
|
|
@ -1,292 +0,0 @@
|
|||||||
{
|
|
||||||
This file is part of the Free Component library.
|
|
||||||
Copyright (c) 2005 by Michael Van Canneyt, member of
|
|
||||||
the Free Pascal development team
|
|
||||||
|
|
||||||
Windows implementation of one-way IPC between 2 processes
|
|
||||||
|
|
||||||
See the file COPYING.FPC, included in this distribution,
|
|
||||||
for details about the copyright.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
**********************************************************************}
|
|
||||||
|
|
||||||
uses Windows,messages;
|
|
||||||
|
|
||||||
Const
|
|
||||||
MsgWndClassName : pwidechar = 'FPCMsgWindowCls';
|
|
||||||
|
|
||||||
Resourcestring
|
|
||||||
SErrFailedToRegisterWindowClass = 'Failed to register message window class';
|
|
||||||
SErrFailedToCreateWindow = 'Failed to create message window %s';
|
|
||||||
|
|
||||||
var
|
|
||||||
MsgWindowClass: TWndClass = (
|
|
||||||
style: 0;
|
|
||||||
lpfnWndProc: Nil;
|
|
||||||
cbClsExtra: 0;
|
|
||||||
cbWndExtra: 0;
|
|
||||||
hInstance: 0;
|
|
||||||
hIcon: 0;
|
|
||||||
hCursor: 0;
|
|
||||||
hbrBackground: 0;
|
|
||||||
lpszMenuName: nil;
|
|
||||||
lpszClassName: Nil);
|
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
|
||||||
TWinMsgServerComm
|
|
||||||
---------------------------------------------------------------------}
|
|
||||||
|
|
||||||
Type
|
|
||||||
TWinMsgServerComm = Class(TIPCServerComm)
|
|
||||||
Private
|
|
||||||
FHWND : HWND;
|
|
||||||
FWindowName : Widestring;
|
|
||||||
FDataPushed : Boolean;
|
|
||||||
Function AllocateHWnd(const cwsWindowName : widestring) : HWND;
|
|
||||||
Public
|
|
||||||
Constructor Create(AOwner : TSimpleIPCServer); override;
|
|
||||||
procedure ReadMsgData(var Msg: TMsg);
|
|
||||||
Procedure StartServer; override;
|
|
||||||
Procedure StopServer; override;
|
|
||||||
Function PeekMessage(TimeOut : Integer) : Boolean; override;
|
|
||||||
Procedure ReadMessage ; override;
|
|
||||||
Function GetInstanceID : String;override;
|
|
||||||
Property WindowName : WideString Read FWindowName;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function MsgWndProc(HWindow: HWnd; Message, WParam, LParam: Longint): Longint;stdcall;
|
|
||||||
|
|
||||||
Var
|
|
||||||
I : TWinMsgServerComm;
|
|
||||||
Msg : TMsg;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Result:=0;
|
|
||||||
If (Message=WM_COPYDATA) then
|
|
||||||
begin
|
|
||||||
I:=TWinMsgServerComm(GetWindowLong(HWindow,GWL_USERDATA));
|
|
||||||
If (I<>NIl) then
|
|
||||||
begin
|
|
||||||
Msg.Message:=Message;
|
|
||||||
Msg.WParam:=WParam;
|
|
||||||
Msg.LParam:=LParam;
|
|
||||||
I.ReadMsgData(Msg);
|
|
||||||
I.FDataPushed:=True;
|
|
||||||
If Assigned(I.Owner.OnMessage) then
|
|
||||||
I.Owner.ReadMessage;
|
|
||||||
Result:=1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result:=DefWindowProc(HWindow,Message,WParam,LParam);
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function TWinMsgServerComm.AllocateHWnd(const cwsWindowName: Widestring): HWND;
|
|
||||||
|
|
||||||
var
|
|
||||||
cls: LPWNDCLASS;
|
|
||||||
isreg : Boolean;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Pointer(MsgWindowClass.lpfnWndProc):=@MsgWndProc;
|
|
||||||
MsgWindowClass.hInstance := HInstance;
|
|
||||||
MsgWindowClass.lpszClassName:=MsgWndClassName;
|
|
||||||
isreg:=GetClassInfo(HInstance,MsgWndClassName,cls);
|
|
||||||
if not isreg then
|
|
||||||
if (Windows.RegisterClass(MsgWindowClass)=0) then
|
|
||||||
Owner.DoError(SErrFailedToRegisterWindowClass,[]);
|
|
||||||
Result:=CreateWindowEx(WS_EX_TOOLWINDOW, MsgWndClassName,
|
|
||||||
PWidechar(cwsWindowName), WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
|
|
||||||
if (Result=0) then
|
|
||||||
Owner.DoError(SErrFailedToCreateWindow,[cwsWindowName]);
|
|
||||||
SetWindowLong(Result,GWL_USERDATA,Longint(Self));
|
|
||||||
end;
|
|
||||||
|
|
||||||
constructor TWinMsgServerComm.Create(AOWner: TSimpleIPCServer);
|
|
||||||
begin
|
|
||||||
inherited Create(AOWner);
|
|
||||||
FWindowName:=Owner.ServerID;
|
|
||||||
If not Owner.Global then
|
|
||||||
FWindowName:=FWindowName+'_'+InstanceID;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.StartServer;
|
|
||||||
|
|
||||||
begin
|
|
||||||
FHWND:=AllocateHWND(FWindowName);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.StopServer;
|
|
||||||
begin
|
|
||||||
DestroyWindow(FHWND);
|
|
||||||
FHWND:=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TWinMsgServerComm.PeekMessage(TimeOut: Integer): Boolean;
|
|
||||||
|
|
||||||
Var
|
|
||||||
Msg : Tmsg;
|
|
||||||
B : Boolean;
|
|
||||||
R : DWORD;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Result:=FDataPushed;
|
|
||||||
If Result then
|
|
||||||
Exit;
|
|
||||||
B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE);
|
|
||||||
If not B then
|
|
||||||
// No message yet. Wait for a message to arrive available within specified time.
|
|
||||||
begin
|
|
||||||
if (TimeOut=0) then
|
|
||||||
TimeOut:=Integer(INFINITE);
|
|
||||||
R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE);
|
|
||||||
B:=(R<>WAIT_TIMEOUT);
|
|
||||||
end;
|
|
||||||
If B then
|
|
||||||
Repeat
|
|
||||||
B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE);
|
|
||||||
if B then
|
|
||||||
begin
|
|
||||||
Result:=(Msg.Message=WM_COPYDATA);
|
|
||||||
// Remove non WM_COPY messages from Queue
|
|
||||||
if not Result then
|
|
||||||
GetMessage(@Msg,FHWND,0,0);
|
|
||||||
end;
|
|
||||||
Until Result or (not B);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.ReadMsgData(var Msg: TMsg);
|
|
||||||
|
|
||||||
Var
|
|
||||||
CDS : PCopyDataStruct;
|
|
||||||
|
|
||||||
begin
|
|
||||||
CDS:=PCopyDataStruct(Msg.Lparam);
|
|
||||||
Owner.FMsgData.Size:=0;
|
|
||||||
Owner.FMsgData.Seek(0,soFrombeginning);
|
|
||||||
Owner.FMsgData.WriteBuffer(CDS^.lpData^,CDS^.cbData);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgServerComm.ReadMessage;
|
|
||||||
|
|
||||||
Var
|
|
||||||
Msg : TMsg;
|
|
||||||
|
|
||||||
begin
|
|
||||||
If FDataPushed then
|
|
||||||
FDataPushed:=False
|
|
||||||
else
|
|
||||||
If Windows.PeekMessage(Msg, FHWND, 0, 0, PM_REMOVE) then
|
|
||||||
if (Msg.Message=WM_COPYDATA) then
|
|
||||||
ReadMsgData(Msg);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TWinMsgServerComm.GetInstanceID: String;
|
|
||||||
begin
|
|
||||||
Result:=IntToStr(HInstance);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
|
||||||
TWinMsgClientComm
|
|
||||||
---------------------------------------------------------------------}
|
|
||||||
|
|
||||||
Type
|
|
||||||
TWinMsgClientComm = Class(TIPCClientComm)
|
|
||||||
Private
|
|
||||||
FWindowName: WideString;
|
|
||||||
FHWND : HWnd;
|
|
||||||
Public
|
|
||||||
Constructor Create(AOWner : TSimpleIPCClient); override;
|
|
||||||
Procedure Connect; override;
|
|
||||||
Procedure Disconnect; override;
|
|
||||||
Procedure SendMessage(MsgType : TMessageType; Stream : TStream); override;
|
|
||||||
Function ServerRunning : Boolean; override;
|
|
||||||
Property WindowName : WideString Read FWindowName;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
constructor TWinMsgClientComm.Create(AOWner: TSimpleIPCClient);
|
|
||||||
begin
|
|
||||||
inherited Create(AOWner);
|
|
||||||
FWindowName:=Owner.ServerID;
|
|
||||||
If (Owner.ServerInstance<>'') then
|
|
||||||
FWindowName:=FWindowName+'_'+Owner.ServerInstance;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgClientComm.Connect;
|
|
||||||
begin
|
|
||||||
FHWND:=FindWindow(MsgWndClassName,Pwidechar(FWindowName));
|
|
||||||
If (FHWND=0) then
|
|
||||||
Owner.DoError(SErrServerNotActive,[Owner.ServerID]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgClientComm.Disconnect;
|
|
||||||
begin
|
|
||||||
FHWND:=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TWinMsgClientComm.SendMessage(MsgType: TMessageType; Stream: TStream
|
|
||||||
);
|
|
||||||
Var
|
|
||||||
CDS : TCopyDataStruct;
|
|
||||||
Data,FMemstr : TMemorySTream;
|
|
||||||
|
|
||||||
begin
|
|
||||||
If Stream is TMemoryStream then
|
|
||||||
begin
|
|
||||||
Data:=TMemoryStream(Stream);
|
|
||||||
FMemStr:=Nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
FMemStr:=TMemoryStream.Create;
|
|
||||||
Data:=FMemstr;
|
|
||||||
end;
|
|
||||||
Try
|
|
||||||
If Assigned(FMemStr) then
|
|
||||||
begin
|
|
||||||
FMemStr.CopyFrom(Stream,0);
|
|
||||||
FMemStr.Seek(0,soFromBeginning);
|
|
||||||
end;
|
|
||||||
CDS.lpData:=Data.Memory;
|
|
||||||
CDS.cbData:=Data.Size;
|
|
||||||
Windows.SendMessage(FHWnd,WM_COPYDATA,0,Integer(@CDS));
|
|
||||||
Finally
|
|
||||||
FreeAndNil(FMemStr);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TWinMsgClientComm.ServerRunning: Boolean;
|
|
||||||
begin
|
|
||||||
Result:=FindWindow(MsgWndClassName,PWidechar(FWindowName))<>0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
|
||||||
Set TSimpleIPCClient / TSimpleIPCServer defaults.
|
|
||||||
---------------------------------------------------------------------}
|
|
||||||
|
|
||||||
|
|
||||||
Function TSimpleIPCServer.CommClass : TIPCServerCommClass;
|
|
||||||
|
|
||||||
begin
|
|
||||||
if (DefaultIPCServerClass<>Nil) then
|
|
||||||
Result:=DefaultIPCServerClass
|
|
||||||
else
|
|
||||||
Result:=TWinMsgServerComm;
|
|
||||||
end;
|
|
||||||
|
|
||||||
Function TSimpleIPCClient.CommClass : TIPCClientCommClass;
|
|
||||||
|
|
||||||
begin
|
|
||||||
if (DefaultIPCClientClass<>Nil) then
|
|
||||||
Result:=DefaultIPCClientClass
|
|
||||||
else
|
|
||||||
Result:=TWinMsgClientComm;
|
|
||||||
end;
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user