*------Faxing With DDE-----------------------by Len Dozois-------- Len Dozois is the President of the ZAC Catalogs. ZAC publishes language-specific tools and add-on catalogs for Visual dBASE, CA-Clipper, Delphi and Visual Basic. Len is a long-time Clipper programmer who took to VdB like the proverbial "fish to water". Just a few months into VdB, Len has already delivered a Visual dBASE version of his catalog and is working on some pretty sophisticated EMail and fax utilties, as witness this article. Len can be contacted at the Zac Web Site: http//www.zaccatalog.com What Is DDE? DDE is an acronym for Dynamic Data Exchange. DDE is used to communicate and share information between different applications running in a Windows environment. Using DDE, the Client application requests or passes information to the Server application which acts upon the request. For example, you can write a Visual dBASE application (the Client) that establishes a DDE session with WinFax Pro (the Server) to automatically send fax messages from your application. Big Deal, You Say?... Yes, I know that WinFax Pro can be setup as a standard printer, and that your user can simply select it from within your VdB app, but that's not what DDE is all about. How many times do you think your user is going to be willing to sit there and click on Print, then fill in all of the information that WinFax needs to print a Fax, when they want to send a sales letter to all 1,500 names in their customer database? Now THAT’S what DDE is all about. The Basics Of A DDE Conversation... In order for a DDE conversation to take place, you have to establish a connection with the program that you want to use as the Server. This requires knowing the application or service name that is registered in the Windows environment. Fortunately, the Server's help file will usually tell you what name to use (it's usually the .EXE file name without the extension), VdB supplies a Class called DDELINK for working with DDE. Here is a summary stolen right from VdB's Help files: CLASS DDELink... Initiates and controls a DDE link between dBASE and a server application, allowing dBASE to send instructions and data-exchange requests to the server. DDE Servers have properties and methods much like Visual dBASE classes. For a full list of the available DDE properties, states and methods for WinFax Pro, check the longer version of this article on the VdDN Web Site: http://www.wji.com/vdb/homepage.html Let's take a look at a real world example: * WinFax.prg * Establishes a DDE link between a Visual dBASE application * (WinFax.prg) and WinFax Pro * Author: Len Dozois * First create a DDE object. The variable oFax will become the new * DDE object. The actual name oFax is not significant. I could have * called it xBananna. oFax=NEW DDELINK() && creates the DDE object * Now, set the state to CONTROL. Control is a WinFax topic. * A "topic" is just a fancy word for a state that the program you * are accessing understands and can relate to. Initiate() is a * method of the DDE class. FAXMNG is WinFax Pro's "official" DDE * name that is registered in the Windows environment. * I should point out that different applications understand and * respond to different Topics. The application's Help files or * manual is where you go to find out what Topics the applications * recognize. These examples are specific to WinFax. lAction=oFax.Initiate("FAXMNG","CONTROL") * Take modem off line so WinFax doesn't do anything stupid, like * answer the phone, while you're trying to set up your Fax. Execute * is a method of the DDE class that sends a command to your server. * "GoIdle" is a command that WinFax understands. lAction=oFax.Execute("GoIdle") * Set WinFax back to Transmit mode to create the queued event. * Transmit, like Control, is a state that WinFax can relate to. * We used the Initiate() method earlier to switch WinFax to the * Control state. Now we *want to switch it to the Transmit state, * so we initiate a new conversation. lAction=oFax.Initiate("FAXMNG","TRANSMIT") * Now that we have WinFax's attention, let's get down to business * and set up the fax, attachments and cover pages: * First, the coverpage: lAction=oFax.Poke("sendfax",'setcoverpage') * Since I didn't specify a coverpage with the setcoverpage command, * WinFax will use whatever I choose as the default when I set up * WinFax Pro. I could have passed a valid coverpage name as a fully * qualified string: C:\WINFAX\DATA\XYZ.CVR or whatever. * Now, let's fill the cover page. Note that WinFax will complete the * From, Date, Time, Page x of x stuff all by itself. We only need to * fill in the message, if any. lAction=oFax.Poke("sendfax",'fillcoverpage("Hi Len:"+chr(13)+; chr(10)+"I hope you are doing well! Here`s the stuff that you; asked me for")') * Now, let's set up the destination (recipient) information. This * is sort of like creating a comma delimited file in that WinFax * expects all of the data to be in the right place with the right * delimiters. You must pass all parameters (or at least a comma for * a place holder) up to the last parameter that you care about. * Any parameters after the last one that you care about need not be * passed. The complete string, if you pass all parameters looks like * this: Recipient("Fax Number", "Time", "Date", "Name", "Company",; "Subject", "Keywords", "Billing Code") * Fax Number Full fax number to be dialed (up to 47 characters) * Time Time to send the fax (hh:mm:ss) * Date Date to send the fax (mm/dd/yy) * Name Recipient's name (up to 29 characters) * Company Recipient's company name (up to 42 characters) * Subject Subject of the fax (up to 79 characters) * Keywords Event keywords (up to 33 characters) * Billing Code Event billing code (up to 26 characters) * In real life, all of the parameters except for the Fax Number * are optional. If you do not pass a time or date, * the Fax will be sent immediately. lAction=oFax.Poke("sendfax",'recipient("1-555-555-5555",,,; "Len Dozois","ZAC Catalogs","Test Message","Development",; "20321","Fax")') * OK. Notice that I passed three commas after the telephone number. * The first comma was the one that separates the phone number from * the Time. The next is the one that separates the time from the * date, and the last one is the one that separates the date from * the Company name. Since I didn't pass an actual time or date * string, the Fax goes out the chute as soon as I tell WinFax that * I'm all done sending data. * Now, let's set the resolution. I'll use HIGH resolution. I could * have passed LOW instead. lAction=oFax.Poke("Sendfax",'resolution("HIGH")') * Time to turn the modem back on because we're ready to send the * fax. lAction=oFax.Execute("GoActive") * Since the application is in control of WinFax, let's turn off * WinFax's default Send dialog. Change the "0" to "1" to show the * Send dialog if you want to force a manual send. lAction=oFax.Poke("sendfax",'showsendscreen("0")') * Now, this part varies depending upon what kind of document you are * sending. If it is already in FAX format, skip the printing part. * Otherwise, you have to turn an ASCII file into a Binary file that * WinFax understands. _pdriver='WinFax' * This makes sure that WinFax is the default printer for this print * job. See _pdriver in VdB's Help file for *more info on _pdriver. Set print on PrintJob Print h:\visualdbase\projects\email\temp.txt EndPrintJob Close Printer * Now let's tell WinFax Pro to attach the newly printed file lAction=oFax.Poke("sendfax", 'attach(H:\VISUALDB\EMAIL\TEMP.TXT') * Send it on its way lAction=oFax.Execute("SendFax") * Now close the DDE channel to WinFax lAction=oFax.Terminate() * And release the oFax object. oFax.Release() Well, if you followed the above EXACTLY, your phone should be complaining that there is no Area Code 555 anywhere in the world. However, if you changed the number to a real Fax phone number, your Fax should be winging it's way to some lucky person. This all assumes, of course, that you had a Temp.txt file to print and send. Bringing It All Together Visual dBASE provides a quick and easy way to take advantage of all the power that DDE has to offer. Just remember that you are actually programming in two languages. You are using Visual dBASE’s language to access the DDE commands via the DDELINK class and the Server's own language to activate the actual command. Just to show you another example, here's a DDE session that I run with Beyond Mail, my Internet mail reader. The following code is attached to a PushButton that exports names from my mailing list, attaches a letter, and sends the whole thing out the Internet to ZAC Catalog customers that have requested to be put on our automatic "New Product" update list. I didn't comment every line of code, the point here is to show you how Topics and commands vary between applications. Beyond Mail has a MAIL topic and uses commands like RunAction. The only thing in common with the WinFax example is the fact that the Visual dBASE DDELINK methods never change! Procedure EXPORTBUTTON_OnClick LOCAL LinkObj, X,cText,cSubj,cSendTo,cFirst select register && my Registration database go top IF MSGBOX("Are You Sure?","Export Names",4+32)=6 LinkObj = NEW DDELINK() IF .not. LinkObj.Initiate("BMAILW","MAIL") Release linkObj, X,cText,cSubj,cSendTo,cFirst MSGBOX("Connection to Beyond Mail Failed","Notice",0) Return ENDIF cText=Letters->letter && a Memo Field in Letters.dbf x=fcreate('temp.txt',"RW") && write the Memo data to temp file fput(x,cText) fclose(x) cSubj=letters->subject Do while .not. eof() && walk through every name in Register.dbf cSendTo=register->email cFirst=iif(.not. empty(register->first),trim(register->first),; 'ZAC Web Site Visitor') lAction=LinkObj.Execute('RunAction(create "Memo" message as WebResponse; set [To] on WebResponse to "&cSendTo"; set [Subject] on WebResponse to "&SUBJ";insert text "Dear &cFirst.," into WebResponse;insert text " "into WebResponse;insert file temp.txt into WebResponse; send WebResponse;)') If .not. lAction MSGBOX("Message to &cSendTo. Failed”,"Notice",0) Replace Failed with .T. Else Replace failed with .f. Endif Skip Enddo lAction=LinkObj.Terminate() lAction=LinkObj.Release() Endif Select Register Go Top Release linkObj, X,cText,cSubj,cSendTo,cFirst Return