How to query a TFDMemTable - c++builder

I am trying to create a simple loop to process a TFDMemTable. I've dropped a TFDMemTable, a TFDQuery, and a TFDConnection on a Form, and I think I have wired everything up correctly, but when I activate the query it gives back an error message that there is no such table as FDMemTable1.
Here is demo code of what I am trying:
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#include "FireDac.Stan.Def.hpp"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
void __fastcall TForm2::FormCreate(TObject *Sender)
{
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Vic", 100, 30)));
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Jeong", 20, 20)));
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Christina", 400, 50)));
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Justina", 0, 60)));
FDConnection1->ConnectionName = L"FDMemTable1";
FDConnection1->DriverName = L"SQLite";
FDConnection1->Connected = true;
FDQuery1->Connection = FDConnection1;
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
UnicodeString x;
FDQuery1->SQL->Text = "SELECT * FROM FDMemTable1";
FDQuery1->Active = true;
if (!FDQuery1->Eof) {
x = FDQuery1->FieldByName(L"FullName")->AsString;
...
FDQuery1->Next();
}
}
How does one go about querying an existing TFDMemTable?

To query an FDMemTable you can use FireDAC's LocalSQL facility. Adding a TFDLocaSQL component to your form enables you to register one or more TDataSet-descendant dataset (using the Add method of its Datasets property), such as your FDMemTable, to be the target of a SQL search using Sqlite's SQL implementation. It should be more than adequate to execute your query and is very easy to use, once you've set it up.
See https://docwiki.embarcadero.com/RADStudio/Sydney/en/Local_SQL_(FireDAC) for more information.
This is the code from an answer of mine which uses FireDAC's localSQL with an FDMemTable. The code is written in Dellphi but should be trivial to translate into c++:
FDConnection1.DriverName := 'SQLite';
FDConnection1.Connected := True;
FDLocalSQL1.Connection := FDConnection1;
FDLocalSQL1.DataSets.Add(FDMemTable1);
FDLocalSQL1.Active := True;
FDQuery1.SQL.Text := 'select * from FDMemTable1 order by ID limit 5';
FDQuery1.Active := True;

The actual answer turned out to be as MartynA suggested. Here was the final code that worked:
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#include "FireDac.Stan.Def.hpp"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "AdvGrid"
#pragma link "AdvObj"
#pragma link "AdvUtil"
#pragma link "BaseGrid"
#pragma link "DBAdvGrid"
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
void __fastcall TForm2::FormCreate(TObject *Sender)
{
FDMemTable1->Active = true;
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Vic", 100, 30)));
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Jeong", 20, 20)));
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Christina, 400, 50)));
FDMemTable1->InsertRecord(ARRAYOFCONST((L"Justina", 0, 60)));
FDConnection1->ConnectionName = L"FDMemTable1";
FDConnection1->DriverName = L"SQLite";
FDConnection1->LoginPrompt = false;
FDConnection1->Connected = true;
FDLocalSQL1->Connection = FDConnection1;
FDLocalSQL1->DataSets->Add(FDMemTable1, L"FDMemTable1");
FDLocalSQL1->Active = true;
FDQuery1->Connection = FDConnection1;
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
UnicodeString x;
FDQuery1->SQL->Text = "SELECT * FROM FDMemTable1";
FDQuery1->Active = true;
if (!FDQuery1->Eof) {
x = FDQuery1->FieldByName(L"FullName")->AsString;
FDQuery1->Next();
}
}

Related

reinit.pas translated to C++

I have semi-successfully translated reinit.pas to C++ to use it in my project. The part where int __fastcall LoadNewResourceModule(LCID locale); is called works fine, in fact I can even call it prior to Application->Initialize() and it will load the proper language at startup. However, the part that calls void __fastcall ReinitializeForms(void); does not work, and gives a runtime error:
Resource TControl not found
Here is the dirty version of .cpp, and .h, I've yet to clean it up and comment it properly, at this point the thing just has to work fully. Please help me sort this out.
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <SysInit.hpp>
#include <Vcl.Forms.hpp>
#pragma hdrstop
#include "reinit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
class TAsInheritedReader : public TReader
{
public:
void __fastcall ReadPrefix(TFilerFlags &_flags, int &_aChildPos);
inline __fastcall TAsInheritedReader(TStream* Stream, int BufSize) : TReader(Stream, BufSize) {}
};
//---------------------------------------------------------------------------
void __fastcall TAsInheritedReader::ReadPrefix(TFilerFlags &_flags, int &_aChildPos)
{
TReader::ReadPrefix(_flags, _aChildPos);
_flags = _flags << ffInherited;
}
//---------------------------------------------------------------------------
int __fastcall SetResourceHInstance(int _newInstance)
{
PLibModule CurModule = LibModuleList;
while(CurModule != NULL) {
if (reinterpret_cast<void*>(CurModule->Instance) == HInstance) {
if (CurModule->ResInstance != CurModule->Instance) {
FreeLibrary(reinterpret_cast<HMODULE>(CurModule->ResInstance));
CurModule->ResInstance = _newInstance;
return _newInstance;
}
CurModule = CurModule->Next;
}
}
return 0;
}
//---------------------------------------------------------------------------
int __fastcall LoadNewResourceModule(LCID locale)
{
wchar_t FileName[260];
PChar P;
wchar_t LocaleName[4];
int NewInst = 0;
GetModuleFileName(HInstance, FileName, sizeof(FileName));
GetLocaleInfo(locale, LOCALE_SABBREVLANGNAME, LocaleName, sizeof(LocaleName));
P = PChar(&FileName) + lstrlen(FileName);
while((*P != L'.') && (P != reinterpret_cast<PChar>(&FileName))) {
--P;
}
if (P != reinterpret_cast<PChar>(&FileName)) {
++P;
if (LocaleName[0] != L'\0') {
NewInst = reinterpret_cast<int>(LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE));
if (NewInst == 0) {
LocaleName[2] = L'\0';
lstrcpy(P, LocaleName);
NewInst = reinterpret_cast<int>(LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE));
}
}
}
if (NewInst != 0) {
return SetResourceHInstance(NewInst);
}
return 0;
}
//---------------------------------------------------------------------------
bool __fastcall InternalReloadComponentRes(const String ResName, THandle HInst, TComponent* Instance)
{
//TResourceStream* ResStream = new TResourceStream;
//TAsInheritedReader* AsInheritedReader = new TAsInheritedReader;
if (HInst == 0) {
HInst = reinterpret_cast<THandle>(HInstance);
}
THandle HRsrc = reinterpret_cast<THandle>(FindResource((HMODULE)HInst, (LPCWSTR)ResName.w_str(), (LPCWSTR)RT_RCDATA));
if(HRsrc != 0) {
return false;
}
/* THIS IS THE OFFENDING LINE OF CODE THAT THROWS EXCEPTION
I checked HInst, it is not 0...
ResName = "TControl"
and it throws exception here for some reason
saying resource tcontrol not found
*/
TResourceStream* ResStream = new TResourceStream(HInst, ResName, RT_RCDATA);
try {
TAsInheritedReader* AsInheritedReader = new TAsInheritedReader(ResStream, 4096);
try {
Instance = AsInheritedReader->ReadRootComponent(Instance);
} __finally {
delete AsInheritedReader;
}
}
__finally {
delete ResStream;
}
return true;
}
//---------------------------------------------------------------------------
bool __fastcall InitComponent(TClass ClassType)
{
if ((ClassType->ClassName() == "TComponent") || (ClassType->ClassName() == "RootAncestor")) {
return false;
}
InitComponent(ClassType->ClassParent());
return InternalReloadComponentRes(ClassType->ClassName(), FindResourceHInstance(FindClassHInstance(ClassType)), (TComponent*)&ClassType);
}
//---------------------------------------------------------------------------
bool __fastcall ReloadInheritedComponent(TComponent* Instance)
{
return InitComponent(Instance->ClassType());
}
//---------------------------------------------------------------------------
void __fastcall ReinitializeForms(void)
{
for(int i=0; i<Screen->FormCount-1; i++) {
ReloadInheritedComponent(Screen->Forms[i]);
}
}
#ifndef _reinit_h
#define _reinit_h
#include <windows.h>
extern int __fastcall LoadNewResourceModule(LCID locale);
extern void __fastcall ReinitializeForms(void);
#endif
You don't really need to translate the code at all. You can use Delphi .pas units as-is in C++Builder projects. Simply add the .pas file to your project and compile it, the IDE will generate a .hpp file that you can then #include in your C++ code.
In any case, your translation is not correct in many places.
For instance, the original code wasn't written with Unicode in mind, but you are using Unicode strings in your code. Expressions like sizeof(FileName) and sizeof(LocaleName) are the wrong buffer sizes to pass to the Win32 APIs being used, which can potentially allow buffer overflows. The code was clearly expecting BYTE-sized narrow characters, not WORD-sized wide characters.
It also looks like the original code was not written with 64-bit in mind, either. It is using 32-bit integers in places where 64-bit integers would be needed (for resource handles, etc).
So, the original code needs some updating to support modern systems properly.
But also, your translation of InitComponent() is wrong. It is using strings where the original code is using metaclass references instead, and it is passing the wrong value in the last parameter of InternalReloadComponentRes(), which you have not even declared correctly.
And also, your loop in ReinitializeForms() is skipping the last TForm in the Screen->Forms[] array.
Now, that all being said, try something more like this:
ReInit.h
#ifndef REINIT_H
#define REINIT_H
void __fastcall ReinitializeForms();
NativeUInt __fastcall LoadNewResourceModule(unsigned long Locale);
#endif
ReInit.cpp
#include "ReInit.h"
#include <Windows.hpp>
#include <SysInit.hpp>
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#include <memory>
class TAsInheritedReader : public TReader
{
public:
void __fastcall ReadPrefix(TFilerFlags &Flags, int &AChildPos) override;
};
void __fastcall TAsInheritedReader::ReadPrefix(TFilerFlags &Flags, int &AChildPos)
{
TReader::ReadPrefix(Flags, AChildPos);
Flags << ffInherited;
}
NativeUInt __fastcall SetResourceHInstance(NativeUInt NewInstance)
{
PLibModule CurModule = LibModuleList;
while (CurModule)
{
if (CurModule->Instance == HInstance)
{
if (CurModule->ResInstance != CurModule->Instance)
::FreeLibrary(reinterpret_cast<HMODULE>(CurModule->ResInstance));
CurModule->ResInstance = NewInstance;
return NewInstance;
}
CurModule = CurModule->Next;
}
return 0;
}
NativeUInt __fastcall LoadNewResourceModule(unsigned long Locale)
{
WCHAR FileName[MAX_PATH+1] = {};
::GetModuleFileNameW(reinterpret_cast<HMODULE>(HInstance), FileName, MAX_PATH+1);
WCHAR LocaleName[5] = {};
::GetLocaleInfoW(Locale, LOCALE_SABBREVLANGNAME, LocaleName, 5);
LPWSTR P = &FileName[lstrlenW(FileName)];
while ((*P != L'.') && (P != FileName)) --P;
HMODULE NewInst = nullptr;
if (P != FileName)
{
++P;
if (LocaleName[0] != L'\0')
{
// Then look for a potential language/country translation
lstrcpyW(P, LocaleName);
NewInst = LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE);
if (!NewInst)
{
// Finally look for a language only translation
LocaleName[2] = L'\0';
lstrcpyW(P, LocaleName);
NewInst = LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE);
}
}
}
if (NewInst)
return SetResourceHInstance(reinterpret_cast<NativeUInt>(NewInst));
return 0;
}
bool __fastcall InternalReloadComponentRes(const UnicodeString &ResName, NativeUInt HInst, TComponent* &Instance)
{
// avoid possible EResNotFound exception
if (HInst == 0) HInst = HInstance;
HRSRC HRsrc = FindResourceW(reinterpret_cast<HMODULE>(HInst), ResName.c_str(), MAKEINTRESOURCEW(10)/*RT_RCDATA*/);
if (!HRsrc) return false;
auto ResStream = std::make_unique<TResourceStream>(HInst, ResName, MAKEINTRESOURCEW(10)/*RT_RCDATA*/);
auto AsInheritedReader = std::make_unique<TAsInheritedReader>(ResStream.get(), 4096);
Instance = AsInheritedReader->ReadRootComponent(Instance);
return true;
}
bool __fastcall ReloadInheritedComponent(TComponent *Instance, TClass RootAncestor)
{
const auto InitComponent = [&Instance,RootAncestor](TClass ClassType) -> bool
{
auto InitComponent_impl = [&Instance,RootAncestor](TClass ClassType, auto& InitComponent_ref) -> bool
{
if ((ClassType == __classid(TComponent)) || (ClassType == RootAncestor)) return false;
bool Result = InitComponent_ref(ClassType->ClassParent(), InitComponent_ref);
return InternalReloadComponentRes(ClassType->ClassName(), FindResourceHInstance(FindClassHInstance(ClassType)), Instance) || Result;
}
return InitComponent_impl(ClassType, InitComponent_impl);
}
return InitComponent(Instance->ClassType());
}
void __fastcall ReinitializeForms()
{
int Count = Screen->FormCount;
for(int i = 0; i < Count; ++i)
{
ReloadInheritedComponent(Screen->Forms[I], __classid(TForm));
}
}

C++ Builder XE4, 10.2 Tokyo > TStreamWriter > clWhite cannot be copied

My environment:
RadStudio 10.2 Tokyo (and also XE4)
I was implementing a copy property method to copy TShape properties.
Following is what I implemented:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
// set Shape1 color to [clWhite]
Shape1->Brush->Color = clRed; // clWhite
Shape2->Brush->Color = clAqua;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
// to Keep original names
String orgName_src = srcCtrl->Name;
String orgName_dst = dstCtrl->Name;
// copy properties
TMemoryStream *strm = new TMemoryStream;
Shape1->Name = L""; // to avoid source collision
try {
strm->WriteComponent(srcCtrl);
strm->Position = 0;
strm->ReadComponent(dstCtrl);
}
__finally
{
delete strm;
}
srcCtrl->Name = orgName_src;
dstCtrl->Name = orgName_dst;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
copyProperties((TControl *)Shape1, (TControl *)Shape2);
// shift to avoid position-overlapping
Shape2->Left = Shape1->Left + 150;
}
//---------------------------------------------------------------------------
The code seems work fine.
But there is a single case, in which the code does not work.
i.e. when the Brush->Color = clWhite for Shape1.
This bug? can be reproduced also for XE4.
I wonder why only the clWhite has this kind of bug? Other colors does not have this kind of bug.
There is no bug in the streaming. It is operating as designed. You are simply using it in a way that it is not intended for.
clWhite is the declared default value of the TBrush.Color property. The DFM streaming system does not stream properties that are currently set to their default values, unless those properties are declared as nodefault or stored=true. TBrush.Color is neither. So the current Brush.Color value will not be streamed when it is set to clWhite.
Consider using the RTTI system directly instead of using the DFM system to copy properties from one object to another. Then you can copy property values regardless of defaults, if you choose to do so. And you can opt to ignore the Name property without having to (re)store it each time.
For example:
#include <System.TypInfo.hpp>
void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
PTypeInfo pDstTypeInfo = static_cast<PTypeInfo>(dstCtrl->ClassInfo());
PPropList srcPropList;
int srcPropCount = GetPropList(srcCtrl, srcPropList);
try
{
for (int i = 0; i < srcPropCount; ++i)
{
PPropInfo pSrcPropInfo = (*srcPropList)[i];
if (pSrcPropInfo->Name == "Name") continue;
PTypeInfo pSrcPropTypeInfo = *(pSrcPropInfo->PropType);
if (pSrcPropTypeInfo->Kind == tkClass)
{
PPropInfo pDstPropInfo = GetPropInfo(pDstTypeInfo, pSrcPropInfo->Name, TTypeKinds() << tkClass);
if (pDstPropInfo)
{
TPersistent *pDstObj = static_cast<TPersistent*>(GetObjectProp(dstCtrl, pDstPropInfo, __classid(TPersistent)));
if (pDstObj)
{
TPersistent *pSrcObj = static_cast<TPersistent*>(GetObjectProp(srcCtrl, pSrcPropInfo, __classid(TPersistent)));
pDstObj->Assign(pSrcObj);
}
}
}
else
{
PPropInfo pDstPropInfo = GetPropInfo(pDstTypeInfo, pSrcPropInfo->Name);
if (pDstPropInfo)
{
Variant value = GetPropValue(srcCtrl, pSrcPropInfo);
SetPropValue(dstCtrl, pDstPropInfo, value);
}
}
}
}
__finally
{
FreeMem(srcPropList);
}
}
Alternatively:
#include <System.Rtti.hpp>
void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
TRttiContext ctx;
TRttiType *pSrcType = ctx.GetType(srcCtrl->ClassInfo());
TRttiType *pDstType = ctx.GetType(dstCtrl->ClassInfo());
DynamicArray<TRttiProperty*> srcProps = pSrcType->GetProperties();
for (int i = 0; i < srcProps.Length; ++i)
{
TRttiProperty *pSrcProp = srcProps[i];
if (pSrcProp->Name == L"Name") continue;
if (pSrcProp->PropertyType->TypeKind == tkClass)
{
TRttiProperty *pDstProp = pDstType->GetProperty(pSrcPropInfo->Name);
if ((pDstProp) && (pDstProp->PropertyType->TypeKind == tkClass))
{
TPersistent *pDstObj = dynamic_cast<TPersistent*>(pDstProp->GetValue(dstCtrl).AsObject());
if (pDstObj)
{
TPersistent *pSrcObj = dynamic_cast<TPersistent*>(pSrcProp->GetValue(srcCtrl).AsObject());
pDstObj->Assign(pSrcObj);
}
}
}
else
{
TRttiProperty *pDstProp = pDstType->GetProperty(pSrcPropInfo->Name);
if (pDstProp)
{
TValue value = pSrcProp->GetValue(srcCtrl);
pDstProp->SetValue(dstCtrl, value);
}
}
}
}

How to cast Interfaces with VCL components in C++Builder

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();
}
}
//---------------------------------------------------------------------------

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

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);
}

Resources