There is a library for parsing.
I added ALXmlDoc.pas to the project, C++Builder created ALXmlDoc.hpp
In ALXmlDoc.pas lines 177,178:
property Nodes [const Name: AnsiString]: TALXMLNode read GetNodeByName; default;
property Nodes [const Index: integer]: TALXMLNode read GetNodeByIndex; default;
In ALXmlDoc.hpp:
__property TALXMLNode * Nodes [const System :: AnsiString Name] = {read = GetNodeByName / *, default */};
__property TALXMLNode * Nodes [const int Index] = {read = GetNodeByIndex};
I get an error about duplication - how to fix it?
In .pas line 705
property OnParseText: TAlXMLParseTextEvent read FonParseText Write FonParseText; // [added from TXMLDocument]
In ALXmlDoc.hpp:
__property _di_TAlXMLParseTextEvent OnParseText = {read = FonParseText, write = FonParseText};
__interface TAlXMLParseTextEvent: public System :: IInterface
{
virtual void __fastcall Invoke (System :: TObject * Sender, const System :: AnsiString Path, const System :: AnsiString Str) = 0;
};
private:
_di_TAlXMLParseTextEvent FonParseText;
protected:
void __fastcall DoParseText (const System :: AnsiString Path, const System :: AnsiString Str);
In my Unit1.h:
void __fastcall OnParseText (System :: TObject * Sender, const System :: AnsiString Path, const System :: AnsiString Str);
In my Unit1.cpp:
void __fastcall TForm1 :: OnParseText (System :: TObject * Sender, const System :: AnsiString Path, const System :: AnsiString Str)
{
ShowMessage(Str);
}
// ------------------------------------------------ ---------------------------
void __fastcall TForm1 :: Button1Click (TObject * Sender)
{
TALXMLDocument * aXMLDocument = new TALXMLDocument ("root");
aXMLDocument-> OnParseText = OnParseText;
}
I get an error:
[bcc32 Error] Unit1.cpp (30): E2235 Member function must be called or its address taken
How to declare an event?
In C++, array properties can't be overloaded solely on their index type. So you will have to rename one of the offending properties, there is no other option. And then I would suggest you file a report with the library author asking to make the library be more friendly to C++ users.
In the Delphi code, TAlXMLParseTextEvent is a reference to an anonymous method:
TAlXMLParseTextEvent = reference to procedure (Sender: TObject; const Path, Str: AnsiString);
Which is why it gets translated to an __interface on the C++ side (because anonymous methods really are implemented behind the scenes using interfaces). Delphi-style anonymous methods require extra handling in C++, as is documented on Embarcadero's DocWiki:
How to Handle Delphi Anonymous Methods in C++
Under the cover, Delphi implements anonymous methods types (also known as method references) via an interface that implements an Invoke(...) method.
So a method that takes a method reference parameter in Delphi is exposed to C++ as a method that takes an interface.
As such, your C++ code would need to do something more like this instead:
struct TParseTextMethod
{
void operator()(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
ShowMessage(Str);
}
};
//------------------------------------------------ ---------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
// the TMethodRef functor is defined in the documentation,
// you can copy/paste it as-is into your code...
typedef TMethodRef<TAlXMLParseTextEvent,
TParseTextMethod,
void,
TObject *Sender,
const AnsiString,
const AnsiString> MyMethRef;
aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new MyMethRef(TParseTextMethod()));
}
Or, you can streamline the functor usage a bit more by not using the TMethodRef wrapper (see Inheritance and Interfaces and Implementing Interfaces):
class TParseTextMethod : public TCppInterfacedObject<TAlXMLParseTextEvent>
{
public:
TParseTextMethod() {}
INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
void __fastcall Invoke(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
ShowMessage(Str);
}
};
//------------------------------------------------ ---------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new TParseTextMethod());
}
Or, if you want to keep using your OnParseText() method as-is, then you will have to wrap it inside a functor, eg:
void __fastcall TForm1::OnParseText(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
ShowMessage(Str);
}
//------------------------------------------------ ---------------------------
typedef void __fastcall (__closure *TAlXMLParseTextMethod)(TObject *Sender, const AnsiString Path, const AnsiString Str);
struct TParseTextMethod
{
TAlXMLParseTextMethod Method;
TParseTextMethod(TAlXMLParseTextMethod aMethod) : Method(aMethod) {}
void operator()(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
Method(Sender, Path, Str);
}
};
//------------------------------------------------ ---------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
typedef TMethodRef<TAlXMLParseTextEvent,
TParseTextMethod,
void,
TObject *Sender,
const AnsiString,
const AnsiString> MyMethRef;
aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new MyMethRef(TParseTextMethod(&OnParseText)));
}
Or:
void __fastcall TForm1::OnParseText(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
ShowMessage(Str);
}
//------------------------------------------------ ---------------------------
typedef void __fastcall (__closure *TAlXMLParseTextMethod)(TObject *Sender, const AnsiString Path, const AnsiString Str);
class TParseTextMethod : public TCppInterfacedObject<TAlXMLParseTextEvent>
{
public:
TAlXMLParseTextMethod Method;
TParseTextMethod(TAlXMLParseTextMethod aMethod) : Method(aMethod) {}
INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
void __fastcall Invoke(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
Method(Sender, Path, Str);
}
};
//------------------------------------------------ ---------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new TParseTextMethod(&OnParseText));
}
Alternatively, if you are using one of the Clang-based compilers then you can use a C++ style lambda instead of a functor:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
aXMLDocument->OnParseText = [](TObject*, const AnsiString, const AnsiString Str) {
ShowMessage(Str);
};
}
Or:
void __fastcall TForm1::OnParseText(TObject *Sender, const AnsiString Path, const AnsiString Str)
{
ShowMessage(Str);
}
//------------------------------------------------ ---------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
aXMLDocument->OnParseText = [this](TObject *Sender, const AnsiString Path, const AnsiString Str) {
OnParseText(Sender, Path, Str);
};
}
Related
The accepted answer in this question shows how to check for and use an interface on a VCL-derived object in Delphi.
How to use Interface with VCL Classes - Part 2
procedure Test;
var
O1: TSomeThing;
Intf: ISomething;
begin
O1 := TSomeThing.Create(nil);
if Supports(O1, ISomething, Intf) then
begin
Intf.DoSomething;
end;
Basically, I want to do the same in C++Builder but haven't worked out how to use "Supports" from C++.
Attempting to use <dynamic_cast> fails at compile time when using VCL-derived classes...
TSomeThing * O1;
ISomething *i = dynamic_cast<ISomething*>(O1); // Error: Can't cast
The suggested Inheritance and Interfaces article mentions TObject::GetInterface() but when I try that I get an error "Pure Virtual Function called".
_di_IFoo mc;
if (this->GetInterface(mc)) ...
Update: First, the objects I'm adding interfaces to are existing VCL controls so NOT derived from TInterfacedObject.
Second - there's no COM involved - I hope! The use of Interfaces is purely to allow me to use the concept of interfaces for multiple inheritance with VCL components which C++Builder (at least, in 2010) does not support.
So my interface looks like this (NOTE that there's no __addref/__release etc...):
__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") IMyInterface : public IInterface
{
public:
virtual UTF8String getHello() = 0;
};
And my objects looks like this
class TMyPanel: public TPanel, IMyInterface
{
...
public:
UTF8String getHello() { return "Hello from a TMyPanel";}
...
};
class TMyLabel: public TLabel, IMyInterface
{
...
public:
UTF8String getHello() { return "Hello from a TMyLabel";}
...
};
That's straightforward, and as described in the Embarcadero docs for Interfaces.
But, how to tell if a particular TObject supports IMyInterface???
The following template function does this for me, based on TObject.GetInterfaceEntry() from system.pas:
template<typename T>
T* getInterface(TObject *obj)
{
T *intf = NULL;
PInterfaceEntry interfaceEntry = obj->GetInterfaceEntry(__uuidof(T) );
if (interfaceEntry && interfaceEntry->IOffset != 0)
{
intf = (T*)(((char *)obj) + interfaceEntry->IOffset);
}
return intf;
}
And we use it like this:
IMyInterface *myIf = getInterface<IMyInterface>(aRandomTObject);
if (myIf)
{
UTF8String s = myIf->getHello();
}
Please let me know if there's a better way than this, as the VTable/Pointer spelunking makes my teeth itch...
You do it the same way in C++ as in Delphi - via the Sysutils::Supports() function.
This works for me when I try it:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
void __fastcall FormClick(TObject *Sender);
private: // User declarations
TPanel *p;
TLabel *l;
void Test();
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm7 *Form1;
//---------------------------------------------------------------------------
__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") IMyInterface : public IInterface
{
public:
virtual UTF8String getHello() = 0;
};
#if !defined(INTFOBJECT_IMPL_IUNKNOWN)
#define INTFOBJECT_IMPL_IUNKNOWN(BASE) \
ULONG __stdcall AddRef() { return BASE::_AddRef();} \
ULONG __stdcall Release(){ return BASE::_Release();} \
HRESULT __stdcall QueryInterface(REFIID iid, void** p){ return BASE::QueryInterface(iid, p);}
#endif
class TMyPanel : public TPanel, public IMyInterface
{
INTFOBJECT_IMPL_IUNKNOWN(TPanel)
public:
__fastcall TMyPanel(TComponent *Owner) : TPanel(Owner) {}
UTF8String getHello() { return "Hello from a TMyPanel"; }
};
class TMyLabel : public TLabel, public IMyInterface
{
INTFOBJECT_IMPL_IUNKNOWN(TLabel)
public:
__fastcall TMyLabel(TComponent *Owner) : TLabel(Owner) {}
UTF8String getHello() { return "Hello from a TMyLabel"; }
};
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
p = new TMyPanel(this);
p->Parent = this;
l = new TMyLabel(this);
l->Parent = p;
l->Caption = L"Test";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClick(TObject *Sender)
{
Test();
}
//---------------------------------------------------------------------------
void TForm1::Test()
{
DelphiInterface<IMyInterface> Intf;
if (Supports(p, __uuidof(IMyInterface), (void*)&Intf))
{
UTF8String s = Intf->getHello();
ShowMessage(s);
Intf.Release();
}
if (Supports(l, __uuidof(IMyInterface), (void*)&Intf))
{
UTF8String s = Intf->getHello();
ShowMessage(s);
Intf.Release();
}
}
//---------------------------------------------------------------------------
No matter how I attempt to use it, I cannot dynamically create a TScrollBox and assign an OnMouseWheelEvent handler to it. I get the following compiler error:
E2034 Cannot convert 'void (_fastcall * (_closure )(TObject *,TShiftState,int,TPoint &,bool &))(TObject *,TShiftState,int,TPoint &,bool &)' to 'TMouseWheelEvent'
My declaration for the OnMouseWheelEvent handler is correct (as far as I can tell):
....
TScrollBox *sb = new TScrollBox(funnelCharts);
sb->Top = 5000;
sb->Parent = funnelCharts;
sb->Align = alClient;
sb->Height = funnelCharts->ClientHeight;
sb->OnMouseWheel = scrollEvent;
....
// --------------------------------------------------------------
void __fastcall TForm1::scrollEvent(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
TScrollBox *scrollbox = dynamic_cast<TScrollBox*>(Sender);
if (scrollbox)
{
for (int i = 1; i < Mouse->WheelScrollLines; i++)
{
if (WheelDelta > 0)
{
scrollbox->Perform(WM_VSCROLL, SB_LINEUP, 0);
}
else
{
scrollbox->Perform(WM_VSCROLL, SB_LINEDOWN, 0);
}
}
scrollbox->Perform(WM_VSCROLL, SB_ENDSCROLL, 0);
Handled = true;
}
}
This is a compiler error, not a linker error.
Look at the actual declaration of TMouseWheelEvent in Controls.hpp. Your scrollEvent() method does not match what is actually declared, otherwise you would not be getting the error.
Depending on whether you are compiling for 32-bit or 64-bit, TMouseWheelEvent (specifically, its MousePos parameter) is declared differently:
32-bit:
typedef void __fastcall (__closure *TMouseWheelEvent)(System::TObject* Sender, System::Classes::TShiftState Shift, int WheelDelta, const System::Types::TPoint &MousePos, bool &Handled);
64-bit:
typedef void __fastcall (__closure *TMouseWheelEvent)(System::TObject* Sender, System::Classes::TShiftState Shift, int WheelDelta, System::Types::TPoint MousePos, bool &Handled);
The reason for this is BCC32 and BCC64 differ in how they pass around 8-byte struct types (like TPoint). This difference is documented on Embarcadero's DocWiki:
Events with Structures or Sets of 5-8 Bytes Are Not Valid for BCC64
Other event types affected by this difference include TGetSiteInfoEvent, TMouseWheelUpDownEvent, and TContextPopupEvent.
To fix this, you will have to #ifdef your code as documented:
class TForm1 : public TForm
{
...
#ifndef _WIN64
void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
#else
void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, TPoint MousePos, bool &Handled);
#endif
...
};
...
#ifndef _WIN64
void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
#else
void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, TPoint MousePos, bool &Handled)
#endif
{
...
}
Or, a little cleaner approach:
class TForm1 : public TForm
{
...
void __fastcall scrollEvent(
TObject* Sender, TShiftState Shift, int WheelDelta,
#ifndef _WIN64
const TPoint &MousePos,
#else
TPoint MousePos,
#endif
bool &Handled);
...
};
...
void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta,
#ifndef _WIN64
const TPoint &MousePos,
#else
TPoint MousePos,
#endif
bool &Handled)
{
...
}
Or, even cleaner:
#ifndef _WIN64
#define SAFE_5TO8_PARAM(type, name) const type &name
#else
#define SAFE_5TO8_PARAM(type, name) type name
#endif
class TForm1 : public TForm
{
...
void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, SAFE_5TO8_PARAM(TPoint, MousePos), bool &Handled);
...
};
...
void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, SAFE_5TO8_PARAM(TPoint, MousePos), bool &Handled)
{
...
}
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...
}
}
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.
How do I use a TComInterface<IStream> object and read it into a TMemoryStream? Can I take TComInterface<IStream> and use it as a TStream* somehow to use the TMemoryStream LoadFromStream call?
One way is to Read() the IStream data into a buffer that you then Write() to the TMemoryStream, eg:
TComInterface<IStream> pIStrm;
TMemoryStream *pMStrm;
...
STATSTG stat = {0};
OleCheck(pIStrm->Stat(&stat, STATFLAG_NONAME));
LARGE_INTEGER li;
li.QuadPart = 0;
ULARGE_INTEGER ul;
OleCheck(pIStrm->Seek(li, STREAM_SEEK_CUR, &ul));
unsigned __int64 ulPos = ul.QuadPart;
BYTE buffer[1024];
while (ulPos < stat.cbSize.QuadPart)
{
ULONG ulRead;
OleCheck(pIStrm->Read(buffer, min(stat.cbSize.QuadPart - ulPos, sizeof(buffer)), &ulRead));
pMStrm->WriteBuffer(buffer, ulRead);
ulPos += ulRead;
}
...
Another option is to write a TStream-derived class that accesses the IStream internally (similar to how the RTL's TStreamAdapter class wraps a TStream so it can be passed around as an IStream), eg:
class TIStreamWrapper : public TStream
{
private:
TComInterface<IStream> pIStrm;
protected:
virtual __int64 __fastcall GetSize();
virtual void __fastcall SetSize(const __int64 NewSize);
public:
__fastcall TIStreamWrapper(IStream *Strm);
virtual int __fastcall Read(void *Buffer, int Count);
virtual int __fastcall Write(const void *Buffer, int Count);
virtual __int64 __fastcall Seek(const __int64 Offset, TSeekOrigin Origin);
};
__fastcall TIStreamWrapper::TIStreamWrapper(IStream *Strm)
: pIStrm(Strm, true)
{
}
__int64 __fastcall TIStreamWrapper::GetSize()
{
STATSTG stat = {0};
OleCheck(pIStrm->Stat(&stat, STATFLAG_NONAME));
return stat.cbSize.QuadPart;
}
void __fastcall TIStreamWrapper::SetSize(const __int64 NewSize)
{
ULARGE_INTEGER ul;
ul.QuadPart = NewSize;
OleCheck(pIStrm->SetSize(ul));
}
int __fastcall TIStreamWrapper::Read(void *Buffer, int Count)
{
ULONG ulRead;
OleCheck(pIStrm->Read(Buffer, Count, &ulRead));
return ulRead;
}
int __fastcall TIStreamWrapper::Write(const void *Buffer, int Count)
{
ULONG ulWritten;
OleCheck(pIStrm->Write(Buffer, Count, &ulWritten));
return ulWritten;
}
static const DWORD IStreamSeekOrigin[] = {STREAM_SEEK_SET, STREAM_SEEK_CUR, STREAM_SEEK_END};
__int64 __fastcall TIStreamWrapper::Seek(const __int64 Offset, TSeekOrigin Origin)
{
LARGE_INTEGER li;
li.QuadPart = Offset;
ULARGE_INTEGER ul;
OleCheck(pIStrm->Seek(li, IStreamSeekOrigin[Origin], &ul));
return ul.QuadPart;
}
TComInterface<IStream> pIStrm;
TMemoryStream *pMStrm;
...
TIStreamWrapper *pWrapper = new TIStreamWrapper(pIStrm);
try
{
pMStrm->LoadFromStream(pWrapper);
// or: pMStrm->CopyFrom(pWrapper, 0);
}
__finally
{
delete pWrapper;
}
...