VISUAL COBOL, .NET and Microsoft Office combined is a great opportunity for a little CRM

Considering that most COBOL apps store customer contact information one way or another, there should be nice opportunities for some CRM tooling, especially when we know how easy it is to interact with Microsoft Office using dot net in VISUAL COBOL.

How about using Microsoft Word in conjunction with your customer database to mail a promo? All automatic of course :-)

To use the following source example;

* Make sure you have a C drive, and write access to the root of it. Otherwise change all filenames in the source to your preferred destination.

* Make sure you have Microsoft Office installed.

* Start up Visual COBOL.

* Select File | New | Project.

* Choose COBOL, Managed, Console Application.

* Enter name, Location and Solution name as desired or use the suggested values.

* Click Ok.

* You should now have gotten the source file (Program1.cbl) editor.

* To the right, you should have the Solution Explorer. If not, open it from the menu (View | Solution Explorer)

* Make sure Solution, and project is expanded, there should be an item in the tree named References.

* Right-click References in the Solution Explorer.

* Click Add Reference in the pop-up menu.

* Depending on your computer, it might take some time to populate the .NET tab. Here, scroll for Microsoft.Interop.Word, note that there might be multiple versions installed. This worked with version 11.0.0.0 for me.

* Click Microsoft.Interop.Word to select this and OK.

* Right-Click References again, press Add Reference again, this time look for System-Windows.Forms, select it and click OK. We use this for the message boxes, if you remove the message boxes, you can skip this.

* Select all content in the editor window (Program1.cbl), delete it and replace with the code below.

* Build.

* Run.

You may of course as well step through in the debugger.When the program is finished, you will find two new files; "c:\merged.doc" and "c:\vcdatasource.doc".

The merged.doc file is the final document to print. The vcdatasource.doc is the datasource we created to merge recepients from.

You may print, fax or even email the documents from your applocation, provided you have the setup for this.

program-id. Program1 as "VCMailMerge.Program1".

working-storage section. *Word is not native .net, but encapsulated COM. In COM you have the opportunity to *omitt optional parameters, this is not supported in most .net native languages. Hence, *we have to provide "dummy" data for these. For this purpose we use the * "System.Reflection.NullObject::Value 01 NullObject object value type System.Reflection.Missing::Value. 01 my-exception type "System.Exception". 01 orgbold binary-long. 01 dummystr string. 01 listsep string. 01 headerstr string.

procedure division. *First get the correct list separator character for your culture. set listsep to type System.Globalization.CultureInfo::CurrentCulture::TextInfo::ListSeparator. *> launch Word, get an instance to it. set WrdApp to new Microsoft.Office.Interop.Word.Application() *> Show Word, so we can see things happen. For production comment out or remove the next line set WrdApp::Visible to true try *> Create master document invoke WrdApp::Documents::Add(NullObject, NullObject, wdBlank, NullObject) giving WrdDoc *> Select the document as current. invoke WrdDoc::Select() *> Get a reference to the current selection set WrdSel to WrdApp::Selection *> Get a reference to the MailMerge object of the master document set WrdMMg to WrdDoc::MailMerge *> Create the Data Source file, for the header we use the list separator character we *> obtained from the current culture on the first line. set headerstr to string::Concat("FirstName" listsep " LastName" listsep " City" listsep " Country") invoke WrdMMg::CreateDataSource( "c:\vcdatasource.doc" as type System.Object, NullObject, NullObject, headerstr as type System.Object, NullObject, NullObject, NullObject, NullObject, NullObject) *> Open the Data Source file invoke WrdApp::Documents::Open( "c:\vcdatasource.doc" as type System.Object, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject) giving WrdDDc *> Get a reference to the table in the Data Source file set WrdTbl to WrdDDc::Tables::Item(1) *> The CreateDataSource method insert a table with 2 rows by default, we expand this *> with another three rows just for having more data. Giving us a total of 5 rows. *> 1 header row (1) and 4 data rows (2..5) perform 3 times Invoke WrdTbl::Rows::Add(NullObject) end-perform *> This following sequence could easily be replaced by you reading your data from a COBOL file.

*> Save the Data Source document invoke WrdDDc::Save() *> Close the Data Source document invoke WrdDDc::Close(WrdNoSave, NullObject, NullObject) *> Let us start typing the template letter, first we make the header, *> let us align the header text center. set WrdSel::ParagraphFormat::Alignment to type Microsoft.Office.Interop.Word.WdParagraphAlignment::wdAlignParagraphCenter *> Make a copy of the current font bold state and name set orgbold to WrdSel::Font::Bold set dummystr to WrdSel::Font::Name *> Set the font to bold and the font type to Tahoma, that looks good :-) set WrdSel::Font::Bold to 1 set WrdSel::Font::Name to "Tahoma" *> Type in Micro Focus University invoke WrdSel::TypeText("Micro Focus University") *> Let us get a new line invoke WrdSel::TypeParagraph() *> Department invoke WrdSel::TypeText("Knowledge department") *> Restore font to original set WrdSel::Font::Bold to orgbold set WrdSel::Font::Name to dummystr *> Two blank lines perform 2 times invoke WrdSel::TypeParagraph() end-perform *> Set left alignment set WrdSel::ParagraphFormat::Alignment to type Microsoft.Office.Interop.Word.WdParagraphAlignment::wdAlignParagraphLeft *> Initiate the MailMergeField object set WrdMMF to WrdMMg::Fields

*> With the MailMergeField object, using the template document (WrdSel) we type in *> the mailmerge fields. *> FirstName field invoke WrdMMF::Add(WrdSel::Range, "FirstName") *> Add a blank for nice formatting invoke WrdSel::TypeText(" ") *> LastName field invoke WrdMMF::Add(WrdSel::Range, "LastName") *> New line invoke WrdSel::TypeParagraph() *> City field invoke WrdMMF::Add(WrdSel::Range, "City") *> New line invoke WrdSel::TypeParagraph() *> Country field invoke WrdMMF::Add(WrdSel::Range, "Country") *> New line invoke WrdSel::TypeParagraph() *> Align right for date set WrdSel::ParagraphFormat::Alignment to type Microsoft.Office.Interop.Word.WdParagraphAlignment::wdAlignParagraphRight *> Insert date object. Behold! Do note that the format here may differ depending *> on your nationality. Make sure you choose a format appropriate for your target *> audience :-) invoke WrdSel::InsertDateTime("dddd, MMMM dd, yyyy" as type System.Object, false as type "System.Object", NullObject, NullObject, NullObject) *> New line invoke WrdSel::TypeParagraph() *> Restore left alignment for body text set WrdSel::ParagraphFormat::Alignment to type Microsoft.Office.Interop.Word.WdParagraphAlignment::wdAlignParagraphLeft *> Be polite, say Dear ;-) invoke WrdSel::TypeText("Dear ") *> Insert FirstName, be personal to make sure you have their attention invoke WrdMMF::Add(WrdSel::Range, "FirstName") *> Just a comma invoke WrdSel::TypeText(",") *> New line invoke WrdSel::TypeParagraph() *> Insert the body text. Note that the concatenation is not just for *> having the source code look good, but also because the compiler has a *> limitation of 255 bytes on a single line of source code. invoke WrdSel::TypeText( "Thank you for your recent r" & "equest for next semesters' class schedule for the" & " Visual COBOL Programming Department. Enclosed wi" & "th this letter is a booklet containing all the cl" & "asses offered next semester at Micro Focus Univer" & "sity. Several new classes will be offered in the " & "dot net Programming Department next semester. The" & "se classes are listed below.") *> New line invoke WrdSel::TypeParagraph() *> Create a table for entry of the courses, apply table behavior, 9 rows and 4 columns *> Note the cast to "System.Object", this is due to the type specification of the method Add's *> parameters being pointer to variant invoke WrdDoc::Tables::Add(WrdSel::Range, 9, 4, type Microsoft.Office.Interop.Word.WdDefaultTableBehavior::wdWord8TableBehavior as type System.Object, type Microsoft.Office.Interop.Word.WdAutoFitBehavior::wdAutoFitFixed as type System.Object) *> To save typing, get a reference to the table item in the object variable WrdTbl set WrdTbl to WrdDoc::Tables::Item(1) *> Set width and alignment for table item 1 invoke WrdTbl::Columns::Item(1)::SetWidth(55, type Microsoft.Office.Interop.Word.WdRulerStyle::wdAdjustNone) *> Set width and alignment for table item 2 invoke WrdTbl::Columns::Item(2)::SetWidth(165, type Microsoft.Office.Interop.Word.WdRulerStyle::wdAdjustNone) *> Set width and alignment for table item 3 invoke WrdTbl::Columns::Item(3)::SetWidth(100, type Microsoft.Office.Interop.Word.WdRulerStyle::wdAdjustNone) *> Set width and alignment for table item 4 invoke WrdTbl::Columns::Item(4)::SetWidth(111, type Microsoft.Office.Interop.Word.WdRulerStyle::wdAdjustNone) *> Let us apply a shade to the title row set WrdTbl::Rows::Item(1)::Cells::Shading::BackgroundPatternColorIndex to type Microsoft.Office.Interop.Word.WdColorIndex::wdGray25 *> Since we shade the title row, it makes sense to have the text here appear in bold *> to ease reading set WrdTbl::Rows::Item(1)::Range::Bold to 1 *> Center the first cell, leave the others left aligned set WrdTbl::Cell(1, 1)::Range::Paragraphs::Alignment to type Microsoft.Office.Interop.Word.WdParagraphAlignment::wdAlignParagraphCenter *> Insert the header row text invoke WrdTbl::Cell(1, 1)::Range::InsertAfter("Class Number") invoke WrdTbl::Cell(1, 2)::Range::InsertAfter("Class Name") invoke WrdTbl::Cell(1, 3)::Range::InsertAfter("Class Time") invoke WrdTbl::Cell(1, 4)::Range::InsertAfter("Instructor")

*> Insert row for course 8, cell by cell invoke WrdTbl::Cell(9, 1)::Range::InsertAfter("EE500") invoke WrdTbl::Cell(9, 2)::Range::InsertAfter("Deploying to multiple targets") invoke WrdTbl::Cell(9, 3)::Range::InsertAfter("3:00 -4:00 M,W,F") invoke WrdTbl::Cell(9, 4)::Range::InsertAfter("Dr. Redist") *> Set value for wdGoToItem to wdGoToLine set wdGotoLine to type Microsoft.Office.Interop.Word.WdGoToItem::wdGoToLine *> Set value for wdGoToDirection to wdGoToLast set wdGoToLast to type Microsoft.Office.Interop.Word.WdGoToDirection::wdGoToLast *> Let us move to the last line in the document invoke WrdSel::GoTo(wdGoToLine, wdGoToLast, NullObject, NullObject) *> Add some more text invoke WrdSel::TypeText("For additional information r" & "egarding the Micro Focus University, you can visit our website at ") *> Today people like links, let us give them the hyperlink to our web site to click on invoke WrdSel::Hyperlinks::Add(WrdSel::Range, "Http://www.microfocus.com", NullObject, NullObject, NullObject, NullObject) *> Conclude the letter, providing a phone number invoke WrdSel::TypeText(". Thank you for your interest in the classes offered at the Micro Focus Univer" & "sity. If you have any other questions, please feel free to give us a call at 800 328 4967 (US).") *> New line invoke WrdSel::TypeParagraph() *> Have a polite end of the letter invoke WrdSel::TypeText("Sincerely, ") invoke WrdSel::TypeParagraph() invoke WrdSel::TypeText("John Doe") invoke WrdSel::TypeParagraph() invoke WrdSel::TypeText("Micro Focus University") invoke WrdSel::TypeParagraph() *> Set the destination of the merge. Here we tell we want it to go to a new document *> but it might as well be fax or email. These two of course will depend on us providing *> respectively fax number or email address set WrdMMg::Destination to type Microsoft.Office.Interop.Word.WdMailMergeDestination::wdSendToNewDocument *> Now run the merge invoke WrdMMg::Execute(1 as object) *> We don't care for the template document, so we tell Word it is already saved to avoid a dialog *> poping up set WrdDoc::Saved to true *> Now close the template document, no dialogs please (WrdNoSave) invoke WrdDoc::Close(WrdNoSave, NullObject, NullObject) *> Set WrdDoc object to the new merged document set WrdDoc to WrdApp::Documents::Item(1) *> Show a message box, telling we store the merged document in C:\merged.doc invoke type System.Windows.Forms.MessageBox::Show("Saved mailmerge to c:\merged.doc", WrdDoc::Name) *> Save the merged document invoke WrdDoc::SaveAs("c:\merged.doc" as type System.Object, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject, NullObject) *> For some odd reason, we have to tell Word it is saved (!) set WrdDoc::Saved to true *> Close the merged document invoke WrdDoc::Close(WrdNoSave, NullObject, NullObject) catch my-exception *> Uh oh, we were not supposed to get here :-( invoke type System.Windows.Forms.MessageBox::Show( my-exception::Message::ToString(), "Try Catch") end-try *> Close Word, we are done, no save dialogs (WrdNoSave) please invoke WrdApp::Quit(WrdNoSave, NullObject, NullObject) *> Clear pointers to indicate we are all set and done set WrdTbl to NULL set WrdDDc to NULL set WrdDoc to NULL set WrdSel to NULL set WrdApp to NULL *> Wow, you just did your first MailMerge from Visual COBOL using dot net and Office Interop! goback end program Program1.

All versions of Visual COBOL support the "quoteless syntax", so please do post any updates you have. It might also be good to make the code snippets use the "Code" formnatting (see the button in the forum editor toolbar) for clarity.

The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.