diff --git a/Test/X2LogTest.dpr b/Test/X2LogTest.dpr
index 6fcbb59..7c82113 100644
--- a/Test/X2LogTest.dpr
+++ b/Test/X2LogTest.dpr
@@ -1,7 +1,8 @@
program X2LogTest;
+{$R *.dres}
+
uses
-// FastMM4,
Forms,
MainFrm in 'source\MainFrm.pas' {MainForm},
X2Log.Intf in '..\X2Log.Intf.pas',
@@ -19,7 +20,9 @@ uses
X2Log.Client.NamedPipe in '..\X2Log.Client.NamedPipe.pas',
X2Log.Client.Base in '..\X2Log.Client.Base.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}
diff --git a/Test/X2LogTest.dproj b/Test/X2LogTest.dproj
index f7074ff..abc09a7 100644
--- a/Test/X2LogTest.dproj
+++ b/Test/X2LogTest.dproj
@@ -192,6 +192,12 @@
+
+
+
+ RCDATA
+ GraphicDetails
+
Cfg_2
Base
diff --git a/Test/X2LogTest.dres b/Test/X2LogTest.dres
new file mode 100644
index 0000000..b41465d
Binary files /dev/null and b/Test/X2LogTest.dres differ
diff --git a/Test/X2LogTestResource.rc b/Test/X2LogTestResource.rc
new file mode 100644
index 0000000..337c6b6
--- /dev/null
+++ b/Test/X2LogTestResource.rc
@@ -0,0 +1 @@
+GraphicDetails RCDATA "resources\\Graphic.jpg"
diff --git a/Test/resources/Graphic.jpg b/Test/resources/Graphic.jpg
new file mode 100644
index 0000000..61ce5ab
Binary files /dev/null and b/Test/resources/Graphic.jpg differ
diff --git a/Test/source/MainFrm.dfm b/Test/source/MainFrm.dfm
index 5ad1a81..330e329 100644
--- a/Test/source/MainFrm.dfm
+++ b/Test/source/MainFrm.dfm
@@ -211,7 +211,7 @@ object MainForm: TMainForm
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 0
- ActivePage = tsText
+ ActivePage = tsBinary
Align = alTop
TabOrder = 2
object tsText: TTabSheet
@@ -309,14 +309,23 @@ object MainForm: TMainForm
object tsBinary: TTabSheet
Caption = 'Binary'
ImageIndex = 2
- object btnBinary: TButton
+ object btnBinaryRawByteString: TButton
Left = 12
- Top = 23
- Width = 62
+ Top = 15
+ Width = 152
Height = 21
- Caption = 'Binary'
+ Caption = 'Binary (RawByteString)'
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
@@ -384,7 +393,7 @@ object MainForm: TMainForm
Left = 552
Top = 176
Bitmap = {
- 494C0101020014003C000C000C00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+ 494C01010200140044000C000C00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000300000000C00000001002000000000000009
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
diff --git a/Test/source/MainFrm.pas b/Test/source/MainFrm.pas
index e7f2aa5..5a85870 100644
--- a/Test/source/MainFrm.pas
+++ b/Test/source/MainFrm.pas
@@ -45,7 +45,7 @@ type
rbAbsolute: TRadioButton;
edtPipeName: TEdit;
lblPipeName: TLabel;
- btnBinary: TButton;
+ btnBinaryRawByteString: TButton;
pcDispatch: TPageControl;
tsText: TTabSheet;
tsException: TTabSheet;
@@ -54,6 +54,7 @@ type
bvlDispatch: TBevel;
pnlObservers: TPanel;
bvlObservers: TBevel;
+ btnGraphic: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@@ -69,6 +70,8 @@ type
procedure btnFileStopClick(Sender: TObject);
procedure btnNamedPipeStartClick(Sender: TObject);
procedure btnNamedPipeStopClick(Sender: TObject);
+ procedure btnBinaryRawByteStringClick(Sender: TObject);
+ procedure btnGraphicClick(Sender: TObject);
private
FLog: IX2Log;
FEventObserver: IX2LogObserver;
@@ -82,11 +85,13 @@ type
implementation
uses
System.SysUtils,
+ Vcl.Imaging.Jpeg,
Winapi.Windows,
X2Log,
X2Log.Constants,
X2Log.Details.Default,
+ X2Log.Details.Intf,
X2Log.Exception.madExcept,
X2Log.Observer.Event,
X2Log.Observer.LogFile,
@@ -181,9 +186,35 @@ begin
else if Sender = btnWarning then
FLog.Warning(edtMessage.Text)
else if Sender = btnError then
- FLog.Error(edtMessage.Text)
- else if Sender = btnBinary then
- FLog.InfoEx(edtMessage.Text, TX2LogBinaryDetails.Create(#0#1#2#3'Test'#12'Some more data'));
+ FLog.Error(edtMessage.Text);
+end;
+
+
+procedure TMainForm.btnBinaryRawByteStringClick(Sender: TObject);
+begin
+ FLog.InfoEx(edtMessage.Text, TX2LogBinaryDetails.Create(#0#1#2#3'Test'#12'Some more data'));
+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;
diff --git a/X2Log.Client.NamedPipe.pas b/X2Log.Client.NamedPipe.pas
index 3bfae15..3781cc0 100644
--- a/X2Log.Client.NamedPipe.pas
+++ b/X2Log.Client.NamedPipe.pas
@@ -29,7 +29,8 @@ uses
Winapi.Windows,
X2Log.Details.Default,
- X2Log.Details.Registry;
+ X2Log.Details.Registry,
+ X2Log.Util.Stream;
type
@@ -271,22 +272,6 @@ end;
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
header: TX2LogMessageHeaderV1;
headerDiff: Integer;
@@ -317,7 +302,7 @@ begin
raise EReadError.Create('Header too small');
{ Message }
- msg := ReadString;
+ msg := TStreamUtil.ReadString(MessageData);
{ Details }
details := nil;
@@ -325,7 +310,7 @@ begin
MessageData.ReadBuffer(serializerIID, SizeOf(TGUID));
if serializerIID <> GUID_NULL then
begin
- MessageData.ReadBuffer(detailsSize, SizeOf(Cardinal));
+ detailsSize := TStreamUtil.ReadCardinal(MessageData);
if detailsSize > 0 then
begin
if TX2LogDetailsRegistry.GetSerializer(serializerIID, serializer) then
diff --git a/X2Log.Details.Default.pas b/X2Log.Details.Default.pas
index 968dbed..7329e9d 100644
--- a/X2Log.Details.Default.pas
+++ b/X2Log.Details.Default.pas
@@ -3,7 +3,9 @@ unit X2Log.Details.Default;
interface
uses
System.Classes,
+ Vcl.Graphics,
+ X2Log.Details.Intf,
X2Log.Intf;
@@ -55,18 +57,49 @@ type
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
uses
System.SysUtils,
Vcl.ClipBrd,
+ Winapi.Windows,
X2Log.Constants,
- X2Log.Details.Registry;
+ X2Log.Details.Registry,
+ X2Log.Util.Stream;
const
StringDetailsSerializerIID: TGUID = '{4223C30E-6E80-4D66-9EDC-F8688A7413D2}';
BinaryDetailsSerializerIID: TGUID = '{05F6E8BD-118E-41B3-B626-1F190CC2A7D3}';
+ GraphicDetailsSerializerIID: TGUID = '{BD31E42A-83DC-4947-A862-79ABAE8D5056}';
@@ -87,6 +120,14 @@ type
end;
+ TX2LogGraphicDetailsSerializer = class(TInterfacedObject, IX2LogDetailsSerializer)
+ public
+ { IX2LogDetailsSerializer }
+ procedure Serialize(ADetails: IX2LogDetails; AStream: TStream);
+ function Deserialize(AStream: TStream): IX2LogDetails;
+ end;
+
+
{ TX2LogStringDetails }
class function TX2LogStringDetails.CreateIfNotEmpty(const AText: string): TX2LogStringDetails;
begin
@@ -190,39 +231,83 @@ begin
end;
-{ TX2LogStringDetailsSerializer }
-procedure TX2LogStringDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
+{ TX2LogGraphicDetails }
+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
- bytes: TBytes;
- bytesLength: Cardinal;
+ format: Word;
+ data: NativeUInt;
+ palette: HPALETTE;
begin
- bytes := TEncoding.UTF8.GetBytes((ADetails as IX2LogDetailsText).AsString);
- bytesLength := Length(bytes);
+ GetAsGraphic.SaveToClipboardFormat(format, data, palette);
+end;
- AStream.WriteBuffer(bytesLength, SizeOf(Cardinal));
- if bytesLength > 0 then
- AStream.WriteBuffer(bytes[0], bytesLength);
+
+procedure TX2LogGraphicDetails.SaveToStream(AStream: TStream);
+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;
function TX2LogStringDetailsSerializer.Deserialize(AStream: TStream): IX2LogDetails;
-var
- bytes: TBytes;
- bytesLength: Cardinal;
-
begin
- AStream.ReadBuffer(bytesLength, SizeOf(Cardinal));
- 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('');
+ Result := TX2LogStringDetails.Create(TStreamUtil.ReadString(AStream));
end;
@@ -230,15 +315,13 @@ end;
procedure TX2LogBinaryDetailsSerializer.Serialize(ADetails: IX2LogDetails; AStream: TStream);
var
stream: TStream;
- streamSize: Cardinal;
begin
stream := (ADetails as IX2LogDetailsBinary).AsStream;
- streamSize := stream.Size;
- AStream.WriteBuffer(streamSize, SizeOf(Cardinal));
- if streamSize > 0 then
- AStream.CopyFrom(stream, streamSize);
+ TStreamUtil.WriteCardinal(AStream, stream.Size);
+ if stream.Size > 0 then
+ AStream.CopyFrom(stream, stream.Size);
end;
@@ -247,7 +330,7 @@ var
streamSize: Cardinal;
begin
- AStream.ReadBuffer(streamSize, SizeOf(Cardinal));
+ streamSize := TStreamUtil.ReadCardinal(AStream);
if streamSize > 0 then
Result := TX2LogBinaryDetails.Create(AStream, streamSize)
else
@@ -257,9 +340,44 @@ begin
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
TX2LogDetailsRegistry.Register(StringDetailsSerializerIID, TX2LogStringDetailsSerializer.Create);
TX2LogDetailsRegistry.Register(BinaryDetailsSerializerIID, TX2LogBinaryDetailsSerializer.Create);
+ TX2LogDetailsRegistry.Register(GraphicDetailsSerializerIID, TX2LogGraphicDetailsSerializer.Create);
end.
diff --git a/X2Log.Details.Intf.pas b/X2Log.Details.Intf.pas
new file mode 100644
index 0000000..fff8720
--- /dev/null
+++ b/X2Log.Details.Intf.pas
@@ -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.
diff --git a/X2Log.Intf.pas b/X2Log.Intf.pas
index fceb355..6dc19d2 100644
--- a/X2Log.Intf.pas
+++ b/X2Log.Intf.pas
@@ -45,23 +45,6 @@ type
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 }
IX2LogBase = interface
['{1949E8DC-6DC5-43DC-B678-55CF8274E79D}']
diff --git a/X2Log.Observer.MonitorForm.dfm b/X2Log.Observer.MonitorForm.dfm
index 1172a16..8400e58 100644
--- a/X2Log.Observer.MonitorForm.dfm
+++ b/X2Log.Observer.MonitorForm.dfm
@@ -73,7 +73,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
Left = 0
Top = 0
Width = 378
- Height = 17
+ Height = 19
Sections = <
item
AutoSize = True
@@ -85,9 +85,9 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
end
object reDetails: TRichEdit
Left = 0
- Top = 17
+ Top = 19
Width = 378
- Height = 453
+ Height = 451
Align = alClient
BorderStyle = bsNone
Font.Charset = ANSI_CHARSET
@@ -100,6 +100,28 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
ReadOnly = True
ScrollBars = ssBoth
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
@@ -123,7 +145,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
Header.Font.Height = -11
Header.Font.Name = 'Tahoma'
Header.Font.Style = []
- Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoHeaderClickAutoSort]
+ Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoVisible]
HintMode = hmHint
Images = ilsLog
TabOrder = 0
@@ -233,7 +255,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
Left = 448
Top = 48
Bitmap = {
- 494C010109004000B80010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+ 494C010109004000BC0010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000400000003000000001002000000000000030
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
diff --git a/X2Log.Observer.MonitorForm.pas b/X2Log.Observer.MonitorForm.pas
index a293ed8..24bbf62 100644
--- a/X2Log.Observer.MonitorForm.pas
+++ b/X2Log.Observer.MonitorForm.pas
@@ -17,6 +17,7 @@ uses
VirtualTrees,
Winapi.Messages,
+ X2Log.Details.Intf,
X2Log.Intf;
@@ -60,6 +61,8 @@ type
actShowWarning: TAction;
actShowError: TAction;
lblFilter: TLabel;
+ sbDetailsImage: TScrollBox;
+ imgDetailsImage: TImage;
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
@@ -106,6 +109,9 @@ type
procedure SetDetails(ADetails: IX2LogDetails);
procedure SetBinaryDetails(ADetails: IX2LogDetailsBinary);
+ procedure SetGraphicDetails(ADetails: IX2LogDetailsGraphic);
+
+ procedure SetVisibleDetails(AControl: TControl);
property Details: IX2LogDetails read FDetails;
property LogObservable: IX2LogObservable read FLogObservable;
@@ -435,6 +441,7 @@ end;
procedure TX2LogObserverMonitorForm.SetDetails(ADetails: IX2LogDetails);
var
+ logDetailsGraphic: IX2LogDetailsGraphic;
logDetailsBinary: IX2LogDetailsBinary;
logDetailsText: IX2LogDetailsText;
@@ -443,13 +450,19 @@ begin
if Assigned(Details) then
begin
- if Supports(ADetails, IX2LogDetailsBinary, logDetailsBinary) then
+ if Supports(ADetails, IX2LogDetailsGraphic, logDetailsGraphic) then
+ SetGraphicDetails(logDetailsGraphic)
+
+ else if Supports(ADetails, IX2LogDetailsBinary, logDetailsBinary) then
SetBinaryDetails(logDetailsBinary)
else if Supports(ADetails, IX2LogDetailsText, logDetailsText) then
+ begin
reDetails.Text := logDetailsText.AsString;
+ SetVisibleDetails(reDetails);
+ end;
end else
- reDetails.Clear;
+ SetVisibleDetails(nil);
actCopyDetails.Enabled := Supports(ADetails, IX2LogDetailsCopyable);
@@ -549,10 +562,38 @@ begin
reDetails.Lines.Add(line);
finally
reDetails.Lines.EndUpdate;
+
+ SetVisibleDetails(reDetails);
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;
var InitialStates: TVirtualNodeInitStates);
var
@@ -648,6 +689,8 @@ end;
procedure TX2LogObserverMonitorForm.actClearExecute(Sender: TObject);
begin
vstLog.Clear;
+ SetDetails(nil);
+
UpdateUI;
end;
diff --git a/X2Log.Observer.NamedPipe.pas b/X2Log.Observer.NamedPipe.pas
index b1ecc22..045a8c2 100644
--- a/X2Log.Observer.NamedPipe.pas
+++ b/X2Log.Observer.NamedPipe.pas
@@ -27,7 +27,8 @@ uses
System.Types,
Winapi.Windows,
- X2Log.Details.Registry;
+ X2Log.Details.Registry,
+ X2Log.Util.Stream;
type
@@ -194,23 +195,10 @@ end;
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
header: TX2LogMessageHeader;
bytesWritten: Cardinal;
lastError: Cardinal;
- detailsSize: Cardinal;
detailsStream: TMemoryStream;
serializerIID: TGUID;
serializer: IX2LogDetailsSerializer;
@@ -229,7 +217,7 @@ begin
WriteBuffer.WriteBuffer(header, SizeOf(header));
{ Message }
- WriteString(AEntry.Message);
+ TStreamUtil.WriteString(WriteBuffer, AEntry.Message);
{ Details }
if TX2LogDetailsRegistry.GetSerializer(AEntry.Details, serializer) then
@@ -241,8 +229,7 @@ begin
serializerIID := AEntry.Details.SerializerIID;
WriteBuffer.WriteBuffer(serializerIID, SizeOf(TGUID));
- detailsSize := detailsStream.Size;
- WriteBuffer.WriteBuffer(detailsSize, SizeOf(Cardinal));
+ TStreamUtil.WriteCardinal(WriteBuffer, detailsStream.Size);
WriteBuffer.CopyFrom(detailsStream, 0);
finally
FreeAndNil(detailsStream);
diff --git a/X2Log.Util.Stream.pas b/X2Log.Util.Stream.pas
new file mode 100644
index 0000000..e0b70cd
--- /dev/null
+++ b/X2Log.Util.Stream.pas
@@ -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.