Wiki Home

Shell Execute


Namespace: Wiki
I've been using Shell Execute for doing interactive email functions within VFP.

I recently had to find an alternative that gave me the same functionality from an end-user perspective since there is a limitation on the length of the string that can be handled by Shell Execute on Win98. (see MSKB Q182985 Offsite link to http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q182985 - notice it's just Outlook Express OR Windows 98, period.)

Here is the syntax I have been using:

DECLARE INTEGER ShellExecute ;
	    IN SHELL32.DLL ;
	    INTEGER nWinHandle,;
	    STRING cOperation,;
	    STRING cFileName,;
	    STRING cParameters,;
	    STRING cDirectory,;
	    INTEGER nShowWindow

RETURN ShellExecute( 0, "Open", "mailto:" + lcEmail + ;
   "?subject=Order Confirmation for Priority No." + ;
   STR(tsfile.pr_number,6,0) + "&body=" + lcBody, "", "", 1 )




The 3rd parameter winds up being something like this:

"mailto:randy@randyjean.com?subject=Order Confirmation for Priority No.400270&body=Order Confirmation: %0D%0DTo: David%0DCompany: ASK Law Offices%0D%0DFrom: HEIDI%0DCompany: Priority Posting and Publishing %0D%0DPhone: (714) 573-7777 %0DFax: (714) 573-7755 %0D%0DDate: 10/25/2001%0D%0DSale Date: 11/29/2001%0D%0DComments: Thank you for your order!%0D%0DYour T.S. #9999%0DPriority #400270%0D%0DCounty: Los Angeles%0DNewspaper: Los Angeles Daily Journal%0DRun Dates: 10/26/2001, 11/02/2001, 11/09/2001"

You can try this in IE if you have Windows 98 to see what happens (take out the dbl quotes and paste into address bar)

It works perfectly in Windows 2000.

Here is the alternative I came up with using OLEAutomation: (note the use of URL Encoded is no longer necessary in the lcBody string. Just use regular CHR(13) or CR.) Note that this is also only a solution if you are using Outlook as your email client and know that it's installed. That's the biggest limitation I see over using Shell Execute. The msoutlook class is simply an OLE wrapper class I use that handles the GetObject/CreateObject and other stuff for me. You can do the same thing by just doing a CREATEOBJECT("Outlook.Application")


loOutlook = CREATEOBJECT("msoutlook")

* Create a new mail item
loMailItem = loOutlook.Do("CreateItem(0)")

WITH loMailItem
   .Recipients.Add(lcEmail)
   .Subject = "Order Confirmation for Priority No. "+ALLTRIM(STR(tsfile.pr_number,6,0))
   .Body = lcBody
   * Display Modal
   .Display(1)
   * May throw an error if user sent "Object has been moved"

   lcOnError = ON('ERROR')
   ON ERROR llSent = .T.
   llSent = .Sent
   ON ERROR &lcOnError
ENDWITH && loMailItem

loMailItem = .NULL.
loOutlook = .NULL.

IF llSent
	* Return normal success code that ShellExecute would return (for now)
	RETURN 42
ELSE
	* Returned user defined value
	RETURN -1
ENDIF


The only limitation I am seeing with this is that it sometimes does not bring the email window forward (even though I've made it modal) and it just stays flashing down on the task bar until the user clicks it. If someone has a solution for this, I would appreciate it. I'm thinking it's a Window State or something that can control this.
*// xEmail.prg
*// KIPDOLE
*//Thanks for the carriage return help I couldn't figure it out.  This may be of use.
*// Example xEmail([nobody@nobody.com],[nobodycc@nobody.com],[RE: Howdy],[blah blah blah]+CHR(13) + CHR(10) +[hi])

LPARAMETERS sMailto, sCC, sSubject, sBody, sBCC

IF EMPTY(sMailto)
  WAIT WINDOW "Email address is needed." NOWAIT
  RETURN .T.
ELSE
  sMailto = [mailto:] + sMailto + [?]
ENDIF
IF NOT EMPTY(sCC)
  sMailto = sMailto + [CC=] + sCC
ENDIF
IF NOT EMPTY(sSubject)
  sMailto = sMailto + [&SUBJECT=] + sSubject
ENDIF
IF NOT EMPTY(sBody)
    sMailto = sMailto + [&BODY=] + sBody
ENDIF
IF NOT EMPTY(sBCC)
    sMailto = sMailto + [&BCC=] + sBCC
ENDIF

DECLARE INTEGER ShellExecute IN "Shell32.dll" ;
    INTEGER hwnd, ;
    STRING lpVerb, ;
    STRING lpFile, ;
    STRING lpParameters, ;
    STRING lpDirectory, ;
    LONG nShowCmd


sMailto = STRTRAN(sMailto,[?&],[?])
sMailto = STRTRAN(sMailto,CHR(13),[%0D])
sMailto = STRTRAN(sMailto,CHR(10),[])

=Shellexecute(0,"Open",sMailto,"","",0)

Using Shell Execute from FPW
(this example opening a .jpg document. Of course long file names work because this is an external function.)

IF !'FOXTOOLS' $ SET('LIBRARY')
	SET LIBRARY TO SYS(2004)+'foxtools'
ENDIF
eshellex=regfn('ShellExecute', 'ICCCCI', 'I', 'SHELL.DLL')
=callfn(eshellex, 0, 0, 'c:\tmp\Milky_Way_galaxy_sun05.jpg', 0, 0, 1)

Any idea why I need "shell.dll" rather than "shell32.dll"? I guess it's a FPW 16bit thing but regfn() certainly can't find 'Shell Execute' without that.
Maybe this should be moved to ShellExecuteForEmail?
See Also: Win API, Category Automation Category Code Samples Category Windows API
Contributors: Randy Jean
( Topic last updated: 2005.09.13 10:00:32 AM )