Quantcast
Channel: SCN : Discussion List - SAP Crystal Reports, version for Visual Studio
Viewing all articles
Browse latest Browse all 3636

Memory Leak using SAP Crystal Reports Runtime for Visual Studio

$
0
0

Hello,

 

We are using SAP Crystal Reports for Visual Studio Runtime (Service Pack 15) as our printing engine in a .NET 4.6 Windows Service and we have found out a memory leak that we cannot avoid and it produces a serious memory increase in the long run.

 

The fact is that it seems that there are several unmanaged objects from the runtime (C++) that are not disposed / free and produces the memory leak because we have not found any memory problem in .NET objects (we have observed it using a Memory Profiler to analyse the process memory).

 

I've reviewed the code and apply a Fix we found for the previous runtime (CR 11 Runtime versión) but the memory leak persists .

 

The code is quite simple and it assures the dipose of the CR objects, I attached the code used to execute the report:

 

public GReportResult PrintReport(string xmldata, int copies, string layoutpath, string outputpath, string outputformat, string filename, string document, string pathSchema)        {            int result = 0;            string error = string.Empty;            try            {                using (SafeReportDocument report = new SafeReportDocument())                {                    using (DataSet reportData = new DataSet())                    {                        reportData.Locale = CultureInfo.InvariantCulture;                        try                        {                            reportData.EnforceConstraints = false;                            using (var xmlSchemaReader = new System.IO.StreamReader(Environment.ExpandEnvironmentVariables(pathSchema)))                            {                                reportData.ReadXmlSchema(xmlSchemaReader);                                using (var xmlDataReader = new System.IO.StringReader(xmldata))                                {                                    reportData.ReadXml(xmlDataReader);                                    try                                    {                                        report.Load(Environment.ExpandEnvironmentVariables(layoutpath));                                        try                                        {                                            report.SetDataSource(reportData);                                            try                                            {                                                switch (outputformat)                                                {                                                    case "Raw":                                                        report.PrintOptions.PrinterName = outputpath;                                                        report.PrintToPrinter(copies, false, 0, 0);                                                        break;                                                    case "Pdf":                                                        report.ExportToDisk(ExportFormatType.PortableDocFormat, filename);                                                        break;                                                    case "Excel":                                                        report.ExportToDisk(ExportFormatType.Excel, filename);                                                        break;                                                    case "Rtf":                                                        report.ExportToDisk(ExportFormatType.EditableRTF, filename);                                                        break;                                                    case "Html":                                                        report.ExportToDisk(ExportFormatType.HTML40, filename);                                                        break;                                                }                                            }                                            catch (Exception prn)                                            {                                                //PRINTERROR                                                result = 1;                                                error = prn.Message;                                            }                                        }                                        catch (Exception data)                                        {                                            //PMDATASOURCEERROR                                            result = 2;                                            error = data.Message;                                        }                                    }                                    catch (Exception load)                                    {                                        //PMLAYOUTERROR                                        result = 3;                                        error = load.Message;                                    }                                    }                                }                            }                        }                        catch (Exception px)                        {                            //PMXMLDATAERROR                            result = 4;                            error = px.Message;                        }                    }                }                GC.Collect();                GC.WaitForPendingFinalizers();                GC.Collect();            }            catch (Exception ex)            {                //PMERRINSTANCECMDOCUMENT                result = 5;                error = ex.Message;            }            GReportResult reportResult = new GReportResult(result, error);            return reportResult;        }

And the SafeReportDocument.class (used to fix the memory leak in CR RT 11):

 

public class SafeReportDocument : ReportDocument, IDisposable    {        private void CleanGlobalEvents()        {            Delegate domainUnloadDelegate = (Delegate)typeof(AppDomain).GetField("_domainUnload",                BindingFlags.Instance | BindingFlags.NonPublic).GetValue(AppDomain.CurrentDomain);            Delegate[] invocationList = domainUnloadDelegate.GetInvocationList();            Delegate ev;            for (short i = 0; i < invocationList.Length; i++)            {                ev = invocationList[i];                if (ev.Target != null && ev.Target.Equals(this))                {                    AppDomain.CurrentDomain.DomainUnload -= (EventHandler)ev;                }            }            Delegate processExitDelegate = (Delegate)typeof(AppDomain).GetField("_processExit",                BindingFlags.Instance | BindingFlags.NonPublic).GetValue(AppDomain.CurrentDomain);            invocationList = processExitDelegate.GetInvocationList();            for (short i = 0; i < invocationList.Length; i++)            {                ev = invocationList[i];                if (ev.Target != null && ev.Target.Equals(this))                {                    AppDomain.CurrentDomain.ProcessExit -= (EventHandler)ev;                }            }        }        /// <summary>        /// Cleans up resources        /// </summary>        /// <param name="disposing"></param>        protected override void Dispose(bool disposing)        {            if (disposing)            {                this.CleanGlobalEvents();            }            base.Dispose(disposing);        }    }

 

Is there any issue and fix regarding this case?

 

Thanks a lot for your time and your support.

 

Kind regards,

Yamel.


Viewing all articles
Browse latest Browse all 3636

Trending Articles