Wiki Home

OLEObjects


Namespace: VB


Overview

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 (www.west-wind.com) 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.
*------------------------------------------------------------------------------------------------
*|ltShowInfo.prg
*| 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
  =AMembers(laMembers,loObj)

  If Type('pcItemName') = 'C' and !Empty(pcItemName)
    lcText = pcItemName
  else
    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)))
  EndIf
	
case Type('pvItem') = 'C'
  If "WWXML" $ Alltrim(Upper(Sys(2001,"CLASSLIB")))
  else
    Set classlib To wwXML.vcx additive
  endif

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


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))
	
  TEXT TO lcText ADDITIVE NOSHOW TEXTMERGE PRETEXT 7
     < < lcProp > >< < chr(13)+chr(10) > >
  EndText
EndFor

On Error &lcCurrError

Push Key clear
loForm = CREATEOBJECT("frmShowInfo")
loForm.show


loForm.edtInfo.Value = lcText
loForm.Hide
loForm.Refresh
loForm.Show(1)

Pop Key
Return


*--------------------------------------------------------------------------------------
* 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
    DoDefault()
    THISFORM.Release()
  ENDPROC
ENDDEFINE

*----------------------------------------------------
*ShowInfo_NoError	Stops error messages temporarily
*----------------------------------------------------
Procedure showinfo_noerror
Return


Contributors: Paul James

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