0

The following code, creates a temporary Word document, inserts the letterbody and returns the bytes for the temporary Word document .

The following code takes 40 secs for 50 documents.

The code for inserting the db is not provided here, but I am sure its the temporary document creation, which takes the most time, as I did a readallbytes of 50 Word documents and inserted them to the db, in less than 5 seconds.

    public async Task<byte[]> ConvertToWordDocument(string letterBody, int index)
    {
       string path = @"E:\Projects\temp" + index.ToString() + ".docx";

       byte[] bytesRead = null;

       await System.Threading.Tasks.Task.Run(() =>
       {
          var tempDoc = this.Application.Documents.Add(Visible: false);
  
          tempDoc.Content.Text = letterBody;
          tempDoc.SaveAs2(path, Word.WdSaveFormat.wdFormatDocumentDefault);
          tempDoc.Close();

          if (tempDoc != null)
             Marshal.ReleaseComObject(tempDoc);

       });

       bytesRead = File.ReadAllBytes(path);

       return bytesRead;
    }

What should be done to code , so that it takes less time.

I am welcome to all suggestions.

Thanks Sujay

EDIT : The code takes 40 seconds for 50 document. Apologies for not mentioning 50 documents earlier.

Sujay Ghosh
  • 2,828
  • 8
  • 30
  • 47
  • 6
    Step 1: Profile your application, figure out where it spends most/all of its time. – Lasse V. Karlsen Nov 28 '20 at 21:10
  • 3
    Don't use interop. Use some library like OpenXml, DocX, SpireDoc, etc. – Alexander Petrov Nov 28 '20 at 21:28
  • I agree with @LasseV.Karlsen that you should profile it, but would be willing to bet that the slowdown comes from writing to a temporary file and then reading back from it. – bisen2 Nov 28 '20 at 21:47
  • Tip: Take this tmp filename generator :) `string path = System.IO.Path.GetTempFileName();` – aepot Nov 28 '20 at 23:22
  • @LasseV.Karlsen, the most time is taken for creating the temporary Word documents. I could insert 50 documents directly to the db in less than 5 seconds. – Sujay Ghosh Nov 29 '20 at 06:51

3 Answers3

3

As I understand, you use Microsoft.Office.Interop that launches Word in a separate process and push data\commands via DCOM. So 40 seconds is a fair amount of time for that operation.

To make it faster, try to compose document without Word application. Take a look to open-xml-sdk: https://learn.microsoft.com/en-us/office/open-xml/open-xml-sdk

Pavlo K
  • 837
  • 9
  • 15
1

Here's an option that uses DocumentFormat.OpenXML. It was tested with v2.11.3

During my testing, when using a RichTextBox to get the document text, it didn't seem to handle newline properly when just setting the text. So I find the newline sequence. Then write the text character-by-character, putting run.AppendChild(new Break()); when the newline sequence is encountered. It's my first time using OpenXML -- maybe there's a better way of handling newline. It's still quite fast. On my computer, this one takes less than 1 second to create 300 files (text in each file is 220 words).

Add Nuget package "DocumentFormat.OpenXml" to project: (VS 2017 / VS 2019)

  • View
  • Solution Explorer
  • In Solution Explorer, right-click <project name>
  • Select Manage Nuget Packages...
  • Click Browse
  • DocumentFormat.OpenXML
  • Click Install

Add a reference to WindowsBase: (VS 2017 / VS 2019)

  • On menu, click Project
  • Select Add Reference
  • Assemblies
  • Framework
  • WindowsBase

Add using statements:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.IO;
using System.Diagnostics;

Create a class to hold the info needed to create the Word document.

WordFileInfo.cs

public class WordFileInfo
{
    public string Filename { get; set; }
    public string LetterBody { get; set; }

    public WordFileInfo()
    {

    }

    public WordFileInfo(string filename, string letterBody)
    {
        this.Filename = filename;
        this.LetterBody = letterBody;
    }
}

ClsHelperOpenXml.cs

public class ClsHelperOpenXml
{
    //depending on the number of files processed,
    //changing this value may increase/decrease performance slightly
    private int _maxConcurrentTasks = 25;

    //store data that needs to be processed
    public List<WordFileInfo> WordData { get; set; } = new List<WordFileInfo>();

    private enum NewLineSequence
    {
        None,
        Ascii10,
        Ascii13,
        Ascii1310,
    }
    public ClsHelperOpenXml()
    {

    }

    public ClsHelperOpenXml(List<WordFileInfo> wordData)
    {
        //set value
        this.WordData = wordData;
    }

    
    public void ConvertToWordDocument()
    {
        Debug.WriteLine("\nConverting to Word doc...");

        using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(_maxConcurrentTasks))
        {
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < WordData.Count; i++)
            {
                concurrencySemaphore.Wait();

                var t1 = Task.Run(() =>
                {
                    try
                    {
                        CreateWordDocument(WordData[i].Filename, WordData[i].LetterBody);
                    }
                    finally
                    {
                        concurrencySemaphore.Release();
                    }

                }).ContinueWith(task =>
                {

                    byte[] fBytes = File.ReadAllBytes(WordData[i].Filename);
                    return fBytes;
                });

                byte[] bytesRead = (byte[])t1.Result;
                //System.Diagnostics.Debug.WriteLine("t1[" + i + "].Length: " + t1.Result.Length);

                //add to list
                tasks.Add(t1);

            }

            Task.WaitAll(tasks.ToArray());

            //clean up
            tasks.Clear();
        }


        Debug.WriteLine("Status: Complete " + DateTime.Now.ToString("HH:mm:ss"));
    }
    private void CreateWordDocument(string filename, string userText)
    {
        string errMsg = string.Empty;
        string result = string.Empty;
        
        if (String.IsNullOrEmpty(filename))
        {
            errMsg = "Error: CreateWordDocument - filename is null or empty.";
            Debug.WriteLine(errMsg);
            return;
        }

        if (String.IsNullOrEmpty(userText))
        {
            errMsg = "Error: CreateWordDocument - userText is null or empty.";
            Debug.WriteLine(errMsg);
            return;
        }

        //get newline sequence
        NewLineSequence nlSequence = GetNewLineSquence(userText);

        // Create a Wordprocessing document. 
        using (WordprocessingDocument doc = WordprocessingDocument.Create(filename, WordprocessingDocumentType.Document))
        {

            // Add a main document part.
            MainDocumentPart mainPart = doc.AddMainDocumentPart();

            // Create the document structure and add some text.
            mainPart.Document = new Document();
            Body body = mainPart.Document.AppendChild(new Body());
            Paragraph para = body.AppendChild(new Paragraph());
            Run run = para.AppendChild(new Run());

            string data = string.Empty;
            int previousVal = 0;

            if (!String.IsNullOrEmpty(userText))
            {
                for (int i = 0; i < userText.Length; i++)
                {
                    int charInt = Convert.ToInt32(userText[i]);

                    if (!(charInt == 10 || charInt == 13))
                    {
                        //append
                        data += userText[i];
                    }
                    else
                    {
                        //Debug.WriteLine(charInt + " " + nlSequence.ToString() + " previousVal: " + previousVal + " charInt: " + charInt );

                        //append text
                        run.AppendChild(new Text(data));

                        //re-initialize
                        data = string.Empty;

                        if ((nlSequence == NewLineSequence.Ascii1310 && previousVal == 13 && charInt == 10))
                        {
                            //add break;
                            run.AppendChild(new Break());
                        }
                        else if (nlSequence == NewLineSequence.Ascii10 && charInt == 10)
                        {
                            //add break
                            run.AppendChild(new Break());
                        }
                        else if (nlSequence == NewLineSequence.Ascii10 && charInt == 13)
                        {
                            //add break
                            run.AppendChild(new Break());
                        }

                    }

                    //set value
                    previousVal = charInt;
                }

                if (!String.IsNullOrEmpty(data))
                {
                    //append text
                    run.AppendChild(new Text(data));
                    //run.AppendChild(new Break());
                }
            }

            // Save changes to the main document part. 
            doc.MainDocumentPart.Document.Save();
        }

    }

    private NewLineSequence GetNewLineSquence(string userText)
    {
        int previousVal = 0;

        for (int i = 0; i < userText.Length; i++)
        {
            int charInt = Convert.ToInt32(userText[i]);

            if (charInt == 10 && previousVal == 13)
            {
                return NewLineSequence.Ascii1310;
            }
            else if (charInt == 10 && previousVal != 13)
            {
                return NewLineSequence.Ascii10;
            }
            else if (previousVal == 13 && charInt != 10)
            {
                return NewLineSequence.Ascii13;
            }

            //set value
            previousVal = charInt;
        }

        return NewLineSequence.None;
    }
}

To Use:

I use the following method to create some filenames and document text (for testing).

CreateTestData

private List<WordFileInfo> CreateTestData(string folderName, string sampleLetterBody)
{
    //create data for testing

    int numTestFiles = 50; //for testing purposes

    List<WordFileInfo> wordData = new List<WordFileInfo>();

    for (int i = 0; i < numTestFiles; i++)
    {
        string filename = System.IO.Path.Combine(folderName, "WordDoc" + (i + 1).ToString() + ".docx");

        //add to list
        wordData.Add(new WordFileInfo(filename, sampleLetterBody));

        //Debug.WriteLine("Filename: '" + filename + "'");
    }

    return wordData;
}

Then use the following to test creating the Word document(s):

string folderName = @"C:\Temp";
string sampleLetterBody = "This is some text.";

//get data for testing
List<WordFileInfo> wordData = CreateTestData(folderName, sampleLetterBody);

//create new instance (passing data using the constructor)
ClsHelperOpenXml helperOpenXml = new ClsHelperOpenXml(wordData);
    
helperOpenXml.ConvertToWordDocument();

helperOpenXml = null;
    

See also this post

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
-1

Updated:

Since some of the information in the original post was updated, I've updated this post.

You can give the following a try. On my computer, Option 1 takes about 8.5 secs. for 50 files (text in each file is 220 words), and Option 2 takes about 7.2 secs:

Add a reference to Microsoft.Word Object Library (ex: Microsoft.Word 16.0 Object Library)

  • On menu, click Project
  • Select Add Reference
  • Select COM
  • Select Microsoft.Word xx.x Object Library (ex: Microsoft.Word 16.0 Object Library)

Add the following using statements:

using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Word = Microsoft.Office.Interop.Word;
using System.Threading;
using System.Threading.Tasks;

Create a class to hold the info needed to create the Word document.

Note: There are two options below. Both options use class "WordFileInfo".

WordFileInfo.cs:

public class WordFileInfo
{
    public string Filename { get; set; }
    public string LetterBody { get; set; }

    public WordFileInfo()
    {

    }

    public WordFileInfo(string filename, string letterBody)
    {
        this.Filename = filename;
        this.LetterBody = letterBody;
    }
}

In the two options below, "CreateWordDocument" is exactly the same in both. However, I've included it in each option, because it's part of "ClsHelperWord.cs".

Option 1:

*Note: This option uses both Task and Backgroundworker. If used with Windows forms, it helps to ensure that the UI remains responsive. Due to it's use of Backgroundworker, it may be slightly slower.

Create the "CurrentState" class which is used to pass data back from BackgroundWorker thread.

CurrentState.cs

public class CurrentState
{
    public string Status { get; set; } = string.Empty;
    public int PercentDone { get; set; } = 0;

}

ClsHelperWord.cs

public class ClsHelperWord : IDisposable
{
    //depending on the number of files processed,
    //changing this value may increase/decrease performance slightly
    private int _maxConcurrentTasks = 25; 

    //create new instance
    private Word.Application _wordApp = new Word.Application();

    //store data that needs to be processed
    public List<WordFileInfo> WordData { get; set; } = new List<WordFileInfo>();


    public ClsHelperWord()
    {

    }

    public ClsHelperWord(List<WordFileInfo> wordData)
    {
        //set value
        this.WordData = wordData;
    }

    public void Close()
    {
        Dispose();
    }

    public void Dispose()
    {
        if (_wordApp != null)
        {
            //close Word
            object oFalse = false;
            _wordApp.Quit(ref oFalse, ref oFalse, ref oFalse);

            //release all resources
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_wordApp);
        }
    }

    public void ConvertToWordDocument(System.ComponentModel.BackgroundWorker worker, System.ComponentModel.DoWorkEventArgs e)
    {
        DateTime lastReportedDateTime = DateTime.MinValue;
        double percentDoneDbl = 0.0;
        int percentDoneInt = 0;

        //create new instance
        CurrentState state = new CurrentState(); 
        
        try
        {
            Debug.WriteLine("\nConverting to Word doc...");

            using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(_maxConcurrentTasks))
            {
                List<Task> tasks = new List<Task>();
                for (int i = 0; i < WordData.Count; i++)
                {
                    concurrencySemaphore.Wait();

                    state.Status = "Processing file " + i + " of " + WordData.Count + "...";
                    Debug.WriteLine(state.Status);

                    //-------------------------------
                    // report progress
                    //-------------------------------
                    if (i % 5 == 0)
                    {
                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        } 

                        //ToDo: Do the following any time you want to
                        //update the status, progressBar, or any other
                        //variables you need updated during the
                        //background operation.
                        //Reporting progress too often will have a
                        //significant performance impact

                       
                        percentDoneDbl = (Convert.ToDouble(i) / Convert.ToDouble(WordData.Count)) * 100.0;
                        percentDoneInt = Convert.ToInt32(percentDoneDbl);
                        state.PercentDone = percentDoneInt;

                        worker.ReportProgress(0, state); //report progress back to form
                        lastReportedDateTime = DateTime.Now; //update last reported time

                    } 

                    //-------------------------------
                    // end of progress reporting
                    //-------------------------------


                    //create Word document(s)
                    var t1 = Task.Run(() =>
                    {
                        try
                        {
                            CreateWordDocument(WordData[i].Filename, WordData[i].LetterBody);
                        }
                        finally
                        {
                            concurrencySemaphore.Release();
                        }

                    }).ContinueWith(task =>
                    {

                        byte[] fBytes = File.ReadAllBytes(WordData[i].Filename);
                        return fBytes;
                    });

                    byte[] bytesRead = (byte[])t1.Result;
                    //System.Diagnostics.Debug.WriteLine("t1[" + i + "].Length: " + t1.Result.Length);

                    //add to list
                    tasks.Add(t1);

                }

                Task.WaitAll(tasks.ToArray());

                //clean up
                tasks.Clear();
            }


            Debug.WriteLine("Status: Complete " + DateTime.Now.ToString("HH:mm:ss"));


            if (e.Cancel == true)
            {
                state.Status = "Status: Cancelled by user.";
            }
            else
            {
                state.PercentDone = 100;
                state.Status = "Status: Complete.";
            }

            worker.ReportProgress(0, state); //report progress back to form
            lastReportedDateTime = DateTime.Now; //update last reported time

        }
        finally
        {
                //don't put any catch statements here so
                //the errors will end up in e.Error in
                //backgroundWorker1_RunWorkerCompleted.
                //Handle the errors in
                //backgroundWorker1_RunWorkerCompleted.
            
        }
    }

private string CreateWordDocument(string filename, string userData)
{
    //*Note: All indices start at 1. 

    string result = string.Empty;

    //set value
    object oMissing = System.Reflection.Missing.Value;
    object oEndOfDoc = "\\endofdoc"; /* \endofdoc is a predefined bookmark */

    Word.Documents documents = null;
    Word.Document doc = null;

    bool isVisible = false;


    try
    {

        //suppress displaying alerts (such as prompting to overwrite existing file)
        _wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

        //set Word visibility
        _wordApp.Visible = isVisible;

        //if writing/updating a large amount of data
        //disable screen updating by setting value to false
        //for better performance.
        //re-enable when done writing/updating data, if desired
        //_wordApp.ScreenUpdating = false;

        if (_wordApp != null)
        {
            if (File.Exists(filename))
            {
                //System.Diagnostics.Debug.WriteLine("'" + filename + "' exists. Existing file will be modified.");

                //open existing Word document
                documents = _wordApp.Documents;
                doc = documents.Open(filename, System.Reflection.Missing.Value, false, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, isVisible, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
                doc.Activate();
            }
            else
            {
                //create new document
                doc = _wordApp.Documents.Add();
                doc.Activate();

                //Debug.WriteLine("Created new document");
            }

            if (doc == null)
            {
                Debug.WriteLine("Error: doc is null");
                return null;
            }

            //set text
            doc.Content.Text = userData;

            if (!_wordApp.ScreenUpdating)
            {
                //in case screen updating was previously disabled, 
                //enable screen updating by setting value to true
                _wordApp.ScreenUpdating = true;

                //refresh screen
                //_wordApp.ScreenRefresh();
            }

            if (!String.IsNullOrEmpty(filename))
            {
                try
                {
                    //Debug.WriteLine("Saving to '" + filename + "'");

                    //save the document
                    //doc.SaveAs(filename, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);

                    doc.SaveAs2(filename, Word.WdSaveFormat.wdFormatXMLDocument, CompatibilityMode: Word.WdCompatibilityMode.wdWord2013);

                }//try
                catch (Exception ex)
                {
                    string errMsg = "Error: WordWriteDocument - " + ex.Message;
                    System.Diagnostics.Debug.WriteLine(errMsg);

                    if (ex.Message.StartsWith("Cannot access read-only document"))
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message + "Please close the Word document, before trying again.", "Error - Saving", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                    }
                }
            }

            //set value
            result = "Success";
        }

    }
    catch (Exception ex)
    {
        string errMsg = "Error: WordWriteDocument - " + ex.Message;
        System.Diagnostics.Debug.WriteLine(errMsg);
    }
    finally
    {
        
        if (doc != null)
        {
            //close document
            doc.Close(Word.WdSaveOptions.wdDoNotSaveChanges, System.Reflection.Missing.Value, System.Reflection.Missing.Value);

            //release all resources
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
        }

    }

    return result;
}

To Use:

Add the following declarations (to a Windows form, UserControl, or Class). Alternatively, if using Windows forms, Backgroundworker can be added from the ToolBox.

private BackgroundWorker backgroundWorker1 = new BackgroundWorker();
private ClsHelperWord helperWord = null;

Set Backgroundworker properties and subscribe to events -- this can be placed in the constructor.

//set properties
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;

//subscribe to events (add listener)
backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += BackgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;

BackgroundWorker1_DoWork

private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    System.ComponentModel.BackgroundWorker worker;
    worker = (System.ComponentModel.BackgroundWorker)sender;
    ClsHelperWord myClsHelperWord = (ClsHelperWord)e.Argument;

    helperWord.ConvertToWordDocument(worker, e);
} 

BackgroundWorker1_ProgressChanged

private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    CurrentState state = (CurrentState)e.UserState;

    Debug.WriteLine(state.Status + " " + state.PercentDone.ToString());
}

BackgroundWorker1_RunWorkerCompleted

private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{

    if (e.Error != null)
    {
        // Handle the errors here.
        // Write error message to console
        // and/or a log file.

        Debug.WriteLine("Error: " + e.Error.Message);

        if (helperWord != null)
        {
            helperWord.Dispose();
            helperWord = null;
        }

    } 
    else if (e.Cancelled)
    {
        Debug.WriteLine("Cancelled by user.");

        if (helperWord != null)
        {
            helperWord.Dispose();
            helperWord = null;
        }

    } 
    else
    {
        string finalStatus = "Status: Complete.";
        Debug.WriteLine(finalStatus);

        //clean up
        if (helperWord != null)
        {
            helperWord.Dispose();
            helperWord = null;
        }
    } 
} 

I use the following method to create some filenames and document text (for testing).

CreateTestData

private List<WordFileInfo> CreateTestData(string folderName, string sampleLetterBody)
{
    //create data for testing

   int numTestFiles = 50; //for testing purposes

   List<WordFileInfo> wordData = new List<WordFileInfo>();

    for (int i = 0; i < numTestFiles; i++)
    {
        string filename = System.IO.Path.Combine(folderName, "WordDoc" + (i + 1).ToString() + ".docx");

        //add to list
        wordData.Add(new WordFileInfo(filename, sampleLetterBody));

        //Debug.WriteLine("Filename: '" + filename + "'");
    }

    return wordData;
}

Then use the following to test creating the Word document(s):

string folderName = @"C:\Temp";
string sampleLetterBody = "This is some text.";

//get data for testing
List<WordFileInfo> wordData = CreateTestData(folderName, sampleLetterBody);

if (helperWord != null)
{
    helperWord.Dispose();
    helperWord = null;
}

//create new instance and set property
helperWord = new ClsHelperWord(wordData);

if (backgroundWorker1.IsBusy != true)
{
    backgroundWorker1.RunWorkerAsync(helperWord);
}//if

Option 2:

*Note: If used with Windows forms, this option may cause the UI to be unresponsive.

ClsHelperWord.cs

public class ClsHelperWord : IDisposable
{
    //depending on the number of files processed,
    //changing this value may increase/decrease performance slightly
    private int _maxConcurrentTasks = 25; 

    //create new instance
    private Word.Application _wordApp = new Word.Application();

    //store data that needs to be processed
    public List<WordFileInfo> WordData { get; set; } = new List<WordFileInfo>();


    public ClsHelperWord()
    {

    }

    public ClsHelperWord(List<WordFileInfo> wordData)
    {
        //set value
        this.WordData = wordData;
    }

    public void Close()
    {
        Dispose();
    }

    public void Dispose()
    {
        if (_wordApp != null)
        {
            //close Word
            object oFalse = false;
            _wordApp.Quit(ref oFalse, ref oFalse, ref oFalse);

            //release all resources
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_wordApp);
        }
    }

    public void ConvertToWordDocument()
    {
        Debug.WriteLine("\nConverting to Word doc...");

        using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim (_maxConcurrentTasks))
        {
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < WordData.Count; i++)
            {
                concurrencySemaphore.Wait();

                var t1 = Task.Run(() =>
                {
                    try
                    {
                        CreateWordDocument(WordData[i].Filename, WordData[i].LetterBody);
                    }
                    finally
                    {
                        concurrencySemaphore.Release();
                    }
                    
                }).ContinueWith(task =>
                {

                    byte[] fBytes = File.ReadAllBytes(WordData[i].Filename);
                    return fBytes;    
                });

                byte[] bytesRead = (byte[])t1.Result;
                //System.Diagnostics.Debug.WriteLine("t1[" + i + "].Length: " + t1.Result.Length);

                //add to list
                tasks.Add(t1);

            }

            Task.WaitAll(tasks.ToArray());

            //clean up
            tasks.Clear();
        }


        Debug.WriteLine("Status: Complete " + DateTime.Now.ToString("HH:mm:ss"));
    }

 
private string CreateWordDocument(string filename, string userData)
    {
        //*Note: All indices start at 1. 

        string result = string.Empty;

        //set value
        object oMissing = System.Reflection.Missing.Value;
        object oEndOfDoc = "\\endofdoc"; /* \endofdoc is a predefined bookmark */

        Word.Documents documents = null;
        Word.Document doc = null;

        bool isVisible = false;


        try
        {

            //suppress displaying alerts (such as prompting to overwrite existing file)
            _wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

            //set Word visibility
            _wordApp.Visible = isVisible;

            //if writing/updating a large amount of data
            //disable screen updating by setting value to false
            //for better performance.
            //re-enable when done writing/updating data, if desired
            //_wordApp.ScreenUpdating = false;

            if (_wordApp != null)
            {
                if (File.Exists(filename))
                {
                    //System.Diagnostics.Debug.WriteLine("'" + filename + "' exists. Existing file will be modified.");

                    //open existing Word document
                    documents = _wordApp.Documents;
                    doc = documents.Open(filename, System.Reflection.Missing.Value, false, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, isVisible, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
                    doc.Activate();
                }
                else
                {
                    //create new document
                    doc = _wordApp.Documents.Add();
                    doc.Activate();

                    //Debug.WriteLine("Created new document");
                }

                if (doc == null)
                {
                    Debug.WriteLine("Error: doc is null");
                    return null;
                }

                //set text
                doc.Content.Text = userData;

                if (!_wordApp.ScreenUpdating)
                {
                    //in case screen updating was previously disabled, 
                    //enable screen updating by setting value to true
                    _wordApp.ScreenUpdating = true;

                    //refresh screen
                    //_wordApp.ScreenRefresh();
                }

                if (!String.IsNullOrEmpty(filename))
                {
                    try
                    {
                        //Debug.WriteLine("Saving to '" + filename + "'");

                        //save the document
                        //doc.SaveAs(filename, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);

                        doc.SaveAs2(filename, Word.WdSaveFormat.wdFormatXMLDocument, CompatibilityMode: Word.WdCompatibilityMode.wdWord2013);

                    }//try
                    catch (Exception ex)
                    {
                        string errMsg = "Error: WordWriteDocument - " + ex.Message;
                        System.Diagnostics.Debug.WriteLine(errMsg);

                        if (ex.Message.StartsWith("Cannot access read-only document"))
                        {
                            System.Windows.Forms.MessageBox.Show(ex.Message + "Please close the Word document, before trying again.", "Error - Saving", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                        }
                    }
                }

                //set value
                result = "Success";
            }

        }
        catch (Exception ex)
        {
            string errMsg = "Error: WordWriteDocument - " + ex.Message;
            System.Diagnostics.Debug.WriteLine(errMsg);
        }
        finally
        {
            
            if (doc != null)
            {
                //close document
                doc.Close(Word.WdSaveOptions.wdDoNotSaveChanges, System.Reflection.Missing.Value, System.Reflection.Missing.Value);

                //release all resources
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
            }

        }

        return result;
    }
}

To use:

I use the following method to create some filenames and document text (for testing).

CreateTestData

private List<WordFileInfo> CreateTestData(string folderName, string sampleLetterBody)
{
    //create data for testing

   int numTestFiles = 50; //for testing purposes

   List<WordFileInfo> wordData = new List<WordFileInfo>();

    for (int i = 0; i < numTestFiles; i++)
    {
        string filename = System.IO.Path.Combine(folderName, "WordDoc" + (i + 1).ToString() + ".docx");

        //add to list
        wordData.Add(new WordFileInfo(filename, sampleLetterBody));

        //Debug.WriteLine("Filename: '" + filename + "'");
    }

    return wordData;
}

Then use the following to test creating the Word document(s):

string folderName = @"C:\Temp";
string sampleLetterBody = "This is some text.";

//get data for testing
List<WordFileInfo> wordData = CreateTestData(folderName, sampleLetterBody);

using (ClsHelperWord helperWord = new ClsHelperWord(wordData))
{
    helperWord.ConvertToWordDocument();
}

The following posts may also be helpful.

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24