I'm moving some C++Builder code to BCB2010 and need to replace calls to LeftStr() and RightStr() with appropriate functions, as there's no UnicodeString overload of these.
AnsiLeftStr() appears to work, but the name is scaring me...
You are right to be wary. Use the SubString method from UnicodeString instead.
All of the Ansi...() functions were migrated to Unicode in CB2009. The naming scheme was preserved to maintain backwards compatibility with pre-2009 code, that's all.
If you don't want to change your code to call AnsiLeftStr() instead of LeftStr(), then you could simply implement your own LeftStr() function that calls AnsiLeftStr() or UnicodeString::SubString() internally, eg:
UnicodeString __fastcall LeftStr(const UnicodeString &AText, const int ACount)
{
return AnsiLeftStr(AText, ACount);
}
.
UnicodeString __fastcall LeftStr(const UnicodeString &AText, const int ACount)
{
return AText.SubString(1, ACount);
}
Related
I'm consuming a C library in Java with GraalVm and I have this field (if_name) I don't know how to implement:
# define IFNAMSIZ 16
struct port_t
{
char if_name[IFNAMSIZ];
}
This is my current code:
#CStruct("port_t")
interface Port extends PointerBase {
#CField("if_name")
WordPointer getIfName();
#CField("if_name")
void setIfName(WordPointer ifName);
}
Using WordPointer I get the following error compiling:
Error: Type WordPointer has a size of 8 bytes, but accessed C value has a size of 16 bytes; to suppress this error, use the annotation #AllowNarrowingCast
I already tried with CCharPointer and CCharPointerPointer but those have fixed lengths to 8 bytes and I got a similar error when compiling.
Anyone can help?
Thanks in advance
As you already guessed, you'll need to get the address of this field to manipulate it.
You can use
#CStruct("port_t")
interface Port extends PointerBase {
#CFieldAddress("if_name")
CCharPointer addressOfIfName();
}
In this case it doesn't make sense to have a setter since you cannot change the address of this field. Instead you can use the read/write methods of CCharPointer.
You'll probably need
#CConstant
static native int IFNAMSIZ();
somewhere as well.
Then you can do things like
String foo(Port p, String newIfName) {
UnsignedWord size = WordFactory.unsigned(IFNAMSIZ());
String oldIfName = CTypeConversion.toJavaString(p.addressOfIfName(), size);
CTypeConversion.toCString(newIfName, p.addressOfIfName(), size);
return oldIfName;
}
Is there a reference to a class property in C++Builder, analogous to a regular reference in C++? To understand what I mean, I will give the code (so far this is my solution to the problem):
void change(TControl* object) {
struct TAccessor : TControl { __property Text; };
static_cast<TAccessor*>(object)->Text = L"some text";
}
This function allows you to change the Text property of any object inherited from TControl.
But maybe there is a more elegant solution to this problem?
Your approach will update the Text of any TControl, even if it doesn't actually expose access to Text (which is declared protected in TControl itself, derived classes decide whether to promote it to public/__published as needed).
To account for that fact, you would have to use RTTI to discover if Text is accessible or not. You can also use RTTI to set the property value, without resorting to the Accessor trick.
For example, old-style RTTI (via the <TypInfo.hpp> header) works only with __published properties, nothing else, eg:
#include <TypInfo.hpp>
void change(TControl* object) {
if (IsPublishedProp(object, _D("Text"))
SetStrProp(object, _D("Text"), _D("some text"));
}
Alternatively:
#include <TypInfo.hpp>
void change(TControl* object) {
PPropInfo prop = GetPropInfo(object, _D("Text"), TTypeKinds() << tkUString);
if (prop)
SetStrProp(object, prop, _D("some text"));
}
Whereas newer-style Extended RTTI (via the <Rtti.hpp> header) supports fields, methods, and properties, and all the supported member visibilities, eg:
#include <Rtti.hpp>
typedef Set<TMemberVisibility, mvPrivate, mvPublished> TMemberVisibilitySet;
void change(TControl* object) {
static const TMemberVisibilitySet WantedVisibilities = TMemberVisibilitySet() << mvPublic << mvPublished;
TRttiContext ctx;
TRttiType *type = ctx.GetType(object->ClassType());
TRttiProperty* prop = type->GetProperty(_D("Text"));
if ((prop) && (WantedVisibilities.Contains(prop->Visibility)) && (prop->IsWritable))
prop->SetValue(object, _D("some text"));
}
This is how my drawing routine for TDBGrid component looks like. I am replacing values from database based on some rules:
void __fastcall TForm_Loadpoint_Details::DBGrid1DrawColumnCell(
TObject *Sender, const TRect &Rect, int DataCol, TColumn *Column,
TGridDrawState State)
{
int row_index = ???;
AnsiString text = GetCustomizedText(row_index, DataCol);
DrawText(text);
}
However I don't know how to tell which row is currently being rendered? Without this knowledge i can't get data for displaying.
You can use the Index or FieldNo property of the Column->Field object, or you can use an accessor class to access the protected TDBGrid::DataLink property and then use its ActiveRecord property.
I'm working on a C++ component for Firefox and I'm trying to wrap my mind around XPCOM and all of its parts. It's really confusing so I'm trying to work through it but I'm trying to walk through a page and get all its links. I'm trying to figure out what all the objects do. So if I have this interface:
interface nsIPageSummary : nsISupports {
boolean saveSummary(in nsIDOMDocument document,
out unsigned long numLinks,
out unsigned long numImages);
};
defined in the IDL, the method in my C++ code would look like:
SaveSummary(nsIDOMDocument* inDoc, PRBool* outSuccess)
{
*outSuccess = PR_FALSE;
nsCOMPtr<nsIDOMNodeList> nodeList;
inDoc->GetElementsByTagName(NS_LITERAL_STRING("A"), getter_AddRefs(nodeList));
}
I know the C++ method needs more parameters to match up with the one defined in the interface but I don't understand how all the typing works yet. In terms of the actual list, am I right in understanding that the
inDoc->GetElementsByTagName(NS_LITERAL_STRING("A"), getter_AddRefs(nodeList));
line puts all the "A" tags from the inDoc into the nodeList? And I would just have to walk through nodeList to get them all?
You compile your interface definition using xpidl to get a C++ header file - you can check that file to see how interface definitions are translated. Your method definition should actually look like thit:
nsresult SaveSummary(nsIDOMDocument* inDoc, PRUint32* outNumLinks, PRUint32* outNumImages, PRBool* outSuccess)
I would suggest to use the type PRUint32 instead of the ambiguous unsigned long in the interface definition as well. I would also suggest getting rid of the return value: XPCOM methods always return nsresult which is either NS_OK or an error code, this is enough to indicate success or failure. An error code is automatically translated into an exception when called from JavaScript. And finally I would recommend using lower-case tag names: while it won't matter in HTML (case-insensitive), in an XHTML document only lower-case tag names are accepted. So your interface definition should look like this:
interface nsIPageSummary : nsISupports {
void saveSummary(in nsIDOMDocument document,
out PRUint32 numLinks,
out PRUint32 numImages);
};
And the corresponding implementation:
nsresult
SaveSummary(nsIDOMDocument* inDoc, PRUint32* outNumLinks, PRUint32* outNumImages)
{
nsresult rv;
nsCOMPtr<nsIDOMNodeList> nodeList;
rv = inDoc->GetElementsByTagName(NS_LITERAL_STRING("a"), getter_AddRefs(nodeList));
if (NS_FAILED(rv))
return rv;
rv = nodeList->GetLength(outNumLinks);
if (NS_FAILED(rv))
return rv;
rv = inDoc->GetElementsByTagName(NS_LITERAL_STRING("img"), getter_AddRefs(nodeList));
if (NS_FAILED(rv))
return rv;
rv = nodeList->GetLength(outNumImages);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}
I'm trying to use C++ Template 'mixins' to create some new VCL components with shared additional functionality. Example...
template <class T> class Mixin : public T
{
private:
typedef T inherited;
// ...additional methods
public:
Mixin(TComponent *owner) : inherited(owner)
{
// .. do stuff here
};
};
Used like this:
class MyLabel : public Mixin<TLabel>
{
....
}
class MyEdit : public Mixin<TEdit>
{
....
}
Now, everything compiles fine, and the mixin stuff seems to work - until I try and save the component to a stream using TStream->WriteComponent, where the inherited properties (eg TLabel.Width/Height/etc.) don't get written. This is even with a 'null' mixin like the one shown above.
My code works fine when just deriving classes directly from TForm, TEdit, etc - and the class is correctly registered with the streaming system.
The quick/simple answer is: no; when dealing with a template, the compiler won't generate the proper descriptors to make streaming working. However, since this has come up before, I peeked under the cover to find out what's missing. And what I found is that it's almost there. So here's a little more information.
Upfront the compiler will never treat a template-based type as a Delphi. For example, do something like this:
void testing()
{
__classid(Mixin<Stdctrls::TLabel>); // Error Here
}
... and you'll see the error
"Error E2242 test.cpp 53: __classid requires Delphi style class type (i.e. class marked __declspec(delphiclass) or derived from System::TObject) in function testing()"
This basically says the compiler does not consider this type/class as compatible with Delphi-classes [i.e. those that derive from TObject]. Internally there's just a flag on the symbol that says whether the type is delphi-compatible or not. And I noticed that I could trick the compiler into marking the type as delphi-style if I forced it to walk up the hierarchy.. which is something it has to do if I create an instance of the object. So, with this hack the error goes away:
void testing()
{
typedef Mixin<Stdctrls::TLabel> __ttype;
std::auto_ptr<__ttype> c2(new __ttype(0));
__classid(Mixin<Stdctrls::TLabel>); // No more errors here
}
But much nicer was actually to use the __declspec(delphiclass) directly on the template, as in:
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
So now that the compiler treats the type as a delphi-style class without hacks, I peeked a little more and found the issue you're probably running into: Delphi classes have the TTypeData.PropCount field - http://docwiki.embarcadero.com/VCL/en/TypInfo.TTypeData - which is a sum of the class' properties, including those of its base classes. Due to the way the various pieces of information are computed, the compiler writes out a '0' for that field when a template is involved:(
You can see this by printing out the PropCount, as in:
#include <Stdctrls.hpp>
#include <cstdio>
#include <memory>
#include <utilcls.h>
class TCppComp : public Classes::TComponent {
int i;
public:
__fastcall TCppComp(TComponent* owner): Classes::TComponent(owner) {};
__published:
__property int AAAA = {read=i, write=i};
};
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
typedef Mixin<TCppComp> TMixinComp;
void showProps(TClass meta) {
PTypeInfo pInfo = PTypeInfo(meta->ClassInfo());
int Count = GetPropList(pInfo, tkAny, NULL);
TAPtr<PPropInfo> List(new PPropInfo[Count]);
std::printf("Class: %s - Total Props:%d\n",
AnsiString(pInfo->Name).c_str(), Count);
GetPropList(pInfo, tkAny, *(reinterpret_cast<PPropList*>(&List)));
for (int i = 0; i < Count; i++) {
AnsiString propName(List[i]->Name);
std::printf("\t%s\n", propName.c_str());
}
}
void test() {
showProps(__classid(TCppComp));
showProps(__classid(TMixinComp));
}
int main() {
test();
return 0;
}
When run the above prints:
Class: TCppComp - Total Props:3
AAAA
Name
Tag
Class: #%Mixin$8TCppComp% - Total Props:0
IOW, Mixin shows up with '0' published properties while its base type has 3:(
I suspect the streaming system relies on this count and that's why inherited properties are not being written out in your setup.
I considered tweaking the generated descriptors at runtime but since we write them to _TEXT it's bound to trigger DEP.
I'll look at the logic that computes the PropCount to see if there's some way to get it to compute the correct number. If time allows, please do open a QC for this: now that I've peek underneath, I believe it would not require much effort to get this working as expected.
Cheers,
Bruneau
PS: In my sample I even had the Mixin publish a property and the compiler generated the correct descriptor for that property; however, the total count was still zero.