Friday, September 8, 2023
Tuesday, July 18, 2023
Remove a former employee
Important
Although we've numbered the steps in this solution and you don't have to complete the solution using the exact order, we do recommend doing the steps this way.

| Step | Why do this |
|---|---|
| Step 1 - Prevent a former employee from logging in and block access to Microsoft 365 services | This blocks your former employee from logging in to Microsoft 365 and prevents the person from accessing Microsoft 365 services. |
| Step 2 - Save the contents of a former employee's mailbox | This is useful for the person who is going to take over the employee's work, or if there is litigation. |
| Step 3 - Wipe and block a former employee's mobile device | Removes your business data from the phone or tablet. |
| Step 4 - Forward a former employee's email to another employee or convert to a shared mailbox | This lets you keep the former employee's email address active. If you have customers or partners still sending email to the former employee's address, this gets them to the person taking over the work. |
| Step 5 - Give another employee access to OneDrive and Outlook data | If you only remove a user's license but don't delete the account, the content in the user's OneDrive will remain accessible to you even after 30 days. Before you delete the account, you should give access of their OneDrive and Outlook to another user. After you delete an employee's account, the content in their OneDrive and Outlook is retained for 30 days. During that 30 days, however, you can restore the user's account, and gain access to their content. If you restore the user's account, the OneDrive and Outlook content will remain accessible to you even after 30 days. |
| Step 6 - Remove and delete the Microsoft 365 license from a former employee | When you remove a license, you can assign it to someone else. Or, you can delete the license so you don't pay for it until you hire another person. When you remove or delete a license, the user's old email, contacts, and calendar are retained for 30 days, then permanently deleted. If you remove or delete a license but don't delete the account, the content in the user's OneDrive will remain accessible to you even after 30 days. |
| Step 7 - Delete a former employee's user account | This removes the account from your admin center. Keeps things clean. Emails to the former employee's user account will not be received. |
Friday, July 29, 2022
Tuesday, September 28, 2021
Microsoft 365
- Microsoft 365 for enterprise overview
https://docs.microsoft.com/en-us/microsoft-365/enterprise/network-planning-and-performance?view=o365-worldwide.
Migrate Exchange to Office 365
A good blog
Some articles:
https://docs.microsoft.com/en-us/exchange/mail-migration-jump
- Hybrid express migration
https://techcommunity.microsoft.com/t5/exchange-team-blog/new-exchange-online-migration-options/ba-p/606109
- How to: Exchange 2016 to Office 365 Hybrid Migration - Step-by-Step
https://community.spiceworks.com/how_to/177811-exchange-2016-to-office-365-hybrid-migration-step-by-step
https://practical365.com/methods-for-migrating-to-office-365/
- Preparing for Hybrid Deployment with Exchange and Office 365
https://practical365.com/preparing-for-hybrid-deployment-with-exchange-office-365/
- Creating a Hybrid Configuration with Exchange and Office 365
https://practical365.com/creating-hybrid-configuration-exchange-office-365/
- How to Set Up a Hybrid Office 365 and Migrate to Exchange Online
https://blog.netwrix.com/2019/01/03/how-to-set-up-a-hybrid-office-365-and-migrate-to-exchange-online/
https://blog.matrixpost.net/migration-from-exchange-and-skype-for-business-onpremise-to-office-365-exchange-hybrid-classic-full-step-by-step/
Tuesday, April 16, 2019
Send a schedule recurring email in Outlook
5 Steps total
Step 1: Create a new appointment
2.. In the Appointment dialog under Appointment tab. You need to:
B: Enter the recipients’ email addresses in the Location (email must be enclosed between "<>" and separated by ";")
C: Configure the Start time and the End time
D: Select the reminder under the Reminder drop-down list.
If you choose 15 minutes, it means it will remind you 15 minutes early when the email is sent.
E: Compose your Appointment body.
Step 2: Create a new category
2. When the Color Categories dialog popping up, please click New button. In the Add New Category dialog, type “Recurring Email” in the Name field; and then choose a color in the Color drop-down list. Then click OK.
3. Then you will see the “Recurring Email” category is listed out, please check the box, and then click OK button.
Step 3: Set the Recurrence
2. In the Appointment Recurrence dialog, configure your Recurrence pattern. If you need an end time, please configure it under Range of recurrence. And then click OK.
3. When it returns to the Appointment dialog, please click Save & Close button.
Step 4: Use the VBA code for sending the Schedule Recurring Email
2. Double click on Project1 > Microsoft Outlook Object > ThisOutlookSession in the left pane.
3. Copy and paste the following VBA code (below) to the VBA editor. And then click Save button.
Dim objMsg As MailItem
Dim objApp As AppointmentItem
Dim Att As Attachment
Dim tmpFolder As String
Dim filePath As String
Set objMsg = Application.CreateItem(olMailItem)
If Item.MessageClass <> "IPM.Appointment" Then
Exit Sub
End If
If Item.Categories <> "Recurring Email" Then
Exit Sub
End If
tmpFolder = Environ("TEMP")
For Each Att In Item.Attachments
filePath = tmpFolder & "\" & Att.FileName
Att.SaveAsFile (filePath)
objMsg.Attachments.Add filePath
Kill filePath
Next Att
objMsg.To = Item.Location
objMsg.Subject = Item.Subject
objMsg.Body = Item.Body
objMsg.Send
Set objMsg = Nothing
End Sub
Step 5: Enable Macros
Step 2: In the Outlook Options dialog box, click the Trust Center in the left bar.
Step 3: Click the Trust Center Settings button.
Step 4: In the Trust Center dialog box, click the Macro Settings in the left bar.
Step 5: In the Macro Settings section:
To enable all macros, please check the Enable all macros (not recommended; potentially dangerous code can run) option.
To disable all macros in your Microsoft Outlook, please uncheck the Enable all macros (not recommended; potentially dangerous code can run) option.
Step 7: Restart your Microsoft Outlook 2010 or 2013 to activate it.
Wednesday, June 1, 2016
Visual Foxpro documentation links
https://msdn.microsoft.com/en-us/library/724fd5h9.aspx
ActiveX Controls for VFP 9.0
https://msdn.microsoft.com/en-us/library/bz6d1tc4(v=vs.80).aspx
"Help files for these ActiveX controls are available when MSDN is installed."
Tuesday, May 24, 2016
Memo file is missing or invalid
Hello,
I have a DBF file an I need to open it. I have VFP9.0 and when I try to open it I get a message suc as:
"Memo file C:\....\myfile.fpt is missing or is invalid."
Is there a way to open this file?
ANSWER:
You might also recover your memo file if problem is in next memo block pointer (get a backup and use at your own risk - yani sorumluluk kabul etmem:)
close data all
m.lcDBF = "c:\mypath\myTable.dbf"
RepairMemo(Forceext(m.lcDBF,'FPT'))
Function RepairMemo
* RepairMemo
* Simply fixes next block pointer, blocksize and filesize
Lparameters tcMemoFilename
Local handle, lnFileSize, lnNextBlockPointer, lnBlockSize, lnFirstBlock, lnCalculatedFileSize
handle=Fopen(tcMemoFilename,12) && Opened readwrite
lnFileSize = Fseek(handle,0,2) && Get file size
With This
* Read header info
lnNextBlockPointer = ReadBytes(handle, 0,4,.T.) && Stored in left-to-right format
lnBlockSize = ReadBytes(handle, 6,2,.T.) && Stored in left-to-right format
* Specific to me - no blocksize setting to something other than default 0x40
If lnBlockSize # 0x40
WriteBytes(handle, 6,2,0x40,.T.)
lnBlockSize=0x40
Endif
*
lnFirstBlock = Ceiling(512/lnBlockSize) && Possible min lnNextblockpointer
lnCalculatedFileSize = lnNextBlockPointer*lnBlockSize
* Fix if needs repair
If !(lnFileSize >= 512 ;
and lnNextBlockPointer >= lnFirstBlock ;
and lnCalculatedFileSize >= lnFileSize) && Memo needs repair
lnNextBlockPointer = Max(lnNextBlockPointer, lnFirstBlock)
lnFileSize = lnNextBlockPointer * lnBlockSize
WriteBytes(handle, 0,4,lnNextBlockPointer,.T.) && Fix next block pointer
=Fchsize(handle, lnFileSize) && Fix filesize
Endif
Endwith
=Fclose(handle)
Function WriteBytes
Lparameters tnHandle, tnPos, tnSize, tnNumber, tlLR
Local lcString, lnLowDword, lnHighDword,ix
lcString=''
If tlLR
For ix=tnSize-1 To 0 Step -1
lcString=lcString+Chr(tnNumber/256^ix%256)
Endfor
Else
For ix=0 To tnSize-1
lcString=lcString+Chr(tnNumber/256^ix%256)
Endfor
Endif
=Fseek(tnHandle, tnPos,0) && Go to pos
Return Fwrite(tnHandle,lcString)
Function ReadBytes
Lparameters tnHandle, tnPos, tnSize, tlLR
Local lcString, lnRetValue,ix
=Fseek(tnHandle, tnPos,0) && Go to pos
lcString = Fread(tnHandle, tnSize) && Read tnSize bytes
lnRetValue = 0
For ix=0 To tnSize-1 && Convert to a number
lnRetValue = lnRetValue + Asc(Substr(lcString,ix+1)) * ;
iif(tlLR,256^(tnSize-1-ix),256^ix)
Endfor
Return Int(lnRetValue)
Monday, April 11, 2016
Access folders in Outlook via VFP automation
Basic #DEFINE
#DEFINE olFolderContacts 10
#DEFINE olFolderDeletedItems 3
#DEFINE olFolderInBox 6
#DEFINE olFolderJournal 11
#DEFINE olFolderNotes 12
#DEFINE olFolderOutBox 4
#DEFINE olFolderSentMail 5
#DEFINE olFolderTask 13
#DEFINE olBusy 2
#DEFINE True .T.
#DEFINE False .F.
#DEFINE olPrivate 2
#DEFINE MAILITEM 0
#DEFINE IMPORTANCELOW 0
#DEFINE IMPORTANCENORMAL 1
#DEFINE IMPORTANCEHIGH 2
Display Outlook's calendar
LOCAL oOutlook,oNameSpace,oDefaultFolder
oOutlook = CREATEOBJECT('outlook.application')
oNameSpace = oOutlook.getnamespace('MAPI')
oDefaultFolder=oNameSpace.GetDefaultFolder(olFolderCalendar) &&Calendar
oDefaultFolder.display()
Display Outlook's contact folder
LOCAL oOutlook,oNameSpace,oDefaultFolder
oOutlook = CREATEOBJECT('outlook.application')
oNameSpace = oOutlook.getnamespace('MAPI')
oDefaultFolder=oNameSpace.GetDefaultFolder(olFolderContacts) &&Contact
oDefaultFolder.display()
How to use the find method, to locate a contact with a userdefined field 'BalanceDue' set to a numeric value.
oOutlook=CREATEOBJECT('outlook.application')
oNameSpace=oOutlook.getNameSpace('mapi')
oDefaultFolder=oNameSpace.getdefaultfolder(10)
oDefaultFolder.items
oItem=odefaultFolder.Items.Find('[BalanceDue]=500')
oItem.display()
Retrieve Outlook's contact, name and email address
CREATE CURSOR myCursor (Name c(40),email c(50))
LOCAL oOutlook,oNameSpace,oDefaultFolder
oOutlook = CREATEOBJECT('outlook.application')
oNameSpace = oOutlook.getnamespace('MAPI')
oDefaultFolder=oNameSpace.GetDefaultFolder(olFolderContacts)
oItems = oDefaultFolder.items
FOR EACH oItem IN oItems
INSERT INTO myCursor (name,email) VALUES (oItem.fullname,oItem.email1address)
ENDFOR
SELECT myCursor
BROWSE
Adding a new field and a value to the Contacts
LOCAL oOutlook,oNameSpace,oDefaultFolder
oOutlook = CREATEOBJECT('outlook.application')
oNameSpace = oOutlook.getnamespace('MAPI')
oDefaultFolder=oNameSpace.GetDefaultFolder(10)
loNewContact = oDefaultfolder.Items.Add()
loNewContact.Fullname = 'Mike Gagnon'
loNewContact.UserProperties.Add('Amount', 14)
loNewContact.UserProperties('Amount').Value = 100.00
loNewContact.save
MESSAGEBOX(TRANSFORM(loNewContact.UserProperties('Amount').Value))
loNewContact.display
Check for unread messages in the Inbox
Local oOutlookObject,olNameSpace
#Define olFolderInBox 6
oOutlookObject = Createobject('Outlook.Application')
olNameSpace = oOutlookObject.GetNameSpace('MAPI')
oItems= olNameSpace.GetDefaultFolder(olFolderInBox).Items
For Each loItem In oItems
If loItem.unRead
**Do something here
loItem.unRead = .F. && Mark it as read
Endif
Next
Retrieve appointements in Outlook's calendar
CREATE CURSOR myCursor (start T,end T,body c(250))
LOCAL oOutlook,oNameSpace,oDefaultFolder
oOutlook = CREATEOBJECT('outlook.application')
oNameSpace = oOutlook.getnamespace('MAPI')
oDefaultFolder=oNameSpace.GetDefaultFolder(olFolderCalendar)
oItems = oDefaultFolder.items
FOR EACH oItem IN oItems
INSERT INTO myCursor (start,end,body) VALUES (oItem.start,oItem.end,oItem.body)
ENDFOR
SELECT myCursor
BROWSE
Delete an appointment
#DEFINE olFolderCalendar 9
LOCAL oNameSpace, oDefaultFolder,oItems
oOutlook = CreateObject("Outlook.Application")
oNameSpace = oOutlook.GetNameSpace("MAPI")
oDefaultFolder = oNameSpace.GetdefaultFolder(olFolderCalendar)
FOR EACH oItem IN oDefaultFolder.items
IF oItem.Subject = 'All day meeting'
lDelete = oItem.Delete
ENDIF
ENDFOR
Send an e-mail without attachment
oOutLookObject = CreateObject('Outlook.Application')
oEmailItem = oOutLookObject.CreateItem(MAILITEM)
WITH oEmailItem
.Recipients.Add('moe@3stooges.com') && uses the Recipients collection
.Subject = 'Automation sample'
.Importance = IMPORTANCENORMAL
.Body = 'This is easy!'
.Send
ENDWITH
RELEASE oEmailItem
RELEASE oOutLookObject
Send an e-mail with attachment
oOutLookObject = CreateObject('Outlook.Application')
oEmailItem = oOutLookObject.CreateItem(MAILITEM)
WITH oEmailItem
.Recipients.Add('moe@3stooges.com') && uses the Recipients collection
.Subject = 'Automation sample'
.Importance = IMPORTANCENORMAL
.Body = 'This is easy!'
.Attachments.Add('c:\mydir\sample.txt') && Note that the fully qualified path and file is required.
.Send
ENDWITH
RELEASE oEmailItem
RELEASE oOutLookObject
Note this is also found in FAQ184-2838
Local lcFilename,lcPath
lcPath='c:\savedattachments\'
If !Directory('c:\savedAttachments')
Md 'c:\savedAttachments' && Create the directory if it doesn't exist.
Endif
oOutLookObject = Createobject('Outlook.Application')
olNameSpace = oOutLookObject.GetNameSpace('MAPI')
myAtts=olNameSpace.GetDefaultFolder(olFolderInbox).Items
For Each loItem In myAtts
If loItem.attachments.Count >0 && Make sure there is an actual attachment.
For i = 1 To loItem.attachments.Count
lcFilename='
lcFilename = loItem.attachments.Item(i).filename
lcFilename = Alltrim(lcPath)+lcFilename
loItem.attachments.Item(i).SaveAsFile(lcFilename)
*loItem.Delete() && The option to delete the message once the attachment has been saved.
Next
Endif
Next
How to change (edit) information in the Contacts folder
LOCAL oOutlook,oNameSpace,oDefaultFolder,oItems
oOutlook = CREATEOBJECT('outlook.application')
oNameSpace = oOutlook.GetNameSpace('mapi')
oDefaultFolder = oNameSpace.GetDefaultfolder(olFolderContacts)
oItems=oDefaultFolder.items
FOR EACH loItem IN oItems
IF loItem.FULLNAME = 'Mis'
loItem.Email1Address = 'mis@suntel.ca'
loItem.Save()
ENDIF
ENDFOR
Adding a folder in Outlook
Local oOutlook,oNameSpace,oNewFolder
oOutlook=CREATEOBJECT('outlook.application')
oNameSpace=oOutlook.GetNamespace('mapi')
oNewFolder=oNameSpace.Folders(2).Folders.Add('myNewFolder') && This will create a folder in the Personal folders' directory of Outlook.
How to find the names of the folders within the inbox folder
#DEFINE olFolderInBox 6
Local oOutlook,oNameSpace,oDefaultFolder
oOutlook=CREATEOBJECT('outlook.application')
oNameSpace=oOutlook.GetNamespace('mapi')
oDefaultFolder =oNameSpace.Getdefaultfolder(olFolderInBox)
oFolders=oDefaultFolder.folders
FOR EACH oFolder IN oFolders
?oFolder.name
ENDFOR
Moving messages from the Inbox to another folder
*!* **Code****
Local oOutlookObject,olNameSpace
#Define olFolderInBox 6
oOutlookObject = Createobject('Outlook.Application')
olNameSpace = oOutlookObject.GetNameSpace('MAPI')
oItems= olNameSpace.GetDefaultFolder(olFolderInBox).Items
For Each loItem In oItems
If !loItem.unRead
loitem.Move(olNameSpace.Folders(1).Folders(12))
Endif
Next
How to determine when new mail has arrived using BindEvents
Note: this code is based on http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfoxtk00/html/ft00j1.asp
Note2 : This code requires that VFPCOM Utility be installed in the target computer (http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=1529819C-2CE8-4E89-895E-15209FCF4B2A)
Note3 : This will work in VFP7.0 and up
#Define VFPCOM_CLSID 'VFPCOM.COMUTIL'
#Define OUTLOOK_CLSID 'OUTLOOK.APPLICATION'
Public goVFPCOM, goOutlook, goLink
goVFPCOM = Create(VFPCOM_CLSID)
goOutlook = Create(OUTLOOK_CLSID)
goLink = Create('OutlookApplicationEvents')
goVFPCOM.BindEvents(goOutlook, goLink)
Define Class OutlookApplicationEvents As Custom
Procedure ItemSend(Item,Cancel)
Endproc
Procedure NewMail
Messagebox('New Mail Has Arrived')
Endproc
Procedure OptionsPagesAdd(Pages)
Endproc
Procedure Quit
Endproc
Procedure Reminder(Item)
Endproc
Procedure Startup
Endproc
Enddefine
Thursday, January 14, 2016
How to avoid the Cannot Quit Visual FoxPro message
http://www.ml-consult.co.uk/foxst-07.htm
Ever tried to close your application, only to be told you can't? Here's the story.
You've developed your application and handed it to the user. Everything is fine. Then you get a phone call. The user tried to close the app, but all that happened was that a message appeared: "Cannot quit Visual FoxPro" (see Figure 1). Why? Because the application is still in an event loop.DO MainMenu.MPR READ EVENTSOnce the program has been put in an event loop (which is what READ EVENTS does), you won't be able to close down until you have exited the event loop. You do that with the CLEAR EVENTS command. You would normally execute CLEAR EVENTS whenever the user signals that they want to close the application – in the Exit command from the File menu, for example.
But what if the user tries to close the application by clicking on the Close box in the title bar? Or by shutting down Windows itself while the application is still running? In those cases, the program won't have had an opportunity to execute CLEAR EVENT. The event loop is still active, so the Cannot Quit message appears.
To avoid this, use the ON SHUTDOWN command. This works in the same way as VFP’s other "On" commands, such as ON ERROR, in that it specifies an action which is to be taken when a certain event occurs. In this case, the event is any attempt to close the application, by whatever means.
So all you have to do is execute ON SHUTDOWN CLEAR EVENTS. You do this near the beginning of the program – in any case before the READ EVENTS. Once you have done that, the user should never again see the Cannot Quit message. When the user hits the Close box in the title bar, the program will execute the ON SHUTDOWN code, which in turn will exit the event loop and pass control to the code following the READ EVENTS. End of problem.
Nothing happens
Well, not quite. Now try running the app from the VFP development environment. Close the app. Then try to quit Visual FoxPro. It makes no difference whether you use the File Exit command, click on the Close box or type QUIT in the Command Window. The result is the same: nothing happens.Why? Because the ON SHUTDOWN command is still in effect. Instead of closing down, VFP is merely executing a CLEAR EVENTS, which has no effect if you are in the development environment and there is no program running.
To avoid this, go back to the app, and add another ON SHUTDOWN command. This time, make it simply ON SHUTDOWN by itself. Put this in the clean-up code, that is, somewhere after the READ EVENTS. The effect will be to cancel the original ON SHUTDOWN.
This pair of commands – ON SHUTDOWN CLEAR EVENTS and ON SHUTDOWN by itself – are the minimum you need to close down gracefully. But, depending on how the app is structured, you might need to do more.
Cleaning up
In our own applications, the File Exit command performs a certain amount of cleaning up before it issues its CLEAR EVENTS. Specifically, it iterates through the collection of open forms (that is, the Forms collection in _SCREEN), closing each form in turn. As it does so, it prompts the user to deal with any unsaved edits. At that point, the user can decide to cancel the shut-down, in which case the exit routine will leave the relevant form open and refrain from clearing the event loop.The application needs to go through this same procedure no matter how the user tries to close down. To achieve this, we put the above processing in a procedure, which we call FileExit. The Exit command on the File menu calls this procedure with a simple DO FileExit. And so does the ON SHUTDOWN command. In other words, instead of executing ON SHUTDOWN CLEAR EVENTS, we execute ON SHUTDOWN DO FileExit. That way, the shut-down procedure is always the same, whatever the user did to initiate it.
Tuesday, September 1, 2015
Manipulate Excel file from VFP using VBA Application Interface
In the main program, create an ExcelPlus object:
SET PROCEDURE TO ExcelPlus
oExcel = CREATEOBJECT("ExcelPlus")
oExcel.StartExcel
Then, include file ExcelPlus.prg in the project. ExcelPlus.prg defines a class, ExcelPlus, which is an inheritance of class Excel.Application in VBA, so class ExcelPlus can access all the methods and properties of class Excel.Application in VBA. New customized methods can also be easily created in ExcelPlus.prg.
This is part of ExcelPlus.prg:
DEFINE CLASS ExcelPlus AS SESSION
#DEFINE OKAY 0
#DEFINE EXCELSTART 1
#DEFINE EXCELSTOP 2
#DEFINE NULLDATA 3
#DEFINE UNKNOWNALIGNMENT 4
#DEFINE UNKNOWNORIENTATION 5
#DEFINE BADPAGEMARGIN 6
#DEFINE ITEMNOTFOUND 7
#DEFINE COLORNOTDEFINED 8
#DEFINE TOOFARRIGHT 1001
#DEFINE TOOFARLEFT 1002
#DEFINE TOOFARUP 1003
#DEFINE TOOFARDOWN 1004
#DEFINE COLOR_BLACK 1
#DEFINE COLOR_DARKRED 9
PROTECTED AddressLo, AddressHi, MaxCol, MaxRow, oExcel, oWorkbook, DATASESSION
HIDDEN CurrentColLo, CurrentColHi
* exposed properties
CurrentCell = [A1]
CurrentCol = [A]
CurrentRow = 1
CurrentSheet = [Sheet1]
ExcelVisible = .F.
NewSheets = 1
ErrorCode = 0
ErrorMsg = [Okay]
* protected properties
AddressLo = [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
AddressHi = [ ABCDEFGHI]
MaxCol = [IV]
MaxRow = 65536
oExcel = .NULL.
oWorkbook = .NULL.
DATASESSION = 1
* hidden properties
CurrentColHi = 1
CurrentColLo = 1
**********************************************
PROCEDURE ErrorStatus(tnErrornumber)
DO CASE
* informational messages
CASE tnErrornumber = OKAY
THIS.ErrorMsg = [Okay]
CASE tnErrornumber = EXCELSTART
THIS.ErrorMsg = [Excel object instanciated.]
CASE tnErrornumber = EXCELSTOP
THIS.ErrorMsg = [Excel object destroyed.]
CASE tnErrornumber = NULLDATA
THIS.ErrorMsg = [Excel returned a NULL. Converted to space.]
CASE tnErrornumber = UNKNOWNALIGNMENT
THIS.ErrorMsg = [Unknown cell alignment. No cell alignment set.]
CASE tnErrornumber = UNKNOWNORIENTATION
THIS.ErrorMsg = [Unknown page orientation. No orientation set.]
CASE tnErrornumber = BADPAGEMARGIN
THIS.ErrorMsg = [Page margin less than 0. No margins set.]
CASE tnErrornumber = ITEMNOTFOUND
THIS.ErrorMsg = [Item not found prior to set limit.]
CASE tnErrornumber = COLORNOTDEFINED
THIS.ErrorMsg = [Color not defined in object.]
* error messages
CASE tnErrornumber = TOOFARRIGHT
THIS.ErrorMsg = [Attempt to go right of column ] + THIS.MaxCol + [.]
CASE tnErrornumber = TOOFARLEFT
THIS.ErrorMsg = [Attempt to go left of column A.]
CASE tnErrornumber = TOOFARUP
THIS.ErrorMsg = [Attempt to go above row 1.]
CASE tnErrornumber = TOOFARDOWN
THIS.ErrorMsg = [Attempt to go below row ] + ALLTRIM(STR(THIS.MaxRow)) + [.]
OTHERWISE
THIS.ErrorMsg = [Unknown]
ENDCASE
THIS.ErrorCode = tnErrornumber
* give the programmer a heads-up.
IF tnErrornumber > 1000
WAIT WINDOW THIS.ErrorMsg
ENDIF
ENDPROC
**********************************************
PROCEDURE StartExcel
THIS.oExcel = CREATEOBJECT("Excel.Application")
THIS.ErrorStatus(EXCELSTART)
ENDPROC
**********************************************
PROCEDURE StopExcel
THIS.oExcel.QUIT()
THIS.oExcel = .NULL.
THIS.ErrorStatus(EXCELSTOP)
ENDPROC
**********************************************
PROCEDURE OpenSpreadSheet(tcPathName)
THIS.oExcel.Workbooks.OPEN(tcPathName,.F.)
THIS.oWorkbook = THIS.oExcel.ActiveWorkbook
ENDPROC
**********************************************
PROCEDURE SaveSpreadSheet(tcFileName,tcPassWord)
IF PARAMETERS() = 1
tcPassWord = []
ENDIF
This.oExcel.DisplayAlerts = .F.
DO CASE
CASE VAL(This.oExcel.Version) > 11 AND EMPTY(tcPassWord)
THIS.oWorkbook.SaveAs(tcFileName+[.xls], 56)
CASE VAL(This.oExcel.Version) > 11
THIS.oWorkbook.SaveAs(tcFileName+[.xls], 56, tcPassWord)
CASE EMPTY(tcPassWord)
THIS.oWorkbook.SaveAs(tcFileName+[.xls])
OTHERWISE
THIS.oWorkbook.SaveAs(tcFileName+[.xls], tcPassWord)
ENDCASE
This.oExcel.DisplayAlerts = .T.
RETURN
ENDPROC
**********************************************
PROCEDURE CloseSpreadSheet
This.oExcel.DisplayAlerts = .F.
This.oWorkbook.Close() && Unsaved changes will be discarded
This.oExcel.DisplayAlerts = .T.
*!* This.oWorkbook.Close
RETURN
ENDPROC
**********************************************
PROCEDURE NewWorkBook
WITH THIS.oExcel
.SheetsInNewWorkbook = THIS.NewSheets
THIS.oWorkbook = .Workbooks.ADD()
ENDWITH
ENDPROC
**********************************************
PROTECTED PROCEDURE ExcelVisible_assign
* automatically sets the visible
* property of excel
LPARAMETERS tlView
THIS.ExcelVisible = tlView
THIS.oExcel.VISIBLE = THIS.ExcelVisible
ENDPROC
**********************************************
FUNCTION GoToCell(tcCell)
LOCAL lcCell
lcCell = UPPER(tcCell)
* check to see if we passed the limits
* these limits are for hand entered
* addresses programmatic addresses
* are checked with the move methods
IF THIS.Limits(lcCell)
* navigate to a particular cell,
* but if already there do nothing
THIS.oExcel.RANGE(lcCell).SELECT
IF THIS.CurrentCell # lcCell
THIS.CurrentCell = lcCell
ENDIF
ENDIF
* return error code established in
* the limits check
RETURN THIS.ErrorCode
ENDFUNC
**********************************************
FUNCTION GoToCol(tcCol)
THIS.GoToCell(tcCol + ALLTRIM(STR(THIS.CurrentRow)))
* return error code established in
* the limits check
RETURN THIS.ErrorCode
ENDFUNC
**********************************************
FUNCTION GoToRow(tnRow)
THIS.GoToCell(THIS.CurrentCol + ALLTRIM(STR(tnRow)))
* return error code established in
* the limits check
RETURN THIS.ErrorCode
ENDFUNC
Reference:
http://www.tomorrowssolutionsllc.com/Conference%20Sessions/Driving%20Word%20and%20Excel%20from%20Visual%20FoxPro.pdf
Thursday, July 23, 2015
VFP small tricks
InputMask Property
Specifies how users enter data and how to display data in a control. Available at design time and run time.
Format Property
Specifies the input and output formatting of a control's Value property. Available at design time and run time.
2. Move cursor to the right in a textbox
This.SelStart = LEN(ALLTRIM(This.Value))
This.SelLength = 0
3. Multiple forms - Modal vs Modeless
Modal forms require user input. A modal form has exclusive focus until it is dismissed. When showing a modal form, the controls outside the modal form will not react until the modal form is closed.
http://fox.wikis.com/wc.dll?Wiki~ModalvsModeless
The property "Desktop" of child form specifies whether a form can appear anywhere on the Windows desktop (if the value is .T.) or is contained in the parent form ( if the value is .F.). The default value is .F.
4. Prevents Visual FoxPro from inserting a key press into the keyboard buffer
Including NODEFAULT in the KeyPress event procedure or function prevents Visual FoxPro from inserting the key press into the Visual FoxPro keyboard buffer. Therefore, you can create a KeyPress procedure so that you can test which key is pressed before the key is sent to the keyboard buffer.
https://msdn.microsoft.com/en-US/library/e525z4k3(v=vs.80).aspx
5. Print immediately
Put these two lines at the end of program:
SET PRINTER TO
SET DEVICE TO SCREEN
Monday, July 13, 2015
VFP: Cancel validation on exit button click
Question:
In a Form, I have several textboxes that are validated against a table. The only logical way to set up the screen is for one of them to have the focus when you enter the form or after a save and ready for the next input (this textbox determines what all the rest have in them [e.g., the order number]). I also have a standard EXIT button which has Thisform.Release().
When I click the EXIT, the Valid() on the order field fires first and I must validate it before I can exit. My current work-around is to set the form's Key Preview on and check for ESCAPE and release.
How can I know in the Valid for order what event caused the valid to fire (i.e., the exit click) so I can conditionally skip the valid and let the form release?
I know I have seen this somewhere but can't remember.
Thanks,
==========================================
Answer:
There are a number of advantages of using an Exit button with the Cancel property set to .T. and checking for LastKey() = 27 in the Valid events of all of your control classes. One is that with Cancel set to .T. clicking the button is the same as pressing Escape so checking for 27 (Escape) as the LastKey() will tell you if the Exit button has been clicked. Secondly with Cancel set to .T. pressing Escape will click the button and fire its Click event thusly allowing you to give the user an expected functionality for the escape key.
In my control classes the beginning of the Valid event is;
IF LastKey() = 27
Keyboard "{CTRL+A}"
RETURN .T.
ENDIF
The keyboard of CTRL+A is to change the value of LastKey() from 27. This is because if the user clicks the exit button and then only uses the mouse, lastkey() will remain 27 until some other key is pressed. Doing the keyboard changes lastkey from 27 so the only way it can be 27 again is by pressing escape or clicking a button that has Cancel set to .T.
http://fox.wikis.com/wc.dll?Wiki~SkipValidOnExit
Wednesday, July 8, 2015
VFP Form Event Sequence
1. DataEnvironmet.openTables()
2. DataEnvironmet.beforeOpenTables()
3. Form.load()
4. [cursurs].Init() - for each cursor in DataEnvironment
5. DataEnvironment.init()
6. [controls].init() - for all controls in a form
7. Form.init()
8. Form.show()
9. Form.activate()
10. Form.refresh()
11. [object1].when() – for the first object in tab order
12. [object1].gotFocus() – for the first object in tab order
But In MSDN There Is A Slight Difference:
1. Form.init()
2. Form.activate()
3. [object1].when() – for the first object in tab order
4. Form.gotFocus()
5. [object1].gotFocus()
6. [object1].message()
-If We Leave An Object And The Next Object Gets The Focus:
Whenever An Object Gets The Focus The Sequence Of The Events Is As Below:
1. [object(i)].when()
2. [object(i)].gotFocus()
3. [object(i)].message()
And Whenever An Object Loses The Focus The Sequence Would Be:
1. [object(j)].valid()
2. [object(j)].lostFocus()
-If We Move To The Next Text Box From Currently Focused Text Box And Type Something In The Next Text Box:
1. Text(i).keyPress()
2. Text(i).valid
3. Text(i).lostFocus
4. Text(i+1).when()
5. Text(i+1).gotFocus()
-When We Type In A Text Box:
1. Text(i).keyPress()
2. Text(i).interactiveChange()
-When We Leave A Form By Calling Realease() Method (Closing The Form):
1. Form.queryUnload()
2. Form.destroy()
3. Form.[command buttons].destroy()
4. Form.[objects].destroy()
5. Form.unload()
6. DataEnvironment.afterCloseTables()
7. DataEnvironment.destroy()
-When We A Form Loses Focus (Like When Another Form Get The Focused):
1. Form.lostFocus()
2. Form.deactivate()
Che - 10/APR/2007
http://fox.wikis.com/wc.dll?Wiki~FormEventSequence
Thursday, June 4, 2015
How to give focus to a FoxPro top-level form at start-up
ThisForm.ShowWindow = 2 && Set the window to As Top-Level Form
In the form Init method:
_Screen.visible = .F.
The problem is the form lost focus when it runs. Users have to click the icon on the taskbar to bring the form to the top.
How to give focus to a FoxPro top-level form at start-up
This is a question I often see in Visual FoxPro forums. An application needs to show a top-level form (typically a log-in screen) at start-up. But when you launch the form, it
appears behind other windows on the desktop. Even if it is at the front, it's not necessarily the active form. So how do you give the form focus programmatically?
None of the obvious techniques seem to work. These include toggling the form's AlwaysOnTop property, and calling the SetFocus method for one of its controls. However, the following code will always do the trick:
DECLARE INTEGER SetForegroundWindow IN WIN32API INTEGER
SetForegroundWindow(thisform.HWnd)
CLEAR DLLS "SetForegroundWindow"
Friday, May 8, 2015
VFP function that combines individual xls files
I need to put get data from VFP and put it into multiple sheets in an Excel file. I found this code on Internet. I have not tested it so far.
--------- Original link and post: ---------
https://social.msdn.microsoft.com/Forums/en-US/a9b81c52-2969-4403-81e2-b5ce891f1a2f/copy-to-excel-and-adding-worksheets?forum=visualfoxprogeneral
I have this function that we use to combine individual xls files:
************************************************************
* Function CombineExcelFiles
************************************************************
* Created...........: Craig Boyd 3/6/2006 23:55:50
*) Description.......:
* Calling Samples...: DIMENSION aXLSFiles(3)
*!* aXLSFiles(1) = "C:\temp1.xls"
*!* aXLSFiles(2) = "C:\temp2.xls"
*!* aXLSFiles(3) = "C:\temp3.xls"
*!* CombineExcelFiles(@aXLSFiles, "C:\XLSCombined.xls")
* Parameter List....:
* Major change list.:
function CombineExcelFiles (taXLSFiles, tcDestination, tlDeleteOriginal)
external array taXLSFiles
local loExcel as Excel.application, ;
loWorkBook as Excel.Worksbook, ;
loWorkSheet , ;
lnCounter, lcWorkSheetCaption, lcError, ;
lcValidChars
lcError = ""
try
lcValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 "
loExcel = newobject("Excel.Application")
with loExcel
.ScreenUpdating = .f.
.DisplayAlerts = .f.
.WorkBooks.add()
lnCounter = 0
** Delete all existing worksheets except 1
for each loWorkSheet in .WorkBooks(1).WorkSheets
lnCounter = m.lnCounter + 1
if m.lnCounter > 1
loWorkSheet.delete
endif
endfor
for lnCounter = 1 to alen(taXLSFiles,1)
if file(taXLSFiles[m.lnCounter])
lcWorkSheetCaption = juststem(taXLSFiles[m.lnCounter])
loWorkBook = .WorkBooks.open(taXLSFiles[m.lnCounter])
loWorkBook.WorkSheets(1).copy(null, ;
.WorkBooks(1).WorkSheets(.WorkBooks(1).WorkSheets.count))
.WorkBooks(1).ActiveSheet.name = ;
right(alltrim(chrtran(m.lcWorkSheetCaption, ;
chrtran(m.lcWorkSheetCaption,m.lcValidChars,"")," ")), 31) &&loWorkBook.Name
loWorkBook.close(.f.) && Do not save changes
if m.tlDeleteOriginal
erase (taXLSFiles[m.lnCounter])
endif
endif
endfor
** Remove the first original sheet from (Sheet1)
.WorkBooks(1).WorkSheets(1).delete
.WorkBooks(1).saveas(m.tcDestination)
.ScreenUpdating = .t.
.DisplayAlerts = .t.
endwith
catch to loError
lcError = Log_Error(m.loError)
finally
if vartype(m.loExcel) = 'O'
with loExcel
.ScreenUpdating = .t.
.DisplayAlerts = .t.
.quit()
endwith
endif
endtry
return m.lcError
endfunc
Naomi Nosonovsky, Sr. Programmer-Analyst
Useful Excel Automation examples
|
Useful Excel Automation examples
Posted: 5 Oct 03 (Edited 8 Oct 03)
|
Here is an on-going compilation of Excel automation samples.
Mike Gagnon |
Thursday, February 26, 2015
A useful search tool, Filer, in Virtual FoxPro
This is a good search tool in VFP.
Filer
Years ago, Filer was what most FoxPro developers used to search and find files. After VFP 3.0, this disappeared and many developers screamed. Well, the Fox Team has listened and decided to bring back a little nostalgia. Enter the following in the Command window to see an example of how it runs:
DO FORM (HOME(1) + 'Tools\Filer\Filer.scx')
Search through the VFP Help file and read up on the new Filer, because this one is object-oriented and you can interact with it and implement it in your own applications. I guess you could call this FilerX!
The original article is here:
https://msdn.microsoft.com/en-us/library/ms947597.aspx
Tuesday, September 30, 2014
FoxPro form flashes on the screen and disappeares
http://www.alvechurchdata.co.uk/company/foxflash.html
FoxPro form flashes on the screen and vanishes
Everybody meets this problem with their first Visual FoxPro executable; the program runs well in the development environment but fails when run as a stand-alone executable from Windows. The FoxPro window just flashes on the screen and then vanishes. You can search VFP Help for terms like "flash", "vanish" and "disappear" but you will find nothing. The information is hidden away under "How to: Control the Event Loop" and you won't be able to ship your exe until you find it.This problem crops up because Visual FoxPro is now an event-driven language. It runs through the code for your form, reaches the end, and the program terminates when there is nothing more for it to do. Everything vanishes from the screen. The same thing will happen if your application is based on a main menu; FoxPro will run through the code to create the menu, the menu will flash on the screen but then the program terminates and the menu vanishes.
The solution is a simple one once you realise what FoxPro is doing. You have to tell VFP to start its event-processing loops. The command that does this is:
If you are using a form then add this as the last line in the Activate event. This will allow the form to load and initialise itself before going into the event processing loop and waiting for mouse and keyboard events.
In a menu, add it to the CleanUp code snippet. Select General Options from the View menu then click the Cleanup... tick box. An edit window will open behind the dialog; click OK to close the dialog window and the CleanUp edit window will remain:
If you have a program as the main element of your project then add the Read Events line immediately after you have set up the user interface by loading a form or menu. Fox will then stop executing this sequential code and will start monitoring keyboard and mouse events, waiting to see what it should do next.
One last thing to remember
You avoid this by using the Clear Events command to stop the event-processing loop. Execution will then continue from the line following the Read Events command in the main program.
Read more details on being unable to quit FoxPro here.
Friday, April 25, 2014
Windows Script Host
Microsoft Windows Script Host (WSH) is a language-independent scripting host for Windows Script compatible scripting engines. It brings simple, powerful, and flexible scripting to the Windows 32-bit platform, allowing you to run scripts from both the Windows desktop and the command prompt.
Using Windows Scripting Host, VBScript performed tasks that the Windows shell (batch scripts) simply could not handle. Windows Script Host is ideal for non-interactive scripting needs, such as logon scripting, administrative scripting, and machine automation.
This is the link for Windows Script Host
http://msdn.microsoft.com/en-us/library/9bbdkx3k(v=vs.84).aspx
In VBScript, we can create Windows Script Host (WSH) Objects and automate manual tasks.
These are the 14 WSH Objects:
Scripting.Signer Object
Enables an author to sign a script with a digital signature and a recipient to verify the signature's authenticity and trustworthiness.
This is the reference page:
http://msdn.microsoft.com/en-us/library/98591fh7(v=vs.84).aspx

