none
Error during local report processing - expression_host_xxxx.dll in use by another process RRS feed

  • Question

  • I have a problem in an application when generating several reports in a short time:
    ----Exception dump:-------------------------------------------
    An error occurred during local report processing.
    The definition of the report 'Main Report' is invalid.
    An unexpected error occurred in Report Processing.
    The process does not get access to the file C:\Documents and Settings\<user name>\Local Settings\Temp\expression_host_0305bdaed5fc4308ac39a8bcb78275d0.dll because it is in use by another process.
    --------------------------------------------------------------------

    (last line translated from Norwegian and may not be exact what would have been said by an English version of Windows XP)

    The application in question is used by several of our customers, but only two of our customers have the problem.
    The reports are generated with output to a printer.

    The problem only occurs when generating several reports in a short time - like invoicing (each invoice is a (new) report).
    The application uses local reports only (no report server involved).

    It looks to me like there is a race condition here where the next report is started before the previous has completely finished.
    The problem does not happen identically every time. Usually some of the generated

    The application was earlier VS2005, FW2.0. It has been upgraded to VS2008, FW3.5SP1 but the problem is still there.

    Here's the code for the PrintUtil class we use for printing reports:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Drawing.Printing;
    using Microsoft.Reporting.WinForms;
    using System.Drawing.Imaging;
    using System.Windows.Forms;

    namespace BBBBB
    {
      
    class PrintUtil
      
    {
         
    private int m_currentPageIndex;
         
    private IList<Stream> m_streams;
         
    private ReportDataSource[] rdsarray;
         
    private ReportParameter[] rparray;
         
    private string fileStreamPath;
         
    private string reportPath;
         
    private string printerPath;

         
    public PrintUtil(string str_fileStream, string str_reportPath, string str_printerPath, ReportDataSource[] rds, ReportParameter[] rp)
          {
             fileStreamPath = str_fileStream;
             reportPath = str_reportPath;
             printerPath = str_printerPath;
             rdsarray = rds;
             rparray = rp;
          }

         
    // Routine to provide to the report renderer, in order to
         
    // save an image for each page of the report.
         
    private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
          {
            
    Stream stream = null;
            
    int x = 0;
            
    string sadd = "", sPath;
            
    bool bSuccess = false;

            
    while (!bSuccess)
             {
               
    try
               
    {
                   sPath = fileStreamPath + name + sadd +
    "." + fileNameExtension;
                   stream =
    new FileStream(sPath, FileMode.Create);
                   bSuccess =
    true;
                }
               
    catch (Exception)
                {
                  
    //Traps to here sometimes with error "file already in use" or similar
                  
    //so have to create a new file name here
                  
    bSuccess = false;
                   sadd =
    "-" + x.ToString();
                   x++;
                }
             }
             m_streams.Add(stream);
            
    return stream;
          }

         
    // Export the given report as an EMF (Enhanced Metafile) file.
         
    private void Export(LocalReport report)
          {
            
    string deviceInfo =
               
    "<DeviceInfo>" +
               
    " <OutputFormat>EMF</OutputFormat>" +
               
    " <PageWidth>8.5in</PageWidth>" +
               
    " <PageHeight>11in</PageHeight>" +
               
    " <MarginTop>0.25in</MarginTop>" +
               
    " <MarginLeft>0.25in</MarginLeft>" +
               
    " <MarginRight>0.25in</MarginRight>" +
               
    " <MarginBottom>0.25in</MarginBottom>" +
               
    "</DeviceInfo>";
            
    Warning[] warnings;
             m_streams =
    new List<Stream>();
            
    try
            
    {
                report.Render(
    "Image", deviceInfo, CreateStream, out warnings);
             }
            
    catch (Exception ex)
             {
               
    string sMsg = ex.Message;
               
    Exception inner = ex.InnerException;
               
    while (inner != null)
                {
                  
    if (inner.Message != null)
                      sMsg +=
    "\n" + inner.Message;
                   inner = inner.InnerException;
                }
               
    MessageBox.Show(sMsg, "Report", MessageBoxButtons.OK, MessageBoxIcon.Warning);
             }
            
    foreach (Stream stream in m_streams)
             stream.Position = 0;
          }

         
    // Handler for PrintPageEvents
         
    private void PrintPage(object sender, PrintPageEventArgs ev)
          {
            
    Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
             ev.Graphics.DrawImage(pageImage, ev.PageBounds);
             m_currentPageIndex++;
             ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
          }

         
    private string Print()
          {
            
    string printerName = printerPath;
            
    if (m_streams == null || m_streams.Count == 0)
               
    return "No documents to print";
            
    PrintDocument printDoc = new PrintDocument();
             printDoc.PrinterSettings.PrinterName = printerName;
            
    if (!printDoc.PrinterSettings.IsValid)
             {
               
    string msg = String.Format("Cannot find printer \"{0}\".", printerName);
               
    return msg;
             }
             printDoc.PrintPage +=
    new PrintPageEventHandler(PrintPage);
             printDoc.Print();
            
    return "1";
          }

         
    // Create a local report for Report.rdlc, load the data,
         
    // export the report to an .emf file, and print it.
         
    public string ExecReport()
          {
            
    LocalReport report = new LocalReport();
             report.ReportEmbeddedResource = reportPath;
             report.EnableExternalImages =
    true;
            
    if (rparray != null) //add parameters to report if included.
               
    report.SetParameters(rparray);
            
    foreach (ReportDataSource rds in rdsarray)
                report.DataSources.Add(rds);
             Export(report);
             m_currentPageIndex = 0;
            
    string result = Print();
            
    return result;
          }
       }
    }

    The report is created by the following code:

       string fileStreamPath = Environment.ExpandEnvironmentVariables("%TEMP%");
       PrintUtil pu =
    new PrintUtil(fileStreamPath, reportPath, printerPath, rdsarray, rparray);
       result = pu.ExecReport();

    ------------------------------------

    Does anybody else experience the problem? Any clues to what's wrong and how the problem can be avoided?
    My theory is that it is a race problem in the reporting code (notice similar problem in the CreateStream routine above where an exception occurs because the file name is already in use- handled by generating a new file name).
    Another indication for a race problem is that it is experienced by only a couple of customers, and after varying numbers of reports generated.

    KE.


    Programmer
    Monday, November 3, 2008 5:00 PM

All replies

  • The race condition is present, but it is in your code, not in the ReportViewer.  If multiple people run your application at one time, your CreateStream callback will generate a new file in the temp directory based only on name of the stream.  Two people running the same report can both have the same named stream in their report.  If that happens, your attempt to create the temp file will fail with the error you are seeing.

    Basically, you need to modify your CreateSteam method to ensure that the name of the file you create is always unique, even when the parameters to the method are the same as a previous call.  I'd recommend calling Path.GetTempFileName() to generate a file name that is unique.
    Wednesday, November 5, 2008 2:35 PM
    Moderator
  • Thanks for the answer!

    I know there is a problem in my CreateStream method so I trap the exception and generates a new file name (adds an increasing number to the file name until the new FileStream(...) call stops failing). I agree that using Path.GetTempFileName() is a better solution, so I will change the code.

    Because I handle the file collision in CreateStream, this method always succeeds. Also, there is only one person running the application at the same time. Can this anyway be the cause of the "expression_host_xxxx.dll failure?

    Programmer
    Wednesday, November 5, 2008 3:49 PM
  • More info about this problem: I have a suspicion that the problem is caused by a resource leak somewhere because when the problem first occurs it tends to stay, that is, outputting the report(s) again often fails - sometimes at once, sometimes after a few reports have been printed.
    Restarting the program does not help, but restarting the computer removes the problem (for one to several days). This indicates to me that there is a resource leak somewhere outside our program's control.

    KE.
    Programmer
    Monday, May 18, 2009 11:44 AM