I require some work done - eMail Merge Feature

User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Hello Ollie,

This is my code.

I create a TXT file in my Fivewin program.

In Word I create a mail merge doc template (I hope this is the right name) and connect this to the data file, my txt file.

From the original template doc (docx) I always make a copy with Fivewin so that the user works with the copy.
With winexec() I call WORD and as parameter I pass the doc-file name.

Then the mass email I send with the option from WORD.

The STRTRAN I do to be sure that there are no wrong characters in the recipients file.

Regards,
Otto
First line in the Text file:
hStrg:= 'BRIEFANREDE; ... ;ORT;TELEFONNR;TELEFAXNR'

nHandle :=fopen( cDoc, O_READWRITE+S_EXCLUSIVE)
select mailing
go top
do while .NOT. Eof()
hStrg:= ;
(STRTRAN(ALLTRIM(mailing->email ), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->KATEGORIE), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->ANREDE), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->NAME), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->VORNAME), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->ZUSATZ), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->STRASSE), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->LKZ), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->PLZ), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->telefonnr ), ";","," ))+";"+;
(STRTRAN(ALLTRIM(mailing->telefax ), ";","," ))

text := fwrite(nHandle, hStrg + CRLF,)

Skip
enddo
Ollie
Posts: 233
Joined: Sat Dec 30, 2006 6:10 am

Post by Ollie »

In Word I create a mail merge doc template (I hope this is the right name) and connect this to the data file, my txt file.
Please can you clarify what you mean by "connect this" - what is in your txt file? : hStrg:= 'BRIEFANREDE; ... ;ORT;TELEFONNR;TELEFAXNR'
? I don't follow.
With winexec() I call WORD and as parameter I pass the doc-file name.
Can you show me this line of code?
Then the mass email I send with the option from WORD.
I know WORD can send email, but how do you invoke it?

Once you are sure that there are no wrong characters in the cDoc file - what do you do with it then?

I need help with the invoking of Word and making it do all these things. I assume the mail merge doc template looks for the TXT file containing your data. So does this TXT file always have the same name so that Word doesn't say "Data file not found"?

Thanks for the help so far.
Many thanks
Ollie.

Using:
xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6406)
Borland C++ 5.5.1
FWH 9.04 (2009 Apr)
Ollie
Posts: 233
Joined: Sat Dec 30, 2006 6:10 am

Post by Ollie »

WORDREPLACE( oSel, "<toreplace>", "Giordano Enrico Maria" )

oWord:Visible = .T.

RETURN NIL


FUNCTION WORDREPLACE( oSel, cSrc, cRpl )

oSel:Start = 0
oSel:End = -1

oSel:Find:Execute( cSrc )

oSel:Range:Text = cRpl

RETURN NIL
When there is no "<toreplace>" in the Word Doc, it places "Giordano Enrico Maria" at the beginning of the file.

How can one check to see if "<toreplace>" is in the document and only if it is, - WORDREPLACE( oSel, "<toreplace>", "Giordano Enrico Maria" )

i.e.
IF "<toreplace>" $ oSel??
WORDREPLACE( oSel, "<toreplace>", "Giordano Enrico Maria" )
ENDIF

(or the check could be done in the WORDREPLACE() function.) - But whats the syntax?[/quote]
Many thanks
Ollie.

Using:
xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6406)
Borland C++ 5.5.1
FWH 9.04 (2009 Apr)
Ollie
Posts: 233
Joined: Sat Dec 30, 2006 6:10 am

Post by Ollie »

It would be perfect if it could work like this:

1. Put your own merge codes in the WORD doc e.g. <<SURNAME>> or <<ALLTRIM(FIRSTNAME)>> (I just chose << >> - there is no special meaning)

2. Search the word DOC for the data between << and >>

3. Then Replace <<SURNAME>> with your data e.g. "Ollewagen "
and <<ALLTRIM(FIRSTNAME)>> with "Ollie"
Many thanks
Ollie.

Using:
xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6406)
Borland C++ 5.5.1
FWH 9.04 (2009 Apr)
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Hello Ollie,

I did this but you have to use RTF format.
Since WORD 2000 ??? RTF format in WORD has a bug which MS never solved. Pictures are not stored as a link. All the code of a picture is inside the RTF doc. Now with harbour such a big document - sometimes many MB - would not be a problem but search/replace would be slow.

Then I tried with htm-format and word. But the users want pure word and all the functionality.

I can’t remember well but I think also WORDREPLACE is slow if you have many placeholders.

Therefore I use the original mail merge function of word.

I am sorry I can’t post the FW code because this part is still VB6.

But I post this maybe we can transform it.

To create a template – which the user can modify from within WORD I use:

(cDatenQuelle = recipients)
This is how a recipients file looks. It is a TXT file ASCII.
ANREDE;NAME;VORNAME;STRASSE;LKZ;PLZ;ORT;ANZHG;DATUM;COMBO;BRIEFANREDE;TITEL;FIRMA1;FIRMA2
An;DEMO;HANS;PDEMOstTR. 25;A;1020;WIEN;150.00;10.06.2008;Scheck;Sehr geehrte Frau TEST;;;

Code: Select all

word.Documents.Add DocumentType:=wdNewBlankDocument
                word.ActiveDocument.SaveAs FileName:=cDatei, FileFormat:=wdFormatDocument, LockComments:=False, Password:="", AddToRecentFiles:=True, WritePassword _
                        :="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
                        SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:=False

                word.ActiveDocument.MailMerge.MainDocumentType = wdFormLetters

                word.ActiveDocument.MailMerge.OpenDataSource Name:=cDatenQuelle _
                        , ConfirmConversions:=False, READONLY:=False, LinkToSource:=True, _
                        AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
                        WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
                        Format:=wdOpenFormatAuto, Connection:="", SQLStatement:="", SQLStatement1 _
                        :=""

                word.ActiveDocument.MailMerge.EditMainDocument

                word.ActiveDocument.MailMerge.OpenDataSource Name:=cDatenQuelle

                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="ANREDE"
                word.Selection.TypeParagraph
                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="NAME"
                word.Selection.TypeText Text:=" "
                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="VORNAME"
                word.Selection.TypeParagraph
                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="STRASSE"
                word.Selection.TypeParagraph
                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="LKZ"
                word.Selection.TypeText Text:="-"
                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="PLZ"
                word.Selection.TypeText Text:=" "
                word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="ORT"
                word.Selection.TypeParagraph
                word.Selection.TypeParagraph
                word.Selection.TypeParagraph
                word.Selection.TypeParagraph

                word.Selection.MoveUp Unit:=wdLine, Count:=10
                word.Selection.HomeKey Unit:=wdLine
                word.Selection.TypeParagraph
                word.Selection.TypeParagraph
                word.Selection.TypeParagraph
                word.Selection.TypeParagraph

To merge and send only a single letter:

Code: Select all

Documents.Open FileName:=cDatei, ConfirmConversions:=False, READONLY _
                        :=False, AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate _
                        :="", Revert:=False, WritePasswordDocument:="", WritePasswordTemplate:="" _
                        , Format:=wdOpenFormatAuto
         
               word.Visible = False
                word.ScreenUpdating = False
                word.DisplayAlerts = False

   With word.ActiveDocument.MailMerge

   .OpenDataSource Name:=cDatenQuelle


   
                 With .DataSource
                        .FirstRecord = 1
                        .LastRecord = 1
                    End With


                    .Execute Pause:=True


‘ This saves the merged letter to disk if you need it later.


                    word.ActiveDocument.SaveAs FileName:=PfadAblage + "anf" + Trim(Str(nbriefnr))

                End With

‘ This part closes the original and brings the merged document to  foreground and closes the original.
I found out that the user has to work with a copy otherwise you always have to assist setting up the letters.

                docFound = True
                For Each aDoc In Documents
                    If InStr(1, aDoc.Name, cOriginal, 1) Then
                        aDoc.Activate
                        ActiveDocument.Close (wdDoNotSaveChanges)
                        docFound = True
                        Exit For
                    Else
                        docFound = False
                    End If
                Next aDoc            word.DisplayAlerts = True
            word.ScreenUpdating = True
            word.Visible = True

‘ If you want to send as email.

            If lEmail = True Then
                word.ActiveWindow.EnvelopeVisible = True
            Else
                word.ActiveDocument.ActiveWindow.EnvelopeVisible = False
            End If

            Set word = Nothing


To send mass letters:
This opens word with the prepared letter.
To invoke I use the menu of WORD.

Code: Select all

    word.Documents.Open cDatei
            word.Visible = True
            Set word = Nothing
This is the same in VB6 what Enrico posted for FW.

Maybe with the help of the group we can transform the code to Fivewin.
Thanks in advance
Otto
User avatar
Enrico Maria Giordano
Posts: 7355
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Contact:

Post by Enrico Maria Giordano »

Ollie wrote:When there is no "<toreplace>" in the Word Doc, it places "Giordano Enrico Maria" at the beginning of the file.

How can one check to see if "<toreplace>" is in the document and only if it is, - WORDREPLACE( oSel, "<toreplace>", "Giordano Enrico Maria" )

Code: Select all

FUNCTION WORDREPLACE( oSel, cSrc, cRpl )

    LOCAL lOk

    oSel:Start = 0; oSel:End = -1

    lOk = oSel:Find:Execute( cSrc )

    IF lOk; oSel:Range:Text = cRpl; ENDIF

    RETURN lOk
EMG
Ollie
Posts: 233
Joined: Sat Dec 30, 2006 6:10 am

Post by Ollie »

This works very nicely:

First make the data file that Word will merge with

Code: Select all

//Create the Datafile for the merge 
NETUSE("DBMAIN")
    SET FILTER TO Surname="Ackerman" //Just to test
    DBMAIN->(DBGOTOP())
    cFilename:="c:\mydata.txt"
    FERASE(cFilename)
    WriteLine("Surname;First Name;Email", cFilename ) //A function that writes the text at the end of cFilename
    DO WHILE !EOF()
       WriteLine(ALLTRIM(DBMAIN->Surname)+";"+ALLTRIM(FirstName)+";"+ALLTRIM(Email), cFilename )
       DBMAIN->(DBSKIP(1))
    ENDDO
    CLOSE DBMAIN
This could be a function to let the user make his Word file and has the ability to insert his Merge fields:

Code: Select all

    MSGINFO("Now make your letter")
    oWord := CREATEOBJECT( "Word.Application" )
    oDoc := oWord:Documents:Add() //Makes new doc.
    oDoc:MailMerge:MainDocumentType:=0 //wdFormLetters=0  // sets the mail merge main document type
    oDoc:MailMerge:EditMainDocument()
    oDoc:MailMerge:OpenDataSource(cfilename)
    oWord:Visible = .T.
You could then have another function that takes that user's word doc and does the merge and emails it off:

Code: Select all

    cLetter := cGetFile( "*.DOC", "Select a Letter", 1, ".\Letters\", .F., .T. )

    oWord := CREATEOBJECT( "Word.Application" )

    IF FILE(cLetter)
       oDoc := oWord:Documents:Open( cLetter )
    ENDIF
    oDoc:MailMerge:MainDocumentType:=0 //wdFormLetters=0  // sets the mail merge main document type
    oDoc:MailMerge:EditMainDocument()
    oDoc:MailMerge:Destination:=2 //wdSendToEmail = 2   //See Word Enumerated Constants: http://msdn.microsoft.com/en-us/library/aa211923.aspx
    oDoc:MailMerge:SuppressBlankLines:=.T.
    oDoc:MailMerge:DataSource:FirstRecord:=1 //    wdDefaultFirstRecord = 1
    oDoc:MailMerge:DataSource:LastRecord:=-16 //wdDefaultLastRecord = -16
    oDoc:MailMerge:MailAddressFieldName = "EMAIL"
    oDoc:MailMerge:MailSubject = "Email sent at: "+TIME()
    oWord:ActiveDocument:MailMerge:Execute(.F.) // Pause:=False
    oDoc:Close( 0 )
    oWord:Quit()
Thanks Enrico and Otto for putting me on the right track.
Many thanks
Ollie.

Using:
xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6406)
Borland C++ 5.5.1
FWH 9.04 (2009 Apr)
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Ollie,

Super. Thank you for your feedback. I tested your functions and they work well.
So I will convert my VB6 part to Fivewin.
Thank you.

Regards,
Otto
User avatar
RAMESHBABU
Posts: 591
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Post by RAMESHBABU »

Mr.Ollie/Mr.Otto,

Can you please post a full working sample here.

Thanks

- Ramesh Babu P
User avatar
dutch
Posts: 1395
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Post by dutch »

Dear Ollie&Otto,

Could you shared me too?

Thanks,
Dutch
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Hello dutch, hello Rameshbabu,

Till now I used VB6 to work with WORD. Therefore I have no
ready application. I only did some tests.

This is what I tried so far.
Not much but maybe it is of some help for starters.

Regards,
Otto

Image


My dataSource steuer.doc
EMAIL@KATEGORIE@ANREDE@NAME@LANDFELD@VORNAME@ZUSATZ@STRASSE@LKZ@PLZ@ORT@BRIEFANRED@TITEL@Z_HD@FIRMA@BEGLEITUNG@KIND1@KIND2@KIND3@KIND4@TELEFON@FAX
KURT,HÖLZL.lkz@SOMMER@An@HÖLZL@@KURT@@ROSENGASSE 11@A@1090@WIEN@Sehr geehrte Frau HÖLZL@@@@@@@@@1090@1090

Code: Select all

#include "FiveWin.ch"
#include "InKey.ch"
#include "xbrowse.ch"

STATIC aInhalt := {}
//----------------------------------------------------------------------------//

function Main()
   LOCAL oWnd
   LOCAL oBrw, oCol
   LOCAL oFnt
   LOCAL oBar

   aInhalt := directory("*.doc*","D")

   DEFINE FONT oFnt NAME "ARIAL" SIZE 6 ,15 BOLD

   DEFINE WINDOW oWnd TITLE "Serienbrief"  ;
      FROM 0,0 TO 800,1024 PIXEL

   oWnd:SetFont(oFnt)

   //substr(oBrw:aArrayData[oBrw:nArrayAt,1],1,( len(oBrw:aArrayData[oBrw:nArrayAt,1])-4)  )

   oBar := TBar():New( oWnd, 65, 65, .T.,"TOP", )

   oBar:l2007 = .T.

   DEFINE BUTTON FILE "new.bmp"  OF oBar ;
      ACTION (makedoc(oBrw),;
      ASIZE(aInhalt,0)  ,;
      aInhalt := directory("*.doc*","D"),;
      oBrw:SetArray( ainHalt,  .T. ),;
      oBrw:refresh()) ;
      PROMPT "Serienbrief"+CRLF+"erstellen"

   DEFINE BUTTON FILE "compile.bmp"  OF oBar ;
      ACTION mailsend(oBrw);
      PROMPT "Email" + CRLF + "senden"

   DEFINE BUTTON FILE "end.bmp"  OF oBar ;
      ACTION oWnd:end();
      PROMPT "Ende"


   oBrw := TXBrowse():New( oWnd )
   oBrw:nTop    := 80
   oBrw:nLeft   := 20
   oBrw:nBottom := 600
   oBrw:nRight  := 400

   oBrw:SetArray( ainHalt,  .T. )
   oBrw:aCols[1]:cHeader := 'Source'
   oBrw:aCols[1]:nWidth  := 157

   oBrw:aCols[2]:cHeader := 'Size'
   oBrw:aCols[3]:cHeader := 'Date'

   oBrw:nMarqueeStyle    := MARQSTYLE_HIGHLROW
   oBrw:nRowDividerStyle := 4

   oBrw:lRecordSelector  := .t.

   //oBrw:bChange := {||          }
   //oBrw:bLDblClick := {||  }
   //oBrw:bKeyDown := {|nkey| iF( nkey = 13, test( oBrw ), ) }

   oBrw:lHScroll := .f.

   oBrw:CreateFromCode()

   ACTIVATE WINDOW oWnd

return nil

func makedoc(oBrw)
   LOCAL cDatei           :=""
   LOCAL oDoc
   LOCAL oWord
   LOCAL cfileDataSource  := "steuer.doc"
   LOCAL suchbeg          := space(30)
   LOCAL cAppPath         := ""

   cAppPath         := cFilePath( GetModuleFileName( GetInstance( ) ) )
   cfileDataSource  := cAppPath+"steuer.doc"

   if MsgGet( "Name:", "Name eingeben", @suchbeg,".\bitmaps\lupa.bmp" )

      cDatei  := cAppPath + ALLTRIM(suchbeg)    //WORD 2007
      msginfo(cDatei)

      oWord := CREATEOBJECT( "Word.Application" )

      oDoc := oWord:Documents:Add()             //Makes new doc.

      oDoc:SaveAs(cDatei)

      oDoc:MailMerge:MainDocumentType:=0        //wdFormLetters=0  // sets the mail merge main document type
      oDoc:MailMerge:EditMainDocument()
      oDoc:MailMerge:OpenDataSource(cfileDataSource)

      oWord:selection:TypeText("Prototype")
      oWord:selection:TypeParagraph()           // new line
      oWord:selection:TypeParagraph()           // new line
      oDoc:mailMerge:Fields:add(oWord:selection:range , "EMAIL")
      oWord:selection:TypeParagraph()           // new line
      oWord:selection:TypeParagraph()           // new line

      oDoc:mailMerge:Fields:add(oWord:selection:range , "ANREDE")

      oDoc:mailMerge:Fields:add(oWord:selection:range , "TITEL")
      oWord:selection:TypeText(" ")             // space between first and last name
      oDoc:mailMerge:Fields:add(oWord:selection:range , "VORNAME")

      oDoc:mailMerge:Fields:add(oWord:selection:range , "NAME")
      oWord:selection:TypeText(" ")             // space between first and last name

      oWord:selection:TypeParagraph()           // new line

      oDoc:mailMerge:Fields:add(oWord:selection:range , "STRASSE")
      oWord:selection:TypeParagraph()           // new line
      oDoc:mailMerge:Fields:add(oWord:selection:range , "PLZ")
      oWord:selection:TypeParagraph()           // new line
      oDoc:mailMerge:Fields:add(oWord:selection:range , "ORT")
      oWord:selection:TypeParagraph()           // new line
      oDoc:mailMerge:Fields:add(oWord:selection:range , "LANDFELD")
      oWord:selection:TypeParagraph()           // new line
      oWord:selection:TypeParagraph()           // new line
      oWord:selection:TypeParagraph()           // new line
      oWord:selection:TypeParagraph()           // new line

      oDoc:mailMerge:Fields:add(oWord:selection:range , "BRIEFANRED")
      oWord:selection:TypeParagraph()           // new line

      oWord:Visible = .T.
   endif
return nil

func mailsend(oBrw)
   LOCAL cLetter   := ""
   LOCAL oWord
   LOCAL cAppPath   :=""
   LOCAL oDoc

   if oBrw:aArrayData[oBrw:nArrayAt,1] <> "steuer.doc"

      cAppPath   := cFilePath( GetModuleFileName( GetInstance( ) ) )
      cLetter    := ALLTRIM(cAppPath +  oBrw:aArrayData[oBrw:nArrayAt,1])
      msginfo(cLetter)
      oWord := CREATEOBJECT( "Word.Application" )

      IF FILE(cLetter)
         oDoc := oWord:Documents:Open( cLetter )
         oWord:Visible = .T.

         oDoc:MailMerge:MainDocumentType:=0     //wdFormLetters=0  // sets the mail merge main document type

         //.OpenDataSource Name:=cDatenQuelle

         oDoc:MailMerge:EditMainDocument()
         // oDoc:MailMerge:Destination:=2                    //wdSendToEmail = 2   //See Word Enumerated Constants: http://msdn.microsoft.com/en-us/library/aa211923.aspx
         oDoc:MailMerge:SuppressBlankLines:=.T.
         oDoc:MailMerge:DataSource:FirstRecord:=1 //wdDefaultFirstRecord = 1
         oDoc:MailMerge:DataSource:LastRecord:=-16 //wdDefaultLastRecord = -16
         // oDoc:MailMerge:MailAddressFieldName = "EMAIL"
         //  oDoc:MailMerge:MailSubject = "Email sent at: "+TIME()
         oWord:ActiveDocument:MailMerge:Execute(.T.) // Pause:=False
         //oDoc:Close( 0 )
      ENDIF
      //oWord:Quit()
   else
      msginfo("kein Serienbrief")
   endif
return nil
Ollie
Posts: 233
Joined: Sat Dec 30, 2006 6:10 am

Post by Ollie »

I let the user "create" a Doc file linked to the data I produce.
I also let him Edit the page
I also let him merge the data to email or a new document.

Code below:

Code: Select all

// ******************************************************************************************************
FUNCTION MSWORD_NEW( cAlias )
   //This creates a new Word Doc that has the link to the data
   LOCAL oDlg, oWord, oDoc
   LOCAL cDataFile, cFilename := SPACE( 200 )
   LOCAL cStr, i, cSubDir
   LOCAL lOK := .F.
   LOCAL lInuse := SELECT( cAlias ) <> 0

   DEFINE DIALOG oDlg RESOURCE "DOCUMENT_NEW"
   REDEFINE GET cFilename ID 10 OF oDlg UPDATE
   REDEFINE BUTTON ID 30 OF oDlg DEFAULT ACTION ( lOK := .T. , oDlg:END() )
   REDEFINE BUTTON ID 40 OF oDlg ACTION oDlg:END()
   ACTIVATE DIALOG oDlg CENTER VALID ( lOK )

   //Take any illegal characters out of cFilename
   cFilename := STRTRAN( cFilename, "\", "" )
   cFilename := STRTRAN( cFilename, "/", "" )
   cFilename := STRTRAN( cFilename, ":", "" )
   cFilename := STRTRAN( cFilename, "*", "" )
   cFilename := STRTRAN( cFilename, "?", "" )
   cFilename := STRTRAN( cFilename, "<", "" )
   cFilename := STRTRAN( cFilename, ">", "" )
   cFilename := STRTRAN( cFilename, "|", "" )

   IF lOK .AND. ! EMPTY( cFilename )
      cSubDir := ALLTRIM( defpath() ) + "Documents\" + ALLTRIM( cAlias )
      IF ! IsDirectory( cSubDir )
         i := MakeDir( cSubDir )
         IF i == 0
            //? "Directory", cSubDir, "successfully created"
         ELSEIF i == 5
            ? "Folder already exists: ", cSubDir
         ELSE
            ? "Error creating folder: ", cSubDir, "OS Error: " + LTrim( Str( i ) )
            lOK := .F.
         ENDIF
      ENDIF

      IF lOK = .T.

         cFilename := ALLTRIM( cSubDir + "\" + ALLTRIM( cFilename ) )
         //? cFilename

         IF ! lInuse
            NETUSE( cAlias )
         ENDIF


         cDataFile := NEEDFILE( "TXT" )
         //? cDataFile

         MSWORD_CREATEDATA( cDataFile, cAlias )

         //WINEXEC("TASKKILL /F /IM WINWORD.EXE") //Kill any Existing WINWORD.EXE - when this crashes, the process is left open.
         //INKEY(2) //Wait a bit

         IF ! lInuse
            ( cAlias ) ->( DBCLOSEAREA() )
         ENDIF

         //Create a new doc that has the merge fields
         //MSGINFO( "Now make your letter" )
         oWord := CREATEOBJECT( "Word.Application" )
         oDoc := oWord:Documents:Add() //Makes new doc.
         oDoc:MailMerge:MainDocumentType := 0 //wdFormLetters=0  // sets the mail merge main document type
         oDoc:MailMerge:EditMainDocument()
         oDoc:MailMerge:OpenDataSource( cDataFile )
         //VB6:
         //word.ActiveDocument.SaveAs FileName:=cDatei, FileFormat:=wdFormatDocument, LockComments:=False, Password:="", AddToRecentFiles:=True, WritePassword _
         //                  :="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
         //                  SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:=False
         //Method:
         //SaveAs(FileName, FileFormat, LockComments, Password, AddToRecentFiles, WritePassword, ReadOnlyRecommended, EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter)
         oDoc:SaveAs( cFilename, 0, .F., "", .T., "", .F., .F., .F., .F., .F. ) //wdFormatDocument = 0
         oWord:Visible = .T.
         //oDoc:PrintOut( .F. ) - Method
      ENDIF
   ENDIF
   RETURN



   // ******************************************************************************************************
// ******************************************************************************************************
// ******************************************************************************************************
// ******************************************************************************************************
// ******************************************************************************************************
FUNCTION MSWORD_EDIT( cAlias )
   LOCAL oSel
   LOCAL oWord
   LOCAL oDoc
   LOCAL cSubDir := ALLTRIM( defpath() ) + "Documents\" + ALLTRIM( cAlias )
   LOCAL lInuse := SELECT( cAlias ) <> 0
   LOCAL cDatafile, cDocument

   //oDoc:PrintOut( .F. ) - Method
   //WINEXEC("TASKKILL /F /IM WINWORD.EXE") //Kill any Existing WINWORD.EXE - when this crashes, the process is left open.
   //INKEY(2) //Wait a bit

    /*
    //Create a new doc that has the merge fields
    MSGINFO("Now make your letter")
    oWord := CREATEOBJECT( "Word.Application" )
    oDoc := oWord:Documents:Add() //Makes new doc.
    oDoc:MailMerge:MainDocumentType:=0 //wdFormLetters=0  // sets the mail merge main document type
    oDoc:MailMerge:EditMainDocument()
    oDoc:MailMerge:OpenDataSource(cfilename)
    oWord:Visible = .T.
    */

   cDocument := cGetFile( "*.DOC", "Select a Document", 1, cSubDir, .F., .T. )


   IF FILE( cDocument )
      IF ! lInuse
         NETUSE( cAlias )
      ENDIF

      cDatafile := NEEDFILE( "TXT" )
      MSWORD_CREATEDATA( cDatafile, cAlias, "1" ) //Just create one word.

      IF ! lInuse
         ( cAlias ) ->( DBCLOSEAREA() )
      ENDIF

      oWord := CREATEOBJECT( "Word.Application" )
      //oDoc := oWord:Documents:Open( "C:\FWH\_MyProgs\PGA\Bin\Letters\TEST.doc" )
      oDoc := oWord:Documents:Open( cDocument )

      //word.Documents.Add DocumentType:=wdNewBlankDocument
      //oDoc:Range:InsertAfter( "<toreplace>" + CHR( 13 ) )   //Types this in the DOC
      //oDoc:Select()  //Selects ALL document
      //oSel = oWord:Selection
      //WORDREPLACE( oSel, "<toreplace>", "Giordano Enrico Maria" )
      //oDoc:SaveAs("mm") //Saves the file as mm.docx

      //VB6:
      //word.ActiveDocument.SaveAs FileName:=cDatei, FileFormat:=wdFormatDocument, LockComments:=False, Password:="", AddToRecentFiles:=True, WritePassword _
      //                  :="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
      //                  SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:=False
      //Method:
      //SaveAs(FileName, FileFormat, LockComments, Password, AddToRecentFiles, WritePassword, ReadOnlyRecommended, EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter)

      //oDoc:SaveAs("My Letter",0,.F.,"",.T.,"",.F.,.F.,.F.,.F.,.F.) //wdFormatDocument = 0

      //VB6:
      //word.ActiveDocument.MailMerge.MainDocumentType = wdFormLetters
      //Method: ??
      oDoc:MailMerge:MainDocumentType := 0 //wdFormLetters=0  // sets the mail merge main document type

      //VB6:
      //word.ActiveDocument.MailMerge.OpenDataSource Name:=cDatenQuelle _
      //                    , ConfirmConversions:=False, READONLY:=False, LinkToSource:=True, _
      //                    AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
      //                    WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
      //                    Format:=wdOpenFormatAuto, Connection:="", SQLStatement:="", SQLStatement1 _
      //                    :=""
      //oDoc:MailMerge:OpenDataSource("c:\testdata.txt")

      //VB6:
      //word.ActiveDocument.MailMerge.EditMainDocument
      oDoc:MailMerge:EditMainDocument()

      //VB6:
      //word.ActiveDocument.MailMerge.OpenDataSource Name:=cDatenQuelle
      oDoc:MailMerge:OpenDataSource( cDatafile ) //"c:\moredata.txt")

      //VB6:
      //word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="ANREDE"
      //oDoc:MailMerge:Fields:Add(oDoc:Range(),"ANREDE")

      //VB6:
      //word.Selection.TypeParagraph
      //oWord:Selection:TypeParagraph()

      //VB6:
      //word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="NAME"
      //oWord:ActiveDocument:MailMerge:Fields:Add(oDoc:Range(),"NAME")

      //VB6:
      //word.Selection.TypeText Text:=" "
      //oWord:Selection:TypeText("This is some text")

      //VB6:
      //With ActiveDocument.MailMerge
      //    .Destination = wdSendToEmail
      //    .SuppressBlankLines = True
      //    With .DataSource
      //        .FirstRecord = wdDefaultFirstRecord
      //        .LastRecord = wdDefaultLastRecord
      //    End With
      //    .Execute Pause:=False
      //End With

      oDoc:MailMerge:Destination := 0
      //wdSendToEmail = 2   //See Word Enumerated Constants: http://msdn.microsoft.com/en-us/library/aa211923.aspx
      //wdSendToFax  3
//wdSendToNewDocument  0
//wdSendToPrinter  1

      oDoc:MailMerge:SuppressBlankLines := .T.
      oDoc:MailMerge:DataSource:FirstRecord := 1 //    wdDefaultFirstRecord = 1
      oDoc:MailMerge:DataSource:LastRecord := - 16 //wdDefaultLastRecord = -16
      oDoc:MailMerge:MailAddressFieldName = "EMAIL"
//      oDoc:MailMerge:MailSubject = "Email sent at: " + TIME()
//      oWord:ActiveDocument:MailMerge:Execute( .F. ) // Pause:=False


      //oWord:Visible = .T. //Makes Word active window

      //oDoc:Close( 0 )

      //oWord:Quit()

      //oDoc:Select()

      //oSel = oWord:Selection

      //WORDREPLACE( oSel, "<amount", "R 10.00" )

      //WORDREPLACE( oSel, "<name>", "Elaine" )

      oWord:Visible = .T.

      //oDoc:Close( 0 )

      //oWord:Quit()
   ENDIF //file not found


   RETURN NIL
// ******************************************************************************************************
FUNCTION MSWORD_MERGE( cAlias )
   LOCAL oSel, oWord, oDoc, oDlg
   LOCAL cSubDir := ALLTRIM( defpath() ) + "Documents\" + ALLTRIM( cAlias )
   LOCAL lInuse := SELECT( cAlias ) <> 0
   LOCAL cDatafile, cDocument := ""
   LOCAL cFilter := ""
   LOCAL cSubject := SPACE( 100 )
   LOCAL nDocOrEmail := 1
   LOCAL lOk := .F.
   LOCAL lCancelled:=.F.

    IF ! lInuse
         NETUSE( cAlias ) //For the Filter Function
      ENDIF


   DEFINE DIALOG oDlg RESOURCE "DOCUMENT_MERGE"
   REDEFINE BUTTON ID 4007 OF oDlg ACTION ( cDocument := cGetFile( "*.DOC", "Select a Document", 1, cSubDir, .F., .T. ) ,oDlg:UPDATE())
   REDEFINE SAY PROMPT cDocument ID 4001 OF oDlg UPDATE
   REDEFINE BUTTON ID 4006 OF oDlg ACTION ( Filter( cAlias ), cFilter:=(cAlias)->(DBFILTER()) ,oDlg:UPDATE())
   REDEFINE SAY PROMPT cFilter ID 4005 OF oDlg UPDATE
   REDEFINE RADIO nDocOrEmail ID 4003, 4004 OF oDlg UPDATE //ON CHANGE (oDlg:UPDATE())
   REDEFINE GET cSubject ID 4008 OF oDlg UPDATE WHEN (nDocOrEmail = 2)
   REDEFINE BUTTON ID 30 OF oDlg DEFAULT ACTION ( lOk := Validate_Merge( cDocument, cFilter,nDocOrEmail,cSubject ) , oDlg:END() )
   REDEFINE BUTTON ID 40 OF oDlg ACTION (lCancelled:=.T.,lOk:=.T.,oDlg:END())
   ACTIVATE DIALOG oDlg CENTER VALID ( lOk )

    IF ! lInuse
         ( cAlias ) ->( DBCLOSEAREA() )
      ENDIF


   //oDoc:PrintOut( .F. ) - Method
   //WINEXEC("TASKKILL /F /IM WINWORD.EXE") //Kill any Existing WINWORD.EXE - when this crashes, the process is left open.
   //INKEY(2) //Wait a bit

    /*
    //Create a new doc that has the merge fields
    MSGINFO("Now make your letter")
    oWord := CREATEOBJECT( "Word.Application" )
    oDoc := oWord:Documents:Add() //Makes new doc.
    oDoc:MailMerge:MainDocumentType:=0 //wdFormLetters=0  // sets the mail merge main document type
    oDoc:MailMerge:EditMainDocument()
    oDoc:MailMerge:OpenDataSource(cfilename)
    oWord:Visible = .T.
    */
   IF lOk == .T. .AND. lCancelled == .F.

      IF ! lInuse
         NETUSE( cAlias )
      ENDIF

      cDatafile := NEEDFILE( "TXT" )
      MSWORD_CREATEDATA( cDatafile, cAlias , cFilter )

      IF ! lInuse
         ( cAlias ) ->( DBCLOSEAREA() )
      ENDIF

      oWord := CREATEOBJECT( "Word.Application" )
      //oDoc := oWord:Documents:Open( "C:\FWH\_MyProgs\PGA\Bin\Letters\TEST.doc" )
      oDoc := oWord:Documents:Open( cDocument )

      //word.Documents.Add DocumentType:=wdNewBlankDocument
      //oDoc:Range:InsertAfter( "<toreplace>" + CHR( 13 ) )   //Types this in the DOC
      //oDoc:Select()  //Selects ALL document
      //oSel = oWord:Selection
      //WORDREPLACE( oSel, "<toreplace>", "Giordano Enrico Maria" )
      //oDoc:SaveAs("mm") //Saves the file as mm.docx

      //VB6:
      //word.ActiveDocument.SaveAs FileName:=cDatei, FileFormat:=wdFormatDocument, LockComments:=False, Password:="", AddToRecentFiles:=True, WritePassword _
      //                  :="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
      //                  SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:=False
      //Method:
      //SaveAs(FileName, FileFormat, LockComments, Password, AddToRecentFiles, WritePassword, ReadOnlyRecommended, EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter)

      //oDoc:SaveAs("My Letter",0,.F.,"",.T.,"",.F.,.F.,.F.,.F.,.F.) //wdFormatDocument = 0

      //VB6:
      //word.ActiveDocument.MailMerge.MainDocumentType = wdFormLetters
      //Method: ??
      oDoc:MailMerge:MainDocumentType := 0 //wdFormLetters=0  // sets the mail merge main document type

      //VB6:
      //word.ActiveDocument.MailMerge.OpenDataSource Name:=cDatenQuelle _
      //                    , ConfirmConversions:=False, READONLY:=False, LinkToSource:=True, _
      //                    AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
      //                    WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
      //                    Format:=wdOpenFormatAuto, Connection:="", SQLStatement:="", SQLStatement1 _
      //                    :=""
      //oDoc:MailMerge:OpenDataSource("c:\testdata.txt")

      //VB6:
      //word.ActiveDocument.MailMerge.EditMainDocument
      oDoc:MailMerge:EditMainDocument()

      //VB6:
      //word.ActiveDocument.MailMerge.OpenDataSource Name:=cDatenQuelle
      oDoc:MailMerge:OpenDataSource( cDatafile ) //"c:\moredata.txt")

      //VB6:
      //word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="ANREDE"
      //oDoc:MailMerge:Fields:Add(oDoc:Range(),"ANREDE")

      //VB6:
      //word.Selection.TypeParagraph
      //oWord:Selection:TypeParagraph()

      //VB6:
      //word.ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:="NAME"
      //oWord:ActiveDocument:MailMerge:Fields:Add(oDoc:Range(),"NAME")

      //VB6:
      //word.Selection.TypeText Text:=" "
      //oWord:Selection:TypeText("This is some text")

      //VB6:
      //With ActiveDocument.MailMerge
      //    .Destination = wdSendToEmail
      //    .SuppressBlankLines = True
      //    With .DataSource
      //        .FirstRecord = wdDefaultFirstRecord
      //        .LastRecord = wdDefaultLastRecord
      //    End With
      //    .Execute Pause:=False
      //End With

      IF nDocOrEmail == 1
         oDoc:MailMerge:Destination := 0 //New Document
      ELSE
         oDoc:MailMerge:Destination := 2 //Email
      ENDIF

      //wdSendToEmail = 2   //See Word Enumerated Constants: http://msdn.microsoft.com/en-us/library/aa211923.aspx
      //wdSendToFax  3
//wdSendToNewDocument  0
//wdSendToPrinter  1

      oDoc:MailMerge:SuppressBlankLines := .T.
      oDoc:MailMerge:DataSource:FirstRecord := 1 //    wdDefaultFirstRecord = 1
      oDoc:MailMerge:DataSource:LastRecord := - 16 //wdDefaultLastRecord = -16
      oDoc:MailMerge:MailAddressFieldName = "EMAIL"
      oDoc:MailMerge:MailSubject = cSubject
      oWord:ActiveDocument:MailMerge:Execute( .F. ) // Pause:=False

      IF nDocOrEmail == 1
         oWord:Visible = .T. //Makes Word active window
      ELSE
         oDoc:Close( 0 )
         oWord:Quit()
      ENDIF


      //oDoc:Select()

      //oSel = oWord:Selection

      //WORDREPLACE( oSel, "<amount", "R 10.00" )

      //WORDREPLACE( oSel, "<name>", "Elaine" )

      //Word:Visible = .T.

      //oDoc:Close( 0 )

      //oWord:Quit()
   ENDIF //lOK
   RETURN NIL

// ******************************************************************************************************
STATIC FUNCTION Validate_Merge( cDocument, cFilter, nDocOrEmail,cSubject)
   LOCAL lOk := .T.
   IF EMPTY( cDocument ) .OR. ! FILE( cDocument )
      lOk := .F.
      MSGSTOP( "Select a document." )
   ENDIF
   IF lOk = .T.
      IF nDocOrEmail==2.AND.EMPTY(cSubject)
         lOk:=MSGYESNO("Email Subject not entered."+CRLF+CRLF+"Continue?")
      ENDIF
   ENDIF
   IF lOk = .T.
      IF EMPTY( cFilter )
         lOk := MSGYESNO( "No filter has been selected." + CRLF + CRLF + "(All records will be used.)" + CRLF + CRLF + "Is this correct?" )
      ENDIF
   ENDIF
   RETURN ( lOk )

// ******************************************************************************************************
STATIC PROCEDURE MSWORD_CREATEDATA( cDataFile, cAlias, cFilter )
   //Create the data text file
   LOCAL cStr, i
   DEFAULT cFilter := ""
   //These are the fieldname descriptions
    /*
    NETUSE( "FINFO" )
    SETORDER("DBFFLDNUM")
    cAlias := FILL( UPPER( ALLTRIM( cAlias ) ), LEN( FINFO->DBF ) )
    FINFO->(DBSEEK(cAlias))
    DO WHILE FINFO->DBF==cAlias .AND. !FINFO->(EOF())
       cStr+=StrTran( ALLTRIM(FINFO->DESC) ,";","")+";"
       FINFO->(DBSKIP(1))
    ENDDO
    */

   cStr := ""
   FOR i := 1 TO ( cAlias ) ->( FCOUNT() )
      cStr += StrTran( FieldName( i ), ";", "" ) + ";"
   NEXT
   cStr := LEFT( cStr, LEN( cStr ) - 1 ) //Take off last ";"
   WriteLine( cStr, cDataFile ) //("Surname;First Name;Email", cDataFile )

   IF cFilter="1"
      //? "Write one line of data"
      cStr := ""
      FOR i := 1 TO ( cAlias ) ->( FCOUNT() )
         cStr += ALLTRIM( StrTran( cStr( FieldGet( i ) ), ";", "" ) ) + ";"
      NEXT
      cStr := LEFT( cStr, LEN( cStr ) - 1 ) //Take off last ";"
      WriteLine( cStr, cDataFile ) //("Surname;First Name;Email", cDataFile )
      cFilter:=""
   ELSE
      //? "Run the filter",cAlias,cFilter
      SELECT ( cAlias )
      SET FILTER TO &cFilter
      (cAlias)->(DBGOTOP())
      DO WHILE !(cAlias)->(EOF())
         //? (cAlias)->(RECNO())
         cStr := ""
         FOR i := 1 TO ( cAlias ) ->( FCOUNT() )
            cStr += ALLTRIM( StrTran( cStr( FieldGet( i ) ), ";", "" ) ) + ";"
         NEXT
         cStr := LEFT( cStr, LEN( cStr ) - 1 ) //Take off last ";"
         WriteLine( cStr, cDataFile ) //("Surname;First Name;Email", cDataFile )
         (cAlias)->(DBSKIP( 1 ))
      ENDDO
   ENDIF
   //? cDataFile
   //cStr:=MEMOREAD(cDataFile)
   //? cStr //WinExec(cDataFile)
   RETURN
Many thanks
Ollie.

Using:
xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6406)
Borland C++ 5.5.1
FWH 9.04 (2009 Apr)
User avatar
RAMESHBABU
Posts: 591
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Post by RAMESHBABU »

Mr.Ollie/Mr.Otto,

Thanks

- Ramesh Babu P
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Hello Ramesh,

I would like to send you the whole word- project and also SNIPKEEPER in the hope you will participate on development.
Here is my email datron&aon.at (please substitute &) .
Regards,
Otto
User avatar
RAMESHBABU
Posts: 591
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Post by RAMESHBABU »

Mr.Otto
hope you will participate on development
Thank you very much and I accept your offer.
would like to send you the whole word- project and also SNIPKEEPER
Please send it.

Regards to you

- Ramesh Babu P
Post Reply