.Net Core

Programmatically generate Microsoft Word files Using Interop in .Net Core

Microsoft Office is the best and most widely suite of desktop productivity designed specifically for office use. It has several products like Microsoft Word, Excel, PowerPoint, Outlook etc. Microsoft also opens access to these products to the developers so they can generate a word or an excel file using the code. In this article, we will see how we can generate these files programmatically using Microsoft Interop, also known COM Interop.

Before starting, see the images of word files we will produce:

Microsoft Word files Using Interop

Let’s start coding it.

Prerequisite: For working on this project, you will require the latest version of Microsoft Office installed and activated.

Open the Visual Studio and create a new “Wpf App (.Net Core)” ass seen in the image below.

.net core create project

First, we will design our front end using the XAML. for this, we will create use Grid element, and create a layout having one column and one row. We will place one button in the row. The button will create the word file of a CV. We will design this layout by using the XAML Code below.

<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A" Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Button Name="btnGenerateCV" Grid.Column="0" Grid.Row="0" Click="btnGenerateCV_Click" Content="Generate CV" Width="100" Height="25"/>

The code is pretty simple, it just creates one column, two rows, and placed two buttons in both of the rows. Remember to put the code inside the “Grid” element in “MainWindow” file. Its time to start the backend code now.

Switch to your “MainWindow.xaml.cs” file, we need to include the “Microsoft.Office.Interop.Word.dll” file as a reference to our project. for this, right-click on your project name, then select “Add -> Reference…”, see the screenshot below for your convenience:

.net core add reference

When you click on “Reference…”, you will see a dialogue box just like the following image:

Click on the browse button, and browse to the following path:
“C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.Word\15.0.0.0__71e9bce111e9429c”
Here, you will see a file named “Microsoft.Office.Interop.Word.dll”, select that file, click Add button and close the dialogue box by clicking the Ok button.
Now we are going to perform an important step, under the name of your project in solution explorer, expand the Dependencies node, then expand the Assemblies node, then select “Microsoft.Office.Interop.Word.dll”, now in the properties tab, select “Embed Interop Types” and change it from No to Yes. See the following screenshot for the reference:

In case, you were unable to find the “Microsoft.Office.Interop.Word.dll” file, get it from the zip file attached at the end of this article, you will find it inside the bin folder.
We are now all set to start.

We will now start creating the CV programmatically and will write all the code for this inside the event listener of the “Generate CV” button.
Let’s create an object of Word, add a document to it, and set it as an active document to work in it, the following code will do this for us:

Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
word.Documents.Add();
word.Visible = false;
word.DisplayAlerts = Microsoft.Office.Interop.Word.WdAlertLevel.wdAlertsNone;
Microsoft.Office.Interop.Word.Document doc = word.ActiveDocument;

The first line will create an object of Word, the second line will add an empty document in it, the third line will make it visibility hide, so everything will be done behind the scenes, the fourth line will make the alerts off, so they will not able to bother us, and the fifth line will get the reference of the empty document we created in line number 2.

We will now write the name of the person as a paragraph in our document, the following code will do this:

Microsoft.Office.Interop.Word.Paragraph paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Kamal Ashraf";
paragraph.Range.Font.Size = 22;
paragraph.Range.Font.Bold = 1;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Range.InsertParagraphAfter();

The first line will create an instance of the Paragraph, the second line will add the text “Kamal Ashraf” to it, the third line will set its font size to 22, the fourth line will make it bold, the fifth line will set its font to “Times New Roman (Heading CS)”, the sixth line will set its alignment to centre and at the end, the seventh line will place it on the document.

The following code will write the address in a very similar manner:

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Gujrat, Pakistan";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.InsertParagraphAfter();

Now, we will write the personal details of the person.

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "CNIC:\t\t\t\t31001-1234567-1";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.InsertParagraphAfter();

As you can see, the above code will write the CNIC of the person, if we want to make just the “CNIC” bold, we can do that by using the following code:

string textToFind = "CNIC:";
Microsoft.Office.Interop.Word.Range range;
Microsoft.Office.Interop.Word.Range textFormat;
range = doc.Range();
range.Find.Execute(textToFind);
object start = range.Start;
object end = range.Start + textToFind.Length + 1;
textFormat = doc.Range(ref start, ref end);
textFormat.Font.Bold = 1;

The above code just finds the text “CNIC” from the document and make it bold. Now let’s write the date of birth, email address, mobile number and the landline number just like we write the CNIC.

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Date of birth:\t\t\t12th November 1992";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.InsertParagraphAfter();

textToFind = "Date of birth:";
range = doc.Range();
range.Find.Execute(textToFind);
start = range.Start;
end = range.Start + textToFind.Length + 1;
textFormat = doc.Range(ref start, ref end);
textFormat.Font.Bold = 1;

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Email address:\t\t" + "[email protected]";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.InsertParagraphAfter();

textToFind = "Email address:";
range = doc.Range();
range.Find.Execute(textToFind);
start = range.Start;
end = range.Start + textToFind.Length + 1;
textFormat = doc.Range(ref start, ref end);
textFormat = doc.Range(ref start, ref end);
textFormat.Font.Bold = 1;

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Mobile number:\t\t+92-300-1234567";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.InsertParagraphAfter();

textToFind = "Mobile number:";
range = doc.Range();
range.Find.Execute(textToFind);
start = range.Start;
end = range.Start + textToFind.Length + 1;
textFormat = doc.Range(ref start, ref end);
textFormat = doc.Range(ref start, ref end);
textFormat.Font.Bold = 1;

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Landline number:\t\t+92-55-66777";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.InsertParagraphAfter();

textToFind = "Landline number:";
range = doc.Range();
range.Find.Execute(textToFind);
start = range.Start;
end = range.Start + textToFind.Length + 1;
textFormat = doc.Range(ref start, ref end);
textFormat = doc.Range(ref start, ref end);
textFormat.Font.Bold = 1;

Now, let’s add a paragraph having the text “About me”, and make it’s background light blue. Then add another paragraph under it.

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "About me";
paragraph.Range.Font.Size = 18;
paragraph.Range.Font.Bold = 1;
paragraph.Range.Font.Name = "Calibri";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorLightBlue;
paragraph.Range.InsertParagraphAfter();

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "I am able to handle multiple tasks on a daily basis. I use a creative approach to problem solve. I am a dependable person who is great at time management. I am always energetic and eager to learn new skills. I am flexible in my working hours, being able to work evenings and weekends. I am hardworking and always the last to leave the office in the evening.";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorWhite;
paragraph.Range.InsertParagraphAfter();

Now, let’s add some bullet points. We will now add the qualification of the person as the bullet points under the “Qualification”.

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Qualification";
paragraph.Range.Font.Size = 18;
paragraph.Range.Font.Bold = 1;
paragraph.Range.Font.Name = "Calibri";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorLightBlue;
paragraph.Range.InsertParagraphAfter();

We will add the qualifications as a string list first:

List<string> qualificationList = new List<string>();
qualificationList.Add("MPhill: 3.0/4.0 CGPA");
qualificationList.Add("MSc: 70% marks");
qualificationList.Add("BSc: 65% marks");
qualificationList.Add("Inter: 70% marks");
qualificationList.Add("Matriculation: 75% marks");

Insert an empty paragraph:

paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorWhite;
paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Range.ListFormat.ApplyBulletDefault();

Converting our list to a paragraph, each list item will occupy one line of the paragraph, then at the end, insert that paragraph into the document and set its format to the bullet points.

for (int i = 0; i < qualificationList.Count; i++)
{
   //Taking a string, which will add our list items one in a line
   string bulletItem = qualificationList[i];
   if (i < qualificationList.Count - 1)
      bulletItem = bulletItem + "\n";
   paragraph.Range.Font.Bold = 0;
   //inserting it in the document
   paragraph.Range.InsertBefore(bulletItem);
}

See the last line of the code above, we used “InsertBefore” here instead of “InsertAfter”, the reason is, we will add it first then set its format as bullet points.

Let’s add the experience in a similar way:

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Experience";
paragraph.Range.Font.Size = 18;
paragraph.Range.Font.Bold = 1;
paragraph.Range.Font.Name = "Calibri";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorLightBlue;
paragraph.Range.InsertParagraphAfter();

List<string> experienceList = new List<string>();
experienceList.Add("Worked in Company A: 2014 to 2015");
experienceList.Add("Worked in Company B: 2015 to 2016");
experienceList.Add("Worked in Company C: 2016 to 2017");
experienceList.Add("Worked in Company D: 2017 to 2018");
experienceList.Add("Worked in Company E: 2018 to 2019");

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
paragraph.Range.Font.Name = "Times New Roman (Headings CS)";
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorWhite;
paragraph.Range.ListFormat.ApplyBulletDefault();

for (int i = 0; i < experienceList.Count; i++)
{
    string bulletItem = experienceList[i];
    if (i < experienceList.Count - 1)
        bulletItem = bulletItem + "\n";
    paragraph.Range.Font.Bold = 0;
    paragraph.Range.InsertBefore(bulletItem);
}

Let’s add the Interests paragraph:

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Interests";
paragraph.Range.Font.Size = 18;
paragraph.Range.Font.Bold = 1;
paragraph.Range.Font.Name = "Calibri";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorLightBlue;
paragraph.Range.InsertParagraphAfter();

paragraph = doc.Content.Paragraphs.Add(System.Reflection.Missing.Value);
paragraph.Range.Text = "Playing video games and cricket";
paragraph.Range.Font.Size = 12;
paragraph.Range.Font.Bold = 0;
paragraph.Range.Font.Name = "Calibri";
paragraph.Range.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Shading.ForegroundPatternColor = Microsoft.Office.Interop.Word.WdColor.wdColorWhite;
paragraph.Range.InsertParagraphAfter();

Now, let’s add the picture of the user in the CV. First, add an image to your project by right-clicking on the project name, then click “Add -> Existing Item…”. Now the following code will add this photo in the top left of the document:

string imagePath = System.AppDomain.CurrentDomain.BaseDirectory + "../../../person.png";

Microsoft.Office.Interop.Word.InlineShape inlineShape = doc.InlineShapes.AddPicture(imagePath, Type.Missing, Type.Missing, Type.Missing);
Microsoft.Office.Interop.Word.Shape shape = inlineShape.ConvertToShape();
shape.HeightRelative = 10f;
shape.WidthRelative = 18f;
shape.Left = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeRight;
shape.Top = 40F;
shape.WrapFormat.Type = Microsoft.Office.Interop.Word.WdWrapType.wdWrapSquare;

In the above code, “System.AppDomain.CurrentDomain.BaseDirectory” is used to get the current directory where the executable file is placed, we then concatenated it with the path of our image.

Let’s add the page numbers in our document:

foreach (Microsoft.Office.Interop.Word.Section wordSection in doc.Sections)
{
    Microsoft.Office.Interop.Word.Range footerRange = wordSection.Footers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
    footerRange.Collapse(Microsoft.Office.Interop.Word.WdCollapseDirection.wdCollapseEnd);

    footerRange.Fields.Add(footerRange, Microsoft.Office.Interop.Word.WdFieldType.wdFieldNumPages);
    Microsoft.Office.Interop.Word.Paragraph p4 = footerRange.Paragraphs.Add();
    p4.Range.Text = " of ";
    footerRange.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphRight;

    footerRange.Fields.Add(footerRange, Microsoft.Office.Interop.Word.WdFieldType.wdFieldPage);
    Microsoft.Office.Interop.Word.Paragraph p1 = footerRange.Paragraphs.Add();
    p1.Range.Text = "Page ";
    footerRange.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphRight;

    footerRange.ParagraphFormat.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphRight;
}

The above code will loop through the pages in a document and will add the page number in the format “Page k of n”, for example, “page 1 of 5”.

Now it’s time to save our document, for this, we will use “Save File Dialog”, where user can select a location and name of the file to save. We will let the user save the file as “.docx” file or as “.pdf” file.

The following code will create a “Save File Dialog” and display it:

Microsoft.Win32.SaveFileDialog dialogBox = new Microsoft.Win32.SaveFileDialog();
dialogBox.Title = "Choose destination to save file";
dialogBox.DefaultExt = ".pdf";
dialogBox.Filter = "Word documents (.docx)|*.docx|PDF documents (.pdf)|*.pdf";
bool? result = dialogBox.ShowDialog();

Now, we have to save the file according to the user choice (.docx or .pdf). the following code will do that:

if (result == true)
{
    string fileName = dialogBox.FileName;
    if (fileName.EndsWith(".docx"))
    {
        doc.SaveAs(fileName);
    }
    else if (fileName.EndsWith(".pdf"))
    {
        doc.ExportAsFixedFormat(fileName, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);
    }
    MessageBox.Show("File \"" + fileName + "\"" + " saved.", "Success");
}

The code is pretty simple, if the file name ends with “Docx”, we will save it as a Word file, or save it as .pdf file if the filename ends with “.pdf”.

Now, the final step is very important, we should properly dispose of all the objects of Word or Document we have created throughout in our code, the following code will do this for:

doc.Close(0);
word.Quit();
Marshal.ReleaseComObject(doc);

We need to first close the Document object, which is “doc”, then we will quit the Word object, then we will finally ask the Runtime Callable Wrapper to release “doc” object.

It’s the end of this article, see you in the next article. You can download the entire source code of this article here.

Here’re some more related articles for you:

GOOGLE SHEETS READ WRITE UPDATE OPERATIONS USING DOTNET CORE

– A COMPLETE GUIDE TO SECURE YOUR ASP.NET CORE APPLICATION & WEB APIs

– HOW I BOOSTED MY ASP.NET CORE APP & API PERFORMANCE 250% BY CACHING

Write A Comment