Wiki Home


Namespace: VB


VFP's ability to interact with ActiveX/COM objects gets better with each version. Version 9.0 is no exception. With the size limits removed from arrays, long integers, etc. VFP is nearly equivalent with VB6 in it's ability to interact with 3rd party components. In fact, I can copy almost any vendor's VB sample, past it into VFP, and with very minor changes it will work flawlessly. This is especially true if you have an "Include" file with many of the VB constants defined already.

There are some anomolies however, and this is the space to discuss them. Unless somebody else edits this text, all examples are for VFP 9.0. Any additional contributors should note the VFP version in their text.

When is a VFP Object, NOT a VFP Object?

When that object points to an OLE object.
If you are using a 3rd party grid control for example, and you have an instance of it on your VFP form (named thisform.myAXGrid for example). If you then set an object variable to this instance (oMyGridObj = thisform.myAXGrid), the object variable oMyGridObj is not actually pointing to the ActiveX object, it is pointing to the VFP OLE wrapper. To get to the actual object, you can use (oMyGridObj = thisform.myAXGrid.Object). Normally, this is not necessary, but I have needed it.

When it is a regular VFP object that was stored in an OLE object, then pulled back out to what was supposed to be a VFP object. whew!
"How would this happen?", you ask. For example, if you are using an ActiveX grid component, and that grid component had a property on each row to store anything you want, you might want to store an "object" representation of the original row. Something like:
Select myTable
Scatter Name oMyRecord
myAXGrid.Row(1).Data = oMyRecord          &&Store object in property in the grid row.
  ...allow user to edit grid...
  ...Now we want to see if changes were made...
oMyObject = myForm.myAXGrid.Row(1).Data	  &&Pull object back from grid to VFP reference.

In this case, the vfp object "oMyObject" in the last line, is not really a vfp object, it is an OLE "wrapped" object.

I have tried all kinds of workarounds (up to VFP 9.0) including: aMembers(,,1) aMembers(,,2) aMembers(,,3) aFields() Field() For Each... all to no avail. All of these methods require you know (and explicity reference) every single property. In this case, I highly recommend using wwXML by Rick Strahl ( to store your VFP object in your component as XML (oXML.ObjectToXML), then you can retrieve it from your component later as an object by using (oXML.XMLToObject). Thank you again Rick!
Select myTable
Scatter Name oMyRecord
myAXGrid.Row(1).Data = oXMLObjectToXML(oMyRecord,1)       &&Store object in grid as XML.
...allow user to edit grid...
...Now we want to see if changes were made...
oMyObject = oXML.XMLToObject(myForm.myAXGrid.Row(1).Data) &&Pull object back

Where did my #[email protected]*9$ Properties go?

Debugging on OLE object is "especially fun". When you put your object in the "Watch" debugger window, what you see may shock you. In fact, it may even "change" while you are watching it! OK, it is not really "changing", it is showing you more (or less) properties than it was a minute ago.

VFP can oly "see" properties of an OLE object in a few situations:
Just remember, if you try to debug an OLE object, you will may or may not see all properties!

Sample Code:

Save this code into a .PRG file named "ltShowInfo.Prg". Then call it and pass it your object or XML.
*| Displays the contents of an object or XML string in a scrollable window.
*| By: Paul James, Life-Cycle Technologies
*| Last Update: 10-2004
*| Parms:
*| pvItem	- Variant, either a VFP object, or an XML string (with definition)
*| pcItemName	- "String name to display at top of output window.

Lparameters pvItem, pcItemName

LOCAL loForm, x, lcProp, lcText, lcTmp, oXML, lcCurrError
Store "" to lcProp, lcText, lcTmp, loObj
Store 0 to x
Store .null. to loForm, oXML, loObj
Local Array laMembers[1]

lcCurrError = On("error")

Do case
case Type('pvItem') = 'O'
  loObj = pvItem

  If Type('pcItemName') = 'C' and !Empty(pcItemName)
    lcText = pcItemName
    Display Memory like pvItem to file c:\temp\titem.txt noconsole
    lcText = FileToStr("c:\temp\titem.txt")
    lcText = Alltrim(Upper(Strtran(lcText, "pvItem", "",-1,-1,1)))
case Type('pvItem') = 'C'
  If "WWXML" $ Alltrim(Upper(Sys(2001,"CLASSLIB")))
    Set classlib To wwXML.vcx additive

  oXML = CREATE("wwXML")
  loObj = oXML.XMLToObject(pvItem)
  If Type('pcItemName') = 'C' and !Empty(pcItemName)
    lcText = pcItemName
  =MessageBox("Invalid data type of: "+Type('pvItem'),48,"ltShowInfo")
  Return .f.

On Error do showinfo_noerror

For x = 1 to Alen(laMembers,1)
  lcProp = "." + Proper(Alltrim(laMembers[x]))
  lcTmp = "loObj"+lcProp
  lcProp = Padr(lcProp+'   ',25,'.') + '  ' + alltrim(Transform(&lcTmp))
     < < lcProp > >< < chr(13)+chr(10) > >

On Error &lcCurrError

Push Key clear
loForm = CREATEOBJECT("frmShowInfo")

loForm.edtInfo.Value = lcText

Pop Key

* Form Definition
DEFINE CLASS frmShowInfo AS Form
  AutoCenter = .t.
  Height = 400
  Width = 600
  BorderStyle = 2
  Closable = .F.
  MaxButton = .F.
  MinButton = .F.
  WindowType = 0
  Name = "frmShowInfo"
  FontName = "Courier New"
  FontSize = 8
  FontBold = .f.
  Caption = "Object/XML Information..."

  ADD OBJECT cmdClose AS commandbutton WITH ;
	Top = this.Height - 25, ;
	Left = this.Width - 50, ;
	Height = 25, ;
	Width = 50, ;
	FontName = "Courier New", ;
	FontBold = .F., ;
	FontSize = 8, ;
	Name = "cmdClose", ;
	Caption = "Close"

  ADD OBJECT edtInfo AS editbox WITH ;
	FontName = "Courier New", ;
	FontBold = .F., ;
	FontSize = 8, ;
	Top = 5, ;
	Left = 5, ;
	Height = this.Height - this.cmdClose.Height - 5, ;
	Width = this.Width - 5, ;
	Enabled = .t., ;
	Name = "edtInfo"

  PROCEDURE cmdClose.Click

*ShowInfo_NoError	Stops error messages temporarily
Procedure showinfo_noerror

Contributors: Paul James

( Topic last updated: 2004.09.28 05:21:43 PM )