Excel Automation - Visual FoxPro Wiki
Excel Automation - Visual FoxPro Wiki
Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
Excel Automation
For clarity's sake, the full object hierarchy is used for each command. Using
a 'With oExcel' will tend to make your code more readable. Contents:
Connecting to Excel
We'll assume throughout this page that you named your Excel object Creating a blank workbook:
Controlling visibility
oExcel = CreateObject("Excel.Application")
Controlling Interaction
if vartype(oExcel) != "O"
Storing data to a cell
* could not instantiate Excel object
Set the font color and style
* show an error message here
Set Excel Cell to Text Format
return .F.
Getting data into Excel
endif
Selecting a range using the Cell
oWorkbook = oExcel.Application.Workbooks.Open("C:\temp\test.xls")
oWorkbook = oExcel.Application.Workbooks.Add()
1 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
oWorkbook = oExcel.Application.Workbooks.Add("C:\temp\template.xlt")
You can turn off Excel's alerts with the Display Alerts property: when set to False, Excel automatically chooses th
message:
oExcel.DisplayAlerts = .F.
oWorkbook.Close() && Unsaved changes will be discarded
oExcel.DisplayAlerts = .T.
if val(oExcel.Version) > 11
oWorkbook.SaveAs("C:\temp\foobar.xls", 56) && xlExcel8
else
oWorkbook.SaveAs("C:\temp\foobar.xls")
endif
Controlling visibility
If the Excel window is not visible it is harder for the user to interact with Excel. This makes it slightly safer for yo
likely to issue commands in the middle of your automation.
oExcel.visible = .T.
oExcel.visible = .F.
2 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
Controlling Interaction
Also, if it is preferred that Excel be seen during automation set these two properties to .F.
oExcel.Application.UserControl=.F.
oExcel.Application.Interactive=.F.
After completing automation, return their value to .T. to allow the user to start interaction
oExcel.Application.UserControl=.T.
oExcel.Application.Interactive=.T.
The Interactive property is the one that controls whether the user is allowed to interact with Excel. When s
hourglass icon when they hover over Excel, and mouse clicks on the Excel application are ignored.
The UserControl property does NOT prevent the user from interacting with Excel. That property indicates whet
opened by the user (.T.), or whether the Excel application was opened programmatically via CREATEOBJECT()
"Excel.Application" ) to get a reference to the Excel application, you can use this property to determine if
with the user or not. One cool thing is that this property is automatically updated if the user closes Excel.
See UserControl Property [Excel 2007 Developer Reference]
Bottom line: even though you CAN change UserControl, I recommend that you NOT do that.
Mike Potjer
oExcel.Range("B6").font.bold = .t.
oExcel.Range("B6").font.colorindex = 3 && red
3 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
or
oExcel.Range("B6").Select()
oExcel.Selection.font.colorindex = 3 && red
oExcel.Selection.font.bold = .t.
-- David Fung
oExcel.Range("A1").NumberFormat = "@"
oExcel.Range("A1").Value = cursorA.MemoField
-- Bryan Palmer
Or if you have a pre-formatted template (.XLS or .XLT) that you want to paste into. Note that this method will no
_VFP.DataToClip(,,3) && current table onto the clipboard, delimited with tab
oExcel.Range("A1").Select
oExcel.ActiveSheet.Paste() && from clipboard. since delimited with tab,
4 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
oExcel.ActiveSheet.UsedRange.EntireColumn.Autofit
-- David Fung
Closing Excel
You'll still need to handle closing questions like saving changes and file format changes. And you'll need to releas
oExcel.quit()
oExcel = .Null.
oExcel.DisplayAlerts = .F.
5 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
-- David Fung
Range("A1:H250") specifies that we're searching columns A to H (inclusive) and rows 1-250.
oExcel.ActiveCell is where to start searching, and -4123 is the constant for xlFormulas. I theorize that this mean
code rather than its output.' 1 is the constant for xlWhole, meaning match against all the text in the cell. You cou
matches.
-- Tom Cerul
You have to be careful when specifying the extra parameters to Find as they persist between searches, as specif
The settings for LookIn, LookAt, SearchOrder, and MatchByte are saved each time you
you don't specify values for these arguments the next time you call the method,
used. Setting these arguments changes the settings in the Find dialog box, and chan
the Find dialog box changes the saved values that are used if you omit the argument
set these arguments explicitly each time you use this method.
-- Stuart Dunkeld
6 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
#define xlLastCell 11
#define xlMaximized -4137
#define xlRangeAutoformatClassic2 2
#define xlPortrait 1
* then open excel and make the data look good, like this
oExcel = CreateObject("Excel.Application")
if vartype(oExcel) != "O"
* could not instantiate Excel object
* show an error message here
return .F.
endif
oExcelApp = oExcel.Application
oExcelApp.WindowState = xlMaximized
7 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
lcLastCell = oExcel.ActiveCell.SpecialCells(xlLastCell).Address()
* save Excel file in new Excel format (COPY TO XLS uses old format)
oWorkbook.Save()
-- Alex Feldstein
Sometimes the Last Cell is not up-to-date after deleting a row in Excel,
Calling ActiveSheet.UsedRange after deleting a row will keep Last Cell
up-to-date.
8 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
loExcel = createobject('Excel.Application')
loExcel.Workbooks.Open(tcFile)
loExcel.Rows("1").Delete(xlUp)
lnLastRowIncorrect = loExcel.Cells.SpecialCells(xlCellTypeLastCell).Row
loExcel.ActiveSheet.UsedRange && add this line
lnLastRowCorrect = loExcel.Cells.SpecialCells(xlCellTypeLastCell).Row
-- David Fung
etc. These commands are version dependant directly within VFP themselve. You immediately lose data with thes
-The number of rows you can copy is limited for example (VFP5 copied 16384 max while VFP9 copies 65536 max
come into market those limits are not sufficient anymore).
-Memo fields are immediately dropped as with any 'copy to' command
Copy to myExcel.xls type fox2x && actually creating a dBaseIII compatible file. Excel recognizes internally
Copy to myExcel.csv type csv && CSV files are natively recognized
Both fail to transfer memo fields and CSV might have problems with datatypes converted correctly (mostly with
better than Data To Clip() and 'copy ... type xls'.
Similar to Data To Clip() you can copy to a tab delimited file, read it into clipboard with FileToStr() and pasteSpe
Data To Clip() but it again falls short of transferring memo fields.
Excel (especially newer versions) also recognizes XML and HTM ( table tags ).
My best preferance is to transfer data using ADO instead. Passing with ADO uses Excel's own VBA commands to
sample sending data to Excel and putting data starting at A10:
LOCAL oExcel
9 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
oExcel = Createobject("Excel.Application")
With oExcel
.WorkBooks.Add
.Visible = .T.
VFP2Excel(_samples+'data\testdata.dbc','select * from employee',.ActiveSheet.
Endwith
function VFP2Excel
lparameters tcDataSource, tcSQL, toRange
Local loConn As AdoDB.Connection, ;
loRS As AdoDB.Recordset,;
ix
loConn = Createobject("Adodb.connection")
loConn.ConnectionString = "Provider=VFPOLEDB;Data Source="+m.tcDataSource
loConn.Open()
loRS = loConn.Execute(m.tcSQL)
Note that .Visible = .T. is very early in code just after adding the workbook. Having that "later after you're done
things faster" is a myth. Surprisingly having it early in code makes your code faster in many cases.
My suggestions:
Working with Excel means you're doing COM calls using VBA which by nature is slow. Therefore, whenever possi
call Excel automation commands as few as you can. ie:
Instead of this:
for ix = 1 to 5000
for jx=1 to 10
.Cells(m.ix,m.jx).Value = m.ix*100+m.jx
endfor
endfor
10 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
Do this:
dimension aExcelData[5000,10]
for ix = 1 to 5000
for jx=1 to 10
aExcelData[m.ix,m.jx] = m.ix*100+m.jx
endfor
endfor
WITH oExcel.ActiveWorkBook.ActiveSheet
.Range(.Cells(1,1), .Cells(5000,10)).Value = GetArrayRef('aExcelData')
endwith
PROCEDURE GetArrayRef(tcArrayName)
RETURN @&tcArrayName
Above code also shows another alternative to transferring data to Excel via array instead of pasting.
Cetin Basoz
#DEFINE xlLastCell 11
* I'm skipping the code to create the oExcel object, load a workbook, and select
11 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
* a worksheet.
WITH oExcel.ActiveWorkBook.ActiveSheet
* This is just asking Excel to give us the last cell for the range of data,
* but you can use whatever technique you want to determine the range to use.
loLastCell = .Cells.SpecialCells( xlLastCell )
* This command re-dimensions and populates the array with all the data from
* the specified Range.
* Note that in this example I assume that the first row contains captions
* or field names.
laData = .Range( .Cells(2,1), m.loLastCell ).Value
ENDWITH
* We need to check how many columns are actually being imported, since the user
* could have omitted some.
lnImportedColumns = MIN( m.lnFieldCount, ALEN( laData, 2 ) )
* Check the data being imported, and convert data types as needed.
FOR lnField = 1 TO m.lnImportedColumns
* For now, assume that any data not being imported into a Character or Varchar
* field is either of a compatible data type, or is invalid and should be ignored.
IF NOT INLIST( laFieldInfo[m.lnField,2], "C", "V" )
LOOP
ENDIF
* You can now process the data directly in the array, or dump it into a cursor:
* INSERT INTO MyAlias FROM ARRAY laData
12 of 13 01-06-2017 14:40
Excel Automation - Visual FoxPro Wiki http://fox.wikis.com/wc.dll?Wiki~ExcelAutomation#Contents_4XJ0G1ALZ
* -- OR --
* SELECT MyAlias
* APPEND FROM ARRAY laData FOR Some Condition
Using what I consider a fairly average modern PC (dual core, 2GB of RAM), I used the above code to read an 8-c
populate a cursor with the data in under 0.15 seconds. Obviously, your mileage may vary, but you should get mo
most situations.
Note that this technique allows you to populate memo fields in a cursor. If a column contains cells with more tha
the entire text is copied to the array, and from there can dumped directly into a memo field using either of the
That's something you can't do with APPEND FROM .. XLS|XL5|XL8.
Note that a data cell in Excel must be compatible with the data type of the VFP cursor field in which you wish t
this isn't a problem, but one notable exception is if you wish to a copy a column of numbers from Excel into a Ch
Excel which are stored as numbers will be ignored when you try to copy them into a VFP character field, leaving
stored as text in Excel are normally differentiated by a little green triangle in the upper left corner of the cell.) Y
spreadsheet to correct this problem, but a far simpler solution is to modify your VFP code to transform the data
into the VFP cursor. The sample code above has been updated to include this solution.
Mike Potjer
If you are using VFP 8 or earlier, arrays are limited to 65,000 elements, so you will get an error if you attem
from Excel into an array. However, VFP 9 raised the limit on arrays to 2GB, which should be more than enough fo
Brian Marston
Contributors: Alex Feldstein Tom Cerul Stuart Dunkeld David Fung Cetin Basoz Mike Potjer
13 of 13 01-06-2017 14:40