unit MegaDemoClientMain; { Activate this define if you are using the demo without having Indy installed. Simply click "Ignore" when opening the form to have the Indy components remove, set the define and rebuild the demo. } {.$DEFINE NO_INDY} {.$DEFINE NO_SYNAPSE} {$I RemObjects.inc} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin, ExtCtrls, ComCtrls, SyncObjs, uROClientIntf, TypInfo, {$IFNDEF NO_INDY} uROIndyTCPChannel, uROIndyHTTPChannel, {$ENDIF NO_INDY} {$IFNDEF NO_SYNAPSE} uROSynapseHttpChannel, {$ENDIF} uROClient, uROBINMessage, uROWinMessageChannel, uROSOAPMessage, uROWinInetHttpChannel, uROXMLIntf, MegaDemoLibrary_Intf, uROTypes, uRORemoteService, uROPoweredByRemObjectsButton, uROXmlRpcMessage, ImgList, Buttons, uRODynamicRequest, uROPostMessage, CheckLst; const msgWarningPorts = 'Issuing many requests in a short period of time can cause the client PC to run out of ip-port combinations.' + sLineBreak + 'Once an ip-port combination has been used, it takes some time (1 to 4 min on Windows) before that combination can be re-used' + sLineBreak + '' + sLineBreak + 'Run netstat from command prompt to see how many connections are in TIME_WAIT state.' + sLineBreak + '' + sLineBreak + 'If you have long loops (i.e 50 cycles or 5 threads running 10) allow your PC to restore some ports by not' + sLineBreak + 'doing anything for a minute or so once the test has completed.' + sLineBreak + '' + sLineBreak + 'Do you want to continue?'; type TArrayType = (atInteger, atString, atTPerson); TStressMethod = function(aService: IMegaDemoService): integer of object; TMegaDemoClientMainForm = class(TForm) IndyHttpChannel: TROIndyHTTPChannel; BINMessage: TROBINMessage; SOAPMessage: TROSOAPMessage; IndyTcpChannel: TROIndyTCPChannel; WinMessageChannel: TROWinMessageChannel; PageControl1: TPageControl; tsSoap: TTabSheet; tsLog: TTabSheet; Memo: TMemo; Memo1: TMemo; Memo2: TMemo; Splitter1: TSplitter; WininetHttpChannel: TROWinInetHTTPChannel; RemoteService: TRORemoteService; Panel3: TPanel; PostMessage: TROPostMessage; Panel4: TPanel; clbTests: TCheckListBox; pagecontrol2: TPageControl; tsStress: TTabSheet; tsSum: TTabSheet; tsEchoPerson: TTabSheet; tsRaiseError: TTabSheet; seA: TSpinEdit; seB: TSpinEdit; Label4: TLabel; seAge: TSpinEdit; cbSex: TComboBox; eLastName: TEdit; eFirstName: TEdit; Label3: TLabel; Label2: TLabel; cbCustomException: TCheckBox; Label5: TLabel; tsTestArrays: TTabSheet; tsEchoBinary: TTabSheet; tsGetServerTime: TTabSheet; tsCustomClass: TTabSheet; Label6: TLabel; seArrayCount: TSpinEdit; rbInteger: TRadioButton; rbString: TRadioButton; rbTPerson: TRadioButton; seBinSize: TSpinEdit; Label7: TLabel; rbStream: TRadioButton; rbXML: TRadioButton; Panel5: TPanel; Panel1: TPanel; GroupBox6: TGroupBox; Label1: TLabel; Label8: TLabel; Label9: TLabel; Label10: TLabel; Label12: TLabel; Bevel1: TBevel; Bevel2: TBevel; Label13: TLabel; rbWinMessage: TRadioButton; rbTcpChannel: TRadioButton; rbHttpChannel: TRadioButton; eServerID: TEdit; cbHTTPURL: TComboBox; cbTCPIP: TComboBox; cbTCPPort: TComboBox; Panel2: TPanel; rbIndyHttp: TRadioButton; rbWinInetHttp: TRadioButton; cbKeepConnection: TCheckBox; Panel6: TPanel; RbIndyTcp: TRadioButton; cbDisableNagle: TCheckBox; GroupBox5: TGroupBox; rbBinary: TRadioButton; rbSOAP: TRadioButton; cbUseCompression: TCheckBox; rbPost: TRadioButton; cbEncrypt: TCheckBox; RoPoweredByRemObjectsButton1: TROPoweredByRemObjectsButton; cbEnableLog: TCheckBox; cbVerbose: TCheckBox; cbWriteTestInfo: TCheckBox; Label11: TLabel; Label16: TLabel; Label17: TLabel; Label18: TLabel; Label19: TLabel; Label20: TLabel; Label21: TLabel; Label22: TLabel; Label23: TLabel; Label24: TLabel; RunTestOnceButton: TButton; RunTestButton: TButton; seRepetitions: TSpinEdit; Label15: TLabel; seThreads: TSpinEdit; Label14: TLabel; pStress: TPanel; pSum: TPanel; pTestArrays: TPanel; pEchoBinary: TPanel; pGetServerTime: TPanel; pCustomClass: TPanel; pRaiseError: TPanel; pPage: TPanel; pEchoPerson: TPanel; rbSynapseHttp: TRadioButton; rbXmlRpc: TRadioButton; XmlRpcMessage: TROXmlRpcMessage; cbAutoDetect: TCheckBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure bTestEchoBinaryClick(Sender: TObject); procedure Image1Click(Sender: TObject); procedure cbEncryptClick(Sender: TObject); procedure rbBinaryClick(Sender: TObject); procedure rbSOAPClick(Sender: TObject); procedure cbDisableNagleClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure bbStressCustomClassClick(Sender: TObject); procedure rbPostClick(Sender: TObject); procedure cbHTTPURLChange(Sender: TObject); procedure SOAPMessageWriteToStream(aStream: TStream); procedure SOAPMessageEnvelopeComplete(Sender: TROSOAPMessage); procedure SOAPMessageReadFromStream(aStream: TStream); procedure BINMessageFinalizeMessage(Sender: TROMessage); procedure BINMessageReadMessageParameter(Sender: TROMessage; const aName: string; aTypeInfo: PTypeInfo; const DataRef: Pointer; Attributes: TParamAttributes); procedure BINMessageWriteMessageParameter(Sender: TROMessage; const aName: string; aTypeInfo: PTypeInfo; const DataRef: Pointer; Attributes: TParamAttributes); procedure BINMessageInitializeMessage(Sender: TROMessage; const aTransport: IROTransport; const anInterfaceName, aMessageName: string); procedure clbTestsClick(Sender: TObject); procedure RunTestOnceButtonClick(Sender: TObject); procedure RunTestButtonClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure clbTestsClickCheck(Sender: TObject); procedure rbHttpChannelClick(Sender: TObject); procedure FormDeactivate(Sender: TObject); procedure rbIndyHttpClick(Sender: TObject); procedure rbXmlRpcClick(Sender: TObject); procedure cbAutoDetectClick(Sender: TObject); private {$IFNDEF NO_SYNAPSE} ROSynapseHttpchannel: TROSynapseHTTPChannel; {$ENDIF} fCritical: TCriticalSection; fThreads: TList; fTerminateTest: boolean; fMessage: TROMessage; fChannel: TROTransportChannel; fMegaTestStart: cardinal; fLogEnabledStatus: boolean; function CreateService: IMegaDemoService; procedure ChangeUrl(iTo: string); procedure Log(const aMessage: string; Force: boolean = FALSE); procedure NotifyThreadTermination(aThread: TThread); function GetMegaTestRunning: boolean; // Methods to invoke the remote service. These are also used by the stress threads later. // They return the time it took to execute function InvokeCustomClass(const aService: IMegaDemoService; UseBinaryStream: boolean): integer; {} function InvokeEchoBinary(const aService: IMegaDemoService; aSize: integer): integer; {} function InvokeEchoPerson(const aService: IMegaDemoService; const aFirstName, aLastName: string; anAge: integer; aSex: TSex): integer; {} function InvokeRaiseError(const aService: IMegaDemoService): integer; {} function InvokeSum(const aService: IMegaDemoService; A, B: integer): integer; {} function InvokeTestArray(const aService: IMegaDemoService; anArrayType: TArrayType; aCount: integer): integer; {} function InvokeGetServerTime(const aService: IMegaDemoService): integer; // Logs procedure WriteSequentialStressEnd(TotalTime, Errors: integer); procedure WriteSequentialStressStart(TestName: string; const ExtraInfo: string = ''); procedure WriteTestInfo(ARunOnce: Boolean); function GetRequestsPerSecond(TotalTimeMS: integer): double; procedure Check_ListBoxClick(isAllDemo: Boolean); procedure Stress(AMethod: TStressMethod); function RunSum(aService: IMegaDemoService): integer; function RunEchoPerson(aService: IMegaDemoService): integer; function RunRaiseError(aService: IMegaDemoService): integer; function RunTestArrays(aService: IMegaDemoService): integer; function int_RunTestArrays(aService: IMegaDemoService; anArrayType: TArrayType): integer; function RunEchoBinary(aService: IMegaDemoService): integer; function RunServerTime(aService: IMegaDemoService): integer; function RunCustomClass(aService: IMegaDemoService): integer; procedure RunAllDemo; procedure StopAllDemo; procedure LoadFromIni; procedure SaveToIni; public constructor Create(aOwner: TComponent); override; destructor Destroy; override; property UserChannel: TROTransportChannel read fChannel; property UserMessage: TROMessage read fMessage; property MegaTestRunning: boolean read GetMegaTestRunning; end; var MegaDemoClientMainForm: TMegaDemoClientMainForm; implementation uses INIFiles, MegaDemoCustomClass, uROXMLSerializer, uROStreamSerializer, ShellAPI, uROEncryption, ActiveX; {$R *.DFM} type { TStressThread } TStressThread = class(TThread) private fMessage: TROMessage; fChannel: TROTransportChannel; fErrors, fSumTime, fEchoPersonTime, fRaiseErrorTime, fArrayTime, fEchoBinaryTime, fGetServerTimeTime, fCustomClassTime, fTotalTime: integer; Fidx: integer; procedure BeforeDestroyThread; procedure Run; public constructor Create; destructor Destroy; override; procedure Execute; override; property Errors: integer read fErrors; property EchoPersonTime: integer read fEchoPersonTime; property RaiseErrorTime: integer read fRaiseErrorTime; property ArrayTime: integer read fArrayTime; property EchoBinaryTime: integer read fEchoBinaryTime; property GetServerTimeTime: integer read fGetServerTimeTime; property CustomClassTime: integer read fCustomClassTime; property TotalTime: integer read fTotalTime; property idx: integer read Fidx write Fidx; end; procedure TMegaDemoClientMainForm.FormCreate(Sender: TObject); var sx: TSex; begin Caption := Application.Title; {$IFDEF NO_INDY} rbIndyHttp.Enabled := false; rbIndyTcp.Enabled := false; {$ENDIF NO_INDY} {$IFDEF NO_SYNAPSE} rbSynapseHttp.Enabled := false; {$ELSE} ROSynapseHttpchannel := TROSynapseHTTPChannel.Create(self); ROSynapseHttpchannel.Encryption.EncryptionSendKey := IndyHttpChannel.Encryption.EncryptionSendKey; ROSynapseHttpchannel.Encryption.EncryptionRecvKey := IndyHttpChannel.Encryption.EncryptionRecvKey; {$ENDIF} LoadFromIni; for sx := Low(TSex) to High(TSex) do cbSex.Items.Add(GetEnumName(TypeInfo(TSex), Ord(sx))); cbSex.ItemIndex := 0; end; procedure TMegaDemoClientMainForm.FormDestroy(Sender: TObject); begin SaveToIni; end; function TMegaDemoClientMainForm.CreateService: IMegaDemoService; begin // Adds the entry if new with cbTCPIP do if (Items.IndexOf(Text) < 0) and (Text <> '') then Items.Add(Text); with cbHTTPURL do if (Items.IndexOf(Text) < 0) and (Text <> '') then Items.Add(Text); with cbTCPPort do if (Items.IndexOf(Text) < 0) and (Text <> '') then Items.Add(Text); { Set up BIN message } BINMessage.UseCompression := cbUseCompression.Checked; { Set up Http Channels } {$IFNDEF NO_INDY} IndyHTTPChannel.TargetURL := cbHTTPURL.Text; IndyHTTPChannel.KeepAlive := cbKeepConnection.Checked; {$ENDIF NO_INDY} {$IFNDEF NO_SYNAPSE} ROSYnapseHttpchannel.TargetURL := cbHTTPURL.Text; ROSYnapseHttpchannel.KeepAlive := cbKeepConnection.Checked; {$ENDIF NO_SYNAPSE} WininetHttpChannel.TargetURL := cbHTTPURL.Text; WininetHttpChannel.KeepConnection := cbKeepConnection.Checked; { Set up Tcp Channels } {$IFNDEF NO_INDY} {$IFDEF RemObjects_INDY10} TIdIndy10HackClient(IndyTCPChannel.IndyClient).Host := cbTCPIP.Text; TIdIndy10HackClient(IndyTCPChannel.IndyClient).Port := StrToInt(cbTCPPort.Text); {$ELSE RemObjects_INDY10} IndyTCPChannel.IndyClient.Host := cbTCPIP.Text; IndyTCPChannel.IndyClient.Port := StrToInt(cbTCPPort.Text); {$ENDIF RemObjects_INDY10} {$ENDIF NO_INDY} { Set up WM Channel } WinMessageChannel.ServerID := LibraryUID; { Select message class based on radio button selection } if rbBinary.Checked then fMessage := BINMessage else if rbPost.Checked then fMessage := PostMessage else if rbXMLRpc.Checked then fMessage := XmlRpcMessage else fMessage := SOAPMessage; { Select channel class based on radio button selection } if rbWinMessage.Checked then begin fChannel := WinMessageChannel end else if rbTCPChannel.Checked then begin {$IFNDEF NO_INDY} fChannel := IndyTCPChannel; {$ENDIF NO_INDY} end else begin {$IFNDEF NO_INDY} if rbIndyHttp.Checked then fChannel := IndyHttpChannel else {$ENDIF NO_INDY} {$IFNDEF NO_INDY} if rbSynapseHttp.Checked then fChannel := ROSynapseHttpchannel else {$ENDIF NO_INDY} fChannel := WininetHttpChannel; end; // Sets up the main components RemoteService.Channel := fChannel; RemoteService.Message := fMessage; result := RemoteService as IMegaDemoService; end; function TMegaDemoClientMainForm.InvokeSum(const aService: IMegaDemoService; A, B: integer): integer; var res: integer; start: cardinal; begin start := GetTickCount; res := aService.Sum(seA.Value, seB.Value); result := GetTickCount - start; Log('Sum'); Log('---'); Log(Format('outgoing:'#9'A=%d B=%d', [seA.Value, seB.Value])); Log(Format('incoming:'#9'Result=%d', [res])); Log(''); end; function TMegaDemoClientMainForm.InvokeEchoPerson(const aService: IMegaDemoService; const aFirstName, aLastName: string; anAge: integer; aSex: TSex): integer; var outgoing, incoming: TPerson; start: cardinal; begin outgoing := TPerson.Create; outgoing.FirstName := eFirstName.Text; outgoing.LastName := eLastName.Text; outgoing.Age := seAge.Value; outgoing.Sex := TSex(cbSex.ItemIndex); try start := GetTickCount; aService.EchoPerson(outgoing, incoming); result := GetTickCount - start; Log('EchoPerson'); Log('----------'); with outgoing do Log(Format('%s:'#9'%s, %s, %s, %s', ['outgoing', FirstName, LastName, IntToStr(Age), GetEnumName(TypeInfo(TSex), Ord(Sex))])); with incoming do Log(Format('%s:'#9'%s, %s, %s, %s', ['incoming', FirstName, LastName, IntToStr(Age), GetEnumName(TypeInfo(TSex), Ord(Sex))])); Log(''); finally incoming.Free; outgoing.Free; end; end; function TMegaDemoClientMainForm.InvokeRaiseError(const aService: IMegaDemoService): integer; var start: cardinal; begin Result := 0; start := GetTickCount; Log('RaiseError'); Log('----------'); try try if not cbCustomException.Checked then aService.RaiseError() else aService.RaiseTestException; finally result := GetTickCount - start; end; except on E: ETestException do if rbXmlRpc.Checked then Log(Format( 'ETestException' + sLineBreak + 'Message:'#9'%s', [E.Message]), true) else Log(Format( 'ETestException' + sLineBreak + 'Message:'#9'%s' + sLineBreak + 'ErrorCode:'#9'%d' + sLineBreak + 'AdditionalInfo:'#9'%s', [E.Message, E.ErrorCode, E.AdditionalInfo]), true); on E: Exception do Log( 'Generic exception:'#9 + E.ClassName + sLineBreak + 'Message:'#9#9 + E.Message, true); end; Log(''); end; function TMegaDemoClientMainForm.InvokeTestArray(const aService: IMegaDemoService; anArrayType: TArrayType; aCount: integer): integer; var i: integer; iarr, iarr2: TIntegerArray; sarr, sarr2: TStringArray; parr, parr2: TPersonArray; s, s1: string; err: boolean; start: cardinal; begin Result := 0; s := ''; err := FALSE; iarr := nil; iarr2 := nil; sarr := nil; sarr2 := nil; parr := nil; parr2 := nil; try case anArrayType of atInteger: try s1 := rbInteger.Caption; Randomize; iarr := TIntegerArray.Create; iarr.Resize(seArrayCount.Value); for i := 0 to (seArrayCount.Value - 1) do iarr[i] := Random(100); start := GetTickCount; iarr2 := aService.TestIntegerArray(iarr); result := GetTickCount - start; for i := 0 to (seArrayCount.Value - 1) do begin s := s + Format('%d:'#9'%d - %d', [i, iarr[i], iarr2[i]]) + sLineBreak; if (iarr2[i] <> iarr[i]) then begin err := TRUE; Exit; end; end; finally iarr.Free; iarr2.Free; end; atString: try s1 := rbString.Caption; Randomize; sarr := TStringArray.Create; sarr.Resize(seArrayCount.Value); for i := 0 to (seArrayCount.Value - 1) do begin sarr[i] := 'Value is ' + IntToStr(Random(1000) + 1000); end; start := GetTickCount; sarr2 := aService.TestStringArray(sarr); result := GetTickCount - start; for i := 0 to (seArrayCount.Value - 1) do begin s := s + Format('%d:'#9'"%s" - "%s"', [i, sarr[i], sarr2[i]]) + sLineBreak; if (sarr2[i] <> sarr[i]) then begin err := TRUE; Exit; end; end; finally sarr.Free; sarr2.Free; end; atTPerson: try s1 := rbTPerson.Caption; parr := TPersonArray.Create; parr.Resize(seArrayCount.Value); for i := 0 to (seArrayCount.Value - 1) do begin parr[i] := TPerson.Create; with parr[i] do begin FirstName := eFirstName.Text; LastName := eLastName.Text; Age := seAge.Value; Sex := TSex(cbSex.ItemIndex); end; end; start := GetTickCount; parr2 := aService.TestPersonArray(parr); result := GetTickCount - start; for i := 0 to (seArrayCount.Value - 1) do begin s := s + Format('%d:'#9'%s %s %d %d - %s %s %d %d', [ i, parr[i].FirstName, parr[i].LastName, parr[i].Age, Ord(parr[i].Sex), parr2[i].FirstName, parr2[i].LastName, parr2[i].Age, Ord(parr2[i].Sex)]) + sLineBreak; if (parr2[i].FirstName <> parr[i].FirstName) or (parr2[i].LastName <> parr[i].LastName) or (parr2[i].Age <> parr[i].Age) or (parr2[i].Sex <> parr[i].Sex) then begin err := TRUE; Exit; end; end; finally parr.Free; parr2.Free; end; end; finally if err then s := 'Arrays are DIFFERENT!' + sLineBreak + s else s := sLineBreak + 'Arrays equal!' + sLineBreak + s; Log('TestArray'); Log('---------'); Log('Mode:'#9 + s1); Log(s); end; end; function TMegaDemoClientMainForm.InvokeEchoBinary(const aService: IMegaDemoService; aSize: integer): integer; var binin, binout: Binary; i: integer; b: byte; start: cardinal; begin Randomize; binin := Binary.Create; binout := nil; try binin.SetSize(seBinSize.Value); binin.Position := 0; for i := 1 to seBinSize.Value do begin b := Random($FF); binin.Write(b, SizeOf(b)); end; binin.Position := 0; start := GetTickCount; aService.EchoBinary(binin, binout); result := GetTickCount - start; Log('EchoBinary'); Log('-------------'); Log('outgoing:'#9 + IntToStr(binin.Size) + ' bytes'); Log('incoming:'#9 + IntToStr(binout.Size) + ' bytes'); if (binin.Size = binout.Size) then begin if CompareMem(binin.Memory, binout.Memory, binout.Size) then Log('Data is equivalent!') else Log('Data is different!'); end else begin Log('Different size!'); end; Log(''); finally binin.Free; binout.Free; end; end; function TMegaDemoClientMainForm.InvokeCustomClass(const aService: IMegaDemoService; UseBinaryStream: boolean): integer; var cls: TCustomClass; stream: Binary; xml: string; start: cardinal; begin stream := nil; cls := nil; try if not UseBinaryStream then begin start := GetTickCount; xml := aService.CustomObjectAsString; result := GetTickCount - start; cls := XMLToObject(xml) as TCustomClass; end else begin start := GetTickCount; stream := aService.CustomObjectAsStream; result := GetTickCount - start; cls := StreamToObject(stream) as TCustomClass; end; Log('CustomClass'); Log('-----------'); Log('incoming:'); // incoming data with cls do begin Log('Random integer:'#9#9 + intToStr(RandomInt)); Log('Random double:'#9#9 + FloatToStr(RandomDouble)); Log('Random string:'#9#9 + RandomStr); Log('Random widestring:'#9 + RandomWideStr); end; finally stream.Free; cls.Free; end; end; function TMegaDemoClientMainForm.InvokeGetServerTime(const aService: IMegaDemoService): integer; var start: cardinal; restime: TDateTime; begin start := GetTickCount; restime := aService.GetServerTime; result := GetTickCount - start; Log('GetServerTime'); Log('------------------'); Log('incoming:'#9 + DateTimeToStr(restime)); Log(''); end; procedure TMegaDemoClientMainForm.bTestEchoBinaryClick(Sender: TObject); begin InvokeEchoBinary(CreateService, seBinSize.Value); end; procedure TMegaDemoClientMainForm.Image1Click(Sender: TObject); begin ShellExecute(Handle, 'open', 'http://www.remobjects.com', nil, nil, SW_SHOWNORMAL); end; procedure TMegaDemoClientMainForm.cbEncryptClick(Sender: TObject); var lEncryption: TROEncryptionMethod; begin if cbEncrypt.Checked then lEncryption := tetDES else lEncryption := tetNone; {$IFNDEF NO_INDY} IndyHttpChannel.Encryption.EncryptionMethod := lEncryption; IndyTcpChannel.Encryption.EncryptionMethod := lEncryption; {$ENDIF NO_INDY} {$IFNDEF NO_SYNAPSE} ROSynapseHttpchannel.Encryption.EncryptionMethod := lEncryption; {$ENDIF} WinMessageChannel.Encryption.EncryptionMethod := lEncryption; WininetHttpChannel.Encryption.EncryptionMethod := lEncryption; end; procedure TMegaDemoClientMainForm.ChangeUrl(iTo: string); begin { lame, but works } if cbAutoDetect.Checked then iTo:=''; cbHTTPURL.Text := StringReplace(cbHTTPURL.Text, '/bin', '/' + iTo, [rfReplaceAll, rfIgnoreCase]); cbHTTPURL.Text := StringReplace(cbHTTPURL.Text, '/soap', '/' + iTo, [rfReplaceAll, rfIgnoreCase]); cbHTTPURL.Text := StringReplace(cbHTTPURL.Text, '/post', '/' + iTo, [rfReplaceAll, rfIgnoreCase]); cbHTTPURL.Text := StringReplace(cbHTTPURL.Text, '/xmlrpc', '/' + iTo, [rfReplaceAll, rfIgnoreCase]); if not cbAutoDetect.Checked and (Pos(iTo, cbHTTPURL.Text) = 0) then cbHTTPURL.Text:=cbHTTPURL.Text+iTo; cbUseCompression.Enabled := rbBinary.Checked; cbVerbose.Enabled := rbBinary.Checked; tsSoap.TabVisible := rbSOAP.Checked; if not tsSoap.TabVisible then tsLog.PageControl.ActivePage := tsLog; end; procedure TMegaDemoClientMainForm.rbBinaryClick(Sender: TObject); begin ChangeUrl('bin'); end; procedure TMegaDemoClientMainForm.rbSOAPClick(Sender: TObject); begin ChangeUrl('soap'); end; procedure TMegaDemoClientMainForm.rbPostClick(Sender: TObject); begin ChangeUrl('post'); end; procedure TMegaDemoClientMainForm.cbDisableNagleClick(Sender: TObject); begin IndyTCPChannel.DisableNagle := cbDisableNagle.Checked; end; function TMegaDemoClientMainForm.GetRequestsPerSecond(TotalTimeMS: integer): double; begin if TotalTimeMS > 0 then result := (seRepetitions.Value) / (TotalTimeMS / 1000) else result := seRepetitions.Value; end; procedure TMegaDemoClientMainForm.NotifyThreadTermination(aThread: TThread); var totaltimemega, idx: integer; overallrsec: double; begin fCritical.Enter; try idx := TStressThread(aThread).idx; Log(Format('Thread %d has terminated. %dms. %f Req/Sec. %d Errors', [idx, TStressThread(aThread).TotalTime, GetRequestsPerSecond(TStressThread(aThread).TotalTime), TStressThread(aThread).Errors]), TRUE); fThreads.Remove(aThread); if fThreads.Count = 0 then begin Screen.Cursor := crDefault; totaltimemega := GetTickCount - fMegaTestStart; overallrsec := (seThreads.Value * seRepetitions.Value) / (totaltimemega / 1000); Log(Format('The test was completed in %dms. %f Total req/second', [totaltimemega, overallrsec]), TRUE); Caption := Application.Title; end else begin Caption := Application.Title + Format(' (%d threads running)', [fThreads.Count]); end; Application.ProcessMessages; finally fCritical.Leave; end; end; constructor TMegaDemoClientMainForm.Create(aOwner: TComponent); begin inherited; fCritical := TCriticalSection.Create; fThreads := TList.Create; end; destructor TMegaDemoClientMainForm.Destroy; begin fCritical.Free; fThreads.Free; inherited; end; procedure TMegaDemoClientMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := not MegaTestRunning; if not CanClose then begin if (MessageDlg('Do you want to stop the mega test?', mtWarning, [mbYes, mbNo], 0) = mrYes) then StopAllDemo else Exit; while MegaTestRunning do Application.ProcessMessages; CanClose := TRUE; end; end; function TMegaDemoClientMainForm.GetMegaTestRunning: boolean; begin result := fThreads.Count > 0 end; procedure TMegaDemoClientMainForm.WriteTestInfo(ARunOnce: Boolean); begin if not cbWriteTestInfo.Checked then Exit; Log('', TRUE); Log('------------------ Test Parameters ------------------', TRUE); Log('Channel:'#9 + UserChannel.ClassName, True); if rbHttpChannel.Checked then begin Log('URL:'#9#9 + cbHTTPURL.Text, True); Log('KeepConnection:'#9 + BoolToStr(cbKeepConnection.Checked, TRUE), True); end else if rbTcpChannel.Checked then begin Log('IP, port:'#9 + cbTCPIP.Text + ':' + cbTCPPort.Text, True); LOG('DisableNagle:'#9 + BoolToStr(cbDisableNagle.Checked, TRUE), True); end else if rbWinMessage.Checked then begin Log('Server ID:'#9 + eServerID.Text, True); end; Log('Message:'#9 + UserMessage.ClassName, True); Log('Encrypt:'#9 + BoolToStr(cbEncrypt.Checked, TRUE), True); if rbBinary.Checked then begin Log('Compression:'#9 + BoolToStr(cbUseCompression.Checked, TRUE), True); end; if not ARunOnce then begin Log(Format('Threads:'#9'%d', [seThreads.Value]), TRUE); Log(Format('Repetitions:'#9'%d', [seRepetitions.Value]), TRUE); Log(format('Total Requests:'#9'%d', [seThreads.Value * seRepetitions.Value]), TRUE); end; Log('-----------------------------------------------------', TRUE); Log('', TRUE); end; procedure TMegaDemoClientMainForm.WriteSequentialStressStart(TestName: string; const ExtraInfo: string); begin WriteTestInfo(False); Log(Format('Starting %s test. %d repetitions %s', [testname, seRepetitions.Value, ExtraInfo]), TRUE); fLogEnabledStatus := cbEnableLog.Checked; cbEnableLog.Checked := FALSE; end; procedure TMegaDemoClientMainForm.WriteSequentialStressEnd(TotalTime, Errors: integer); var reqsecond: double; begin reqsecond := GetRequestsPerSecond(TotalTime); Log(Format('Test complete. %dms. %f Req/Second. %d Errors', [TotalTime, reqsecond, Errors]), TRUE); cbEnableLog.Checked := fLogEnabledStatus; end; procedure TMegaDemoClientMainForm.bbStressCustomClassClick(Sender: TObject); begin end; { TStressThread } procedure TStressThread.BeforeDestroyThread; begin MegaDemoClientMainForm.NotifyThreadTermination(Self); end; constructor TStressThread.Create; begin inherited Create(TRUE); FreeOnTerminate := TRUE; end; destructor TStressThread.Destroy; begin // Synchronize(BeforeDestroyThread); inherited; end; procedure TStressThread.Execute; begin Synchronize(Run); end; procedure TStressThread.Run; var svc: IMegaDemoService; maxcount: integer; i: integer; begin // Makes internal copies of the channel and the message fMessage := CloneObject(MegaDemoClientMainForm.UserMessage) as TROMessage; fChannel := CloneObject(MegaDemoClientMainForm.UserChannel) as TROTransportChannel; try svc := CoMegaDemoService.Create(fMessage, fChannel); maxcount := MegaDemoClientMainForm.seRepetitions.Value - 1; fTotalTime := 0; with MegaDemoClientMainForm do try if clbTests.Checked[1] then begin for i := 0 to (maxcount - 1) do try Inc(fSumTime, RunSum(svc)); except Inc(fErrors); end; if Terminated then Exit; end; if clbTests.Checked[2] then begin for i := 0 to (maxcount - 1) do try Inc(fEchoPersonTime, RunEchoPerson(svc)); except Inc(fErrors); end; if Terminated then Exit; end; if clbTests.Checked[3] then begin for i := 0 to (maxcount - 1) do try Inc(fArrayTime, int_RunTestArrays(svc, atInteger)) except Inc(fErrors); end; if Terminated then Exit; for i := 0 to (maxcount - 1) do try Inc(fArrayTime, int_RunTestArrays(svc, atString)) except Inc(fErrors); end; if Terminated then Exit; for i := 0 to (maxcount - 1) do try Inc(fArrayTime, int_RunTestArrays(svc, atTPerson)) except Inc(fErrors); end; if Terminated then Exit; end; if clbTests.Checked[4] then begin for i := 0 to (maxcount - 1) do try Inc(fEchoBinaryTime, RunEchoBinary(svc)); except Inc(fErrors); end; if Terminated then Exit; end; if clbTests.Checked[5] then begin for i := 0 to (maxcount - 1) do try Inc(fGetServerTimeTime, RunServerTime(svc)); except Inc(fErrors); end; if Terminated then Exit; end; if clbTests.Checked[6] then begin for i := 0 to (maxcount - 1) do try Inc(fCustomClassTime, RunCustomClass(svc)); except Inc(fErrors); end; if Terminated then Exit; end; { if clbTests.Checked[7] then begin for i := 0 to (maxcount - 1) do try Inc(fRaiseErrorTime, RunRaiseError(svc)); except //Inc(fErrors); end; if Terminated then Exit; end; } finally fTotalTime := fSumTime + fEchoPersonTime + fArrayTime + fEchoBinaryTime + fGetServerTimeTime + fCustomClassTime // + fRaiseErrorTime + ; Terminate; end; finally fChannel.Free; fMessage.Free; BeforeDestroyThread; end; end; procedure TMegaDemoClientMainForm.cbHTTPURLChange(Sender: TObject); begin if Pos('/bin', cbHTTPURL.Text) > 0 then rbBinary.Checked := true else if Pos('/soap', cbHTTPURL.Text) > 0 then rbSoap.Checked := true else if Pos('/post', cbHTTPURL.Text) > 0 then rbPost.Checked := true else if Pos('/xmlrpc', cbHTTPURL.Text) > 0 then rbXmlRpc.Checked := true; cbUseCompression.Enabled := rbBinary.Checked; end; procedure TMegaDemoClientMainForm.SOAPMessageWriteToStream(aStream: TStream); begin // memo1.Lines.LoadFromStream(aStream); end; procedure TMegaDemoClientMainForm.SOAPMessageEnvelopeComplete(Sender: TROSOAPMessage); begin sender.HeaderNode.Add('Test').Value := '1234'; if cbEnableLog.Checked then memo1.Lines.Text := Sender.EnvelopeNode.XML; end; procedure TMegaDemoClientMainForm.SOAPMessageReadFromStream(aStream: TStream); begin if cbEnableLog.Checked then Memo2.Lines.LoadFromStream(aStream); end; procedure TMegaDemoClientMainForm.BINMessageFinalizeMessage(Sender: TROMessage); begin if cbVerbose.Checked then Log(Sender.Name + ' is finalized'); end; procedure TMegaDemoClientMainForm.BINMessageReadMessageParameter(Sender: TROMessage; const aName: string; aTypeInfo: PTypeInfo; const DataRef: Pointer; Attributes: TParamAttributes); begin if cbVerbose.Checked then begin Log(Sender.Name + ' is reading ' + aName); Log(''); end; end; procedure TMegaDemoClientMainForm.BINMessageWriteMessageParameter(Sender: TROMessage; const aName: string; aTypeInfo: PTypeInfo; const DataRef: Pointer; Attributes: TParamAttributes); begin if cbVerbose.Checked then Log(Sender.Name + ' is writing ' + aName); end; procedure TMegaDemoClientMainForm.BINMessageInitializeMessage(Sender: TROMessage; const aTransport: IROTransport; const anInterfaceName, aMessageName: string); begin if cbVerbose.Checked then Log(Sender.Name + ' is initialized'); end; function TMegaDemoClientMainForm.RunSum(aService: IMegaDemoService): integer; begin Result := InvokeSum(aService, seA.Value, seB.Value); end; function TMegaDemoClientMainForm.RunEchoPerson(aService: IMegaDemoService): integer; begin Result := InvokeEchoPerson( aService, eFirstName.Text, eLastName.Text, seAge.Value, TSex(cbSex.ItemIndex)); end; function TMegaDemoClientMainForm.RunRaiseError(aService: IMegaDemoService): integer; begin Result := InvokeRaiseError(aService); end; procedure TMegaDemoClientMainForm.Stress(AMethod: TStressMethod); var tot, errors, i: integer; svc: IMegaDemoService; begin tot := 0; errors := 0; svc := CreateService; WriteSequentialStressStart(clbTests.Items[clbTests.ItemIndex]); for i := 1 to (seRepetitions.Value) do try Inc(tot, AMethod(svc)); if (i mod 10 = 0) then Application.ProcessMessages; if fTerminateTest then Break; except Inc(errors); end; WriteSequentialStressEnd(tot, errors); end; function TMegaDemoClientMainForm.RunTestArrays(aService: IMegaDemoService): integer; begin Result := 0; if rbInteger.Checked then Result := int_RunTestArrays(aService, atInteger) else if rbString.Checked then Result := int_RunTestArrays(aService, atString) else if rbTPerson.Checked then Result := int_RunTestArrays(aService, atTPerson); end; function TMegaDemoClientMainForm.RunEchoBinary(aService: IMegaDemoService): integer; begin Result := InvokeEchoBinary(aService, seBinSize.Value); end; function TMegaDemoClientMainForm.RunServerTime(aService: IMegaDemoService): integer; begin Result := InvokeGetServerTime(aService); end; function TMegaDemoClientMainForm.RunCustomClass(aService: IMegaDemoService): integer; begin Result := InvokeCustomClass(aService, rbStream.Checked); end; procedure TMegaDemoClientMainForm.clbTestsClick(Sender: TObject); procedure HidePanels; begin pStress.Visible := False; pSum.Visible := False; pEchoPerson.Visible := False; pTestArrays.Visible := False; pEchoBinary.Visible := False; pGetServerTime.Visible := False; pCustomClass.Visible := False; pRaiseError.Visible := False; end; var t_panel: TPanel; begin HidePanels; case clbTests.ItemIndex of 1: t_panel := pSum; 2: t_panel := pEchoPerson; 3: t_panel := pTestArrays; 4: t_panel := pEchoBinary; 5: t_panel := pGetServerTime; 6: t_panel := pCustomClass; 7: t_panel := pRaiseError; else t_panel := pStress; end; t_panel.Parent := pPage; t_panel.Visible := True; if clbTests.ItemIndex = 0 then begin RunTestOnceButton.Caption := 'Run Stress Test'; RunTestButton.Caption := 'Stop Stress Test'; RunTestOnceButton.Hint := 'Run Stress Test'; RunTestButton.Hint := 'Stop Stress Test'; end else begin RunTestOnceButton.Caption := 'Run Test once'; RunTestButton.Caption := 'Run Test'; RunTestOnceButton.Hint := 'Starts the chosen test once'; RunTestButton.Hint := 'Starts the chosen test some times'; end; end; procedure TMegaDemoClientMainForm.RunTestOnceButtonClick(Sender: TObject); var serv: IMegaDemoService; s: string; begin s := ''; if clbTests.ItemIndex > 0 then begin clbTests.Checked[clbTests.ItemIndex] := True; serv := CreateService; WriteTestInfo(True); Screen.Cursor := crHourGlass; end; try case clbTests.ItemIndex of 0: RunAllDemo; 1: begin RunSum(serv); s := 'Sum'; end; 2: begin RunEchoPerson(serv); s := 'EchoPerson'; end; 3: begin RunTestArrays(serv); s := 'TestArrays'; end; 4: begin RunEchoBinary(serv); s := 'EchoBinary'; end; 5: begin RunServerTime(serv); s := 'ServerTime'; end; 6: begin RunCustomClass(serv); s := 'CustomClass'; end; 7: begin RunRaiseError(serv); S := 'RaiseError'; end; end; finally if clbTests.ItemIndex > 0 then Screen.Cursor := crDefault; end; if (s <> '') and not cbEnableLog.Checked then Log(s + ':'#9'Done', True); end; procedure TMegaDemoClientMainForm.RunAllDemo; var i: integer; trd: TStressThread; begin Beep; if ( (seRepetitions.Value > 10) and (MessageDlg(msgWarningPorts, mtWarning, [mbOK, mbCancel], 0) <> mrOK) ) then Exit; Screen.Cursor := crHourGlass; cbEnableLog.Checked := FALSE; fTerminateTest := FALSE; MegaDemoClientMainForm.CreateService; // Makes sure UserChannel and UserMessage are set. The threads will reference them in their constructor WriteTestInfo(False); try Log(Format('Sum test:'#9#9 + '%s', [BoolToStr(clbTests.Checked[1], TRUE)]), TRUE); Log(Format('EchoPerson test:'#9 + '%s', [BoolToStr(clbTests.Checked[2], TRUE)]), TRUE); // Log('RaiseError test:'#9+'%s', [BoolToStr(clbTests.Checked[3], TRUE)], -1, TRUE); Log(Format('Array test:'#9#9 + '%s (%d items)', [BoolToStr(clbTests.Checked[4], TRUE), seArrayCount.Value]), TRUE); Log(Format('EchoBinary test:'#9 + '%s (%d bytes)', [BoolToStr(clbTests.Checked[5], TRUE), seBinSize.Value]), TRUE); Log(Format('GetServerTime test:'#9 + '%s', [BoolToStr(clbTests.Checked[6], TRUE)]), TRUE); Log(Format('CustomClass test:'#9 + '%s (Use XML=%s)', [BoolToStr(clbTests.Checked[7], TRUE), BoolToStr(rbXML.Checked, TRUE)]), TRUE); Log('', TRUE); Log('Starting mega test'); Log('', TRUE); for i := 1 to seThreads.Value do begin trd := TStressThread.Create; trd.idx := fThreads.Add(trd); end; Caption := Application.Title + Format(' (%d threads running)', [fThreads.Count]); fMegaTestStart := GetTickCount; for i := 0 to seThreads.Value - 1 do TStressThread(fThreads[i]).Resume; finally // Screen.Cursor := crDefault; end; end; procedure TMegaDemoClientMainForm.StopAllDemo; var i: integer; begin fCritical.Enter; try for i := 0 to (fThreads.Count - 1) do TThread(fThreads[i]).Terminate; finally fCritical.Leave; end; end; procedure TMegaDemoClientMainForm.RunTestButtonClick(Sender: TObject); begin Screen.Cursor := crHourGlass; try if clbTests.ItemIndex > 0 then clbTests.Checked[clbTests.ItemIndex] := True; case clbTests.ItemIndex of 0: StopAllDemo; 1: Stress(RunSum); 2: Stress(RunEchoPerson); 3: Stress(RunTestArrays); 4: Stress(RunEchoBinary); 5: Stress(RunServerTime); 6: Stress(RunCustomClass); 7: Stress(RunRaiseError); end; finally Screen.Cursor := crDefault; end; end; procedure TMegaDemoClientMainForm.FormShow(Sender: TObject); begin pagecontrol2.Visible := False; clbTests.ItemIndex := 1; clbTests.OnClick(clbTests); cbHTTPURLChange(cbHTTPURL); end; procedure TMegaDemoClientMainForm.clbTestsClickCheck(Sender: TObject); begin Check_ListBoxClick(clbTests.ItemIndex = 0); end; procedure TMegaDemoClientMainForm.Check_ListBoxClick(isAllDemo: Boolean); procedure SetMode(AMode: Boolean); var i: integer; begin for i := 1 to clbTests.Items.Count - 2 do clbTests.Checked[i] := AMode; end; var i: integer; iChecked, iUnChecked: byte; begin if not isAllDemo then begin iChecked := 0; iUnChecked := 0; for i := 1 to clbTests.Items.Count - 2 do begin if clbTests.Checked[i] then inc(iChecked) else inc(iUnChecked); end; if iChecked = 0 then clbTests.State[0] := cbUnchecked else if iUnChecked = 0 then clbTests.State[0] := cbChecked else clbTests.State[0] := cbGrayed; end else begin case clbTests.State[0] of cbUnchecked: SetMode(False); cbChecked: SetMode(True); end; end; end; function TMegaDemoClientMainForm.int_RunTestArrays(aService: IMegaDemoService; anArrayType: TArrayType): integer; begin Result := InvokeTestArray(aService, anArrayType, seArrayCount.Value); end; procedure TMegaDemoClientMainForm.Log(const aMessage: string; Force: boolean); begin if cbEnableLog.Checked or Force then Memo.Lines.Add(AMessage); end; procedure TMegaDemoClientMainForm.LoadFromIni; var i: integer; begin with TINIFile.Create(ChangeFileExt(Application.EXEName, '.ini')) do try ReadSectionValues('IPs', cbTCPIP.Items); for i := 0 to (cbTCPIP.Items.Count - 1) do cbTCPIP.Items[i] := cbTCPIP.Items.Values[cbTCPIP.Items.Names[i]]; ReadSectionValues('HTTP Urls', cbHTTPURL.Items); for i := 0 to (cbHTTPURL.Items.Count - 1) do cbHTTPURL.Items[i] := cbHTTPURL.Items.Values[cbHTTPURL.Items.Names[i]]; ReadSectionValues('Ports', cbTCPPort.Items); for i := 0 to (cbTCPPort.Items.Count - 1) do cbTCPPort.Items[i] := cbTCPPort.Items.Values[cbTCPPort.Items.Names[i]]; cbHTTPURL.Text := ReadString('Misc', 'HTTP URL', 'http://localhost:8099/bin'); cbHTTPURLChange(nil); eServerID.Text := ReadString('Misc', 'Server ID', '{E46A5995-2260-44EA-AC60-121ADB4CC2D0}'); cbTCPIP.Text := ReadString('Misc', 'TCP Address', '127.0.0.1'); cbTCPPort.Text := ReadString('Misc', 'TCP Port', '8090'); rbIndyHttp.Checked := ReadBool('Misc', 'Indy HTTP', FALSE); rbWinInetHttp.Checked := ReadBool('Misc', 'WinINet HTTP', TRUE); rbSynapseHttp.Checked := ReadBool('Misc', 'Synapse HTTP', TRUE); cbKeepConnection.Checked := ReadBool('Misc', 'Keep Connection', FALSE); cbDisableNagle.Checked := ReadBool('Misc', 'Disable Nagle', FALSE); cbEncrypt.Checked := ReadBool('Misc', 'Encryption Communication', FALSE); cbEncryptClick(cbEncrypt); seThreads.Value := ReadInteger('Misc', 'Threads', 5); seRepetitions.Value := ReadInteger('Misc', 'Repetitions', 10); cbWriteTestInfo.Checked := ReadBool('Misc', 'Write Test Info', True); rbXML.Checked := ReadBool('Misc', 'CustomClass as XML', FALSE); rbStream.Checked := not rbXML.Checked; cbEnableLog.Checked := ReadBool('Misc', 'Enable Log', TRUE); cbVerbose.Checked := ReadBool('Misc', 'Verbose', True); clbTests.Checked[1] := ReadBool('Misc', 'Test Sum', TRUE); clbTests.Checked[2] := ReadBool('Misc', 'Test EchoPerson', TRUE); clbTests.Checked[3] := ReadBool('Misc', 'Test TestArrays', TRUE); clbTests.Checked[4] := ReadBool('Misc', 'Test EchoBinary', TRUE); clbTests.Checked[5] := ReadBool('Misc', 'Test GetServerTime', TRUE); clbTests.Checked[6] := ReadBool('Misc', 'Test CustomClass', TRUE); clbTests.Checked[7] := ReadBool('Misc', 'Test RaiseError', TRUE); Check_ListBoxClick(False); finally Free; end; end; procedure TMegaDemoClientMainForm.SaveToIni; var i: integer; begin with TINIFile.Create(ChangeFileExt(Application.EXEName, '.ini')) do try for i := 0 to (cbTCPIP.Items.Count - 1) do WriteString('IPs', IntToStr(i), cbTCPIP.Items[i]); for i := 0 to (cbHTTPURL.Items.Count - 1) do WriteString('HTTP Urls', IntToStr(i), cbHTTPURL.Items[i]); for i := 0 to (cbTCPPort.Items.Count - 1) do WriteString('Ports', IntToStr(i), cbTCPPort.Items[i]); WriteString('Misc', 'HTTP URL', cbHTTPURL.Text); WriteString('Misc', 'Server ID', eServerID.Text); WriteString('Misc', 'TCP Address', cbTCPIP.Text); WriteString('Misc', 'TCP Port', cbTCPPort.Text); WriteBool('Misc', 'Indy HTTP', rbIndyHttp.Checked); WriteBool('Misc', 'WinINet HTTP', rbWinInetHttp.Checked); WriteBool('Misc', 'Synapse HTTP', rbSynapseHttp.Checked); WriteBool('Misc', 'Keep Connection', cbKeepConnection.Checked); WriteBool('Misc', 'Disable Nagle', cbDisableNagle.Checked); WriteBool('Misc', 'Encryption Communication', cbEncrypt.Checked); WriteInteger('Misc', 'Threads', seThreads.Value); WriteInteger('Misc', 'Repetitions', seRepetitions.Value); WriteBool('Misc', 'Write Test Info', cbWriteTestInfo.Checked); WriteBool('Misc', 'CustomClass as XML', rbXML.Checked); WriteBool('Misc', 'Enable Log', cbEnableLog.Checked); WriteBool('Misc', 'Verbose', cbVerbose.Checked); WriteBool('Misc', 'Test Sum', clbTests.Checked[1]); WriteBool('Misc', 'Test EchoPerson', clbTests.Checked[2]); WriteBool('Misc', 'Test TestArrays', clbTests.Checked[3]); WriteBool('Misc', 'Test EchoBinary', clbTests.Checked[4]); WriteBool('Misc', 'Test GetServerTime', clbTests.Checked[5]); WriteBool('Misc', 'Test CustomClass', clbTests.Checked[6]); WriteBool('Misc', 'Test RaiseError', clbTests.Checked[7]); finally Free; end; end; procedure TMegaDemoClientMainForm.rbHttpChannelClick(Sender: TObject); begin cbAutoDetect.Enabled := Sender = rbHttpChannel; end; procedure TMegaDemoClientMainForm.FormDeactivate(Sender: TObject); begin // end; procedure TMegaDemoClientMainForm.rbIndyHttpClick(Sender: TObject); begin cbKeepConnection.Enabled := rbWinInetHttp.Checked; cbKeepConnection.Checked := rbWinInetHttp.Checked; end; procedure TMegaDemoClientMainForm.rbXmlRpcClick(Sender: TObject); begin ChangeUrl('xmlrpc'); end; procedure TMegaDemoClientMainForm.cbAutoDetectClick(Sender: TObject); begin if rbBinary.Checked then rbBinaryClick(rbBinary) else if rbPost.Checked then rbPostClick(rbPost) else if rbXMLRpc.Checked then rbXmlRpcClick(rbXMLRpc) else rbSOAPClick(rbSOAP); end; initialization CoInitializeEx(nil, COINIT_MULTITHREADED); finalization CoUninitialize; end.