ReportPro 3.60 for XSharp 2.60 memory exception

This forum is the place to discuss issues related to ReportPro, Xs2Ado, Vo2Ado, bBrowser and other 3rd party products
User avatar
Michal Rajnoha
Posts: 23
Joined: Wed Sep 29, 2021 6:57 am

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Michal Rajnoha »

Chris wrote: Thu Apr 25, 2024 8:33 am Hi Michal,

Thanks for the very good sample, but unfortunately I could not reproduce the problem here, all 65 pages are always printed ok here. Does the problem happen with any printer driver? Even when selecting a pdf driver, like PDF creator or Microsoft's print to pdf driver from Windows? To be honest that's what I used as well, wanted to avoid wasting 65 pages of paper..
Yes, tried it with both virtual (Microsoft's Print to PDF) and physical printers and the problem occurs regardless of which one is used. What bothers me now is why I can't make it crash in XIDE in Debug mode.
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Chris »

Hi Michal,
Michal Rajnoha wrote: Thu Apr 25, 2024 8:46 am
Chris wrote: Thu Apr 25, 2024 8:33 am Thanks for the very good sample, but unfortunately I could not reproduce the problem here, all 65 pages are always printed ok here. Does the problem happen with any printer driver? Even when selecting a pdf driver, like PDF creator or Microsoft's print to pdf driver from Windows? To be honest that's what I used as well, wanted to avoid wasting 65 pages of paper..
Yes, tried it with both virtual (Microsoft's Print to PDF) and physical printers and the problem occurs regardless of which one is used. What bothers me now is why I can't make it crash in XIDE in Debug mode.
Memory corruption issues can be like that, when running through the debugger some memory locations may be different, preventing the underlying problem to expose itself. What OS are you using and what is the .Net Framework version installed? Also since I don't have your email address, can you please send me a short email and I will send you a link to a set of slightly newer RP3 files, they might make a difference as we fixed another issue that could be related recently.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
User avatar
Michal Rajnoha
Posts: 23
Joined: Wed Sep 29, 2021 6:57 am

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Michal Rajnoha »

Chris wrote: Thu Apr 25, 2024 9:18 am Memory corruption issues can be like that, when running through the debugger some memory locations may be different, preventing the underlying problem to expose itself. What OS are you using and what is the .Net Framework version installed? Also since I don't have your email address, can you please send me a short email and I will send you a link to a set of slightly newer RP3 files, they might make a difference as we fixed another issue that could be related recently.

We tried it on Windows 11 and Windows 10.
2 PCs where X# is installed and 1 with only redistributables. All have the same issue.
The latest version of .NET Framework we use is 4.8.1.

I will send the email soon.
xor_ag
Posts: 3
Joined: Wed May 29, 2024 11:56 am
Location: Switzerland

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by xor_ag »

Greetings,

We observe the exact same problem. It turns out that printing through the cPrinter class crashes with memory errors whenever we compile Classmate with the "Build/Optimize" flag. It only happens when using the printer DC, print preview is not affected. Disabling Optimize in Release builds (or using Debug builds) stops the crashes.

Is this a compiler bug or a Classmate bug? Is there a known fix?

Code: Select all

Anwendung: WorkSuite.exe
Frameworkversion: v4.0.30319
Beschreibung: Der Prozess wurde aufgrund einer unbehandelten Ausnahme beendet.
Ausnahmeinformationen: System.AccessViolationException
   bei VOWin32APILibrary.Functions.DrawText(Void*, IntPtr, Int32, VO._winRECT*, UInt32)
   bei Classmate.cHDC.DrawText(System.String, Int32, XSharp.__Float, XSharp.__Float, XSharp.__Float, XSharp.__Float, UInt32)
   bei PP_Server.PrintString(XSharp.__Usual[])
   bei PP_Server.PrintElement(XSharp.__Usual[])
   bei PP_Server.PrintSection(XSharp.__Usual[])
   bei PP_Server.PrintPageBody()
   bei Classmate.cPrinter._PrintPage()
   bei Classmate.cPrinter._PrintDoc()
   bei Classmate.cPrinter._PrintStart()
   bei Classmate.cPrintMsgDialog.OnTimer(Classmate.cEvent)
   bei Classmate.cWindow.Dispatch(Classmate.cEvent)
   bei Classmate.cBaseDialog.Dispatch(Classmate.cEvent)
   bei Classmate_Gui.Functions._cDialogProc(Void*, UInt32, UInt32, Int32)
   bei VOWin32APILibrary.Functions.IsDialogMessage(Void*, VO._winMSG*)
   bei Classmate.cWindow._PreProcessMessage(VO._winMSG*)
   bei Classmate.cDialog._ModalExec()
   bei Classmate.cDialog.Show(Int32)
   bei Classmate.cPrintMsgDialog.Show(Int32)
   bei Classmate.cPrinter.Print()
   bei PP_Server.Print(XSharp.__Usual[])
   bei SQLRuntime.Functions.PPC_Install(XSharp.__Usual[])
   bei DynamicClass.PPC_Install(RTE_L(39),NIL,ARR_Get(RTE_L(14),4),RTE_L(11),RTE_L(12),ARR_Get(RTE_L(14),5))(RTE_L(39),NIL,ARR_Get(RTE_L(14),4),RTE_L(11),RTE_L(12),ARR_Get(RTE_L(14),5))(XSharp.__Usual[])
   bei XSharp.MacroCompiler.UsualMacro.MacroCodeblock.Eval(XSharp.__Usual[])
   bei XSharp.RT.Functions.Eval(XSharp.ICodeblock, XSharp.__Usual[])
   bei XSharp.RT.Functions.MExec(XSharp.Codeblock)
   bei SQLRuntime.Functions.RTE_ExecMacroP(XSharp.__Usual, XSharp.__Usual, XSharp.__Usual)
   bei SQLRuntime.Functions.RTE_Exec(XSharp.__Usual[])
   bei SQLRuntime.Functions.RTE_Func(XSharp.__Usual[])
   bei DynamicClass.RTE_Func("SYS.STDFForm",{"QUOTE","QUOTE_KOPF","QUOTE_HPOS","QUOTENR",DWN_Selected(),""})("SYS.STDFForm",{"QUOTE","QUOTE_KOPF","QUOTE_HPOS","QUOTENR",DWN_Selected(),""})(XSharp.__Usual[])
   bei XSharp.MacroCompiler.UsualMacro.MacroCodeblock.Eval(XSharp.__Usual[])
   bei XSharp.RT.Functions.Eval(XSharp.ICodeblock, XSharp.__Usual[])
   bei XSharp.RT.Functions.MExec(XSharp.Codeblock)
   bei SQLRuntime.Functions.RTE_ExecMacroP(XSharp.__Usual, XSharp.__Usual, XSharp.__Usual)
   bei SQLRuntime.Functions.RTE_Exec(XSharp.__Usual[])
   bei MN_Object.Execute(XSharp.__Usual[])
   bei MN_Object.mnuODIExec(XSharp.__Usual[])

Ausnahmeinformationen: System.Reflection.TargetInvocationException
   bei System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)
   bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[])
   bei System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
   bei XSharp.RT.OOPHelpers.SendHelper(System.Object, System.Reflection.MethodInfo, XSharp.__Usual[], XSharp.__Usual ByRef, Boolean)
   bei XSharp.RT.OOPHelpers.SendHelper(System.Object, System.String, XSharp.__Usual[], XSharp.__Usual ByRef, Boolean)
   bei XSharp.RT.OOPHelpers.DoSend(System.Object, System.String, XSharp.__Usual[], System.String)
   bei XSharp.RT.Functions.Send(XSharp.__Usual, XSharp.__Usual, XSharp.__Usual[])
   bei Classmate.cMenu._ProcessCommandMsg(Classmate.cEvent)
   bei Classmate.cWindow.OnCommand(Classmate.cEvent)
   bei WN_Dialog.OnCommand(Classmate.cEvent)
   bei Classmate.cWindow.Dispatch(Classmate.cEvent)
   bei Classmate.cBaseDialog.Dispatch(Classmate.cEvent)
   bei WN_Dialog.Dispatch(Classmate.cEvent)
   bei Classmate_Gui.Functions._cDialogProc(Void*, UInt32, UInt32, Int32)
   bei VOWin32APILibrary.Functions.IsDialogMessage(Void*, VO._winMSG*)
   bei WN_Dialog._PreProcessMessage(VO._winMSG*)
   bei Classmate.cApp.Exec()
   bei cWorkSuite.Start(XSharp.__Usual[])

Ausnahmeinformationen: System.Reflection.TargetInvocationException
   bei System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)
   bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[])
   bei System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
   bei XSharp.RT.OOPHelpers.SendHelper(System.Object, System.Reflection.MethodInfo, XSharp.__Usual[], XSharp.__Usual ByRef, Boolean)
   bei XSharp.RT.OOPHelpers.SendHelper(System.Object, System.String, XSharp.__Usual[], XSharp.__Usual ByRef, Boolean)
   bei XSharp.RT.OOPHelpers.DoSend(System.Object, System.String, XSharp.__Usual[], System.String)
   bei XSharp.RT.Functions.Send(XSharp.__Usual, XSharp.__Usual, XSharp.__Usual[])
   bei Classmate_Gui.Functions.CmStart(XSharp.__Symbol)
   bei WorkSuite.Exe.Functions.Start()
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Chris »

I am afraid that building without the optimize flag is the only solution for now, that fixed the problem Michal reported, too. Unfortunately so far we haven't been able to reproduce the problem locally, so it is very difficult to find what's causing it.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
xor_ag
Posts: 3
Joined: Wed May 29, 2024 11:56 am
Location: Switzerland

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by xor_ag »

Chris wrote: Thu Apr 25, 2024 9:18 am a set of slightly newer RP3 files, they might make a difference as we fixed another issue that could be related recently.

Hi Chris,

do these have changes within Classmate Gui? Maybe we should try that fix?
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Chris »

xor_ag wrote: Thu May 30, 2024 2:53 pm
Chris wrote: Thu Apr 25, 2024 9:18 am a set of slightly newer RP3 files, they might make a difference as we fixed another issue that could be related recently.

Hi Chris,

do these have changes within Classmate Gui? Maybe we should try that fix?
This didn't fix Michal's problem unfortunately, but it's still worth a try. Please open the file \Classmate, Gui\Printer\Printer, Printer.prg

and change the code in METHOD _PrintDoc() from

Code: Select all

LOCAL dAbort							AS _AbortProc32Delegate
LOCAL pAbort							AS IntPtr

dAbort := _AbortProc32Delegate{ NULL, @_AbortProc32() }
pAbort := Marshal.GetFunctionPointerForDelegate( (System.Delegate) dAbort )
to

Code: Select all

STATIC LOCAL dAbort := _AbortProc32Delegate{ NULL, @_AbortProc32() }							AS _AbortProc32Delegate
STATIC LOCAL pAbort := Marshal.GetFunctionPointerForDelegate( (System.Delegate) dAbort )		AS IntPtr
This keeps the values in the locals always alive and prevents the garbage collector from collecting them, which was causing some other issues.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
xor_ag
Posts: 3
Joined: Wed May 29, 2024 11:56 am
Location: Switzerland

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by xor_ag »

Well, we changed these variables to STATIC and it fixed the problem. Release builds with compiler optimization for the entire solution can now print documents without crashing. I've only done some preliminary testing, but it looks good so far. Beforehand, it basically couldn't print at all.

It's strange that this did not work for Michal, as his problem appears to be identical. When running the faulty release build in the debugger, it literally tells me that a delegate of type "Classmate.Gui!Classmate._AbortProc32Delegate::Invoke" has been garbage collected too early.

Would you say it's required for all Windows API callback functions to have their delegates and function pointers static?

Thanks and best regards
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Chris »

Oh my, I just realized that when I sent the "fixed" dlls to Michal, I forgot to actually include the STATIC keyword! Really thanks for the heads up, Michal I will resend the files and they should fix the problem for you, with the release dlls, too.

Regarding WinAPI functions in general, you just have to make sure that the delegate they use is still active when they are called and when they call back your own code. Delegates are like normal objects, and when they go out of scope, the GC can collect them, like other objects. And the .Net GC does not manage WinAPI code, so it does not know that a delegate is used in them.

So one way is to make the LOCAL declaration of the delegate STATIC (so never goes out of scope), or make it a class variable (but of course that object itself must not get collected before thw WinAPI callbacks either!), or if you are sure that the current entity (method/function etc) will be still executing when the WinAPI makes the call(s), you can put at the end of it a

GC.KeepAlive(object_to_make_sure_is_not_collected)

to make sure the object is still alive when reaching that line of code.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Re: ReportPro 3.60 for XSharp 2.60 memory exception

Post by Chris »

One more thing, when you rebuild RP3, please open the file \Include\Rp3.vh and set the DESIGNENV #define to FALSE, for the dlls that you will be referencing in your application (for when you want to build/run the standalone RP3 designer, then you need to have it set to TRUE again). Without doing this (when it's on TRUE), the build process includes some additional code which might interfere with the rest of your code, like changing things like SetEpoch(), separators etc.

In a future RP3 release, we will make separate projects for the designer and reference dlls, so those will be in different output locations when you build them.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
Post Reply