Reading stream of Data using TIdIOHandlerStream and TIdTCPClient - delphi

I have an app that needs to connect to a server using TCP/IP and then just wait for server to send data, and what ever server sends should be saved into a file.
Here is what I did:
The Header file
#ifndef MainH
#define MainH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
#include <IdBaseComponent.hpp>
#include <IdComponent.hpp>
#include <IdIOHandler.hpp>
#include <IdIOHandlerStream.hpp>
#include <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>
#include <boost/scoped_ptr.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TIdTCPClient *pTCP;
TIdIOHandlerStream *IdIOHandlerStream;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall IdIOHandlerStreamGetStreams(TIdIOHandlerStream *ASender, TStream *&VReceiveStream, TStream *&VSendStream);
private: // User declarations
boost::scoped_ptr<TFileStream> mFile;
boost::scoped_ptr<TMemoryStream> mMem;
void __fastcall StopTcpClick(TObject* Sender);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
and the CPP file:
include <fmx.h>
#pragma hdrstop
#include "Main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner),
mFile(new TFileStream(L"C:\\IbsData.txt", fmCreate | fmOpenReadWrite | fmShareDenyWrite)),
mMem(new TMemoryStream())
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
pTCP->Connect();
Button1->Text = L"Stop";
Button1->OnClick = StopTcpClick;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::StopTcpClick(TObject* Sender)
{
pTCP->Disconnect();
Button1->Text = L"Start";
Button1->OnClick = Button1Click;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdIOHandlerStreamGetStreams(TIdIOHandlerStream *ASender, TStream *&VReceiveStream, TStream *&VSendStream)
{
VReceiveStream = mFile.get();
VSendStream = mMem.get();
}
I have to note that IdIOHandlerStream has been set as the IOHandler of pTCP.
The problem is, I know server is sending lots of data, but nothing gets written into the file.
Does anyone know why?

You are using the wrong IOHandler class.
TIdIOHandlerStream performs I/O using TStream objects. It is typically used for replaying previously captured sessions for debugging purposes, without needing a physical connection to a real server.
You need to use TIdIOHandlerStack instead, which performs I/O using a TCP/IP socket connection. It is Indy's default IOHandler class, so you don't even need to create an instance of it 1, TIdTCPClient::Connect() will create one internally for you if you do not assign your own.
1: unless you need more advanced usage, like connecting to a server through a proxy, etc, then you need your own instance so you can configure it as needed.
For what you are attempting, let TIdTCPClient use TIdIOHandlerStack and then you can call the TIdIOHandler::ReadStream() method after connecting to the server. Pass in a TFileStream for it to read into, and set its AByteCount parameter to -1 and AReadUntilDisconnect parameter to True so it will read continuously until the socket connection is closed.
Also, like most operations in Indy, ReadStream() blocks the calling thread until finished, so to avoid blocking your UI, you should call ReadStream() in a worker thread. But, if you don't want to use a thread, you can alternately put a TIdAntiFreeze component on your Form instead.

Related

Getting recycle bin folder with CSIDL_BITBUCKET resulting in garbled strings

My environment
C++ Builder XE4 on Windows 7 Pro (32bit)
I am trying to get Path for "Recycle Bin" using CSIDL_XXX.
Unit2.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::B_checkRecycleBinClick(TObject *Sender)
{
//LPTSTR getPath[255];
wchar_t appdata[255];
SHGetSpecialFolderPath(NULL, appdata, CSIDL_APPDATA, false);
OutputDebugString(appdata);
wchar_t recycle[255];
SHGetSpecialFolderPath(NULL, recycle, CSIDL_BITBUCKET, false);
OutputDebugString(recycle);
}
//---------------------------------------------------------------------------
With the above code,
I can get APPDATA path
recycle path is garbled
Q. What is the mistake you can recognize?

C++ builder (no idea what to do with this code)

Sorry if this is wrong place to ask. I have 2 pieces of code given to me:
IdHTTP1->Head("http://dsrt.dyndns.org/files/MAIN.zip");
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Date));
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Expires));
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->LastModified));
and also this:
TDateTime dt;
AnsiString str = DateToStr(dt);
IdHTTP1->Head("http://dsrt.dyndns.org/files/MAIN.zip");
if(DateToStr(IdHTTP1->Response->Date) != str)
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Date));
if(DateToStr(IdHTTP1->Response->Expires) != str)
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Expires));
if(DateToStr(IdHTTP1->Response->LastModified) != str)
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->LastModified));
Somehow it's supposed to return a date when file was uploaded. But I have no clue how to get c++ builder to compile it. I get syntax errors and "multiple memo1 something" error. Please help.
TMemo is an Embarcadero visual UI component. TIdHTTP is a component of the Indy Project, which ships preinstalled in Delphi and C++Builder.
The code you were given is UI-related code, so create UI for it. In the C++Builder IDE, create a new TForm class, drop a TMemo on it and name it Memo1, and drop a TIdHTTP component and name it IdHTTP1, and then use something like a button OnClick handler to invoke the HTTP code, eg:
Unit1.h:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <IdHTTP.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMemo *Memo1;
TButton *Button1;
TButton *Button2;
TIdHTTP *IdHTTP1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include <System.Sysutils.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
IdHTTP1->Head("http://dsrt.dyndns.org/files/MAIN.zip");
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Date));
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Expires));
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->LastModified));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
TDateTime dt = ...; // assign some value
// see functions such as Date(), Now(), EncodeDateTime(), etc,
// or use the TDateTimePicker component...
System::String str = DateToStr(dt);
IdHTTP1->Head("http://dsrt.dyndns.org/files/MAIN.zip");
if (DateToStr(IdHTTP1->Response->Date) != str)
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Date));
if (DateToStr(IdHTTP1->Response->Expires) != str)
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->Expires));
if (DateToStr(IdHTTP1->Response->LastModified) != str)
Memo1->Lines->Add(DateTimeToStr(IdHTTP1->Response->LastModified));
}
//---------------------------------------------------------------------------
That being said, using strings to compare date/time values is not a good idea in general. Such strings are subject to locale issues. You are using conversion functions that are dependent on the local machine's current locale, not HTTP's standardized date/time formats. The TIdHTTP properties you are using are TDateTime values, where TIdHTTP has already translated the HTTP-provided values into binary values in local date/time (based on the local machine's current timezone). You can compare those values as-is without worrying about any string conversions, eg:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
TDateTime dt = ...; // assign some value
// see functions such as Date(), Now(), EncodeDateTime(), etc,
// or use the TDateTimePicker component...
IdHTTP1->Head("http://dsrt.dyndns.org/files/MAIN.zip");
if (IdHTTP1->Response->Date != dt)
{
//...
}
if (IdHTTP1->Response->Expires != dt)
{
//...
}
if (IdHTTP1->Response->LastModified != dt)
{
//...
}
}
Doing TDateTime comparisons is much more accurate and reliable than string comparisons. And you are not limited to just the == and != operators, you can use the < and > operators as well:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
TDateTime dt = Date();
IdHTTP1->Head("http://dsrt.dyndns.org/files/MAIN.zip");
if (IdHTTP1->Response->Date < dt)
{
// older than today...
}
if (IdHTTP1->Response->Expires < dt)
{
// expired prior to today...
}
if (IdHTTP1->Response->LastModified < dt)
{
// last modified prior to today...
}
}

unresolved external 'xercesc_3_1::XMLPlatformUtils::Initialize' in C++ Builder test app

I am trying to learn how to use the Xerces-c-3.1.4 DLL. I downloaded the source and built the DLL using the xerces-all.sln in VS Studio Express 2015.
I have written a very simple VCL app (a button on a form). This yields three linker errors:
Unresolved external 'xercesc_3_1::XMLPlatformUtils::Terminate()
Unresolved external 'xercesc_3_1::XMLUni::fgXercescDefaultLocale
Unresolved external 'xercesc_3_1::XMLPlatformUtils::Initialize()
The possible causes that occur to me include:
I did something wrong when building the DLL
Don't I need a .DEF file to deal with VC++ name mangling? None in the .sln provided, though.
Don't I need to call GetProcAddress for any DLL functions I use? But where can I find templates for all of the functions in the DLL?
Here's the code for my test app:
#ifndef MainFrmH
#define MainFrmH
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
XERCES_CPP_NAMESPACE_USE
class TMainForm : public TForm
{
__published: // IDE-managed Components
TButton *InitButton;
void __fastcall InitButtonClick(TObject *Sender);
private: // User declarations
HINSTANCE hXercesLib;
public: // User declarations
__fastcall TMainForm(TComponent* Owner);
__fastcall ~TMainForm();
};
extern PACKAGE TMainForm *MainForm;
#endif
#include <vcl.h>
#include <iostream>
#pragma hdrstop
#include "MainFrm.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainForm *MainForm;
using namespace xercesc;
__fastcall TMainForm::TMainForm(TComponent* Owner)
: TForm(Owner)
{
hXercesLib = NULL;
} // ctor
__fastcall TMainForm::~TMainForm()
{
if (hXercesLib)
{
XMLPlatformUtils::Terminate();
FreeLibrary(hXercesLib);
hXercesLib = NULL;
}
} // dtor
void __fastcall TMainForm::InitButtonClick(TObject *Sender)
{
if (!hXercesLib)
{
hXercesLib = LoadLibrary("xerces-c_3_1.dll");
try
{
XMLPlatformUtils::Initialize();
ShowMessage("XMLPlatformUtils::Initialize succeeded");
}
catch (Exception& e)
{
FreeLibrary(hXercesLib);
hXercesLib = NULL;
ShowMessage(e.Message);
}
}
}
You can use GetProcAddress() but it is more work for your code to setup. You can use C++Builder's command-line tdump.exe tool to get a list of the DLL's exported function names.
You can alternatively use C++Builder's command-line implib.exe tool, with or without a .def file, to create a static import .lib file for the DLL, and then add that .lib file to your project.

Problems with property editor in Embarcadero XE6

As usual, every new release of c++ builder takes days of changes...
I'm having trouble fixing a property editor, the code is:
***************** THE H FILE ****************************
//---------------------------------------------------------------------------
#ifndef ufrmLabelEditorH
#define ufrmLabelEditorH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Buttons.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <DesignIntf.hpp>
#include <TypInfo.hpp>
#include <DesignEditors.hpp>
#include <Classes.hpp>
// Add DesignIDE.bpi to your package's Requires list in the Project Manager
#pragma comment(lib, "DesignIDE.bpi")
//---------------------------------------------------------------------------
class TfrmLabelEditor : public TForm
{
__published: // IDE-managed Components
TPanel *Panel1;
TMemo *Memo1;
TBitBtn *BitBtn1;
TBitBtn *BitBtn2;
private: // User declarations
public: // User declarations
__fastcall TfrmLabelEditor(TComponent* Owner);
};
class PACKAGE TLabelProperty : public TStringProperty
{
public:
virtual Designintf::TPropertyAttributes __fastcall GetAttributes() {
return TStringProperty::GetAttributes()<<paDialog;
}
virtual void __fastcall Edit(void) {
TfrmLabelEditor *frmEditor = new TfrmLabelEditor(Application);
frmEditor->Memo1->Lines->Text = GetStrValue();
try {
if (frmEditor->ShowModal()==mrOk) {
int i;
for (i = 0; i < PropCount; i++) {
((TLabel*)GetComponent(i))->Caption = frmEditor->Memo1->Lines->Text;
}
Modified();
}
} catch (...) {
}
frmEditor->Free();
}
};
//---------------------------------------------------------------------------
extern PACKAGE TfrmLabelEditor *frmLabelEditor;
//---------------------------------------------------------------------------
#endif
************** THE CPP FILE *************************
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "ufrmLabelEditor.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmLabelEditor *frmLabelEditor;
//---------------------------------------------------------------------------
__fastcall TfrmLabelEditor::TfrmLabelEditor(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
namespace Labelproperty {
void __fastcall PACKAGE Register()
{
TTypeInfo* typeInfo = new TTypeInfo();
typeInfo->Name = "AnsiString";
typeInfo->Kind = tkLString;
Designintf::RegisterPropertyEditor(typeInfo,__classid(TfrmLabelEditor),"Caption", __classid(TLabelProperty));
TComponentClass classes[1] = {__classid(TfrmLabelEditor)};
RegisterComponents(L"SGM", classes, 0);
}
}
Both files are part of a design time only c++ package....
Any help? If not, please tell me about some c++ ide that realy works!!!!! THANKS.....
Your Register() function relies on an unnecessary hack to fake AnsiString RTTI. Not only that, but the VCL uses Unicode strings in XE6, so unless your Caption property is actually declared as AnsiString then your property editor will not register correctly.
Let the property itself provide the correct RTTI to you. The RegisterPropertyEditor() documentation even demonstrates this. This approach works in every version of C++Builder (and Delphi):
void __fastcall PACKAGE Register()
{
PPropInfo pProp = GetPropInfo(__typeinfo(TfrmLabelEditor), "Caption");
RegisterPropertyEditor(*(pProp->PropType), __classid(TfrmLabelEditor), "Caption", __classid(TLabelProperty));
TComponentClass classes[1] = {__classid(TfrmLabelEditor)};
RegisterComponents(L"SGM", classes, 0);
}
Update: That being said, this registration will never work, because you are setting the second parameter of RegisterPropertyEditor() to the wrong value.
TfrmLabelEditor is itself implemented and exists only in a design-time package. By setting the second parameter to TfrmLabelEditor, the Object Inspector will invoke TLabelProperty only when an instance of TfrmLabelEditor is active in the Form Designer and its Caption property is edited in the Object Inspector. But the Form Designer will never see instances of TfrmLabelEditor in projects, so the Object Inspector will never invoke your TLabelProperty editor. That is why you don't see anything happen.
Read the documentation more carefully. The second parameter specifies a specific runtime component type, or NULL for all component types, that have the specified property of the specified property type. TfrmLabelEditor does not qualify for that.
A little adaptation of REMY SOLUTION have worked, not sure why:
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TfrmLabelEditor)};
//********* register my editors ******************
PPropInfo PropInfo = GetPropInfo(__typeinfo(TForm), "Caption");
Designintf::RegisterPropertyEditor(*(PropInfo->PropType),NULL,"Caption", __classid(TLabelProperty));
//*************************************************
RegisterComponents(L"SGM", classes, 0);
}

Builder c++ TButton problems?

I'm using Builder C++ 6.
in the folowing code I want my function KreirajPOlja() to generate random AnsiString characters on the buttons but what i always gain is just matrix 9*9 with just one generated character as in the picture:
void __fastcall TForm1::KreirajPolja()
{
int tr;
for(int i=0;i<dim_x;i++)
for(int j=0;j<dim_y;j++) {
Dugme[i][j]->Height=20;
Dugme[i][j]->Width=Dugme[i][j]->Height;
Dugme[i][j]->Left=i*Dugme[i][j]->Height;
Dugme[i][j]->Top=j*Dugme[i][j]->Height;
Dugme[i][j]->Parent=this;
tr=PostaviRandom();
Dugme[i][j]->Caption= NizSlova[tr];
}
Button1->Caption="submit";
Button1->Enabled=false;
Form1->Width=dim_x* 20+5;
Form1->Height=(dim_y+2)* 20+25;
}
//---------------------------------------------------------------------------
int __fastcall TForm1::PostaviRandom(){
int k;
srand(time(0));
k=rand()%sizeof(NizSlova);
return k;}
and here is the folowing cpp code
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <time.h>
//--- ------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
void __fastcall FormCreate(TObject *Sender);
public: // User declarations
TButton*** Dugme;
TImage *** Slike;
TEdit *brojac;
int dim_x, dim_y;
int vrijeme,kr;
int BrojSlova, br;
AnsiString NizSlova;
__fastcall TForm1(TComponent* Owner);
void __fastcall KreirajSlova();
void __fastcall AlocirajProstor();
void __fastcall BrisiProstor();
void __fastcall AlocirajProstorZaSlova();
void __fastcall BrisiProstorZaSlova();
void __fastcall KreirajPolja();
virtual int __fastcall PostaviRandom();
AnsiString __fastcall DajSlovo();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Don't call srand in your loop. Call it once at the start of the program.
Each time you call srand you reset the random number generator. Since you call it with the same parameter each time (your code runs in less than a second so the value of time(NULL) doesn't change), you get the same result from rand().
There is no need to call srand multiple times in the same program unless you intentionally want to reproduce an old sequence of random numbers.

Resources