• Welcome to PlanetSquires Forums.
 

Solved - WinFBE 3.0.0 BETA 2 x64 crashes when trying to open a file

Started by Bruce Huber, April 09, 2022, 05:21:13 PM

Previous topic - Next topic

Bruce Huber

Paul, it does a GPF on the first SciMsg() call in CreateCodeWindow().



   ' Disable scintilla vertical scroll bar (wParam = 1 to enable)
   SciMsg( m_pSci(0), SCI_SETVSCROLLBAR, 0, 0 )    '' <=== dies here.
   SciMsg( m_pSci(0), SCI_SETHSCROLLBAR, 0, 0 )
   SciMsg( m_pSci(1), SCI_SETVSCROLLBAR, 0, 0 )
   SciMsg( m_pSci(1), SCI_SETHSCROLLBAR, 0, 0 )



CBruce

Paul Squires

Hi Bruce,

Thanks for the report, so if you comment out those lines then you are able to run the program and load files without any GPF's? If yes, then I can easily fix this problem.

Thanks,
Paul
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Paul Squires

Maybe you can try the following code. Just comment out the SciMsg calls and replace them with SciExec calls after the document pointer to the split window is set.


   ' Disable scintilla vertical scroll bar (wParam = 1 to enable)
'   SciMsg( m_pSci(0), SCI_SETVSCROLLBAR, 0, 0 )
'   SciMsg( m_pSci(0), SCI_SETHSCROLLBAR, 0, 0 )
'   SciMsg( m_pSci(1), SCI_SETVSCROLLBAR, 0, 0 )
'   SciMsg( m_pSci(1), SCI_SETHSCROLLBAR, 0, 0 )
   
   ' Get the document pointer from our main control and assign it to the other split windows
   dim as any ptr pDoc = cast(any ptr, SciMsg(m_pSci(0), SCI_GETDOCPOINTER, 0, 0))
   if pDoc then SciMsg( m_pSci(1), SCI_SETDOCPOINTER, 0, cast(LPARAM, pDoc))
   
   SciExec( this.hWindow(0), SCI_SETVSCROLLBAR, 0, 0 )
   SciExec( this.hWindow(0), SCI_SETHSCROLLBAR, 0, 0 )
   SciExec( this.hWindow(1), SCI_SETVSCROLLBAR, 0, 0 )
   SciExec( this.hWindow(1), SCI_SETHSCROLLBAR, 0, 0 )



See if that makes a difference for you. I am not getting any GPF's on my machine.

Thanks,
Paul
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Bruce Huber

Paul, when I replace the "Disable" SciMsg() calls with the SciExec() calls, I get past the SciExec() calls with no problem... BUT...

Still get an access violation GPF on the first SciMsg() call:



   ' Get the document pointer from our main control and assign it to the other split windows
   dim as any ptr pDoc = cast(any ptr, SciMsg(m_pSci(0), SCI_GETDOCPOINTER, 0, 0))



... whether that is before or after SciExec() calls.

NOTE:
I see some internet references to Scintilla access violations due to data structures being incorrect for x64 platforms. Perhaps that is related.

Possible data corruption(Plugin Failure) in x64 environment due to usage of int where intptr_t should have been used
https://github.com/kbilsted/NotepadPlusPlusPluginPack.Net/issues/74

[x64 fix]: Scintilla structures required correction for x64
https://github.com/kbilsted/NotepadPlusPlusPluginPack.Net/pull/75

Paul Squires

Thanks Bruce, so it appears that the direct function pointers returned from the SCI_GETDIRECTPOINTER must be invalid. SciMsg is used a lot throughout the source code so we'll need to find the source of the problem, otherwise I will have to change all SciMsg with SciExec.

         ' Call the direct function for speed purposes rather than relying on the traditional SendMessage method.
         m_pSci(i) = cast(any ptr, SendMessage( this.hWindow(i), SCI_GETDIRECTPOINTER, 0, 0 ))

Can you output debug what the values are for the above variable m_pSci(i). Is it zero? Maybe it is some random number that is not actually a function pointer. Every document loaded or created in WinFBE will have 2 Scintilla windows associated with it. One is the main editing window and the other is the split editing window. The array variables m_pSci(0) and m_pSci(1) simply hold the pointers to the direct function call handler within Scintilla.

You may be right about the 64 bit alignment issue. I remember early in WinFBE development that there was some alignment issues that needed to be taken care of with regards to the Notification structure. Their might be more now.
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Bruce Huber

Paul, here's the debug output and my instrumented code for the first part of CreateCodeWindow().

The m_pSci() elements are = 0 when we get to the SciMsg() calls.

But the m_pSci() elements are never set at the beginning of CreateCodeWindow(). We never get inside the "if IsWindow(this.hWindow(i)) then" to set them.



[11012] BEH says: ONCOMMAND_FILEOPEN :: Before: pDoc = frmMain_OpenFileSafely(HWnd, _
[11012] BEH says: FRMMAIN_OPENFILESAFELY :: Before: pDoc = gApp.AddNewDocument()
[11012] BEH says: FRMMAIN_OPENFILESAFELY :: After:  pDoc = gApp.AddNewDocument()
[11012] BEH says: FRMMAIN_OPENFILESAFELY :: Before: wszName = OnCommand_FileAutoSaveFileCheck( wszName )
[11012] BEH says: FRMMAIN_OPENFILESAFELY :: After:  wszName = OnCommand_FileAutoSaveFileCheck( wszName )
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 1
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 2
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 3
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 4
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 2
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 3
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 4
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 12
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: m_pSci(0) = 0
[11012] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: m_pSci(1) = 0





function clsDocument.CreateCodeWindow( _
            byval hWndParent as HWnd, _
            byval IsNewFile  as boolean, _     
            byval IsTemplate as boolean = false, _
            byref wszFile    as wstring = "" _
            ) as HWnd   

dim ibeh as integer = 0
beh(__function__ + " :: " + str(1))

   ' Creates a Scintilla editing window (initially not visible). Optionally, load a diskfile
   ' into the window and apply properties to it.
   for i as long = lbound(this.hWindow) to ubound(this.hWindow)
beh(__function__ + " :: " + str(2))
      this.hWindow(i) = CreateWindowEx( 0, "Scintilla", "", _
                        WS_CHILD or WS_TABSTOP or WS_CLIPCHILDREN, _
                        0,0,0,0,hWndParent, _
                        cast(HMENU, IDC_SCINTILLA+i), GetModuleHandle(null), null)

beh(__function__ + " :: " + str(3))
       SendMessage( this.hWindow(i), SCI_SETMODEVENTMASK, _
                      SC_MOD_INSERTTEXT or SC_MOD_DELETETEXT, 0 )
beh(__function__ + " :: " + str(4))
   
      ' Initialize our direct access to the Scintilla code windows. This is much faster than
      ' using SendMessage to the window. Only need to initialize once no matter how many
      ' code windows that are eventually opened.
      if IsWindow(this.hWindow(i)) then
beh(__function__ + " :: " + "INSIDE 'if IsWindow(this.hWindow(i))' and i = " + str(i))                    '' <<=== NEVER GET HERE
         ' NOTE: In my testing, need to only set the Scintilla lexer to the base editing
         ' window only and NOT both split windows. Also need to do this immediately after
         ' the window is created and do not send the message again afterwards.
         ' Also, every window must have a separate new call to CreateLexer. We can not
         ' just get one lexer and then try to share it amongst multiple new windows. When
         ' a window is destroyed then the pointer would be as well causing other existing
         ' windows to GPF.
         if i = 0 then
            ' Load the FB lexer from Lexilla and feed it into Scintilla
beh(__function__ + " :: " + str(5))
            dim as any ptr pLexer = gApp.pfnCreateLexerfn( "winfbe" )
beh(__function__ + " :: " + str(6))
            SendMessage( this.hWindow(i), SCI_SETILEXER, 0, cast(LPARAM, pLexer) )
beh(__function__ + " :: " + str(7))
         end if
         if SciMsg = 0 then
beh(__function__ + " :: " + str(8))
            SciMsg = cast( Scintilla_Directfunction, SendMessage( this.hWindow(0), SCI_GETDIRECTFUNCTION, 0, 0 ) )
beh(__function__ + " :: " + str(9))
         end if
         ' Call the direct function for speed purposes rather than relying on the traditional SendMessage method.
beh(__function__ + " :: " + str(10))
         m_pSci(i) = cast(any ptr, SendMessage( this.hWindow(i), SCI_GETDIRECTPOINTER, 0, 0 ))        '' <<=== SO THESE DON'T GET SET
beh(__function__ + " :: " + str(11))
      end if
   next

ibeh = 11

   ' Disable scintilla vertical scroll bar (wParam = 1 to enable)
   '   SciMsg( m_pSci(0), SCI_SETVSCROLLBAR, 0, 0 )
   '   SciMsg( m_pSci(0), SCI_SETHSCROLLBAR, 0, 0 )
   '   SciMsg( m_pSci(1), SCI_SETVSCROLLBAR, 0, 0 )
   '   SciMsg( m_pSci(1), SCI_SETHSCROLLBAR, 0, 0 )
   
   ' Get the document pointer from our main control and assign it to the other split windows
   '   dim as any ptr pDoc = cast(any ptr, SciMsg(m_pSci(0), SCI_GETDOCPOINTER, 0, 0))
   '   if pDoc then SciMsg( m_pSci(1), SCI_SETDOCPOINTER, 0, cast(LPARAM, pDoc))
   
   ' Disable scintilla vertical scroll bar (wParam = 1 to enable)
   SciExec( this.hWindow(0), SCI_SETVSCROLLBAR, 0, 0 )
   SciExec( this.hWindow(0), SCI_SETHSCROLLBAR, 0, 0 )
   SciExec( this.hWindow(1), SCI_SETVSCROLLBAR, 0, 0 )
   SciExec( this.hWindow(1), SCI_SETHSCROLLBAR, 0, 0 )

   ' Get the document pointer from our main control and assign it to the other split windows
ibeh += 1 : beh(__function__ + " :: " + str(ibeh))                                                            '' <<=== # 12
            beh(__function__ + " :: " + "m_pSci(0) = " + str(m_pSci(0)))
            beh(__function__ + " :: " + "m_pSci(1) = " + str(m_pSci(1)))
   dim as any ptr pDoc = cast(any ptr, SciMsg(m_pSci(0), SCI_GETDOCPOINTER, 0, 0))
ibeh += 1 : beh(__function__ + " :: " + str(ibeh))
   if pDoc then SciMsg( m_pSci(1), SCI_SETDOCPOINTER, 0, cast(LPARAM, pDoc))
ibeh += 1 : beh(__function__ + " :: " + str(ibeh))




NOTE: beh() is just a wrapper for OutputDebugString()...



' ------------------------------------------------------------
' ------------------------------------------------------------
declare sub beh(sstr as string)

' ------------------------------------------------------------
' BEH()
' ------------------------------------------------------------
#include once "windows.bi"
sub beh(sstr as string)
  sstr = "BEH says: " + sstr + chr(13) + chr(10)
  OutputDebugString(sstr)
end sub



Bruce Huber

#21
Added a couple of more debugs to verify variables used when calling CreateCodeWindow()...

pDoc gets set via gApp.AddNewDocument().
And wszName got set by the file picker.

But CREATEWINDOWEX() appears to be failing in CreateCodeWindow()!  this.hWindow(i) = 0 after each call!

EDITED with debugs to show that the hWnd is getting passed properly to CreateCodeWindow().

EDITED AGAIN to show GETLASTERROR() = 1407 after CREATEWINDOWEX()

Microsoft says:
ERROR_CANNOT_FIND_WND_CLASS
    1407 (0x57F)
    Cannot find window class.



[16416] BEH says: ONCOMMAND_FILEOPEN :: pDoc   = 0
[16416] BEH says: ONCOMMAND_FILEOPEN :: pDocIn = 0
[16416] BEH says: ONCOMMAND_FILEOPEN :: pDoc   = 0
[16416] BEH says: ONCOMMAND_FILEOPEN :: pDocIn = 0
[16416] BEH says: ONCOMMAND_FILEOPEN :: Before: pDoc = frmMain_OpenFileSafely(HWnd, _
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: Before: pDoc = gApp.AddNewDocument()
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: pDoc   = 0
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: pDocIn = 0
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: After:  pDoc = gApp.AddNewDocument()
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: pDoc   = 47886208
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: pDocIn = 0
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: Before: wszName = OnCommand_FileAutoSaveFileCheck( wszName )
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: wszName = D:\FreeBASICx64\00_BRUCE\WinFBE-master\Examples\CADODB\EX_CADO_Command_Execute.bas
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: After:  wszName = OnCommand_FileAutoSaveFileCheck( wszName )
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: wszName = D:\FreeBASICx64\00_BRUCE\WinFBE-master\Examples\CADODB\EX_CADO_Command_Execute.bas
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: Before: pDoc->CreateCodeWindow( HWnd, false, bIsTemplate, wszName )
[16416] BEH says: FRMMAIN_OPENFILESAFELY :: hWnd = 3675218
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 1
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: hWndParent = 3675218
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 2
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: behLastError = 1407
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: this.hWindow(i) = 0 :: i = 0
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 3
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 4
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 2
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: behLastError = 1407
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: this.hWindow(i) = 0 :: i = 1
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 3
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 4
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: 12
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: m_pSci(0) = 0
[16416] BEH says: CLSDOCUMENT.CREATECODEWINDOW :: m_pSci(1) = 0


Bruce Huber

#22
Referring to the 1407 error in my post above... I don't see a LoadLibrary() call for the Scintilla DLL anywhere in the WinFBE source code.

CBruce

EDIT: Oops! I just discovered FB's DYLIBLOAD().

Paul Squires

The LoadLibrary code is located in the "WinFBE.bas" main file. I am using FB's DyLibLoad which is just simply a wrapper around the Windows API call to LoadLibrary.


   #IfDef __FB_64BIT__
      ' Load the Scintilla code editing dll
      dim as any ptr pLibLexilla = dylibload("Lexilla64.dll")
      dim as any ptr pLibScintilla = dylibload("Scintilla64.dll")
   #Else
      ' Load the Scintilla code editing dll
      dim as any ptr pLibLexilla = dylibload("Lexilla32.dll")
      dim as any ptr pLibScintilla = dylibload("Scintilla32.dll")
   #EndIf
   gApp.pfnCreateLexerfn = cast(CreateLexerFn , GetProcAddress(pLibLexilla, "CreateLexer"))


You do have Scintilla64.dll and Lexilla64.dll in the same folder as your WinFBE64.exe ?
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Bruce Huber


Paul Squires

Quote from: Bruce Huber on April 12, 2022, 07:13:36 PM
Yep... everything is as originally unzipped.
Interesting. Does the pLibScintilla variable return a value, or just zero?
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Bruce Huber

That's what I was thinking too...

[13256] BEH says: WINMAIN :: pLibLexilla   = 0
[13256] BEH says: WINMAIN :: pLibScintilla = 0

Paul Squires

Hmmmm... interesting that it is not loading the DLL. I don't know the reason yet because it loads on my machine. Odd.

Asa complete aside, I don't need to use OutputDebugString because I compile using the build "Win32 Console (Release)" which allows a console window to display when WinFBE runs. This allows me to sprinkle "?" print statements in the code. I just need to remember to go back and delete those "?" print statements when they are no longer needed.
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Bruce Huber

#28
Paul, can I replace the Scintilla DYLIBLOAD/FREE with LoadLibrary/Free to see if there is an issue there? Or is DYLIB* giving you additional functionality?

FYI: I like OutputDebugStr() because it doesn't slow down the app even when I'm shoveling out data like crazy. I use a little wrapper (in the code a coupe of posts back) with some short name to make it easy to type, and that also allows me to do things like automatically add a CRLF to the end of the output string so that it auto flushes the output buffer and I can watch in real time in DebugView from SysInternals. (I usually implement it as a little macro so I can easily disable it completely).

Paul Squires

Hi Bruce, yes you should be able to substitute Loadlibrary/Freelibrary. Hope making that change actually fixes the problem!  :-)
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer