Believe it or not, the following technique arose out of a real need, and I think that it might come in useful in several places.
I have come up with a technique that allows me to effectively 'subclass' any COM object. We can already do this with ActiveX controls, but have previously been unable to do it with non-visual COM objects.
The key is a little used VFP method called THIS_Access. Giving an object a THIS_Access method causes that method to run when any process accesses the object, even over COM boundaries. The THIS_Access method normally returns a reference to THIS, but you can return a reference to any object you want. The THIS_Access method receives a single parameter that holds the name of the PEM being accessed. So I can create an object that holds a reference to a COM object, and in the THIS_Access method put code to check the PEM being accessed against any PEM in my object. If it exists, return a reference to THIS, if it does not, assume that the caller wants to access a property native to the 'subclassed' object, and return a reference to that object.
Using this technique, I can use a 'subclass' of a COM object to set default values, or create wrapper methods around commonly used methods, all the while giving the caller the impression that she is accessing the COM object directly.
The object below is a simple wrapper around the Microsoft XML parser. All it does 'change' a couple of default properties in the DOM object, and ensure that any XML passed to the LoadXML method starts with ''.
I have done this by setting the property values in the Init method (note the use of "THIS.Async"), and by creating an overriding "LoadXML" method where I can place my own code. In the overriding method, I can call the 'superclass' LoadXML method by simply calling THIS.oDOM.LoadXML. (Note DODEFAULT() will not work since I am not really overriding a parent class method).
Besides the inability to call DODEFAULT(), and the fact that Intellisense doesn't work correctly on 'subclassed' object (I already tried IMPLEMENTS), this technique is perfectly analogous to real subclassing.
oXML = CREATEOBJECT("myXML")
?oXML.Async
?oXML.loadxml('<test></test>')
?oXML.XML
DEFINE CLASS myXML AS Session
oDOM = .NULL.
LastXML = ""
FUNCTION Init
THIS.Async = .T.
THIS.PreserveWhiteSpace = .T.
ENDFUNC
FUNCTION oDOM_Access
IF ISNULL(THIS.oDom)
THIS.oDom = CREATEOBJECT("Microsoft.XMLDOM")
ENDIF
RETURN THIS.oDom
ENDFUNC
FUNCTION THIS_Access
LPARAMETERS cPEM
IF PEMSTATUS(THIS, cPEM, 5)
RETURN THIS
ELSE
RETURN THIS.oDOM
ENDIF
ENDFUNC
FUNCTION LoadXML
LPARAMETERS cXML
IF cXML <> '<?xml version="1.0">'
cXML = '<?xml version="1.0"?>' + cXML
ENDIF
RETURN THIS.oDOM.LoadXML(cXML)
ENDFUNC
ENDDEFINE
Erik Moore
Clientelligence