That was Quick

I know it’s only been two days since I last posted an update, but there were a few things still nagging me. I wanted to get them working, fixed. or updated and today seemed like a good day to do so.

Improved EMSend

The EMSend function now provides for an optional parameter that allows the developer to send the email(s) immediately rather than having them pile up in the user’s Outbox. Emails can be sent regardless of whether the user’s email client is running or not.

EMDisplay Function

A few of my blog readers asked that the library allow them to display the client’s email composition window as they could with CDO and such. This has been provided for. The function also returns a .T. or .F. indicating whether the user sent the email or just closed the window when it popped up. The email composition window can be popped up regardless of whether the user’s email client is running or not.

EMBindEvent and EMUnbindEvent Functions

A good enough start has been made on these functions to allow Visual FoxPro developers to effectively hook MAPI Notification Events. An additional library function(s) will be provided in the near future so that Visual FoxPro developers can make heads or tails of the dizzying array of pointers and structures that these events give access to (such as just returning a VFP object, array, or cursor with the pertinent information).

Default Directory Bug Fix

A bug was reported regarding the default directory being changed in Visual FoxPro when the SET LIBRARY TO VFPEXMAPI.FLL command was executed. This has been addressed in this release as well.

That’s All For Now

I hope you find this library useful as it now sits. I will continue adding to it from time to time (MAPI has so much more to offer), but for now I will be working on the vfpencryption.fll and the RAPI class library wrapper in my spare time. Any bugs in this library will certainly be addressed as they are reported, and should you have enhancement requests I urge you to leave them in the comments below so that all of the blog readers can see what has been asked for and discuss the possibilities.

While the full examples and documentation are still being held in my first blog post concerning this library, here is the obligatory download link,  the example code as it now sits and the portions of the documentation that have been added or changed by this latest release.

Special thanks to Bo Durban who stayed up late with me to help me workaround a serious problem with the MAPI hooks.

VFP Extended MAPI FLL:

VFPExMAPI FLL Download (14 KB approx.)


VFP Extended MAPI Sample Code:

***************************
*!* See the following link for more information
*!*    http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,baccc84d-4d91-458b-a839-ad03662dfc34.aspx
***************************

#Define MAPI_ORIG 0
#Define MAPI_TO 1
#Define MAPI_CC 2
#Define MAPI_BCC 3

#Define IMPORTANCE_LOW 0
#Define IMPORTANCE_NORMAL 1
#Define IMPORTANCE_HIGH 2

#Define FNEVCRITICALERROR            0X00000001
#Define FNEVNEWMAIL                    0X00000002
#Define FNEVOBJECTCREATED            0X00000004
#Define FNEVOBJECTDELETED            0X00000008
#Define FNEVOBJECTMODIFIED            0X00000010
#Define FNEVOBJECTMOVED                0X00000020
#Define FNEVOBJECTCOPIED            0X00000040
#Define FNEVSEARCHCOMPLETE            0X00000080
#Define FNEVTABLEMODIFIED            0X00000100
#Define FNEVSTATUSOBJECTMODIFIED    0X00000200

#Define WM_USER 0x0400

#DEFINE FLLPATH “E:\SPS Blog\vfpexmapi71\vfpexample\”
#DEFINE RECIP “
craig@sweetpotatosoftware.com
Public goMapiEvent
Local lcAttachment, lcHTML, lcRTF, lcText
Set Library To Locfile(FLLPATH + “
vfpexmapi.fll“)

*****************************
*!* Send Text Email
*****************************
m.lcText = “Here’s a plain text email.
?”
Sending Text Email
?EMCreateMessage(“
Text Test“, m.lcText, IMPORTANCE_NORMAL)
?EMAddRecipient(EMAILRECIP, MAPI_TO)
*!* More recipients could be added here
*!* Create a temp file to attach – just for example purposes
m.lcAttachment = ADDBS(SYS(2023)) + SYS(2015) + “
.TXT
=STRTOFILE(“
Visual FoxPro Rocks!“, m.lcAttachment, 0)
?EMAddAttachment(m.lcAttachment)
*!* More attachments could be added here
?EMSend() && don’t send yet, just put it in the Outbox

*****************************
*!* Send HTML Email
*****************************
TEXT TO m.lcHTML NOSHOW
<html>
<body>
<p>Here’s an HTML email.</p>
<ul>
<li>The</li>
<li><a href=”http://www.sweetpotatosoftware.com/SPSBlog/”>SPS Weblog</a></li>
<li>is Back.</li>
</ul>
<p>Visual FoxPro Rocks!</p>
</body>
</html>
ENDTEXT
?
?“Sending HTML Email”
?EMCreateMessageEx(“HTML Test”, m.lcHTML, IMPORTANCE_HIGH)
?EMAddRecipient(EMAILRECIP, MAPI_TO)
?EMAddAttachment(m.lcAttachment)
?EMSend() && don’t send yet, just put it in the Outbox

*****************************
*!* Send RTF Email
*****************************
TEXT TO m.lcRTF NOSHOW
{\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard
Here is a {\b Rich Text Format} email.\par
}
ENDTEXT
?
?“Sending RTF Email”
?EMCreateMessageEx(“RTF Test”, m.lcRTF, IMPORTANCE_LOW)
?EMAddRecipient(“someone@somedomain.com”, MAPI_TO)
?EMAddAttachment(m.lcAttachment)
?EMSend(.T.) && Send all 3 emails now
*****************************
*!* Display Email Form to User
*****************************
m.lcText = “User can decide whether to send this or not.”
?
?“Displaying Email”
?EMCreateMessage(“Text Test”, m.lcText, IMPORTANCE_NORMAL)
?EMAddRecipient(EMAILRECIP, MAPI_TO)
?EMDisplay() && display email form returns .T./.F. indicating whether user sent email
*****************************
*!* Clean up the temp file we created as an attachment
*****************************
IF FILE(m.lcAttachment)
ERASE (m.lcAttachment)
ENDIF
SET LIBRARY TO

*****************************
*!* MAPI Bindevent Example
*****************************
Set Library To Locfile(FLLPATH + “vfpexmapi.fll”)
m.lcText = “User can decide whether to send this or not.”
Clear
?
?“Displaying Email”
?EMCreateMessage(“Text Test”, m.lcText, IMPORTANCE_NORMAL)
?EMAddRecipient(EMAILRECIP, MAPI_TO)
m.goMapiEvent = Createobject(“EMEvents”)
Bindevent(_vfp.HWnd,WM_USER + 1, goMapiEvent, “ExtendedMapiEvent”) && custom application events are between WM_USER and 0x7FFF
?EMBindEvent(FNEVNEWMAIL)
?EMSend(.T.) && After this go do a Send/Receive in Outlook so that the New Mail event fires
*!* Calling SET LIBRARY TO here would unhook the event, so we don’t do it

*****************************
Define Class EMEvents As Custom
*!* Class to bind the _vfp WM_USER + 1 window message to
*****************************
    Function ExtendedMapiEvent(HWnd,Msg,WPARAM,LPARAM)
    Local lnType, lcInfoStruct, lnStructMembersTotal, lnStructCounter, lcEventMessage
    m.lnType = CToBin(Sys(2600,Lparam,4),“4RS”)
*!* More work to do on this, an FLL function that dev can send LPARAM
*!* to will be created and an array or object will be created in VFP
    Do Case
    Case m.lnType = 1 && ERROR_NOTIFICATION 20 bytes
        m.lcEventMessage = “ERROR_NOTIFICATION event has occurred!”
        m.lnStructMembersTotal = 5
    Case m.lnType = 2 && NEWMAIL_NOTIFICATION 28 bytes
        m.lcEventMessage = “NEWMAIL_NOTIFICATION event has occurred!”
        m.lnStructMembersTotal = 7
    Case Bitand(m.lnType,252) > 0 && OBJECT_NOTIFICATION 40 bytes
        m.lcEventMessage = “OBJECT_NOTIFICATION event has occurred!”
        m.lnStructMembersTotal = 10
    Case m.lnType = 256 && TABLE_NOTIFICATION ??? bytes
        m.lcEventMessage = “TABLE_NOTIFICATION event has occurred!”
        m.lnStructMembersTotal = ???
    Case m.lnType = 512 && STATUS_OBJECT_NOTIFICATION 16 bytes
        m.lcEventMessage = “STATUS_OBJECT_NOTIFICATION event has occurred!”
        m.lnStructMembersTotal = 4
    Otherwise && EXTENDED_NOTIFICATION 12 bytes
        m.lcEventMessage = “EXTENDED_NOTIFICATION event has occurred!”
        m.lnStructMembersTotal = 3
    Endcase
    ?m.lcEventMessage
    *!* Comment out the line below to leave the event bound
    EMUnbindEvents() && Now remove the hook (SET LIBRARY TO does an implicit hook removal as well)
*!*        LOCAL ARRAY laValues(m.lnStructMembersTotal)
*!*        FOR m.lnStructCounter = 1 TO m.lnStructMembersTotal
*!*            laValues(m.lnStructCounter) = CTOBIN(SYS(2600,LPARAM + 8 + ((m.lnStructCounter 1) * 4),4),“4RS”)
*!*        ENDFOR
    Endfunc
Enddefine

VFP Extended MAPI Updated Functions:


Function EMSend()

Signature: EMSend([lSendImmediately])

Parameters:

lSendImmediately – .T. or .F. value indicating whether the email message should be sent immediately or remain in the Outbox (see disclaimer in Remarks below)

Return Value:

Logical – indicating whether the email was successfully placed into the email client send queue (outbox) – .T. for success and .F. for failure

Remarks:

This function should be called after the EMCreateMessage function. Also, it is important to note that just because the file has been placed to the outbox of the email client and is waiting to be sent does not mean that the email will be immediately sent. When the email actually gets sent (right away or after a certain delay) is dependent on the user-defined settings in the email client for sending email that is sitting in the send queue. If you wish to send the email(s) in the outbox immediately (regardless of user settings) you can pass .T. for the lSendImmediately parameter. The email(s) in the outbox can be sent immediately regardless of whether or not the user currently has their email client open.

Be aware that the autosend feature provided by the lSendImmediately parameter does not work for Outlook 2002-2003. If anyone knows a way around this limitation I would appreciate it if you would contact me. For more details on this limitation see http://support.microsoft.com/kb/317412


Function EMDisplay()

Signature: EMDisplay()

Parameters: None

Return Value:

Logical – indicating whether the user sent the email from the compose window or cancelled the operation by clicking the close button – .T. for sent and .F. for cancelled.

Remarks:

This function should be called after the EMCreateMessage function. Rather than submitting the email directly to the outbox, this function allows you to show the client’s email composition window. The email can be displayed whether or not the user has their email client open.


Function EMBindEvent()

Signature: EMBindEvent(nEvent)

Parameters:

nEvent – numeric value indicating the type of MAPI Notification Event to watch for. The following is a list of possible values:

  • Critical Error = 1
  • New Email Arrival = 2
  • Object Created = 4
  • Object Deleted = 8
  • Object Modified = 16
  • Object Moved = 32
  • Object Copied = 64
  • Search Complete = 128
  • Table Modified = 256
  • Status Object Modified = 512
  • Reserved For MAPI = 1024
  • Extended = 2048

Return Value:

Logical – indicating whether the event was successfully bound – .T. for success and .F. for failure

Remarks:

This function is most easily understood by running the example provided. When the bound event is fired it sends a message to the _VFP window that can easily be bound to using Visual FoxPro’s BindEvent. Information regarding the notfication event that fired can be extracted from the LPARAM parameter. This is just a beginning. Eventually the library will provide other methods of easily extracting the information from all the pointers and structures. For now I would like developers to get a feel for how this works.

It should be noted that for now only a single MAPI Notification Event can be bound to at a time. Calling the EMBindEvent function releases the previous hook (if it exists) before instituting the new one. In the future simultaneous hooks will be provided for.

Special thanks to Bo Durban for providing a workaround that made this method possible.


Function EMUnbindEvents()

Signature: EMUnbindEvents()

Parameters: None

Return Value:

Logical – indicating whether a hook that was created using EMBindEvent was removed – .T. for success and .F. for failure

Remarks:

This function should be called after the EMBindEvent function when you wish to remove the hook. Issuing SET LIBRARY TO also releases any active hook that may exist. Crashing or closing out of a system without removing an active MAPI Notification Event hook can cause the user’s email client to become unstable. It is strongly recommended that a hook are removed as soon as you are through using it using EMUnbindEvents. Calling the EMUnbindEvents function when no hook is active does not cause any problems or errors.