1
0
mirror of synced 2024-09-19 10:26:08 +00:00

Added: FS#7 - Add support for graphics as details

Added: TStreamUtil to clean up the code a bit
This commit is contained in:
Mark van Renswoude 2014-06-01 13:32:21 +00:00
parent bf0bb05983
commit 3cbf8c520f
15 changed files with 408 additions and 104 deletions

View File

@ -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}

View File

@ -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

Binary file not shown.

View File

@ -0,0 +1 @@
GraphicDetails RCDATA "resources\\Graphic.jpg"

BIN
Test/resources/Graphic.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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.

View File

@ -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}']

View File

@ -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

View File

@ -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;

View File

@ -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
View 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.