0

Im trying to create a lot of PDF's from several word documents. Unfortuntately Im not able to close/clean up (Garbage Collection). Therefore memory consumption rices a lot, and eventually the program dumps.

Here is my code. I hope that you clever guys can guide me to a solution.

//**************************************************************
// Please notice:
//
// this.Files is an array with filepath and filenames e.g.:
// {"x:\doc\doc1.doc", "x:\doc\doc2.doc",...,"x:\doc\docn.doc"}.
//
// Please notice:
//**************************************************************


public void wordToPDF() {

    string LS_fileName = "";
    string LS_fileExtension = "";
    string LS_PDF = ".pdf";

    try
    {
        foreach (string Filename in this.Files)
        {
            LS_fileName = Path.GetFileName( Filename );
            if (Path.GetExtension( Filename ) == ".doc" || Path.GetExtension( Filename ) == ".docx")
            { 
                // Convert to PDF:
                Microsoft.Office.Interop.Word.Application appWord = new Microsoft.Office.Interop.Word.Application();
                wordDocument = appWord.Documents.Open(GlobalVar.TempFiles + LS_fileName);
                LS_fileExtension = Path.GetExtension(Filename);

                LS_fileName = LS_fileName.Replace( LS_fileExtension, LS_PDF );                  int i = 0;
                foreach (string value in this.Files)
                {
                    if (value == Filename)
                    {
                         this.Files[i] = this.Files[i].Replace(LS_fileExtension, LS_PDF);
                         break;
                    }
                    i++;
                }
                wordDocument.ExportAsFixedFormat(GlobalVar.TempFiles + LS_fileName, MSWORD.WdExportFormat.wdExportFormatPDF);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(appWord);
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("getFiles Hello I must be going.");
    }
}
}

//UPDATE #1:

public void wordToPDF() {

    string LS_fileName = "";
    string LS_fileExtension = "";
    string LS_PDF = ".pdf";
    int i = 0;

    MSWORD.Application appWord = new MSWORD.Application();

    try
    {
        foreach (string Filename in this.Files)
            {
                LS_fileName = Path.GetFileName( Filename );
                    if (Path.GetExtension( Filename ) == ".doc" || Path.GetExtension( Filename ) == ".docx")
                    { 
                        // Convert to PDF:
                        wordDocument = appWord.Documents.Open(GlobalVar.TempFiles + LS_fileName);
                        LS_fileExtension = Path.GetExtension(Filename);

                        LS_fileName = LS_fileName.Replace( LS_fileExtension, LS_PDF );
                        i = 0;
                        foreach (string value in this.Files)
                        {
                            if (value == Filename)
                            {
                               this.Files[i] = this.Files[i].Replace(LS_fileExtension, LS_PDF);
                                break;
                            }
                            i++;
                            }
                            wordDocument.ExportAsFixedFormat(GlobalVar.TempFiles + LS_fileName, MSWORD.WdExportFormat.wdExportFormatPDF);
                    }
    }
}
    catch (Exception ex)
    {
        Console.WriteLine("getFiles Hello I must be going.");
        System.Runtime.InteropServices.Marshal.ReleaseComObject(appWord);
    wordDocument.Close();
    if (appWord != null)
    {
        appWord.Quit();
        appWord = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
    System.Runtime.InteropServices.Marshal.ReleaseComObject(appWord);
wordDocument.Close();
    if (appWord != null)
    {
        appWord.Quit();
        appWord = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

//UPDATE #2:

public void wordToPDF() 
{

    string LS_fileName = "";
    string LS_fileExtension = "";
    string LS_PDF = ".pdf";
    object missingType = Type.Missing;
    object SaveChanges = Type.Missing;
    object OriginalFormat = Type.Missing;
    object RouteDocument = Type.Missing;

    MSWORD.Application appWord = new MSWORD.Application();

    try
    {
        foreach (string Filename in this.Files)
            {
                LS_fileName = Path.GetFileName( Filename );
                    if (Path.GetExtension( Filename ) == ".doc" || Path.GetExtension( Filename ) == ".docx")
                    { 
                            // Convert to PDF:
            wordDocument = appWord.Documents.Open(GlobalVar.TempFiles + LS_fileName);
                            LS_fileExtension = Path.GetExtension(Filename);

                            LS_fileName = LS_fileName.Replace( LS_fileExtension, LS_PDF );
                            int i = 0;
                            foreach (string value in this.Files)
                            {
                                if (value == Filename)
                                {
                                    this.Files[i] = this.Files[i].Replace(LS_fileExtension, LS_PDF);
                                    break;
                                }
                                i++;
                            }
                            wordDocument.ExportAsFixedFormat(GlobalVar.TempFiles + LS_fileName, MSWORD.WdExportFormat.wdExportFormatPDF);

                            wordDocument.Close();
                    }
                }
    }
            catch (Exception ex)
            {
                Console.WriteLine("getFiles Hello I must be going.");
                System.Runtime.InteropServices.Marshal.ReleaseComObject(appWord);

                if (appWord != null)
                {
                    appWord.Quit();
                    appWord = null;
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(appWord);

            appWord.Quit(ref object SaveChanges = Type.Missing, ref object OriginalFormat);
            if (appWord != null)
            {
                appWord = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                GC.WaitForPendingFinalizers();
        }
    }
}
Lars Hansen
  • 155
  • 1
  • 2
  • 16

4 Answers4

2

1)Try to move this line out of you loop. (foreach (string Filename in this.Files))

 Microsoft.Office.Interop.Word.Application appWord = new Microsoft.Office.Interop.Word.Application();

2) Close all Documents at the end of the loop (foreach (string Filename in this.Files)) that will close all Word windows, or you can save you link for saved document and close it.

Edit:

foreach (string Filename in this.Files)
        {
            LS_fileName = Path.GetFileName( Filename );
                if (Path.GetExtension( Filename ) == ".doc" || Path.GetExtension( Filename ) == ".docx")
                { 
                    // Convert to PDF:
                    wordDocument = appWord.Documents.Open(GlobalVar.TempFiles + LS_fileName);
                    LS_fileExtension = Path.GetExtension(Filename);

                    LS_fileName = LS_fileName.Replace( LS_fileExtension, LS_PDF );
                    i = 0;
                    foreach (string value in this.Files)
                    {
                        if (value == Filename)
                        {
                           this.Files[i] = this.Files[i].Replace(LS_fileExtension, LS_PDF);
                            break;
                        }
                        i++;
                        }
                        wordDocument.ExportAsFixedFormat(GlobalVar.TempFiles + LS_fileName, MSWORD.WdExportFormat.wdExportFormatPDF);
                       wordDocument.Close(missing, missing, missing);
                }
}

Discription: Due to word model, word is an app that have one main body Microsoft.Office.Interop.Word.Application it's contains all documents that open at runtime, those documents looks like a standalone applications (windows) but they are not.

Shakra
  • 501
  • 2
  • 8
  • I have read your comment and some articles. I have followed your step 1 as in "Adviced practice" This works - However. Regarding your step 2: It seems I can't close the document. Can you please guide me? Thanks in advance. – Lars Hansen Jul 28 '16 at 09:26
  • Please refer to Update # 1. – Lars Hansen Jul 28 '16 at 09:41
  • 1
    [Word.Document.Close()](https://msdn.microsoft.com/en-US/library/af6z0wa2.aspx) **Closing a Document That You Specify By Name** paragraph would be the easiest example if you have a link for an open document. – Shakra Jul 28 '16 at 10:11
  • As you see in my Update #1, I actually does this: wordDocument.Close(); But stil a worddocument remains open. – Lars Hansen Jul 28 '16 at 10:22
  • 1
    Sorry didn't see Udate #1 )) Change use wordDocument.Close() at the and of global foreach `foreach (string Filename in this.Files)` so it will close it on every run, due to your `Document.Open` on each iteration. And try to change it to `wordDocument.Close(missing,missing,missing)` where `object missing = Missing.Value;` – Shakra Jul 28 '16 at 10:47
  • Im declaring these outside the loop: object SaveChanges = Type.Missing; object OriginalFormat = Type.Missing; object RouteDocument = Type.Missing; ..And then if (appWord !=null){ appWord.Quit(ref missingType = SaveChanges, ref missingType = OriginalFormat, ref missingType = RouteDocument); appWord=null; GC... } Now the compiler says: A ref or out argument must be an assignable variable. Im getting tunnelvision :-( – Lars Hansen Jul 28 '16 at 13:49
  • You must close document right after it's using, after ending of inner `foreach` but **befor** outter `foreach` will ends. If you wouldn't do that all opened documents will stay opened, and you will close only the last one (with current code). Right now you open `this.Files.Lenght` documents **but** close only 1. – Shakra Jul 28 '16 at 13:56
  • Please refer to Update #2. This is (I think) what we both agree about, but still I get: "A ref or out argument must be an assignable variable." – Lars Hansen Jul 28 '16 at 15:25
1

Make sure to close the document and application before releasing the COM Object, then dispose and maybe force GC.Collect().
Edit: If you use word multiple times, it's sufficient to start word once and open your files for pdf export, then close, one by one. Finally close wordApp.
Edit2: you should reset i to 0 each time you start your inner loop

Sebastian
  • 379
  • 1
  • 7
  • I have tried this without luck. This is what I need help for. Thanks in advance. – Lars Hansen Jul 27 '16 at 12:53
  • can you add the close wordDocument and finally close appWord to your code? Maybe it was misplaced... – Sebastian Jul 27 '16 at 12:55
  • wordDocument.Close(); works fine Then appWord.Quit(); results in:"A COM-object, witch has been separated from its RCW, can not be used." this is the message I get – Lars Hansen Jul 27 '16 at 13:02
  • maybe look here: http://stackoverflow.com/questions/2260990/com-object-that-has-been-separated-from-its-underlying-rcw-cannot-be-used – Sebastian Jul 27 '16 at 13:05
1
  1. Use "using" clause
  2. Extract the loop contents into a separate method to simplify things for the GC
  3. GC collect should be called only if you dont have a choice

I dont understand why do you do the inner for loop

Mitzi
  • 2,652
  • 1
  • 20
  • 15
  • 1. Somehow I can't use using- it didn't work :-( 2 + 3. I will try this. The reason for this, is that this.Files contains other documents (PDFs). So It must only create PDF's based on the word documents. the content of this.Files (if word document) is then updated with the PDF extension. The end result is then that this.Files only contains the PDF's path, name and extension. – Lars Hansen Jul 27 '16 at 13:16
  • Using is just for IDisposable objects – Mitzi Jul 27 '16 at 16:33
0

Apparently quitting the winword application doesn't work. Hense a more rudimentary solution is applied:

Process[] processes = Process.GetProcessesByName("winword");
foreach (var process in processes)
{
    try
    {
        process.Kill();
    }
    catch (Exception)
    {
    // handle the exception...                    
    }

}
// That solved the problem.
// Thanks for your help :-).
Lars Hansen
  • 155
  • 1
  • 2
  • 16