Using PDFNet in a Windows service

Q: I'm having problems using the PDFNet dll in a windows service
application I created. The Windows Service is multi-threaded and each
thread opens at least one existing PDF, edits hyperlinks in that PDf,
and then saves it, converts it to image, and so on, before moving onto
the next PDF.

The problem I'm getting isn't easily reproducible. Sometimes the
PDFNet gets through 2 PDF files just fine and then crashes with an
"Unknown Exception" thrown on the third PDF file.
-----
A: A most common reason for this error is that PDFNet is not
initalized properly. You can fix the problem by making sure that
PDFNet is one time initialized in the same module where it is used.
For example:

namespace PdfServiceLibrary
{
    public class PdfService : MarshalByRefObject
    {
        public static bool _init = false;

        public byte[] WritePdfAsPng(String filename)
        {
                if (_init == false) {
                        _init = true;
                        pdftron.PDFNet.Initialize();

pdftron.PDFNet.SetResourcesPath(PDFNET_RESOURCES_PATH);
                }

                try {
                        ... Use PDFNet ...
                }
                catch (Exception e)
                {
                        EventLog.WriteEntry("PDF Load Test", e.Message
+ "\n" + e.StackTrace);
                        return new byte[0];
                }
        }
    }
}

Q: I have found another issue when using PDFTRON PDFNet in a Windows
Service.

I made a small test application that all it does is loop through 10
pdf files, edits them, then saves them to a brand new location. When
it's finished with the 10 pdf files, I then call close and dispose on
the PDFTRON.PDF.PDFDoc object. This works fine for one iteration.

But when I try to run that code a second time, using an output
location that is different from the first iteration, an error is
thrown of "Unknown Exception". I have found that if I take the close
and dispose out of the code, it no longer breaks. I can re-run the
code as many times as I want without any issue. Plus I have found
that if I try to close and dispose the PDFTRON.PDF.PDFDoc object after
saving each PDF file, I get that same error message.

The problem I have is with my real application, after I finish editing
and saving a batch of PDF files, I need to remove any connections to
those resources, so that I can delete the resulting pdf files later.
It appears to me that PDFTRON isn't letting go of the saved PDF files
until after I close down the application. This really wouldn't be
much of an issue if the application was a desktop app, but I'm making
a windows service that needs to be constantly running. I can't keep
shutting it down so that I can them clean up PDF files that PDFTRON
won't let go of.

Is there something I'm not doing to force PDFTRON to let go of any PDF
files it has saved?
-----
A: The problem is actually related to a bug in .NET Framework and
Visual Studio (known as "Mixed DLL loading problem").

In your case when .NET garbage collector cleans-up all PDFNet objects
Windows service decides to unload and reload PDFNet DLL (resulting in
"Mixed DLL loading problem"). You can prevent Windows service from
unloading PDFNet by keeping a static reference to a dummy PDFNet
object. Please note that after we drop support for older versions
of .NET Framework you will not need to use this technique. Also you
don't need to use this technique is you are developing stand-alone of
web based (ASP.NET) application.

For example:

namespace PdfServiceLibrary {
  public class PdfService : MarshalByRefObject {

    public static PDFDoc _init = null;

    public byte[] WritePdfAsPng(String filename) {
      if (_init == null) {
        pdftron.PDFNet.Initialize();
        pdftron.PDFNet.SetResourcesPath(PDFNET_RESOURCES_PATH);
        _init = new PDFDoc();
      }
      else {
        // call a random function to keep dummy object in memory...
        _init.GetPageCount();
      }

      try {
        // ... Use PDFNet ...
        MemoryStream stream = new MemoryStream();
        PDFDraw pdfDraw = new PDFDraw();
        PDFDoc document = new PDFDoc(filename);
        Bitmap bitmap = pdfDraw.GetBitmap(document.GetPage(1));
        bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        bitmap.Dispose();
        document.Close();
        document.Dispose();
        return stream.ToArray();
      }
      catch (Exception e) {
        EventLog.WriteEntry("PDF Service Test", e.Message + "\n" +
e.StackTrace);
        return new byte[0];
      }
    }
  }
}