Visual Foxpro code to calculate the next working day. Taking into account that our working week is from Monday (1) to Friday (5).
Connection Strings
Listing of many types of connections strings to databases using several driver types. Tip from the YouTube clip “Everything You Wanted to Know About ODMC”.
LDAP Query from Foxpro
Needing LDAP access to be able to create some sort of Single Sign-On (SSO), I googled and created this testcode that is able to query the LDAP and place the results in a cursor. Continue reading “LDAP Query from Foxpro”
Outlook.Application
Using the Outlook.Application object to read e-mails from Visual Foxpro.
Trying to read e-mail using POP3 or IMAP proved to be hell to me. Documentation is not present or hardly legible. Because we use Microsoft® Outlook® at our company, I was able to connect to Outlook using the Outlook.Application object.
This simple code finds all mails in a certain folder (loTelecomMap):
loOutlook = CREATEOBJECT("Outlook.application")
loMAPI = loOutlook.GetNameSpace("MAPI")
loTelecomMap = loMAPI.GetDefaultFolder(6).Folders([Business]).folders([Telecom])
loMails = loTelecomMap.Items
loMessage = loMails.Find("[Subject]='Mail subject title'") && starts with the last (newest) message
DO WHILE NOT ISNULL(loMessage)
ldDate = TTOD(loMessage.ReceivedTime)
lcMessage = loMessage.Body
lcHTMLsource = loMessage.HTMLbody
* More actions on the loMessage object
loMessage = loMails.FindNext() && Next message
ENDDO
RELEASE loOutlook
I had great help using a whitepaper by Andrew MacNeill. Linking to his page is prohibited, so you have to copy-and-paste the URL yourself: http://www.aksel.com/whitepapers/OutlookAutomation.htm. To accommodate for possible closing of that reference, I have included the pages contents (the whitepaper) in PDF form on this page.
Read from Excel using MS ODBC
If you just want to read the contents of an Excel spreadsheet, there is an easier way using the Microsoft Excel (ODBC) Driver.
In a previous post (Foxpro and Excel) we have shown how to control Excel using the Excel.Application object. But if you are just interested in the contents, there is an even easier way to achieve this: The Microsoft Excel (ODBC) driver. that is present on most systems with MS Office installed.
Source: Importing data from a Microsoft Excel 2007 workbook using Visual FoxPro 9.0 (Microsoft Support)
To get an SQL connection to an Excel sheet is no more difficult than this:
lcXLfile = [c:\temp\demo.xlsx]
* Warning: The driver wil never fail!
* If the file does not exist, this driver wil create the file.
IF !FILE(lcXLfile)
? [Excel file not found]
RETURN .F.
ENDIF
lcConnection = [DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=]+lcXLfile
lnHandle = SQLSTRINGCONNECT(lcConnection)
* Get all sheetnames in a cursor (every sheet is a Table)
? SQLTABLES(lnHandle,[],[crSheets])
lcQuery = [SELECT * FROM ]+TRIM(STRTRAN(crSheets.Table_Name,['],["]))
? SQLEXEC(lnHandle, lcQuery, [crResults])
SQLDISCONNECT(lnHandle)
The SQLTABLES command creates a cursor with a row for each sheet in the Excel file. You can filter the kind of tables in the second parameter. This is a typical row:
Field name | Field type | Length | Example | |
---|---|---|---|---|
TABLE_CAT | Memo | 4 | C:\TEMP\DEMO.XLSX | |
TABLE_SCHEM | Character | 128 | .NULL. | |
TABLE_NAME | Character | 128 | ‘Sheet1$’ | |
TABLE_TYPE | Character | 128 | TABLE | |
REMARKS | Character | 254 | .NULL. |
Remarks
Quotes in the SQLTABLES result
The TABLE_NAME field contains single quotes, These seem not to work in a SQL statement. So you have to replace them with double quotes. Check out the lcQuery line in the code above..
Field names in queries
Only when a sheet is properly filled the field names in queries are automatically named correctly: The titles in the first row are accepted as fieldnames. However, if the first row is left blank or there are multiple tables on a page, the result becomes erratic.. In this situation some or all fields get the title F1. and so on (number being the column number).
Field types
It seems the unaltered query results deliver just 2 kinds of columns: Numbers and Memo’s. Both columns may contain .NULL. values.
Quotes in query’s
To compare or use strings in SQL query’s, you need to use the single quotes again. For instance:
lcQuery = [SELECT * FROM "Sheet1$" WHERE surname='de Graaf']
SQLEXEC(lnHandle,lcQuery,[crDeGraaf])
Double complex because the sheet (table) name has to be encapsulated in double quotes, while a compare string has to be encapsulated in single quotes.. I can’t think of a reason for this odd behavior.
Read only
As to be expected, this ODBC method to an Excel file is limited to reading the file. Trying to insert or update using SQL commands renders the result that the query has to be updatable.
Installing Visual Foxpro on Windows 10 64bit
After replacing my computer, I needed to reinstall Visual Foxpro. I had the install disc contents, but whatever executable I started with: it kept on crashing. A Google search brought silly advice, but fortunately there was a gem: an article on wOOdy’s Blog. This explained what the right procedure is and what file to start with (VFPSTART.HTA). It stil would not work. Not from a folder, and not from a mapped network disc. I found the free AnyBurn software that gave me the opportunity to create an ISO file from my install folder. Now it was as easy as double clicking the ISO file to have Windows mount the CD image and assign it a drive letter. Now everything worked like a charm. Then we have to apply both service packs, and perhaps some useful suggestions wOOdy made.
Foxpro ReturnObject
Function to prevent problems during object creation to crash your program. When problems arise, your program might be unable to continue, but at least you can show the user what went wrong instead of an uninformative crash warning.
* ReturnObject
* 2011.05.31 start
* 2012.07.06 parameters added
* Tries to create an object and return this. If object creation failed, a false is returned
* Parameters: Class to instantiate object from, max 2 parameters
FUNCTION ReturnObject( tcClass,tuPar1,tuPar2)
LOCAL loReturn,lnCount,loError
lnCount = PCOUNT()
TRY
DO CASE
CASE lnCount = 1
loReturn = CREATEOBJECT(tcClass,tuPar1)
CASE lnCount = 2
loReturn = CREATEOBJECT(tcClass,tuPar1,tuPar2)
OTHERWISE
loReturn = CREATEOBJECT(tcClass)
ENDCASE
CATCH TO loError
loReturn = .f.
ENDTRY
RETURN loReturn
ENDFUNC
Foxpro and Excel
It is very possible to automate spreadsheets from Visual Foxpro using VBA/ COM automation. Here I wil document the parts I need.
Connecting to Excel
oExcel = CreateObject("Excel.Application")
if vartype(oExcel) != "O"
* could not instantiate Excel object
* show an error message here
return .F.
endif
I use my own library (JLIB) containing a ReturnObject function that fetches errors. Using that function my code looks like this:
PUBLIC goX && global Excel object
IF InitiateExcel()
* Code here
ELSE
? [Error initiating Excel automation]
ENDIF
PROCEDURE InitiateExcel
goX = ReturnObject([excel.application])
RETURN (VARTYPE(goX)=[O])
ENDPROC
Open an existing spreadsheet
oWorkbook = oExcel.Application.Workbooks.Open("C:\temp\test.xls")
Create a new blank spreadsheet
oWorkbook = oExcel.Application.Workbooks.Add()
Create a new spreadsheet from a template
oWorkbook = oExcel.Application.Workbooks.Add("C:\temp\template.xlt")
Sheets collection/ objects
oWorkbook.sheets.count && returns the number of tabs/ sheets
oSheet = oWorkbook.sheets(1) && get an object to control the sheet
? oSheet.name && show the sheet name
Tables
A table is called a ListObject in Excel/ Microsoft terminology
oSheet.ListObjects.count && gives the number of tables on the sheet
oTable = oSheet.ListObjects(1) && get an object to control the table
? oTable.ListRows.count && displays the number of data rows in the table
oTable.DataBodyRange.delete && deletes al rows. Error (crash) if there are no rows!
Working with table rows
Adding a table row needs several steps: 1. Add the row and keep the reference to it. 2. Add the column data 1 by 1:
oRow = oTable.ListRows.Add && you have a new row and a reference to it
oRow.Range(1) = Date(2020,7,6) && Add a date in the first column
Using named cells
? oSheet.Range("ProductionDate").value && show value of cell named ProductionDate
oSheet.Range("TotalPages").value = 13
Saving and closing
The save method is in the workbook object. And you can quit from the Excel application object:
oSheet.SaveAs([x:\reports\report.xlsx]) && Save
oExcel.Quit && quit Excel
The Quit only works on this Excel application you’ve initiated. So existing opened Excel sheets are untouched (remain opened).
Sources used
VFP: Create header files
Header files (.H) contain declarations and sometimes code. Software uses codes for specific actions or settings, but these codes are illegible for most humans. The header file for Microsoft Word 2016 contains more than 4.500 lines. It starts like this:
* WdMailSystem
#DEFINE wdNoMailSystem 0
#DEFINE wdMAPI 1
#DEFINE wdPowerTalk 2
#DEFINE wdMAPIandPowerTalk 3
* WdTemplateType
#DEFINE wdNormalTemplate 0
#DEFINE wdGlobalTemplate 1
#DEFINE wdAttachedTemplate 2
The header files are not included in the distributions, so you have to search for them yourself or create them if possible.
This program originates from an old Microsoft article. It creates a dialog where you can locate an .OLB file (Object Library). It then extracts all constants and gives you the ability to save them to your header file.
* Bron: https://web.archive.org/web/20110808014156/http://support.microsoft.com/kb/285396
****************START CODE****************
PUBLIC oform1
oform1=NEWOBJECT("form1")
oform1.SHOW
RETURN
****************FORM CODE****************
DEFINE CLASS form1 AS FORM
HEIGHT = 445
WIDTH = 567
DOCREATE = .T.
AUTOCENTER = .T.
BORDERSTYLE = 1
CAPTION = ".OLB Constants Extractor"
MAXBUTTON = .F.
MINBUTTON = .F.
NAME = "Form1"
ADD OBJECT txtolbfile AS TEXTBOX WITH ;
HEIGHT = 27, ;
LEFT = 65, ;
READONLY = .T., ;
TABINDEX = 2, ;
TOP = 6, ;
WIDTH = 458, ;
NAME = "txtOLBFILE"
ADD OBJECT label1 AS LABEL WITH ;
AUTOSIZE = .T., ;
CAPTION = ".\<OLB File:", ;
HEIGHT = 17, ;
LEFT = 4, ;
TOP = 11, ;
WIDTH = 55, ;
TABINDEX = 1, ;
NAME = "Label1"
ADD OBJECT cmdsave AS COMMANDBUTTON WITH ;
TOP = 411, ;
LEFT = 394, ;
HEIGHT = 27, ;
WIDTH = 84, ;
CAPTION = "\<Save to .h", ;
ENABLED = .F., ;
TABINDEX = 6, ;
NAME = "cmdSAVE"
ADD OBJECT cmdquit AS COMMANDBUTTON WITH ;
TOP = 411, ;
LEFT = 480, ;
HEIGHT = 27, ;
WIDTH = 84, ;
CAPTION = "\<Quit", ;
TABINDEX = 7, ;
NAME = "cmdQUIT"
ADD OBJECT edtconstants AS EDITBOX WITH ;
HEIGHT = 347, ;
LEFT = 6, ;
READONLY = .T., ;
TABINDEX = 4, ;
TOP = 52, ;
WIDTH = 558, ;
NAME = "edtConstants"
ADD OBJECT cmdgetfile AS COMMANDBUTTON WITH ;
TOP = 6, ;
LEFT = 533, ;
HEIGHT = 27, ;
WIDTH = 26, ;
CAPTION = "...", ;
TABINDEX = 3, ;
NAME = "cmdGETFILE"
ADD OBJECT cmdextract AS COMMANDBUTTON WITH ;
TOP = 411, ;
LEFT = 280, ;
HEIGHT = 27, ;
WIDTH = 110, ;
CAPTION = "\<Extract Constants", ;
ENABLED = .F., ;
TABINDEX = 5, ;
NAME = "cmdEXTRACT"
PROCEDURE cmdsave.CLICK
STRTOFILE(THISFORM.edtconstants.VALUE,PUTFILE([Header File], ;
JUSTSTEM(THISFORM.txtolbfile.VALUE) + [.h],[.h]))
ENDPROC
PROCEDURE cmdquit.CLICK
THISFORM.RELEASE
ENDPROC
PROCEDURE cmdgetfile.CLICK
LOCAL lcOLBFile
lcOLBFile = GETFILE([OLB],[OLB File],[Open])
IF EMPTY(lcOLBFile)
RETURN .F.
ENDIF
IF UPPER(RIGHT(lcOLBFile,3)) # [OLB]
MESSAGEBOX([Invalid File],0,[])
RETURN .F.
ENDIF
THISFORM.txtolbfile.VALUE = lcOLBFile
THISFORM.cmdextract.ENABLED= .T.
ENDPROC
PROCEDURE cmdextract.CLICK
WAIT WINDOW [Processing...] NOCLEAR NOWAIT
LOCAL oTLB_INFO, oConstants, lcConstantsStr, Obj, member
#DEFINE CRLF CHR(13) + CHR(10)
oTLB_INFO = CREATEOBJECT([tli.typelibinfo])
oTLB_INFO.ContainingFile = (THISFORM.txtolbfile.VALUE)
oConstants = oTLB_INFO.Constants
lcConstantsStr = []
FOR EACH Obj IN oTLB_INFO.Constants
lcConstantsStr = lcConstantsStr + CRLF + "* " + Obj.Name + CRLF
FOR EACH member IN Obj.Members
lcConstantsStr = lcConstantsStr + [#DEFINE ] + ;
member.NAME + [ ] + ;
TRANSFORM(member.VALUE) + CRLF
NEXT member
NEXT Obj
THISFORM.edtconstants.VALUE=lcConstantsStr
THISFORM.cmdsave.ENABLED= .T.
WAIT CLEAR
WAIT WINDOW [Complete!] TIMEOUT 2
ENDPROC
ENDDEFINE
****************END CODE****************
VFP: Check already running (NL)
Draait een programma al?
Door jasperdg op 16 Jul 2007
Het is soms niet handig als je een programma start terwijl dit al draait. Vooral bij programma’s die bewerkingen uitvoeren op databases is dit zeer ongewenst (indexeer programma’s etc). Hier een geschikte module die met Win32Api functies de actieve vensters uitleest en kijkt of een specifiek programma in de actieve titels voorkomt…
Met dank aan FoxStuff.
Programma IsRunning.prg :
(0 als niet gevonden, anders het handle nummer)
* Generic routine to check if a given * application is running on the user's system. * Parameter is all or part of the window's title. LPARAMETERS tcTitle DECLARE INTEGER GetActiveWindow IN Win32API DECLARE INTEGER GetWindow IN Win32API ; INTEGER hWnd, INTEGER nType DECLARE INTEGER GetWindowText IN Win32API ; INTEGER hWnd, STRING @cText, INTEGER nType lhNext = GetActiveWindow() && current app's window * iterate through the open windows DO WHILE lhNext#0 lcText = REPLICATE(CHR(0),80) GetWindowText(lhNext,@lcText,80) && get window title IF UPPER(ALLTRIM(tcTitle)) $ UPPER(lcText) * parameter text is present in window title RETURN lhNext ENDIF lhNext = GetWindow(lhNext,2) && next window ENDDO * required window not found RETURN 0