There is a fair amount of help around for using Visual Basic and Delphi, but not for C++ Builder, likewise for using databases for mailmerge, but not text files, so this article is provided to help bridge the gap.
The example used is to generate raffle tickets, as the finished program may be useful for those running village fetes, etc., but the same principle is true for personalised letters, envelopes, company despatch notes, and so on.
Click here to unzip the program and data only, free for use with our compliments. It is a 32-bit Windows application (Win95 98 ME NT 2000) using Microsoft Word 2000 upwards (Word 2000 2001 2002XP) - but it could be recompiled for Word 97, if enough requests. If you have no program to unzip files, you can download an evaluation copy of WinZip from http://www.winzip.com/
Click here for information on creating/editing the Word document, ie what is printed on the tickets.
Click here to unzip the C++ Builder Raffle project.
Click here to read the tutorial for new users.
Read on for the outline of the project, code snippets, tips and references.
There are essentially 3 files, the program Raffle.exe, the data source file Raffle.htm, and the Word mailmerge document Raffle.doc
The program rewrites Raffle.htm, retaining the first line which contains the header etc, and generates the numbers to create the data lines.
When complete, Raffle.doc is opened in Word, the newly rewritten Raffle.htm data source is connected, merged to a new document and sent to the printer.
From the "Servers" tab, "WordApplication" and "WordDocument". These are either Word 97 or Word 2000, dependent on installation. If you only have C++ Builder 4, you will need to create your own automation servers - see chapters 13, 14 and 15 of "Borland C++Builder 4 Unleashed" by Kent Reisdorph, et al - References below.
Note the object types for interfacing with Word - Variant, OleVariant, _DocumentPtr
Variant NoPrompt = wdDoNotSaveChanges; _DocumentPtr ResultName;
Start Word, visible is nice so you can see something is happening.
try
{
WordApplication1->Connect();
}
catch(...)
{
ShowMessage("Unable to load Word"); return;
}
WordApplication1->Visible = true;
Send to Word and print
WordDocument1->ConnectTo(WordApplication1->Documents->Open((OleVariant)EditDestDoc->Text));
WordDocument1->Activate();
WordDocument1->MailMerge->OpenDataSource((Variant)EditSourceHtm->Text, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam);
WordDocument1->MailMerge->Destination = wdSendToNewDocument;
WordDocument1->MailMerge->SuppressBlankLines = true;
WordDocument1->MailMerge->DataSource->FirstRecord = wdDefaultFirstRecord;
WordDocument1->MailMerge->DataSource->LastRecord = wdDefaultLastRecord;
int i = WordApplication1->Documents->Count;
WordDocument1->MailMerge->Execute();
Application->ProcessMessages();
ResultName = WordApplication1->ActiveDocument;
if (i == WordApplication1->Documents->Count)
{
Application->BringToFront();
Application->MessageBox(EditDestDoc->Text.c_str(), "!!! Merge failed.", MB_OK | MB_ICONEXCLAMATION);
WordDocument1->Close(NoPrompt, EmptyParam, EmptyParam);
}
else
{
WordDocument1->Close(NoPrompt, EmptyParam, EmptyParam);
ResultName->Activate();
ResultName->PrintOut((Variant)false, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam);
ResultName->Close(NoPrompt, EmptyParam, EmptyParam);
}
WordDocument1->Disconnect();
Application->BringToFront();
If you were doing a complicated mailmerge that required only selected records, in the above code, set FirstRecord and LastRecord to the actual record numbers.
If you were doing a mailmerge that used strings from a data file not under your control, there are a few key codes that need to be translated to HTML. 3 parts:-
a) In your class (Unit1.h) define variable RepAll under private: // User declarations
TReplaceFlags RepAll;
b) Set up the variable RepAll in your constructor subroutine (Unit1.cpp) __fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
RepAll << rfReplaceAll;
c) Where you want to translate the codes, for String s
s = StringReplace(s, "&", "&", RepAll); s = StringReplace(s, ">", ">", RepAll); s = StringReplace(s, "<", "<", RepAll);
If you want to use a non-default printer, eg defined in an Edit component named EditPrinter (Start > Settings > Printers. 2 slow clicks on the printer name to get into edit. CTRL C to copy the name, ESC to quit. In EditPrinter CTRL V to paste the exact name, at design time or run time.)
after starting word
WordApplication1->ActivePrinter = (Variant)EditPrinter->Text;
Non-default trays are not so simple as the drivers do not always obey Word. In an ideal world the code would be
before ResultName->PrintOut
ResultName->PageSetup->FirstPageTray = wdPrinterMiddleBin; // example tray 2 ResultName->PageSetup->OtherPagesTray = wdPrinterMiddleBin;
In the real world there are a couple of options you could try if it fails to work:-
Default the printer to tray 2, and only change to tray 1 when required
ResultName->PageSetup->FirstPageTray = wdPrinterUpperBin; // tray 1 ResultName->PageSetup->OtherPagesTray = wdPrinterUpperBin;
If this also fails or is unsatisfactory, install your printer driver twice under two different names, one defaulted to tray 1 and one defaulted to tray 2, and use as two separate printers with
WordApplication1->ActivePrinter = (Variant)EditPrinter->Text;
This method does have a "hand-shake" problem and you need to wait for one "printer" to finish before sending to the other.
When automating Word, a clue to the coding required can often be found by looking at the Visual Basic in a macro. ie In Word, menu Tools>Macro>Record New Macro. Do what you want to automate manually. Stop the macro, menu Tools>Macro>Macros... select your macro, Edit.
This information is mainly for people who are required to mailmerge from a text delimited file, ie normally each record is a new line, within a line each field is separated by a unique code (say ~).
The secret to automating Word is to prevent it stopping to "ask questions", which it does if the source file is a .txt type. Ideally, it would like your source file to be a table in a Word document. This is a time consuming complicated task, and presents problems if you have a large number of fields. However, it does seem happy with simple HTML which is easy and quick to create.
If you are unfamiliar with HTML, use the data file Raffle.htm as a starting point.
Use a text editor like Notepad or the superb Programmer's File Editor (PFE) - see References below.
In the first line you may want to change the language (<meta http-equiv="Content-Language" content="en-gb">).
Each record is a table row - enclosed between <TR> ... </TR>
Each field within the record is a table cell - enclosed between <TD> ... </TD>
except for the first record if it is the header, in which case each field is enclosed between <TH> ... </TH>
For this program, do not split the first line before the end of the first row - </TR>
In Raffle.htm only one field is required, but if you were doing letters the header record and first data record would be something like
<TR><TH>NAME</TH><TH>ADDR1</TH><TH>ADDR2</TH><TH>ADDR3</TH></TR>
<TR><TD>Mr Smith</TD><TD>1 Station Road</TD><TD>Mumsbury</TD><TD>Kent DW9 5NB</TD></TR>
where NAME, ADDR1, ADDR2, ADDR3 are the names of mailmerge fields in your Word document.
See StringReplace above for codes within fields.
Note: If you are running mailmerge manually (ie from Word) with an HTML data source, if it asks you to "Confirm Data Source", you must choose "Word Documents (*.doc)" - reason unknown.
Sams Teach Yourself Borland C++ Builder in 21 Days by Kent Reisdorph.
An excellent book, a must for anyone new to C++ Builder. Although written for version 3, most of it is still applicable today. Well laid out, it is easy to find what you are looking for, and goes into far more basic detail than the later books.
Borland C++Builder 4 Unleashed by Kent Reisdorph, et al.
Also an excellent book, but an extension of "C++ Builder in 21 Days", not a replacement. It covers a huge range of more advanced topics, especially web & database related. Most of interest to myself were components, type libraries, and automation servers and clients.
C++ Builder 5 Developer's Guide by Jarrod Hollingworth, Dan Butterfield, Bob Swart, Jamie Allsop, et al.
A third excellent book (otherwise it wouldn't be mentioned here) also covering more advanced topics. I must confess to having not read most of it, but the explanations of how to use the new components (automating Microsoft Office) are essential.
Programmer's File Editor (PFE), by Alan Phillips. The most superb text editor that no-one should be without - and it's FREE!
HTML 4.0 Reference A windows help file with the complete HTML 4.0 reference as published by WDG, the Web Design Group. This HTML 4.0 reference was originally created by Liam Quinn, compiled by Gerben Hoekstra.
Free 3 of 9 Barcode A code 39 barcode font, an absolute boon if you need to automate despatch labels, even works on dot matrix printers. Thank you, Matthew Welch.
| ||||