MSDN Library:
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."
Wednesday, June 1, 2016
Tuesday, May 24, 2016
Memo file is missing or invalid
QUESTION:
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)
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)
Friday, September 23, 2005 4:17 PM
* I have not tested this program yet.
Original post:
Monday, April 11, 2016
Access folders in Outlook via VFP automation
Here are
various ways to access different folders in Outlook via VFP automation:
Basic #DEFINE
#DEFINE
olFolderCalendar 9
#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
#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
*!* **Code****
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(olFolderCalendar) &&Calendar
oDefaultFolder.display()
Display Outlook's contact folder
*!* **Code****
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.
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.
*!* **Code****
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
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
*!* **Code****
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
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
*!* **Code****
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 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
*!* **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
**Do something here
loItem.unRead = .F. && Mark it as read
Endif
Next
Retrieve appointements in Outlook's calendar
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
*!* **Code****
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
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
*!* **Code****
#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
#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
*!* **Code****
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!'
.Send
ENDWITH
RELEASE oEmailItem
RELEASE oOutLookObject
Send an e-mail with attachment
*!* **Code****
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
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
Retrieve
attachements for all e-mail in the inbox
*!* **Code****
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 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
*!* **Code****
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,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
*!* **Code****
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
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
*!* **Code****
#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
#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
The trick is
to determine the folder ID number of your 'Seen' folder, once you have
determined that (Typically the folder ID number is in order of creation, for
example I just created a folder called 'seen' and determined that the folder
was the 12th folder to be created) , that following will do it for you, it will
move all Read messages to the folder number 12.
*!* **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
*!* **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
You can use
the following code to create a COM server
DLL and take action when a new e-mail arrives in Outlook. Please note that only
the NewMail procedure is functional, but you can add your own code to make the
others functional.
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
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
*!* **Code****
#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
#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
[i]Mike
Gagnon[/i]
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.
Figure 1: The dreaded Cannot Quit message
Somewhere in the app's controlling logic, you have code that looks like this: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.
Subscribe to:
Comments (Atom)