In VFP, VFP Advanced 32-bit you can use any of the following versions:
/COM indicates the 32-bit edition of the ActiveX version
The application built using /COM version runs on any Windows 32 or 64-bit machine.
In VFP Advanced (x64) you can use any of the following versions:
/COM/64 indicates the 64-bit edition of the ActiveX version
The application built using /COM/64 version runs on Windows 64-bit machine only. The application built using /COM/64 version cannot run on Windows 32-bit machine.
If you want to use your application on 32 and 64-bit machines, you can go for:
/COM/ANY indicates the 32 and 64-bit editions of the ActiveX versions
There can be a problem with VFP responding to events.
Make sure you call
AutoYield = .F.
within your code.
The AutoYield property specifies whether an instance of Visual FoxPro processes pending Windows events between execution of each line of user program code.
A> The following method uses the
Items.DefaultItem / Template methods
The following code works for eXG2antt control, but
the idea is the same for all controls that support Items.DefaultItem /
Template property like: eXGantt, eXGrid, eXTree, eXList, eXComboBox,
eXPlorerTree, and so on.
Let's say that your code looks like follows:
LOCAL h
SCAN
_key="K_"+ALLTRIM(STR(projekte.ID))
WITH THISFORM.myplan.Items
h = .AddItem(ALLTRIM(projekte.project_name))
.AddBar( h,"Project Summary" , DTOT(projekte.sdate),DTOT(projekte.edate), _key, "" )
.ItemBar( h ,_key,3 ) = "my text"
ENDWITH
ENDSCAN
The h variable indicates the handle of the newly created item. This
value is always greater than 65000, so the VFP environment fires
an error when compiling the AddBar and ItemBar properties because it
considers accessing an array, and its limit is 65000. Of course this
problem is related to VFP ignoring the fact that it is calling a
property of a COM object! not an array, so our products provide a DefaultItem property
that help VFP users to pass this error. So, in VFP the above code should
look like follows:
The difference ( marked in red ) is that the first parameter for
properties like AddBar and ItemBar is 0, and before calling them the
Items.DefaultItem property indicates the handle of the item being
accessed. How it works? The control uses the value of the
Items.DefaultItem property, when the first parameter of the ItemBar,
AddBar and so on is 0. The AddItem property saves before the handle of
the newly created item to the DefaultItem property, and so the VFP error
is gone, and the code works like you expect.
B> The following method uses the TemplateDef / Template
methods
The following code works for eXG2antt control, but
the idea is the same for all controls that support TemplateDef /
Template and so on.
Let's say that your code looks like follows:
LOCAL h
with thisform.G2antt1
.BeginUpdate
.Columns.Add("Tasks")
with .Chart
.FirstVisibleDate = {^2000-12-25}
.PaneWidth(0) = 48
endwith
with .Items
h = .AddItem("Task")
.AddBar(h,"Task",{^2001-1-2},{^2001-1-6},"K","exBarHAlignCaption = 1")
.ItemBar(h,"K",4) = 18
endwith
.EndUpdate
endwith
The h variable indicates the handle of the newly created item. This
value is always greater than 65000, so the VFP environment fires
an error when compiling the AddBar and ItemBar properties because it
considers accessing an array, and its limit is 65000. Of course this
problem is related to VFP ignoring the fact that it is calling a
property of a COM object! not an array, so our products provide a DefaultItem property
that help VFP users to pass this error. So, in VFP the above code should
look like follows:
LOCAL h
with thisform.G2antt1
.BeginUpdate
.Columns.Add("Tasks")
with .Chart
.FirstVisibleDate = {^2000-12-25}
.PaneWidth(0) = 48
endwith
with .Items
h = .AddItem("Task")
.AddBar(h,"Task",{^2001-1-2},{^2001-1-6},"K","exBarHAlignCaption = 1")
WITH thisform.G2antt1
.TemplateDef = "Dim h"
.TemplateDef = h
.Template = "Items.ItemBar(h,`K`,4) = 18"
ENDWITH
endwith
.EndUpdate
endwith
The following sample changes the Items.ItemBar(exBarCaption) and Items.ItemBar(exBarHAlignCaption) properties:
LOCAL h
with thisform.G2antt1
.BeginUpdate
.Columns.Add("Tasks")
with .Chart
.FirstVisibleDate = {^2000-12-25}
.PaneWidth(0) = 48
endwith
with .Items
h = .AddItem("Task")
.AddBar(h,"Task",{^2001-1-2},{^2001-1-6},"K")
WITH thisform.G2antt1
.TemplateDef = "Dim h"
.TemplateDef = h
.Template = "Items.ItemBar(h,`K`,3) = `new caption and different alignment`"
.Template = "Items.ItemBar(h,`K`,4) = 18"
ENDWITH
endwith
.EndUpdate
endwith
or:
with thisform.G2antt1
.BeginUpdate
.Columns.Add("Tasks")
with .Chart
.FirstVisibleDate = {^2000-12-25}
.PaneWidth(0) = 48
endwith
with .Items
.DefaultItem = .AddItem("Task")
.AddBar(0,"Task",{^2001-1-2},{^2001-1-6},"K")
WITH thisform.G2antt1
.Template = "Items.ItemBar(0,`K`,3) = `new caption and different alignment`"
.Template = "Items.ItemBar(0,`K`,4) = 18"
ENDWITH
endwith
.EndUpdate
endwith
The Template / TemplateDef methods can run any x-script code described here.
Calling the HTMLPicture property from Object, makes the compiler to
call the property of the inside control instead confusing calling or
setting an array.
Another approach, is using the Template property like in the
following samples:
with thisform.ExplorerBar1
.Template = "HTMLPicture(`pic`)= `E:/Temp/watch.gif`"
.Groups.Add("<img>pic</img> Group 1").CaptionFormat = 1
endwith
or
with thisform.ExplorerBar1
.Object.HTMLPicture("pic") = "E:/Temp/watch.gif"
.Groups.Add("<img>pic</img> Group 1").CaptionFormat = 1
endwith
instead
with thisform.ExplorerBar1
.HTMLPicture("pic") = "E:/Temp/watch.gif"
.Groups.Add("<img>pic</img> Group 1").CaptionFormat = 1
endwith
The exTree component (any ATL based component) causes a change from
the normal form method firing order when placed on a form. For
example, VFP normally fires the following methods in the following
order when instantiating a form: Load, Init, Show, Activate, GotFocus.
When the exTree object is placed on the form, the VFP method firing
order changes as follows: Load, Activate, GotFocus, GotFocus, Init,
Show. This is obviously a big problem. Many methods were attempted to
get around this including creating the object programmatically (which
did successfully correct the firing order problem, but I could not get
all things to work correctly, like showing the plus sign for root
items among other things). I also attempted to set the object to
invisible and set to visible in gotfocus and many other things...
Eventually, I came to the solution explained below. This solution just
forces the VFP method firing order to be correct by calling methods
explicitly.
Create a custom form property (CFP) and set it equal to 0 in
form.load.
Set the CFP equal to 1 in form.init. It should be done at the
BOTTOM of the method.
Surround all code in form.show with IF CFP>0 ? ENDIF. At
the end of all code within the IF stmt (as in, right before endif),
explicitly call the form.activate method.
Surround all code in form.activate with IF CFP>0 ? ENDIF.
At the end of all code within the IF stmt (as in, right before
endif), explicitly call the form.gotfocus method.
Surround all code in form.gotfocus with IF CFP>0 ? ENDIF.
Additionally, if any code is in the form.resize event, it should
be surrounded by the IF CFP>0 ? ENDIF statement. This may
also hold true for other methods that I have not yet encountered.
Another issue concerns the visibility of the form. Even with the
above code, I was getting a flash of the form at position 0,0 on
the desktop before it then repositioned itself where I directed
it. So, set form.visible to .F. in form.load and then set it to
.T. in form.gotfocus.
** ANOTHER NOTE. Have to set APPLICATION.AUTOYIELD=.F. I am
doing this in my startup program (unless I have problems and if
so, I will set it equal to .F. in form.load and to .T. in
form.unload). The VFP help system says that this should be set to
.F. (as opposed to .T. which is the default) on any form on which
an activex object is placed. It will prevent the activex from
executing code in the middle of foxpro execution of code. As an
example, if it was set to .T., sometimes when I clicked on another
choice in the treeview, it would appear as highlighted, but the
remaining objects on the form did not reflect that I just changed
my selection. If I click it again, the remaining objects do change
correctly. Setting it to .F. corrected the problem.
This will cause the firing order to be correct. If you don't have
any code in activate, show or gotfocus you don't have to do any of
this. However, if you later add code to any of these events, you would
have to go back and modify to adhere to these standards. So, it may be
a good idea to just put the IF STMT code in each of the events with a
note that all code must be within the stmt, since 6 months later, one
could easily forget what needed to be done.
Thanks to Tim Stickley, Decision Modeling, Inc who submitted the note.
This note is related to VFP 7.0, and it seems to be corrected in VFP
8.0
I just wanted to say, that using the Exontrol exSuite has been
really great! Thank you for making such a nice product.I mainly
program in VFP (Visual FoxPro) and I am currently working with VFP 9.0
(beta). During my experience with exGrid (which has just
started), I decided to share the information I collected with other
Visual Foxpro programmers. I would also like to share it with
you in case you find it useful for assisting VFP developers. The
information and code I am providing is "public domain" and
"free of charge" to any VFP developer, so long as the
comments are left "as-is" and they are distributed free of
charge.
The zip file contains:
VFP project
Sample VFP Screen
exVGrid Class code (including event handler, event logging,
printing)
exGrid #DEFINE (constants)
VFP exGrid "events" Interface Class
I have also created an information page specific to VFP and OLE
Objects that might be helpful to any VFP programmers using your
controls. You can find it at: http://fox.wikis.com/wc.dll?Wiki~OLEObjects
Thanks to Paul James, QORE, Inc, Inc who submitted the note. This
note is related to VFP 9.0 ( beta ).
The controls like ExComboBox, ExTree, ExGrid,
ExplorerTree includes plenty of methods to load data using one or more
of the followings :
AddItem, InsertItem, InsertControlItem
DataSource property
PutItems
In VFP, the controls provide the DefaultItem property of the Items
collection that helps users to access the properties that are using
HITEM type for the Item parameter. The VFP fires "Invalid Subscript
Range" error, while it tries to process a number grater than 65000.
Since, the HITEM is a long value that most of the time exceeds 65000,
the VFP users have to use this property, instead passing directly the
handles to properties.
The following sample shows to change the cell's image:
In VFP the following sample fires:
"Invalid Subscript Range":
i = .Items.AddItem("Item 1")
.Items.CellImage(i,1) = 2
because the i variable is grater than
65000.
The following VFP sample loads data to an ExplorerTree control in
Form.Init event using all of the mentioned methods ( The sample can be
modified to run for any of the other components )
* Initializes a BASE64 encoded string that holds 3 icons.
local s, i
s = "gBJJgBAIDAAGAAEAAQhYAf8Pf4hh0QihCJo2AEZjQAjEZFEaIEaEEaAIAkcbk0olUrlktl0vmExmUzmk1m03nE5nU7nk9n0/oFBoVDolFo1HpFJpVLplNp1PqFRqVTqlVq1XrFZrVb"
s = s + "rldr1fsFhsVjslls1ntFptVrtltt1vuFxuVzul1u13vF5vV7vl9v1/wGBwWDwkbiAAQGJqrAxgAxjAruJQETf+FnmHx+Ux2NzOSpuZ0GcxtUw+YxuHy0yzOlh+byGh1+Nz1A2G"
s = s + "u22r1uoo+e1mV3G+0+t1Mo02Q4sZyfIjO12mjjW13+a3tB6fR4/X4WD62tzOI5ej5Pdnfi7+Qje1w+83Pryu6mXq9vc4PA43s23Yyt46P72WK7rwucnTZufAL7vs9LFPgzSaOq+bNOi5TlPwvMJuO/6NQAyEBtU/rkwJDT/QdBUGvMmbPQU/j6vy70I"
s = s + "O890KQPGL4vo27RRLDjYxBDzyuk+0TsU6cGI1FcfsnCcJPtJEVr06MisRBMgPs5jxxtAzKw86bjqBFciShIz5RLD0vyWvrOyjGceyvL0HwLLcZO9CM0qTJ0nSOwcRx9M7NQUpkszAqs6TW4bDSTIcpSqrEgq3J1B0bR1H0guqLB8ldKI8kCRJIACSpRTicRfSKbIo4R+H+edTPyeAfnAf9WIycAHnBVYf1eA5gAfW9amAAdd1qQ"
s = s + "AA1+5YD1/YLHINY7l2Qg1jEBYYD2ScAD2jV4BnwB9rIyeABn8B9uIyfIHn+T9xIzUb"
s = s + "8oCA"
with this.explorerTree1
.BeginUpdate
.Images(s)
with .Groups
with .Add("Group <b>1</b>")
* Using the AddItem, InsertItem methods
.ToolTip = "Using the <b>AddItem</b>, <b>InsertItem</b> methods to create your own hierarchy"
.Image = 1
.FullRowSelect = .F.
.CaptionFormat = 1
.LinesAtRoot = -1
.Indent = 17
with .Items
.DefaultItem = .AddItem("Root 1")
.CellImage(0,0) = 1
i = .DefaultItem()
.DefaultItem = .InsertItem(i, ,"Child 1")
.CellImage(0,0) = 2
.DefaultItem = .InsertItem(i, ,"Child 2")
.CellImage(0,0) = 3
i = .DefaultItem()
.DefaultItem = .InsertItem(i, ,"Child 1")
.CellImage(0,0) = 2
.DefaultItem = .InsertItem(i, ,"Child 2")
.CellImage(0,0) = 1
endwith
.Expanded = .t.
endwith
with .Add("Group <b>2</b>")
* Using the DataSource method
.ToolTip = "Using the <b>DataSource</b> method to to bind a recordset to the group."
.Image = 2
.CaptionFormat = 1
rs=CREATEOBJECT('ADODB.RECORDSET')
rs.Open('Select * From workouts', 'Driver=Microsoft Visual FoxPro Driver;SourceType=DBC;Exclusive=NO;SourceDB= ' + Home(1) + 'Wizards\Template\Workout\Data\WORKOUT.DBC', 3)
.DataSource = rs
.Expanded = .t.
endwith
with .Add("Group <b>3</b>")
* Using the PutItems method
.ToolTip = "Using the <b>PutItems</b> method to load data from an array."
.Image = 2
.CaptionFormat = 1
.Expanded = .T.
set udfpa to reference
DIMENSION MYARRAY[4]
MYARRAY(1) = "1"
MYARRAY(2) = "2"
MYARRAY(3) = "3"
MYARRAY(4) = "4"
.PutItems(MYARRAY)
set udfpa to value
endwith
with .Add("Group <b>4</b>")
* Enumerating records using the AddItem method
.ToolTip = "Loading data using the <b>AddItem</b> method by enumerating the fields."
.Image = 3
.CaptionFormat = 1
.ColumnAutoResize = .F.
.BeginUpdate
.HeaderVisible = .t.
Close Databases
clear
USE Home(1) + "foxuser.dbf" IN 0 AGAIN ALIAS Foxuser EXCLUSIVE
go Top
with .Columns
.Clear
for i = 1 to FCount()
.Add(field(i))
next i
endwith
with .Items
DO WHILE NOT EOF()
.DefaultItem = .AddItem(eval(field(1)))
for i = 2 to FCOUNT()
.CellCaption(0,i-1) = eval(field(i))
next
Skip 1
ENDDO
endwith
.EndUpdate
.Expanded = .T.
endwith
endwith
.EndUpdate
endwith
When you show a modal window, Visual FoxPro disables
all OLE host windows on the form. The ActiveX can not receive any user
input related messages anymore, because the window is disabled (the
WS_DISABLED windows style is added to the window that hosts the ActiveX
control so actually it is disabled) . As a result, the control does not
respond to mouse or keyboard events, nor does it receive the
focus.
In order to fix this, you can call the following code on form's
GotFocus event:
thisform.OleControl1.OBJECT.Enabled = .T.
where the OleControl is any of our UI components. Also, you can
easily use API functions to remove the WS_DISABLED window style.
The "Object class is invalid for this container"
error may occurs, in case the parameters for the AddObject are not what
it expects. For instance, the ActiveX must uses its program identifier
for cOLEClass parameter, while for other elements, this parameter is not
used.
>>>> When using ActiveX, the correct syntax for
object.AddObject is like follows:
LOCAL aka
aka = THISFORM
aka.AddObject("myctrl","olecontrol","Exontrol.ExMenu")
WITH aka.myctrl
.Visible = .T.
.Items.ToString = "A[id=10](B[id=20],C[id=30](D[id=40],E[id=50]),F[id=60])"
ENDWITH
where the "Exontrol.ExMenu", is the program identifier, which can be found on the control's help main page.
For instance, On the page G2antt_default.htm,
you can find the "The object's program identifier is: ...
" The program identifier specifies the string to be passed for the
cOLEClass ( 3rd parameter ) of the AddObject
method.
>>>> In case the aka is _SCREEN, the code fails as it
gives "Object class is invalid for this container", which
indicates that you can not place any ActiveX on the main Visual FoxPro
window, instead you can follow the trick to do the job, inserting some
UI elements to your man window. IN this case the container is still the form, while the visual container is the _SCREEN which specifies the main Visual FoxPro window. In other words the form receives all events, so you can write there your handlers.
The form does not need to be visible, so you can set its Visible
property on .F..
The extended control in VFP that hosts the control,
provides a few properties like Enabled, Edit, Visible, Width, Height, Edit, .... In
order to call the original control's Edit, Enabled method rather than Edit,
Enabled method
of the wrapper control in VFP, you must call the Edit method of the
Object property of the control like in the following sample:
The VFP fires the "Missing or invalid" or
"File access is denied" error, when it is trying to open a sct file from a folder with no
Full Control permission set
The error may looks as follows:
In order to prevent that, you can:
Copy the C:\Program Files\Exontrol\Control\Sample
folder to some other folder, where you have Full Control.
Change the Security Permission of the folder where you run the
sample, to include the Full Control permission.
By default, the Security of the Sample folder my looks as:
An application is considered an isolated application if all of its components are side-by-side assemblies. A side-by-side assembly is a collection of resources?a group of DLLs, windows classes, COM servers, type libraries, or interfaces?available for an application to use at runtime. Typically, a side-by-side assembly is one to several DLLs.
Isolated COM allows your application to use ActiveX components without having to register them. The original vision of this was to allow copy deployment of the application, but Isolated COM has many benefits. You can have a private copy of the DLL without worrying that another application will install an older or newer copy that breaks your application. Isolated COM also allows you to successfully install and run on non-Administrator accounts.
The
solution is to include the control's manifest file to the application's
resource under 24 ( Manifest Resource Type ) with the identifier 1. !The
solution for VFP it's a bit tricky, so please download and check the VFP
sample bellow for more details!
Build the EXE file from your VFP project
Open the EXE using the Visual Studio
Locate the 24\1 resource in the EXE. By default, the VFP generates a
manifest like:
The Anchor property defines which borders of the parent container that a visual control is anchored to when resizing the container. In other words, the Anchor defines the position /size of the control based on its parent. The Anchor property works for all components that you can resize in design-mode. The eXComboBox, eXCalendar, or any other library that provides drop down components, works in the same way, excepts that control's height is not the same as the control's label height ( by design ). In case, you need to use the Anchor property with any of these components, you need to change the control's LabelHeight when the form's Resize event occurs. As a separate issue, you can use the Anchor and the eXComboBox, with no change, if you are using the control's Style property on Simple. In this case, you are allowed to change the size of the control on the form, and so Anchor property will change all borders of the control when user resizes the form.
In order to change the control's label height and Anchor property on 240, you should do the following:
Place the control to a form in design mode
Define the control's Name property ( for instance ComboBox1 )
Specify the control's Style property to what you need to have. If using the control's Simple mode nothing than change the Anchor property to 240 is required, else
Resize and move the control in design mode to desired position
Change the control's Anchor property to 240
Save and run the form
If using the control's Simple mode, you will notice that all margins of the control are adjusted based on the Anchor property.
If using the control's DropDown or DropDownList mode, you will notice that the control's top and bottom margins of the control ( label ), are not changed if resizing the control, and this is happen because the Anchor property changes the control's height not the control's label height. In order to change the control's label height too, you need to add a handler for Resize event, as shown bellow:
Go to design mode, select the component, and change the LabelHeight and
Height properties to have the same values
Select the Form, and add the Resize event for the form, with the following code
WITH thisform.ComboBox1
.LabelHeight = .Height
ENDWITH
Save and run the form
Now, everything works smoothly. This behavior is not a problem of VFP or of the control's itself.
In case, you are wondering why the eXComboBox, eXCalendar ( drop down components ) are the single one that work this way, please insert any of the following:
An array is an ordered series of data values, called elements, which are referenced by number. Because arrays exist in memory, they provide fast data access and easy manipulation. You can easily specify, locate, or manipulate elements in an array.
Unfortunately, the VFP is not able to pass any array to a property of a COM
object, so we need to use the TemplatePut method as shown bellow:
For instance, the following code:
LOCAL laMyArray(3)
laMyArray(1)=1
laMyArray(2)=3
laMyArray(3)=5
WITH thisform.exGrid as EXGRIDLib.Grid
.SingleSel = .F.
.Items.Selection = @laMyArray
ENDWITH
generates the "Syntax Error" at compiling time, so
instead you have to use the following code:
LOCAL laMyArray(3)
laMyArray(1)=1
laMyArray(2)=3
laMyArray(3)=5
WITH thisform.exGrid as EXGRIDLib.Grid
.SingleSel = .F.
.TemplateDef = "Dim selArray"
.TemplatePut(@laMyArray)
.Template = "Items.Selection = selArray"
ENDWITH
The green section is a replica of exactly what red section should
do. Shortly, the sample passes the VFP reference of the laMyArray to an
internal variable selArray, which using the Template method is passed to the
Items.Selection property using the x-script language.
You may encounter a syntax error when calling a set property with multiple properties. Because VFP can not handle properly properties with multiple properties,
you can use the Template
feature as explained bellow.
For instance, let's say we are trying to change the Link property of the Items object as follows:
generates a syntax error as Link(...) = 4 line, as VFP can handle properties (set) with multiple parameters, so instead you can use the following code:
In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in such a way that memory which is no longer needed is not released.
We have been asked to check for a memory leak when using one of ours controls (exgrid) in VFP. Shortly, memory leaks may occur once the user resizes the form that contains one of our controls.
We have tested it and the conclusion is that just resizing an empty form generates "possible" memory leaks as explained bellow:
run VFP
type "create screen" into command window
save the form/screen
run the form/screen (empty form)
open the Task Manager
locate the "Microsoft Visual FoxPro 9.0"
you should get something like:
monitor the memory column while resizing the form
and later you get something like:
In conclusion, resizing an empty form in VFP generates "possible" memory leaks.
You can observe that after a while the memory won't increase anymore, so we won't consider
it memory leak (for instance, the VFP may cache the screen behind the form, or
something similar). Investigating memory leaks are not easy tasks. When we receive a request for
memory "leaks", we try to replicate the sample and scenario within
several programming languages, development environments, not only VFP, as if
there is a "true" memory leak that belongs to one of our components it
occurs in all development environments.
We have created a basic VB application that hosts the ExGrid component (as
isolated, so no installation is required or regsvr32 is required), which resizes
randomly the form (and so the control). The following picture shows the graph(middle) of
memory consumption while running the rmemleak.exe application: