X-Sharp / XSharpPublic

Public repository for the source code for the XSharp Compiler, Runtime, Project System and Tools.
Apache License 2.0
112 stars 38 forks source link

Problem with DoEvents #872

Closed ecosSystem closed 11 months ago

ecosSystem commented 2 years ago

In Terminal.PRG exists the function DoEvents():

FUNCTION DoEvents() AS VOID UnSafeNativeMethods.DoEvents()

INTERNAL CLASS UnSafeNativeMethods STATIC METHOD DoEvents() AS VOID local msg as xMessage local handle as HandleRef msg := xMessage{} handle := HandleRef{} DO WHILE UnSafeNativeMethods.PeekMessage( REF msg,handle, 0,0, PM_NOREMOVE) IF UnSafeNativeMethods.GetMessage( REF msg, handle,0,0 ) UnSafeNativeMethods.TranslateMessage(REF msg) UnSafeNativeMethods.DispatchMessage(REF msg) ENDIF ENDDO RETURN

In VO this function was defined like this:

FUNCTION DoEvents() LOCAL msg IS _WINMSG WHILE(PeekMessage(@msg,0, 0,0, PM_NOREMOVE)) IF GetMessage(@msg, 0,0,0 ) TranslateMessage(@msg) DispatchMessage(@msg) ENDIF ENDDO

RETURN NIL

ReportPro (and our Application) uses Doevents() a lot which creates a crash:

Der folgende Fehler ist aufgetreten während der Bewegung auf den ersten logischen Satz.: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.

If I insert the VO-Function into ReportPro-source and our Application-source everything works as before.

cpyrgas commented 2 years ago

Karl, did you get a callstack showing where the problem happened? I guess not inside the DoEvents() function itself, since this does not use an object that could be null.

ecosSystem commented 2 years ago

Hi Chris,

It's a bit tricky to reproduce the problem, but I could create an example (attached solution). Problem occurs on OK-Button in About-Dialog. If you uncomment the DoEvents-Function, all is working.

Here is the errormessage:

Description : Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. Subsystem : Anonymously Hosted DynamicMethods Assembly GenCode : EG_EXCEPTION Exception raised by CLR or external code FuncSym : OOPHELPERS:SENDHELPER Severity : ES_ERROR Can Default : False Can Retry : False Can Substitute : False Stack Trace :
{||DOEVENTS()} (Line: 0) MACROCODEBLOCK:EVAL (Line: 0) HELPABOUT:PUSHBUTTON1 (Line: 85) OOPHELPERS:SENDHELPER (Line: 0) OOPHELPERS:DOSEND (Line: 0) SEND (Line: 0) WINDOW:COMMANDFROMEVENT (Line: 0) WINDOW:DISPATCH (Line: 0) WCDIALOGPROC (Line: 0) CALLWINDOWPROC (Line: 0) WCCONTROLPROC (Line: 0) ISDIALOGMESSAGE (Line: 0) APP:EXEC (Line: 0) DIALOGWINDOW:EXECMODAL (Line: 0) DIALOGWINDOW:SHOWMODAL (Line: 0) DIALOGWINDOW:SHOW (Line: 0) RUNTIMEMETHODHANDLE:INVOKEMETHOD (Line: 0) RUNTIMEMETHODINFO:UNSAFEINVOKEINTERNAL (Line: 0) RUNTIMEMETHODINFO:INVOKE (Line: 0) OOPHELPERS:SENDHELPER (Line: 0) OOPHELPERS:SENDHELPER (Line: 0) OOPHELPERS:DOSEND (Line: 0) WINDOW:COMMANDFROMEVENT (Line: 0) WINDOW:PREMENUCOMMAND (Line: 0) WINDOW:DISPATCH (Line: 0) APPWINDOW:DISPATCH (Line: 0) SHELLWINDOW:DISPATCH (Line: 0) WCSHELLWNDPROC (Line: 0) DISPATCHMESSAGE (Line: 0) APP:EXEC (Line: 0) XAPP:START (Line: 19) START (Line: 2) VOMDIApp1.zip

cpyrgas commented 2 years ago

Ah thanks, so the problem happens only when calling DoEvents() from the macro compiler. Or does it happen in regular code for you, too?

What I see here, is that the above runtime exception happens when trying to execute a macro with DoEvents() from inside a VOGUI application, as a response to a button click, like that:

METHOD PushButton1()
MExec(MCompile("DoEvents()")) // crash on MExec()

when executing the same macro as a direct response to a menu command, then the exception does not happen. Also when defining the function locally (even with the exact same code), the problem again does not happen, Karl I think that's the reason why you do not get the problem anymore with your redefined function.

ecosSystem commented 2 years ago

It also happens in regular code but that is not so easy to show... I noticed it when printing a report in ReportPro. We have integrated RP into our application and it crashes in the StartPrint-method of PtrDevice. (integrating the original VO-Function into the RP-Runtime also solves the problem). Integrating the Doevents-function with the x#-version doesn't solve the problem for me. Problem seems to be msg as xMessage [DllImport("User32.dll", CharSet := CharSet.Ansi)]; PRIVATE STATIC METHOD PeekMessage(msg REF xMessage, hwnd as HandleRef, msgMin as INT, msgMax as INT, iremove as Int) AS LOGIC

PARTIAL CLASS PtrDevice IMPLEMENTS IPtrDevice

METHOD StartPrint() AS VOID STRICT

// This method is called from the print message window to allow start the printing process // This approach allows the print message window to be modal

LOCAL lResult,lFromPreview AS LOGIC // LOCAL dAbort AS _AbortProc32Delegate // MAY per 22.09.2011: Delegate darf nur Klassenvar. sein! LOCAL pAbort AS IntPtr IF SELF:nBusy > 0 RETURN ENDIF lResult:=TRUE // result of print to file dialog, if req

IF SELF:Print2File .AND. SELF:PromptForFile // prompt for the print file name if req SELF:cFileName := GetPrintFileName(SELF:oPrintWin:Handle(0),rpLangString(IDL_PRINT_FILE_NAME),"",SELF:cFileName,rpLangString(IDL_PRINT_FILES),rpLangString(IDL_ALL_PRINT_FILES)) lResult :=!Empty(SELF:cFileName) ENDIF IF lResult lFromPreview :=SELF:lInPreview // save if we came from preview SELF:lInPreview :=FALSE // reset the print preview flag SELF:lInPrint :=TRUE // set the print in progress flag SELF:nPageNo :=0 // initialize page numbers SELF:nNextPageNo :=1 SELF:nLastPageNo :=MAX_PAGE_COUNT SELF:nTotalPages := 0

DoEvents()                                        // give windows some time slices
// start the printing process
IF !Empty(SELF:hDC:=SELF:CreatePrinterDC())     // create printer device context
    SELF:hPrinterDC:=SELF:hDC                   // set the WYSIWYG DC for compatibility
    SELF:InitPrintDeviceContext()               // setup the device context...
    // note if we came from preview, we
    // don't have to call print start
    IF (lFromPreview .OR. SELF:CallPrintStart()==PRINT_OK) .AND. !SELF:Quit
        // set the printing abort proc
        SELF:dAbort := _AbortProc32Delegate{ NULL, @_AbortProc32() }
        pAbort := Marshal.GetFunctionPointerForDelegate( SELF:dAbort )

        SetAbortProc(SELF:hDC,pAbort)

        IF SELF:StartDoc()                          // start the windows print manager
                IF SELF:lSupport1ofN                    // If we need to support the Page 1 of N, goto end of report
                    SELF:oPrintWin:SetPageNo(-1)
                    IF !SELF:_DetermineLastPage()
                        SELF:_AbortDoc()
                        SELF:QuitPrint()
                        RETURN // SELF
                    ENDIF
                    SELF:oPrintWin:SetRange(SELF:nTotalPages)
                ENDIF
                IF SELF:_CollectPrintPages()            // print the report
                    SELF:EndDoc()                   // if we were sucessful close the job
                ELSE
                    SELF:_AbortDoc()                    // else abort it
                ENDIF
        ENDIF

    ENDIF
ENDIF

ENDIF SELF:QuitPrint() RETURN // SELF

Hope this helps

Karl

cpyrgas commented 2 years ago

OK, but if there was a general problem with the DoEvents() call in StartPrint(), then almost everybody using RP2 should be having problems, but I cannot recall any other similar report. I suspect that the underlying problem is still the one with the macrocompiler, maybe a previous macro compilation did some harm (like corrupted memory or similar) and that surfaced later when printing. Let's see if fixing the problem in the macro compiler will take care of this as well.

ecosSystem commented 2 years ago

Might be just a problem with the macro compiler but maybe most others use RP as a standalone Application and do integrate the RP-Designer directly. Perhaps this might cause the problem. I'll check that as soon as you have fixed the macro-bug :)

cpyrgas commented 2 years ago

Ah, you have integrated the designer, did not realize that before. Maybe you can try if you can reproduce the problem in a small test app integrating the designer in a similar way as in your real system?

ecosSystem commented 2 years ago

Chris, Robert has converted a smaller part of our application to x# last year. I could send you this project via private mail. The problem is reproducable with it.

cpyrgas commented 2 years ago

Yes, please do Karl!

ecosSystem commented 2 years ago

Did you get the project ?

RobertvanderHulst commented 2 years ago

Karl, I think I have found something. Can you add a reference to XSharp.VFP to your project ? Do you still see the problem ?

ecosSystem commented 2 years ago

Robert, same behaviour with the standard VOGUI-app and immediate crash in my test app: grafik

RobertvanderHulst commented 2 years ago

Ok, thanks. I will look further.

cpyrgas commented 2 years ago

Karl, yes I got it. Sorry I did not get back to you yet, I had trouble compiling it due to some change in the compiler. Will look further into it tomorrow and will get back to you.

cpyrgas commented 2 years ago

Guys, unfortunately I could not get the app to run, I am getting runtime errors with ADS. Robert, since you helped converting this app, do you still have it, so you can reproduce the problem?

But the code really helps in investigating the other problem with passing values by references. And I would not be surprised if that has to do with the current problem as well...

ecosSystem commented 2 years ago

Chris, I think the problem with the values by reference is solved with 2.9a. What kind of runtime errors do you get ? Are any ADS-files missing ?

cpyrgas commented 2 years ago

Karl, there are still some "hidden" issues, as you can see in the discussion for https://github.com/X-Sharp/XSharpPublic/issues/810 One of the revealad problems is that your code in line 1041 of System-Masterabgleich.prg:

Send(SELF,sMethod,cVermNr,cTmpOrdner,@nSatz,nGesamt,nStep)

does not actually pass nSatz by reference, instead it passes a pointer to this var.Our current internal compiler reports an error on this code.

About running your app, I am getting an exception:

Managed Debugging Assistant 'LoaderLock' : 'Attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initialization function since doing so can cause the application to hang.'

in the code

DBFAXSAdsIsServerLoaded ( String2Psz( cFileName ), @usLoaded )

which now I looking into it more closely, also has to do with values by reference! Will further investigate..

ecosSystem commented 2 years ago

In #810 you wrote: grafik this looks a lot like the DoEvents()-problem with the first parameter to PeekMessage...

cpyrgas commented 2 years ago

Karl, Not sure about that, since this is relatively straightforward, a structure passed by reference, while the errors posted in this ticket are more complicated. But you never know..

For sure we have a reproducible problem with DoEvents() in the macro compiler for starters. Let's see if fixing that one fixes the rest as well.

RobertvanderHulst commented 2 years ago

Karl, The problems in the DoEvents() code is certainly something different than the #810, That ticket is about how the compiler treats the @ operator, And the DoEvents() in the terminal code uses the REF modifier to pass the arguments and not the @ operator

RobertvanderHulst commented 12 months ago

I have changed DoEvents() to no longer use a HandleRef but an IntPtr. That way the code looks more like the VO implementation.

ecosSystem commented 11 months ago

Hi Robert,

I did some more testing with Doevents() The following code produces an error in bBlock:Eval():

METHOD PushButton1() LOCAL bBlock AS _CODEBLOCK doevents() infobox{SELF,"","Start"}:Show() bBlock := &( "{||DoEvents()}" ) bBlock:Eval() infobox{SELF,"","Ok"}:Show() return self

Description : Exception raised by CLR or external code: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. Subsystem : Anonymously Hosted DynamicMethods Assembly GenCode : EG_NULLVAR Variable not initialized FuncSym : ERROR.WRAPRAWEXCEPTION Severity : ES_ERROR Can Default : False Can Retry : False Can Substitute : False Stack Trace :
{||DOEVENTS()} (Line: 0) MACROCODEBLOCK:EVAL (Line: 0) HELPABOUT:PUSHBUTTON1 (Line: 95) ...

I don't think the problem is the HandleRef, I think there is a problem in

PRIVATE STRUCT xMessage PRIVATE hWnd AS IntPtr PRIVATE msg AS LONG PRIVATE wParam as IntPtr PRIVATE lParam as IntPtr PRIVATE result as IntPtr END STRUCT

In VO the _winMSG-structure is:

STRUCTURE _winMSG MEMBER hwnd AS PTR MEMBER message AS DWORD MEMBER wParam AS DWORD MEMBER lParam AS LONG MEMBER time AS DWORD MEMBER pt IS _winPOINT

If I enhance the xMessage-STRUCT to

PRIVATE STRUCT xMessage PRIVATE hWnd AS IntPtr PRIVATE msg AS LONG PRIVATE wParam AS IntPtr PRIVATE lParam AS IntPtr PRIVATE result AS IntPtr PRIVATE pt IS _winPOINT END STRUCT

no error occurs. (However I am not sure whether IS _winPoint is really correct here...)

In addition in _winMSG.PRG where the _winMSG-struct is defined in xSharp I found

PUBLIC SEALED STRUCTURE VO._winMSG INHERIT System.ValueType

region Fields

PUBLIC hwnd AS PTR PUBLIC lParam AS INT PUBLIC message AS DWORD PUBLIC pt AS VO._winPOINT PUBLIC time AS DWORD PUBLIC wParam AS DWORD

endregion Fields

END STRUCTURE

Is this correct ? The members seem to be in a wrong order, they are ordered alphabetically

Karl

RobertvanderHulst commented 11 months ago

Karl, We have changed HandleRef to an IntPtr for the next build. See commit https://github.com/X-Sharp/XSharpPublic/commit/1ab2a525298b3aa288155195735880f0a830818b

ecosSystem commented 11 months ago

Robert, as I mentioned above, I don't think the Handleref is the problem but the xMessage struct...

ecosSystem commented 11 months ago

Robert, this additional fix seems to solve it! No more crashes...

cpyrgas commented 11 months ago

Also from me confirmed fixed