Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.
GetPEM()
, PEMStatus()
These two functions were added in version 3.0b. They let you ask questions about the properties, events and methods of objects and classes. Although these two are extremely useful, they have some problems.
uValue = GetPEM( oObject | cClass, cPEMName )
uResult = PEMStatus( oObject | cClass,
cPEMName | cObjectName, nAttribute )
Parameter |
Value |
Meaning |
oObject |
Object |
The object about which PEM information is to be returned. |
cClass |
Character |
The name of a class about which PEM information is to be returned. |
cPEMName |
Character |
The name of the property, event or method about which information is to be returned. |
cObjectName |
Character |
Name of a contained object of oObject or cClass. |
nAttribute |
0 |
Has the property changed? |
1 |
Is the property read-only? |
|
2 |
Is the PEM protected? |
|
3 |
Which is this: property, event, method or (contained) object? |
|
4 |
Is the PEM user-defined? |
|
5 |
Is there such a PEM? |
|
6 |
Is this PEM inherited from a class higher in the class hierarchy? |
|
uValue |
Character, Numeric, Currency, Date, DateTime, Logical |
The current value of the specified PEM. If cPEMName refers to an event or method, uValue receives (as a character string) the code contained in the event or method. |
uResult |
Logical or Character |
The value of the specified attribute for the specified PEM. |
These functions let you poke around in an object or a class definition to see what’s what. Used together with AMEMBERS()
, you can put together quite a complete picture of an object or class.
GetPEM()
might seem a little redundant for properties. After all, you can just check the property’s value. But having one function that works on both properties and methods makes lots of coding easier. We suspect GetPEM()
will find lots of use in builders and developer tools, though it doesn’t replace the ReadExpression method. Even at design-time, GetPEM()
evaluates the property value. If a property is defined with an expression (such as “=DATE()
”), it doesn’t return the expression, it returns the current value of the expression.
For methods, GetPEM()
is equivalent to the ReadMethod method (sounds redundant, doesn’t it?). Like ReadMethod, it works only at design-time.
PEMStatus()
provides a lot of useful information about classes and objects that lets you figure out who they are and where they came from. The last value for nAttribute, 6, which indicates whether the PEM was inherited or added at this level, was added in VFP 6. Also added in VFP 6 was the ability to ask about a member object by passing its name. We’re a little puzzled by this one, frankly, since it doesn’t seem to tell anything you couldn’t find out elsewhere.
Although you can find out whether a property is protected, there’s no way to check whether it’s hidden. We suspect that Microsoft simply hasn’t noticed yet that that’s a useful piece of information.
Both functions have a nasty bug when working with classes at runtime. In order to use the function, the class definition has to be in memory. To get it there, you have to instantiate the class at least once. You can destroy the instance immediately, but you have to have done it. Since we understand why it works this way, we might be inclined to lay this one at design's door, if only it were documented. |
Passing 0 for PEMStatus()'s third parameter is supposed to work only for properties. In fact, you can do it with methods of visual classes (though not code classes), too, but the results aren't quite what you'd expect. If the method has code at any level in the class hierarchy, PEMStatus() returns .T. While this is somewhat useful (and more than the docs would lead you to expect), it doesn't help you figure out if you've overridden a method in this particular subclass or instance. Use AMembers() to do that. |
And yet another bug, this one more serious than either of the others. In some situations, if an object calls PEMStatus() more than twice in the same line of code, the object can't be released. We've been unable to nail down exactly the combination of circumstances that causes this one. For sure, using PEMStatus(_SCREEN.ActiveForm,...,5) three or more times in a line is one way to do it. In general, if you have an object that won't go away, check for multiple uses of PEMStatus(). It appears that this bug was fixed in one of the VFP 6 service packs. We're reluctant to commit absolutely on the subject, since the bug was so hard to pin down, but our test form that demonstrates the problem in VFP 5 and the original release of VFP 6 works properly in VFP 6 SP5 and VFP 7. |
oForm = CreateObject("FORM")
oForm.Left = 20
? GetPEM(oForm, "Left") && Returns 20
? PEMStatus(oForm, "Left", 0) && Returns .T.
? PEMStatus(oForm, "BaseClass", 1) && Returns .T.
? PEMStatus(oForm, "Init", 3) && Returns "Event"
SET CLASSLIB TO CoolStuf && From the Downloads
oSpin = CreateObject("DateSpin") && To work around bug
RELEASE oSpin
? GetPEM("DateSpin", "BackStyle") && Returns 0
? PEMStatus("DateSpin", "nYear", 2) && Returns .F.
? PEMStatus("DateSpin", "nYear", 4) && Returns .T.
AMembers(), ReadExpression, ReadMethod, Sys(1269), WriteExpression, WriteMethod