Added: FS#7 - Add support for graphics as details
Added: TStreamUtil to clean up the code a bit
This commit is contained in:
parent
bf0bb05983
commit
3cbf8c520f
@ -1,7 +1,8 @@
|
|||||||
program X2LogTest;
|
program X2LogTest;
|
||||||
|
|
||||||
|
{$R *.dres}
|
||||||
|
|
||||||
uses
|
uses
|
||||||
// FastMM4,
|
|
||||||
Forms,
|
Forms,
|
||||||
MainFrm in 'source\MainFrm.pas' {MainForm},
|
MainFrm in 'source\MainFrm.pas' {MainForm},
|
||||||
X2Log.Intf in '..\X2Log.Intf.pas',
|
X2Log.Intf in '..\X2Log.Intf.pas',
|
||||||
@ -19,7 +20,9 @@ uses
|
|||||||
X2Log.Client.NamedPipe in '..\X2Log.Client.NamedPipe.pas',
|
X2Log.Client.NamedPipe in '..\X2Log.Client.NamedPipe.pas',
|
||||||
X2Log.Client.Base in '..\X2Log.Client.Base.pas',
|
X2Log.Client.Base in '..\X2Log.Client.Base.pas',
|
||||||
X2Log.Details.Default in '..\X2Log.Details.Default.pas',
|
X2Log.Details.Default in '..\X2Log.Details.Default.pas',
|
||||||
X2Log.Details.Registry in '..\X2Log.Details.Registry.pas';
|
X2Log.Details.Registry in '..\X2Log.Details.Registry.pas',
|
||||||
|
X2Log.Details.Intf in '..\X2Log.Details.Intf.pas',
|
||||||
|
X2Log.Util.Stream in '..\X2Log.Util.Stream.pas';
|
||||||
|
|
||||||
{$R *.res}
|
{$R *.res}
|
||||||
|
|
||||||
|
@ -192,6 +192,12 @@
|
|||||||
<DCCReference Include="..\X2Log.Client.Base.pas"/>
|
<DCCReference Include="..\X2Log.Client.Base.pas"/>
|
||||||
<DCCReference Include="..\X2Log.Details.Default.pas"/>
|
<DCCReference Include="..\X2Log.Details.Default.pas"/>
|
||||||
<DCCReference Include="..\X2Log.Details.Registry.pas"/>
|
<DCCReference Include="..\X2Log.Details.Registry.pas"/>
|
||||||
|
<DCCReference Include="..\X2Log.Details.Intf.pas"/>
|
||||||
|
<DCCReference Include="..\X2Log.Util.Stream.pas"/>
|
||||||
|
<RcItem Include="resources\Graphic.jpg">
|
||||||
|
<ResourceType>RCDATA</ResourceType>
|
||||||
|
<ResourceId>GraphicDetails</ResourceId>
|
||||||
|
</RcItem>
|
||||||
<BuildConfiguration Include="Debug">
|
<BuildConfiguration Include="Debug">
|
||||||
<Key>Cfg_2</Key>
|
<Key>Cfg_2</Key>
|
||||||
<CfgParent>Base</CfgParent>
|
<CfgParent>Base</CfgParent>
|
||||||
|
BIN
Test/X2LogTest.dres
Normal file
BIN
Test/X2LogTest.dres
Normal file
Binary file not shown.
1
Test/X2LogTestResource.rc
Normal file
1
Test/X2LogTestResource.rc
Normal file
@ -0,0 +1 @@
|
|||||||
|
GraphicDetails RCDATA "resources\\Graphic.jpg"
|
BIN
Test/resources/Graphic.jpg
Normal file
BIN
Test/resources/Graphic.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@ -211,7 +211,7 @@ object MainForm: TMainForm
|
|||||||
Margins.Top = 8
|
Margins.Top = 8
|
||||||
Margins.Right = 8
|
Margins.Right = 8
|
||||||
Margins.Bottom = 0
|
Margins.Bottom = 0
|
||||||
ActivePage = tsText
|
ActivePage = tsBinary
|
||||||
Align = alTop
|
Align = alTop
|
||||||
TabOrder = 2
|
TabOrder = 2
|
||||||
object tsText: TTabSheet
|
object tsText: TTabSheet
|
||||||
@ -309,14 +309,23 @@ object MainForm: TMainForm
|
|||||||
object tsBinary: TTabSheet
|
object tsBinary: TTabSheet
|
||||||
Caption = 'Binary'
|
Caption = 'Binary'
|
||||||
ImageIndex = 2
|
ImageIndex = 2
|
||||||
object btnBinary: TButton
|
object btnBinaryRawByteString: TButton
|
||||||
Left = 12
|
Left = 12
|
||||||
Top = 23
|
Top = 15
|
||||||
Width = 62
|
Width = 152
|
||||||
Height = 21
|
Height = 21
|
||||||
Caption = 'Binary'
|
Caption = 'Binary (RawByteString)'
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
OnClick = btnLogClick
|
OnClick = btnBinaryRawByteStringClick
|
||||||
|
end
|
||||||
|
object btnGraphic: TButton
|
||||||
|
Left = 170
|
||||||
|
Top = 15
|
||||||
|
Width = 79
|
||||||
|
Height = 21
|
||||||
|
Caption = 'Graphic'
|
||||||
|
TabOrder = 1
|
||||||
|
OnClick = btnGraphicClick
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -384,7 +393,7 @@ object MainForm: TMainForm
|
|||||||
Left = 552
|
Left = 552
|
||||||
Top = 176
|
Top = 176
|
||||||
Bitmap = {
|
Bitmap = {
|
||||||
494C0101020014003C000C000C00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
|
494C01010200140044000C000C00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
|
||||||
0000000000003600000028000000300000000C00000001002000000000000009
|
0000000000003600000028000000300000000C00000001002000000000000009
|
||||||
0000000000000000000000000000000000000000000000000000000000000000
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
@ -45,7 +45,7 @@ type
|
|||||||
rbAbsolute: TRadioButton;
|
rbAbsolute: TRadioButton;
|
||||||
edtPipeName: TEdit;
|
edtPipeName: TEdit;
|
||||||
lblPipeName: TLabel;
|
lblPipeName: TLabel;
|
||||||
btnBinary: TButton;
|
btnBinaryRawByteString: TButton;
|
||||||
pcDispatch: TPageControl;
|
pcDispatch: TPageControl;
|
||||||
tsText: TTabSheet;
|
tsText: TTabSheet;
|
||||||
tsException: TTabSheet;
|
tsException: TTabSheet;
|
||||||
@ -54,6 +54,7 @@ type
|
|||||||
bvlDispatch: TBevel;
|
bvlDispatch: TBevel;
|
||||||
pnlObservers: TPanel;
|
pnlObservers: TPanel;
|
||||||
bvlObservers: TBevel;
|
bvlObservers: TBevel;
|
||||||
|
btnGraphic: TButton;
|
||||||
|
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure FormDestroy(Sender: TObject);
|
procedure FormDestroy(Sender: TObject);
|
||||||
@ -69,6 +70,8 @@ type
|
|||||||
procedure btnFileStopClick(Sender: TObject);
|
procedure btnFileStopClick(Sender: TObject);
|
||||||
procedure btnNamedPipeStartClick(Sender: TObject);
|
procedure btnNamedPipeStartClick(Sender: TObject);
|
||||||
procedure btnNamedPipeStopClick(Sender: TObject);
|
procedure btnNamedPipeStopClick(Sender: TObject);
|
||||||
|
procedure btnBinaryRawByteStringClick(Sender: TObject);
|
||||||
|
procedure btnGraphicClick(Sender: TObject);
|
||||||
private
|
private
|
||||||
FLog: IX2Log;
|
FLog: IX2Log;
|
||||||
FEventObserver: IX2LogObserver;
|
FEventObserver: IX2LogObserver;
|
||||||
@ -82,11 +85,13 @@ type
|
|||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
|
Vcl.Imaging.Jpeg,
|
||||||
Winapi.Windows,
|
Winapi.Windows,
|
||||||
|
|
||||||
X2Log,
|
X2Log,
|
||||||
X2Log.Constants,
|
X2Log.Constants,
|
||||||
X2Log.Details.Default,
|
X2Log.Details.Default,
|
||||||
|
X2Log.Details.Intf,
|
||||||
X2Log.Exception.madExcept,
|
X2Log.Exception.madExcept,
|
||||||
X2Log.Observer.Event,
|
X2Log.Observer.Event,
|
||||||
X2Log.Observer.LogFile,
|
X2Log.Observer.LogFile,
|
||||||
@ -181,12 +186,38 @@ begin
|
|||||||
else if Sender = btnWarning then
|
else if Sender = btnWarning then
|
||||||
FLog.Warning(edtMessage.Text)
|
FLog.Warning(edtMessage.Text)
|
||||||
else if Sender = btnError then
|
else if Sender = btnError then
|
||||||
FLog.Error(edtMessage.Text)
|
FLog.Error(edtMessage.Text);
|
||||||
else if Sender = btnBinary then
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMainForm.btnBinaryRawByteStringClick(Sender: TObject);
|
||||||
|
begin
|
||||||
FLog.InfoEx(edtMessage.Text, TX2LogBinaryDetails.Create(#0#1#2#3'Test'#12'Some more data'));
|
FLog.InfoEx(edtMessage.Text, TX2LogBinaryDetails.Create(#0#1#2#3'Test'#12'Some more data'));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMainForm.btnGraphicClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
graphic: TJPEGImage;
|
||||||
|
resourceStream: TResourceStream;
|
||||||
|
|
||||||
|
begin
|
||||||
|
graphic := TJPEGImage.Create;
|
||||||
|
try
|
||||||
|
resourceStream := TResourceStream.Create(SysInit.HInstance, 'GraphicDetails', RT_RCDATA);
|
||||||
|
try
|
||||||
|
graphic.LoadFromStream(resourceStream);
|
||||||
|
finally
|
||||||
|
FreeAndNil(resourceStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
FLog.InfoEx('Graphic', TX2LogGraphicDetails.Create(graphic));
|
||||||
|
finally
|
||||||
|
FreeAndNil(graphic);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.btnExceptionClick(Sender: TObject);
|
procedure TMainForm.btnExceptionClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
|
@ -29,7 +29,8 @@ uses
|
|||||||
Winapi.Windows,
|
Winapi.Windows,
|
||||||
|
|
||||||
X2Log.Details.Default,
|
X2Log.Details.Default,
|
||||||
X2Log.Details.Registry;
|
X2Log.Details.Registry,
|
||||||
|
X2Log.Util.Stream;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -271,22 +272,6 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
procedure TX2LogNamedPipeClientWorkerThread.HandleMessage;
|
procedure TX2LogNamedPipeClientWorkerThread.HandleMessage;
|
||||||
|
|
||||||
function ReadString: WideString;
|
|
||||||
var
|
|
||||||
size: Cardinal;
|
|
||||||
|
|
||||||
begin
|
|
||||||
MessageData.ReadBuffer(size, SizeOf(cardinal));
|
|
||||||
if size > 0 then
|
|
||||||
begin
|
|
||||||
SetLength(Result, size);
|
|
||||||
MessageData.ReadBuffer(Result[1], size * SizeOf(WideChar));
|
|
||||||
end else
|
|
||||||
Result := '';
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
var
|
var
|
||||||
header: TX2LogMessageHeaderV1;
|
header: TX2LogMessageHeaderV1;
|
||||||
headerDiff: Integer;
|
headerDiff: Integer;
|
||||||
@ -317,7 +302,7 @@ begin
|
|||||||
raise EReadError.Create('Header too small');
|
raise EReadError.Create('Header too small');
|
||||||
|
|
||||||
{ Message }
|
{ Message }
|
||||||
msg := ReadString;
|
msg := TStreamUtil.ReadString(MessageData);
|
||||||
|
|
||||||
{ Details }
|
{ Details }
|
||||||
details := nil;
|
details := nil;
|
||||||
@ -325,7 +310,7 @@ begin
|
|||||||
MessageData.ReadBuffer(serializerIID, SizeOf(TGUID));
|
MessageData.ReadBuffer(serializerIID, SizeOf(TGUID));
|
||||||
if serializerIID <> GUID_NULL then
|
if serializerIID <> GUID_NULL then
|
||||||
begin
|
begin
|
||||||
MessageData.ReadBuffer(detailsSize, SizeOf(Cardinal));
|
detailsSize := TStreamUtil.ReadCardinal(MessageData);
|
||||||
if detailsSize > 0 then
|
if detailsSize > 0 then
|
||||||
begin
|
begin
|
||||||
if TX2LogDetailsRegistry.GetSerializer(serializerIID, serializer) then
|
if TX2LogDetailsRegistry.GetSerializer(serializerIID, serializer) then
|
||||||
|
@ -3,7 +3,9 @@ unit X2Log.Details.Default;
|
|||||||
interface
|
interface
|
||||||
uses
|
uses
|
||||||
System.Classes,
|
System.Classes,
|
||||||
|
Vcl.Graphics,
|
||||||
|
|
||||||
|
X2Log.Details.Intf,
|
||||||
X2Log.Intf;
|
X2Log.Intf;
|
||||||
|
|
||||||
|
|
||||||
@ -55,18 +57,49 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TX2LogGraphicDetails = class(TInterfacedObject, IX2LogDetails, IX2LogDetailsGraphic,
|
||||||
|
IX2LogDetailsCopyable, IX2LogDetailsStreamable)
|
||||||
|
private
|
||||||
|
FGraphic: TGraphic;
|
||||||
|
protected
|
||||||
|
{ Dummy parameter to prevent 'Duplicate constructor inaccessible from C++' warning }
|
||||||
|
constructor CreateOwned(AGraphic: TGraphic; ADummy: Integer = 0);
|
||||||
|
public
|
||||||
|
class function CreateIfNotEmpty(AGraphic: TGraphic): TX2LogGraphicDetails;
|
||||||
|
|
||||||
|
constructor Create(AGraphic: TGraphic);
|
||||||
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
{ IX2LogDetails }
|
||||||
|
function GetSerializerIID: TGUID;
|
||||||
|
|
||||||
|
{ IX2LogDetailsGraphic }
|
||||||
|
function GetAsGraphic: TGraphic;
|
||||||
|
|
||||||
|
{ IX2LogDetailsCopyable }
|
||||||
|
procedure CopyToClipboard;
|
||||||
|
|
||||||
|
{ IX2LogDetailsStreamable }
|
||||||
|
procedure SaveToStream(AStream: TStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
Vcl.ClipBrd,
|
Vcl.ClipBrd,
|
||||||
|
Winapi.Windows,
|
||||||
|
|
||||||
X2Log.Constants,
|
X2Log.Constants,
|
||||||
X2Log.Details.Registry;
|
X2Log.Details.Registry,
|
||||||
|
X2Log.Util.Stream;
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
StringDetailsSerializerIID: TGUID = '{4223C30E-6E80-4D66-9EDC-F8688A7413D2}';
|
StringDetailsSerializerIID: TGUID = '{4223C30E-6E80-4D66-9EDC-F8688A7413D2}';
|
||||||
BinaryDetailsSerializerIID: TGUID = '{05F6E8BD-118E-41B3-B626-1F190CC2A7D3}';
|
BinaryDetailsSerializerIID: TGUID = '{05F6E8BD-118E-41B3-B626-1F190CC2A7D3}';
|
||||||
|
GraphicDetailsSerializerIID: TGUID = '{BD31E42A-83DC-4947-A862-79ABAE8D5056}';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -87,6 +120,14 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
TX2LogGraphicDetailsSerializer = class(TInterfacedObject, IX2LogDetailsSerializer)
|
||||||
|
public
|
||||||
|
{ IX2LogDetailsSerializer }
|
||||||
|
procedure Serialize(ADetails: IX2LogDetails; AStream: TStream);
|
||||||
|
function Deserialize(AStream: TStream): IX2LogDetails;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TX2LogStringDetails }
|
{ TX2LogStringDetails }
|
||||||
class function TX2LogStringDetails.CreateIfNotEmpty(const AText: string): TX2LogStringDetails;
|
class function TX2LogStringDetails.CreateIfNotEmpty(const AText: string): TX2LogStringDetails;
|
||||||
begin
|
begin
|
||||||
@ -190,39 +231,83 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TX2LogStringDetailsSerializer }
|
{ TX2LogGraphicDetails }
|
||||||
procedure TX2LogStringDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
|
class function TX2LogGraphicDetails.CreateIfNotEmpty(AGraphic: TGraphic): TX2LogGraphicDetails;
|
||||||
|
begin
|
||||||
|
if Assigned(AGraphic) and (not AGraphic.Empty) then
|
||||||
|
Result := Self.Create(AGraphic)
|
||||||
|
else
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
constructor TX2LogGraphicDetails.Create(AGraphic: TGraphic);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
if not Assigned(AGraphic) then
|
||||||
|
raise EInvalidGraphic.Create('AGraphic can not be nil');
|
||||||
|
|
||||||
|
FGraphic := TGraphicClass(AGraphic.ClassType).Create;
|
||||||
|
FGraphic.Assign(AGraphic);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
constructor TX2LogGraphicDetails.CreateOwned(AGraphic: TGraphic; ADummy: Integer);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FGraphic := AGraphic;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TX2LogGraphicDetails.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FGraphic);
|
||||||
|
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TX2LogGraphicDetails.GetSerializerIID: TGUID;
|
||||||
|
begin
|
||||||
|
Result := GraphicDetailsSerializerIID;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2LogGraphicDetails.CopyToClipboard;
|
||||||
var
|
var
|
||||||
bytes: TBytes;
|
format: Word;
|
||||||
bytesLength: Cardinal;
|
data: NativeUInt;
|
||||||
|
palette: HPALETTE;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
bytes := TEncoding.UTF8.GetBytes((ADetails as IX2LogDetailsText).AsString);
|
GetAsGraphic.SaveToClipboardFormat(format, data, palette);
|
||||||
bytesLength := Length(bytes);
|
end;
|
||||||
|
|
||||||
AStream.WriteBuffer(bytesLength, SizeOf(Cardinal));
|
|
||||||
if bytesLength > 0 then
|
procedure TX2LogGraphicDetails.SaveToStream(AStream: TStream);
|
||||||
AStream.WriteBuffer(bytes[0], bytesLength);
|
begin
|
||||||
|
FGraphic.SaveToStream(AStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TX2LogGraphicDetails.GetAsGraphic: TGraphic;
|
||||||
|
begin
|
||||||
|
Result := FGraphic;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TX2LogStringDetailsSerializer }
|
||||||
|
procedure TX2LogStringDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
|
||||||
|
begin
|
||||||
|
TStreamUtil.WriteString(AStream, (ADetails as IX2LogDetailsText).AsString);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TX2LogStringDetailsSerializer.Deserialize(AStream: TStream): IX2LogDetails;
|
function TX2LogStringDetailsSerializer.Deserialize(AStream: TStream): IX2LogDetails;
|
||||||
var
|
|
||||||
bytes: TBytes;
|
|
||||||
bytesLength: Cardinal;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
AStream.ReadBuffer(bytesLength, SizeOf(Cardinal));
|
Result := TX2LogStringDetails.Create(TStreamUtil.ReadString(AStream));
|
||||||
if bytesLength > 0 then
|
|
||||||
begin
|
|
||||||
SetLength(bytes, bytesLength);
|
|
||||||
AStream.ReadBuffer(bytes[0], bytesLength);
|
|
||||||
|
|
||||||
Result := TX2LogStringDetails.Create(TEncoding.UTF8.GetString(bytes));
|
|
||||||
end else
|
|
||||||
{ Do not return nil; the fact that Deserialize is called means an
|
|
||||||
empty Details was serialized. }
|
|
||||||
Result := TX2LogStringDetails.Create('');
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -230,15 +315,13 @@ end;
|
|||||||
procedure TX2LogBinaryDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
|
procedure TX2LogBinaryDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
|
||||||
var
|
var
|
||||||
stream: TStream;
|
stream: TStream;
|
||||||
streamSize: Cardinal;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
stream := (ADetails as IX2LogDetailsBinary).AsStream;
|
stream := (ADetails as IX2LogDetailsBinary).AsStream;
|
||||||
streamSize := stream.Size;
|
|
||||||
|
|
||||||
AStream.WriteBuffer(streamSize, SizeOf(Cardinal));
|
TStreamUtil.WriteCardinal(AStream, stream.Size);
|
||||||
if streamSize > 0 then
|
if stream.Size > 0 then
|
||||||
AStream.CopyFrom(stream, streamSize);
|
AStream.CopyFrom(stream, stream.Size);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -247,7 +330,7 @@ var
|
|||||||
streamSize: Cardinal;
|
streamSize: Cardinal;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
AStream.ReadBuffer(streamSize, SizeOf(Cardinal));
|
streamSize := TStreamUtil.ReadCardinal(AStream);
|
||||||
if streamSize > 0 then
|
if streamSize > 0 then
|
||||||
Result := TX2LogBinaryDetails.Create(AStream, streamSize)
|
Result := TX2LogBinaryDetails.Create(AStream, streamSize)
|
||||||
else
|
else
|
||||||
@ -257,9 +340,44 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TX2LogGraphicDetailsSerializer }
|
||||||
|
procedure TX2LogGraphicDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
|
||||||
|
var
|
||||||
|
graphic: TGraphic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
graphic := (ADetails as IX2LogDetailsGraphic).AsGraphic;
|
||||||
|
TStreamUtil.WriteString(AStream, graphic.ClassName);
|
||||||
|
graphic.SaveToStream(AStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TX2LogGraphicDetailsSerializer.Deserialize(AStream: TStream): IX2LogDetails;
|
||||||
|
var
|
||||||
|
graphicClass: TGraphicClass;
|
||||||
|
graphic: TGraphic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
graphicClass := TGraphicClass(GetClass(TStreamUtil.ReadString(AStream)));
|
||||||
|
if Assigned(graphicClass) then
|
||||||
|
begin
|
||||||
|
graphic := graphicClass.Create;
|
||||||
|
try
|
||||||
|
graphic.LoadFromStream(AStream);
|
||||||
|
Result := TX2LogGraphicDetails.CreateOwned(graphic);
|
||||||
|
except
|
||||||
|
FreeAndNil(graphic);
|
||||||
|
raise;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
TX2LogDetailsRegistry.Register(StringDetailsSerializerIID, TX2LogStringDetailsSerializer.Create);
|
TX2LogDetailsRegistry.Register(StringDetailsSerializerIID, TX2LogStringDetailsSerializer.Create);
|
||||||
TX2LogDetailsRegistry.Register(BinaryDetailsSerializerIID, TX2LogBinaryDetailsSerializer.Create);
|
TX2LogDetailsRegistry.Register(BinaryDetailsSerializerIID, TX2LogBinaryDetailsSerializer.Create);
|
||||||
|
TX2LogDetailsRegistry.Register(GraphicDetailsSerializerIID, TX2LogGraphicDetailsSerializer.Create);
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
39
X2Log.Details.Intf.pas
Normal file
39
X2Log.Details.Intf.pas
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
unit X2Log.Details.Intf;
|
||||||
|
|
||||||
|
interface
|
||||||
|
uses
|
||||||
|
System.Classes,
|
||||||
|
Vcl.Graphics,
|
||||||
|
|
||||||
|
X2Log.Intf;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
IX2LogDetailsText = interface(IX2LogDetails)
|
||||||
|
['{D5F194E9-8633-4575-801D-E8983124118F}']
|
||||||
|
function GetAsString: string;
|
||||||
|
|
||||||
|
property AsString: string read GetAsString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
IX2LogDetailsBinary = interface(IX2LogDetails)
|
||||||
|
['{265739E7-BB65-434B-BCD3-BB89B936A854}']
|
||||||
|
function GetAsStream: TStream;
|
||||||
|
|
||||||
|
{ Note: Stream Position will be reset by GetAsStream }
|
||||||
|
property AsStream: TStream read GetAsStream;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
IX2LogDetailsGraphic = interface(IX2LogDetails)
|
||||||
|
['{ED8200AA-0D0F-4D8D-BE7D-A32AC7D630AF}']
|
||||||
|
function GetAsGraphic: TGraphic;
|
||||||
|
|
||||||
|
property AsGraphic: TGraphic read GetAsGraphic;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
end.
|
@ -45,23 +45,6 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
IX2LogDetailsText = interface(IX2LogDetails)
|
|
||||||
['{D5F194E9-8633-4575-801D-E8983124118F}']
|
|
||||||
function GetAsString: string;
|
|
||||||
|
|
||||||
property AsString: string read GetAsString;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
IX2LogDetailsBinary = interface(IX2LogDetails)
|
|
||||||
['{265739E7-BB65-434B-BCD3-BB89B936A854}']
|
|
||||||
function GetAsStream: TStream;
|
|
||||||
|
|
||||||
{ Note: Stream Position will be reset by GetAsStream }
|
|
||||||
property AsStream: TStream read GetAsStream;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
{ Logging }
|
{ Logging }
|
||||||
IX2LogBase = interface
|
IX2LogBase = interface
|
||||||
['{1949E8DC-6DC5-43DC-B678-55CF8274E79D}']
|
['{1949E8DC-6DC5-43DC-B678-55CF8274E79D}']
|
||||||
|
@ -73,7 +73,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
|
|||||||
Left = 0
|
Left = 0
|
||||||
Top = 0
|
Top = 0
|
||||||
Width = 378
|
Width = 378
|
||||||
Height = 17
|
Height = 19
|
||||||
Sections = <
|
Sections = <
|
||||||
item
|
item
|
||||||
AutoSize = True
|
AutoSize = True
|
||||||
@ -85,9 +85,9 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
|
|||||||
end
|
end
|
||||||
object reDetails: TRichEdit
|
object reDetails: TRichEdit
|
||||||
Left = 0
|
Left = 0
|
||||||
Top = 17
|
Top = 19
|
||||||
Width = 378
|
Width = 378
|
||||||
Height = 453
|
Height = 451
|
||||||
Align = alClient
|
Align = alClient
|
||||||
BorderStyle = bsNone
|
BorderStyle = bsNone
|
||||||
Font.Charset = ANSI_CHARSET
|
Font.Charset = ANSI_CHARSET
|
||||||
@ -100,6 +100,28 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
|
|||||||
ReadOnly = True
|
ReadOnly = True
|
||||||
ScrollBars = ssBoth
|
ScrollBars = ssBoth
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
object sbDetailsImage: TScrollBox
|
||||||
|
Left = 0
|
||||||
|
Top = 19
|
||||||
|
Width = 378
|
||||||
|
Height = 451
|
||||||
|
HorzScrollBar.Tracking = True
|
||||||
|
VertScrollBar.Tracking = True
|
||||||
|
Align = alClient
|
||||||
|
BorderStyle = bsNone
|
||||||
|
DoubleBuffered = True
|
||||||
|
ParentDoubleBuffered = False
|
||||||
|
TabOrder = 2
|
||||||
|
Visible = False
|
||||||
|
object imgDetailsImage: TImage
|
||||||
|
Left = 0
|
||||||
|
Top = 0
|
||||||
|
Width = 25
|
||||||
|
Height = 25
|
||||||
|
AutoSize = True
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -123,7 +145,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
|
|||||||
Header.Font.Height = -11
|
Header.Font.Height = -11
|
||||||
Header.Font.Name = 'Tahoma'
|
Header.Font.Name = 'Tahoma'
|
||||||
Header.Font.Style = []
|
Header.Font.Style = []
|
||||||
Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoHeaderClickAutoSort]
|
Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoVisible]
|
||||||
HintMode = hmHint
|
HintMode = hmHint
|
||||||
Images = ilsLog
|
Images = ilsLog
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
@ -233,7 +255,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
|
|||||||
Left = 448
|
Left = 448
|
||||||
Top = 48
|
Top = 48
|
||||||
Bitmap = {
|
Bitmap = {
|
||||||
494C010109004000B80010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
|
494C010109004000BC0010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
|
||||||
0000000000003600000028000000400000003000000001002000000000000030
|
0000000000003600000028000000400000003000000001002000000000000030
|
||||||
0000000000000000000000000000000000000000000000000000000000000000
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
@ -17,6 +17,7 @@ uses
|
|||||||
VirtualTrees,
|
VirtualTrees,
|
||||||
Winapi.Messages,
|
Winapi.Messages,
|
||||||
|
|
||||||
|
X2Log.Details.Intf,
|
||||||
X2Log.Intf;
|
X2Log.Intf;
|
||||||
|
|
||||||
|
|
||||||
@ -60,6 +61,8 @@ type
|
|||||||
actShowWarning: TAction;
|
actShowWarning: TAction;
|
||||||
actShowError: TAction;
|
actShowError: TAction;
|
||||||
lblFilter: TLabel;
|
lblFilter: TLabel;
|
||||||
|
sbDetailsImage: TScrollBox;
|
||||||
|
imgDetailsImage: TImage;
|
||||||
|
|
||||||
procedure FormShow(Sender: TObject);
|
procedure FormShow(Sender: TObject);
|
||||||
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
||||||
@ -106,6 +109,9 @@ type
|
|||||||
|
|
||||||
procedure SetDetails(ADetails: IX2LogDetails);
|
procedure SetDetails(ADetails: IX2LogDetails);
|
||||||
procedure SetBinaryDetails(ADetails: IX2LogDetailsBinary);
|
procedure SetBinaryDetails(ADetails: IX2LogDetailsBinary);
|
||||||
|
procedure SetGraphicDetails(ADetails: IX2LogDetailsGraphic);
|
||||||
|
|
||||||
|
procedure SetVisibleDetails(AControl: TControl);
|
||||||
|
|
||||||
property Details: IX2LogDetails read FDetails;
|
property Details: IX2LogDetails read FDetails;
|
||||||
property LogObservable: IX2LogObservable read FLogObservable;
|
property LogObservable: IX2LogObservable read FLogObservable;
|
||||||
@ -435,6 +441,7 @@ end;
|
|||||||
|
|
||||||
procedure TX2LogObserverMonitorForm.SetDetails(ADetails: IX2LogDetails);
|
procedure TX2LogObserverMonitorForm.SetDetails(ADetails: IX2LogDetails);
|
||||||
var
|
var
|
||||||
|
logDetailsGraphic: IX2LogDetailsGraphic;
|
||||||
logDetailsBinary: IX2LogDetailsBinary;
|
logDetailsBinary: IX2LogDetailsBinary;
|
||||||
logDetailsText: IX2LogDetailsText;
|
logDetailsText: IX2LogDetailsText;
|
||||||
|
|
||||||
@ -443,13 +450,19 @@ begin
|
|||||||
|
|
||||||
if Assigned(Details) then
|
if Assigned(Details) then
|
||||||
begin
|
begin
|
||||||
if Supports(ADetails, IX2LogDetailsBinary, logDetailsBinary) then
|
if Supports(ADetails, IX2LogDetailsGraphic, logDetailsGraphic) then
|
||||||
|
SetGraphicDetails(logDetailsGraphic)
|
||||||
|
|
||||||
|
else if Supports(ADetails, IX2LogDetailsBinary, logDetailsBinary) then
|
||||||
SetBinaryDetails(logDetailsBinary)
|
SetBinaryDetails(logDetailsBinary)
|
||||||
|
|
||||||
else if Supports(ADetails, IX2LogDetailsText, logDetailsText) then
|
else if Supports(ADetails, IX2LogDetailsText, logDetailsText) then
|
||||||
|
begin
|
||||||
reDetails.Text := logDetailsText.AsString;
|
reDetails.Text := logDetailsText.AsString;
|
||||||
|
SetVisibleDetails(reDetails);
|
||||||
|
end;
|
||||||
end else
|
end else
|
||||||
reDetails.Clear;
|
SetVisibleDetails(nil);
|
||||||
|
|
||||||
|
|
||||||
actCopyDetails.Enabled := Supports(ADetails, IX2LogDetailsCopyable);
|
actCopyDetails.Enabled := Supports(ADetails, IX2LogDetailsCopyable);
|
||||||
@ -549,10 +562,38 @@ begin
|
|||||||
reDetails.Lines.Add(line);
|
reDetails.Lines.Add(line);
|
||||||
finally
|
finally
|
||||||
reDetails.Lines.EndUpdate;
|
reDetails.Lines.EndUpdate;
|
||||||
|
|
||||||
|
SetVisibleDetails(reDetails);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2LogObserverMonitorForm.SetGraphicDetails(ADetails: IX2LogDetailsGraphic);
|
||||||
|
begin
|
||||||
|
imgDetailsImage.Picture.Assign(ADetails.AsGraphic);
|
||||||
|
SetVisibleDetails(sbDetailsImage);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2LogObserverMonitorForm.SetVisibleDetails(AControl: TControl);
|
||||||
|
begin
|
||||||
|
if Assigned(AControl) then
|
||||||
|
begin
|
||||||
|
AControl.BringToFront;
|
||||||
|
AControl.Visible := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
reDetails.Visible := (AControl = reDetails);
|
||||||
|
sbDetailsImage.Visible := (AControl = sbDetailsImage);
|
||||||
|
|
||||||
|
if not reDetails.Visible then
|
||||||
|
reDetails.Clear;
|
||||||
|
|
||||||
|
if not sbDetailsImage.Visible then
|
||||||
|
imgDetailsImage.Picture.Assign(nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TX2LogObserverMonitorForm.vstLogInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
|
procedure TX2LogObserverMonitorForm.vstLogInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
|
||||||
var InitialStates: TVirtualNodeInitStates);
|
var InitialStates: TVirtualNodeInitStates);
|
||||||
var
|
var
|
||||||
@ -648,6 +689,8 @@ end;
|
|||||||
procedure TX2LogObserverMonitorForm.actClearExecute(Sender: TObject);
|
procedure TX2LogObserverMonitorForm.actClearExecute(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
vstLog.Clear;
|
vstLog.Clear;
|
||||||
|
SetDetails(nil);
|
||||||
|
|
||||||
UpdateUI;
|
UpdateUI;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ uses
|
|||||||
System.Types,
|
System.Types,
|
||||||
Winapi.Windows,
|
Winapi.Windows,
|
||||||
|
|
||||||
X2Log.Details.Registry;
|
X2Log.Details.Registry,
|
||||||
|
X2Log.Util.Stream;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -194,23 +195,10 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
function TX2LogNamedPipeClient.DoSend(AEntry: TX2LogQueueEntry): Boolean;
|
function TX2LogNamedPipeClient.DoSend(AEntry: TX2LogQueueEntry): Boolean;
|
||||||
|
|
||||||
procedure WriteString(const ASource: WideString);
|
|
||||||
var
|
|
||||||
sourceLength: Cardinal;
|
|
||||||
|
|
||||||
begin
|
|
||||||
sourceLength := Length(ASource);
|
|
||||||
WriteBuffer.WriteBuffer(sourceLength, SizeOf(Cardinal));
|
|
||||||
WriteBuffer.WriteBuffer(PWideChar(ASource)^, sourceLength * SizeOf(WideChar));
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
var
|
var
|
||||||
header: TX2LogMessageHeader;
|
header: TX2LogMessageHeader;
|
||||||
bytesWritten: Cardinal;
|
bytesWritten: Cardinal;
|
||||||
lastError: Cardinal;
|
lastError: Cardinal;
|
||||||
detailsSize: Cardinal;
|
|
||||||
detailsStream: TMemoryStream;
|
detailsStream: TMemoryStream;
|
||||||
serializerIID: TGUID;
|
serializerIID: TGUID;
|
||||||
serializer: IX2LogDetailsSerializer;
|
serializer: IX2LogDetailsSerializer;
|
||||||
@ -229,7 +217,7 @@ begin
|
|||||||
WriteBuffer.WriteBuffer(header, SizeOf(header));
|
WriteBuffer.WriteBuffer(header, SizeOf(header));
|
||||||
|
|
||||||
{ Message }
|
{ Message }
|
||||||
WriteString(AEntry.Message);
|
TStreamUtil.WriteString(WriteBuffer, AEntry.Message);
|
||||||
|
|
||||||
{ Details }
|
{ Details }
|
||||||
if TX2LogDetailsRegistry.GetSerializer(AEntry.Details, serializer) then
|
if TX2LogDetailsRegistry.GetSerializer(AEntry.Details, serializer) then
|
||||||
@ -241,8 +229,7 @@ begin
|
|||||||
serializerIID := AEntry.Details.SerializerIID;
|
serializerIID := AEntry.Details.SerializerIID;
|
||||||
WriteBuffer.WriteBuffer(serializerIID, SizeOf(TGUID));
|
WriteBuffer.WriteBuffer(serializerIID, SizeOf(TGUID));
|
||||||
|
|
||||||
detailsSize := detailsStream.Size;
|
TStreamUtil.WriteCardinal(WriteBuffer, detailsStream.Size);
|
||||||
WriteBuffer.WriteBuffer(detailsSize, SizeOf(Cardinal));
|
|
||||||
WriteBuffer.CopyFrom(detailsStream, 0);
|
WriteBuffer.CopyFrom(detailsStream, 0);
|
||||||
finally
|
finally
|
||||||
FreeAndNil(detailsStream);
|
FreeAndNil(detailsStream);
|
||||||
|
77
X2Log.Util.Stream.pas
Normal file
77
X2Log.Util.Stream.pas
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
unit X2Log.Util.Stream;
|
||||||
|
|
||||||
|
interface
|
||||||
|
uses
|
||||||
|
System.Classes,
|
||||||
|
System.SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
TStreamUtil = class(TObject)
|
||||||
|
protected
|
||||||
|
class function GetEncoding(AEncoding: TEncoding): TEncoding;
|
||||||
|
public
|
||||||
|
class function ReadCardinal(AStream: TStream): Cardinal;
|
||||||
|
class procedure WriteCardinal(AStream: TStream; AValue: Cardinal);
|
||||||
|
|
||||||
|
class function ReadString(AStream: TStream; AEncoding: TEncoding = nil): string;
|
||||||
|
class procedure WriteString(AStream: TStream; const AValue: string; AEncoding: TEncoding = nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
|
||||||
|
{ TStreamUtil }
|
||||||
|
class function TStreamUtil.GetEncoding(AEncoding: TEncoding): TEncoding;
|
||||||
|
begin
|
||||||
|
if Assigned(AEncoding) then
|
||||||
|
Result := AEncoding
|
||||||
|
else
|
||||||
|
Result := TEncoding.UTF8;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
class function TStreamUtil.ReadCardinal(AStream: TStream): Cardinal;
|
||||||
|
begin
|
||||||
|
AStream.ReadBuffer(Result, SizeOf(Cardinal));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
class procedure TStreamUtil.WriteCardinal(AStream: TStream; AValue: Cardinal);
|
||||||
|
begin
|
||||||
|
AStream.WriteBuffer(AValue, SizeOf(Cardinal));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
class function TStreamUtil.ReadString(AStream: TStream; AEncoding: TEncoding): string;
|
||||||
|
var
|
||||||
|
bytes: TBytes;
|
||||||
|
bytesLength: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
bytesLength := ReadCardinal(AStream);
|
||||||
|
if bytesLength > 0 then
|
||||||
|
begin
|
||||||
|
SetLength(bytes, bytesLength);
|
||||||
|
AStream.ReadBuffer(bytes[0], bytesLength);
|
||||||
|
|
||||||
|
Result := GetEncoding(AEncoding).GetString(bytes);
|
||||||
|
end else
|
||||||
|
Result := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
class procedure TStreamUtil.WriteString(AStream: TStream; const AValue: string; AEncoding: TEncoding);
|
||||||
|
var
|
||||||
|
bytes: TBytes;
|
||||||
|
bytesLength: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
bytes := GetEncoding(AEncoding).GetBytes(AValue);
|
||||||
|
bytesLength := Length(bytes);
|
||||||
|
|
||||||
|
WriteCardinal(AStream, bytesLength);
|
||||||
|
if bytesLength > 0 then
|
||||||
|
AStream.WriteBuffer(bytes[0], bytesLength);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user