Board index » cppbuilder » Re: Pointer to AnsiString

Re: Pointer to AnsiString


2003-12-17 05:59:53 PM
cppbuilder112
Hmmm.... Looks like somehow when I think I am accessing the name property of
the parameter, I might actually be access it's type? Just tried the same
thing with a third party NumberEdit box, the field is called Value, but when
I used the code below, the pTypeInfo->Name field starts with 'Double'.
Still none the wiser tho as to what I am doing wrong...
Phil V
"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
Not sure what is happening then, I am only adding the Edit to the list
now,
maybe I am accessing things incorrect, can you have a quick look at the
relevant code below and see if you can see any thing obvious?

It is on the line marked (******************* HERE) that the
pTypeInfo->Name
field contains "TCaption", where I would expect it to contain "TText". I
have included the function that puts the entry into the list as well as
the
two calls to the functions for completeness.

Thanks,

Phil V

/////////////////// CODE FOLLOWS ///////////////////////////////

void __fastcall TForm1::RadioButtonAddClick(TObject *Sender)
{
AddStringPropertyToList(Form1->Edit1, "Text");
}

void __fastcall TForm1::RadioButtonRemoveClick(TObject *Sender)
{
RemoveFromDisplayedOn(Form1->Edit1, "Text");
}

struct TComponentProperty
{
TObject* Object;
PPropInfo Property;
};

// *********************
// Code to Add item to List
// *********************
int __fastcall Form1::AddStringPropertyToList(TObject* object, const
AnsiString &PropertyName)
{
/*
Will return the position of the entry if succesful.
Will return -1 if Property is not found for Object
Will return -2 if entry is already in list.
*/

TPropInfo* pPropertyInfo = GetPropInfo(object, PropertyName,
tkAny/*StringType*/); // Gets a pointer to that 'property' of that
'type',
of the 'object'

int pos = -1;
if (pPropertyInfo) // If pointer is valid
{
TComponentProperty* pProperty = new TComponentProperty; // Create a
new
Property, (or a row in the list / table)
pProperty->Object = object;
pProperty->Property = pPropertyInfo;

// Check if already in list, avoid multiple entries for same field
bool AlreadyInList = false;
for(int index=0; index < DisplayedOnList->Count; index++)
{
TComponentProperty* pPropInList =
static_cast<TComponentProperty*>(DisplayedOnList->Items[index]);
if ( (pProperty->Object == pPropInList->Object) &&
(pProperty->Property == pPropInList->Property) &&
(pProperty->Type == pPropInList->Type)
)
{
AlreadyInList = true;
delete pProperty; // Not used, so added to list, so must delete it
now!
pos = -2;
break;
}
}
if (!AlreadyInList)
pos = DisplayedOnList->Add(pProperty);
}
return pos;
}

//**********************
// Code to Remove Item from list
//***********************
int __fastcall Form1::RemoveFromDisplayedOn(TObject* object, const
AnsiString &PropertyName)
{
// Remove an item from the list by item

int return_data = -1;

for(int index=0; index < DisplayedOnList->Count; index++)
{
TComponentProperty* pPropInList =
static_cast<TComponentProperty*>(DisplayedOnList->Items[index]);
PPropInfo pPropInfo = pPropInList->Property;
PTypeInfo pTypeInfo = *(pPropInfo->PropType);

if ( (object == pPropInList->Object) &&
(AnsiString("T" + PropertyName) == pTypeInfo->Name) //
******************* HERE
)
{
DisplayedOnList->Delete(index);
return_data = 1;
break;
}

}
return return_data;
}


"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in
message
news:3fdf5932$ XXXX@XXXXX.COM ...
>
>"Phil V" < XXXX@XXXXX.COM >wrote in
message
>news:3fdf32ca$ XXXX@XXXXX.COM ...
>
>>when I look at the PTypeInfo for the Text property of the
>>Edit box, it's 'name' field is showing Caption?!?!?
>
>Not possible. TEdit has no Caption property to begin with (actually, it
>does inherit one from TControl, but it is not published, thus would not
have
>a PPropInfo available). You must have been looking at the TLabel's
>PPropInfo instead and just did not realize it.
>
>
>Gambit
>
>


 
 

Re:Re: Pointer to AnsiString

Ok, have now found and used the SetVariantProp(), (guessing you made a typo
here), but doesn't want to work for me;
I have passed the AnsiString containing a random number as a string, eg
"87".
If I use SetStrProp the Label, (as that is what I have in my
DisplayedOnList), is updated correctly, however if I use the SetVariantProp,
then the label is just set blank?
TComponentProperty is the same structure as before, but I have put it here
for completeness,
thanks,
Phil V
PS I still don't know what an 'Ordinal' type is
//**********************
// CODE FOLLOWS
//**********************
struct TComponentProperty
{
TObject* Object;
PPropInfo Property;
};
void __fastcall Form1::UpdatePropertyValues(const AnsiString &value)
{
for(int index=0; index<DisplayedOnList->Count; index++)
{
TComponentProperty* pProperty =
static_cast<TComponentProperty*>(DisplayedOnList->Items[index]);
// SetStrProp(pProperty->Object, pProperty->Property, value);
SetVariantProp(pProperty->Object, pProperty->Property, value);
}
}
"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
StrVariantProp()?

I have tried searching the web for this, and also looking thru the BCB5
docs, but can't find anything about it? Can you point me in the right
direction?

Ordinal Property?

What exactly IS an ordinal property?

Phil V

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in
message
news:3fdf58a4$ XXXX@XXXXX.COM ...
>
<SNIP>
>
>You could alternative just use StrVariantProp() and let it figure all of
>that out internally for you.
>
>>Incidently how do you set an int?
>
>If you look at TypInfo.hpp, you will see all of the available functions,
>such as SetOrdProp() (set an ordinal property).
>
<SNIP>


 

Re:Re: Pointer to AnsiString

Ok, Confused....
Is SetStrProp the only SetxxxxProp that doesn't give an access violation? I
figured that as they didn't give errors, and would simply fail there would
be no harm in doing something along the lines of:
SetStrProp(myobject, myproperty, myAnsiString);
SetFloatProp(myobject, myproperty, myAnsiString.ToDouble());
SetOrdProp(myobject, myproperty, myAnsiString.ToInt());
But both the SetFloat, and the SetOrd give Access Violations if the property
is not actually a float/Ord? I guess I could probably just try{} catch{}
these AV's but just wondering why the SetStrProp seems to be different?
I have tried the SetVariantProp, but can't get it to work, (See my other
reply).
Phil V
"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Phil V" < XXXX@XXXXX.COM >wrote in
message
news: XXXX@XXXXX.COM ...

>Is there anyway to check whether the
>SetStrProp actually works? (Or rather is there some
>way to tell if it fails?)

No. If the property really is a string value, it will be assigned,
otherwise it will simply be ignored. In the case of assignment, the only
error that would occur would be an exception thrown by either the
particular
component itself if it were designed to throw an exception an on invalid
value, or from the memory manager itself if it cannot allocate the needed
AnsiString values. Otherwise, you will have no other indication at all
whether the assignment failed or succeeded.


Gambit


 

{smallsort}

Re:Re: Pointer to AnsiString

Here is a stripped down version that should be simple?
void __fastcall TForm1::FormClick(TObject *Sender)
{
TTypeKinds Strings = TTypeKinds() << tkLString;
TPropInfo* pPropertyInfo = GetPropInfo(Form1->Label1, "Caption", Strings);
// Gets a pointer to the 'Caption' property of type', of the 'object'
if (pPropertyInfo) // If pointer is valid
SetVariantProp(Form1->Label1, pPropertyInfo, "My New Text, But This wont
Appear!");
}
But this results in Label1's caption becoming blank?
Phil V
"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
Ok, have now found and used the SetVariantProp(), (guessing you made a
typo
here), but doesn't want to work for me;
<SNIP>
 

Re:Re: Pointer to AnsiString

Ok So I figure that SetVariantProp() (presuming your typo), can be used in
place of most of the other Set/Gets, what I don't understand is why the
following code gives me an access violation when using Get or Set Variant
Prop, as opposed to working fine when I use Get or Set Str Prop.
TTypeKinds Strings = TTypeKinds() << tkLString;
TPropInfo* pPropertyInfo = GetPropInfo(Label1, "Caption", Strings); // Gets
a pointer to that 'property' of that 'type', of the 'object'
if (pPropertyInfo) // If pointer is valid
{
if (IsPublishedProp(Label1, pPropertyInfo->Name))
{
AnsiString text=GetVariantProp(Label1, pPropertyInfo); //**** This line
and the one marked below work fine when xxxVariantProp is substituted with
xxxStrProp. I thought the whole point of Variante was that it would work
this way?
ShowMessage(text);
SetVariantProp(Label1, pPropertyInfo, "My Text, Only displayed using
SetStrProp"); //****
}
}
<SNIP>
Quote
>so that at a later time I know whether to use SetStrProp(), or
SetFloatProp()

You could alternative just use StrVariantProp() and let it figure all of
that out internally for you.

<SNIP>
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
I have tried searching the web for this, and also looking
thru the BCB5 docs, but can't find anything about it?
None of the TypInfo functions are documented to begin with, let alone
SetVariantProp() specifically. You just have to study the header file and
source code directly to know what is available and what they do.
Quote
Can you point me in the right direction?
SetVariantProp() is just like any of the other setter functions, except that
it accepts a Variant as the data value. Internally, it determines what the
property type actually is, and converts the Variant value accordingly to
match the property type, and then calls the appropriate setter function
(SetStrProp(), SetOrdProp(), etc).
Quote
What exactly IS an ordinal property?
Ordinal = Numeric, aka Integer.
Gambit
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
TTypeKinds Strings = TTypeKinds() << tkLString;
If you are going to test for string, I would suggest that you include
tkString, and possible also tkWString. That way, you can support all kinds
of String-based property types.
TTypeKinds Strings = TTypeKinds() << tkLString << tkString << tkWString;
Quote
TPropInfo* pPropertyInfo = GetPropInfo(Form1->Label1, "Caption",
Strings);
You are already inside Form1 to begin with, so there is no need to use the
global Form1 pointer to access the component, just use the implicit 'this'
pointer instead:
PPropInfo pPropertyInfo = GetPropInfo(this->Label1, "Caption", Strings);
Or simply:
PPropInfo pPropertyInfo = GetPropInfo(Label1, "Caption", Strings);
Quote
SetVariantProp(Form1->Label1, pPropertyInfo, "My New Text, But This
wont
Appear!");
Try casting the string to an AnsiString explitically:
SetVariantProp(Label1, pPropertyInfo, AnsiString("My New Text, But This
wont Appear!"));
You were passing a char*, which SetVariantProp()'s Variant parameter will
probably interpret as a 'bool' instead of a string.
Gambit
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
Is SetStrProp the only SetxxxxProp that doesn't give an access violation?
*None* of the setter functions do exception handling. There is always a
potential that any of then can throw an exception, particular does that have
to allocate additional memory, such as with a string. If you provide
invalid property information, any of them could potentally throw an AV.
Quote
But both the SetFloat, and the SetOrd give Access Violations
if the property is not actually a float/Ord?
SetStrProp() checks the actual property type before assigning the value to
the property. It does this because there are three different types of
string properties that it supports, and thus needs to know which internal
processing to invoke. SetFloatProp() and SetOrdProp(), on the other hand,
do not check the property type before attempting to assign the value.
Quote
I guess I could probably just try{} catch{} these AV's but
just wondering why the SetStrProp seems to be different?
It is your own responsibility to check the property type beforehand so that
you can call the appropriate setter function. Keep in mind that the TypInfo
functions are not very user-friendly because they were not meant to be used
directly in the first place. They are primarily meant as helper functions
for the DFM streaming system, which does its own type checking and error
checking as needed. They are publically accessible only because they had to
be so that the various VCL units could access them. They useful at time,
*if* you know how to use them correctly.
Gambit
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
Ok So I figure that SetVariantProp() (presuming your typo), can be
used in place of most of the other Set/Gets, what I don't understand
is why the following code gives me an access violation when using
Get or Set Variant Prop, as opposed to working fine when I use Get
or Set Str Prop.
Please disregard my previous comments on that matter. I was looking at the
wrong function. The correct functions to use are Get/SetPropValue(), not
Get/SetVariantProp(). Get/SetVariantProp() is just another specialized
property getter/setter for properties that are declared as type 'Variant'
specifically. Get/SetPropValue() is the function that I was actually
thinking of all along, they are the ones that actually test the actual
property type and then call the appropriate getter/setter internally.
Quote
if (IsPublishedProp(Label1, pPropertyInfo->Name))
That is redundant. The TypInfo functions only work with published
properties to begin with. All IsPublishedProp() does is calls GetPropInfo()
and returns whether the pointer is NULL or not. Since you already have the
PPropInfo pointer, you already know if the property is available or not.
Gambit
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
It is on the line marked (******************* HERE) that
the pTypeInfo->Name field contains "TCaption"
As well it should. If you were to look at the actual VCL source code, you
would see that the Text property (which is inherited from TControl) is
declared as type TCaption in Controls.pas, not as type String or TTxt or
anything else:
property Text: TCaption read GetText write SetText;
Keep in mind that the VCL is written in Delphi Pascal, not C++. Any
information obtained by the TypInfo unit, which is also written in Delphi
Pascal, is going to reflect the RTTI generated by the Pascal compiler, not
the C++ compiler. If you looked at Controls.pas, you would see that
TCaption is just a typedef for the String type:
TCaption = type string;
When C++ header files are generated from the Pascal source code, the
compiler notices the typedef and just makes the C++ property declaration to
be an AnsiString directly. But that does not negate that in the original
Pascal source code, the property is actually a TCaption instead. That is
why you see "TCaption" when you look at the property's type name.
Gambit
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
{
AlreadyInList = true;
delete pProperty; // Not used, so added to list, so must delete it
now!
pos = -2;
break;
}
If you are going to create a TComponentProperty instance and then just
destroy it right away, then it would be better to no create it at all. You
have the original TObject and PPropInfo pointers available, just use them
directly, and then create a new TComponentProperty instance only if you
actually need to. For example:
int __fastcall Form1::AddStringPropertyToList(TObject* object, const
AnsiString &PropertyName)
{
/*
Will return the position of the entry if succesful.
Will return -1 if Property is not found for Object
Will return -2 if entry is already in list.
*/
PPropInfo pPropertyInfo = GetPropInfo(object, PropertyName, tkAny);
if( !pPropertyInfo )
return -1;
for(int index=0; index < DisplayedOnList->Count; index++)
{
TComponentProperty* pPropInList =
static_cast<TComponentProperty*>(DisplayedOnList->Items[index]);
if ( (pPropInList->Object == object) && (pPropInList->Property
== pPropertyInfo) )
return -2;
}
TComponentProperty* pProperty = new TComponentProperty;
pProperty->Object = object;
pProperty->Property = pPropertyInfo;
return DisplayedOnList->Add(pProperty);
}
Quote
//**********************
// Code to Remove Item from list
//***********************
Asside from having a memory leak in that code, it also does not actually do
what you expect it to do. Try this instead:
bool __fastcall Form1::RemoveFromDisplayedOn(TObject* object, const
AnsiString &PropertyName)
{
PPropInfo pPropertyInfo = GetPropInfo(object, PropertyName, tkAny);
if( pPropertyInfo )
{
for(int index = 0; index < DisplayedOnList->Count; ++index)
{
TComponentProperty* pPropInList =
static_cast<TComponentProperty*>(DisplayedOnList->Items[index]);
if ( (pPropInList->Object == object) &&
(pPropInList->Property == pPropertyInfo) )
{
DisplayedOnList->Delete(index);
delete pPropInList;
return true;
}
}
}
return false;
}
Gambit
 

Re:Re: Pointer to AnsiString

"Phil V" < XXXX@XXXXX.COM >wrote in message
Quote
Looks like somehow when I think I am accessing the name
property of the parameter, I might actually be access it's type?
Correct.
Quote
Just tried the same thing with a third party NumberEdit box,
the field is called Value, but when I used the code below, the
pTypeInfo->Name field starts with 'Double'.
Exactly. TTypeInfo reflects *type* information, whereas TPropInfo reflects
*property* information. If you are trying to extract the name of the
*property*, not the name of the *type*, then you should be looking at the
TPropInfo::Name member, not the TTypeInfo::Name member.
Gambit