X-Sharp / XSharpPublic

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

Uncaught error when trying to load a non-existent file from a UNC path via filespec. #1384

Closed christianschmid200272 closed 11 months ago

christianschmid200272 commented 1 year ago

An error is triggered if an attempt is made to load an INI file via Filespec which does not exist. The X# application is started via a UNC path. The VO application has no problem at the same point via the UNC path.

   bei System.IO.Path.LegacyNormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)    bei System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)    bei System.IO.Path.InternalGetDirectoryName(String path)    bei XSharp.Core.Functions._SplitPath(String cPath, String& cDrive, String& cDir, String& cName, String& cExt)    bei VOSystemClasses.Functions.SplitPath(Usual[] Xs$Args) in C:\XSharp\Dev\src\Runtime\VOSDK\Source\VOSDK\System_Classes_SDK\FileSpec.prg:Zeile 1796.    bei VO.FileSpec.set_FullPath(__Usual value) in C:\XSharp\Dev\src\Runtime\VOSDK\Source\VOSDK\System_Classes_SDK\FileSpec.prg:Zeile 821.    bei IniFile..ctor(Usual[] Xs$Args) in D:\MyPgm\Kabel_XSharp\Kabel\CAVO2IVO28\IniFile.prg:Zeile 170.    bei EMailSetup.ReadIni() in D:\MyPgm\Kabel_XSharp\Kabel\System_Tools\dlgSetupOptions (Window).prg:Zeile 457.    bei dlgSetupOptions..ctor(Usual[] Xs$Args) in D:\MyPgm\Kabel_XSharp\Kabel\System_Tools\dlgSetupOptions (Window).prg:Zeile 284.    bei winShell.OnBrowserOptions(Usual[] Xs$Args) in D:\MyPgm\Kabel_XSharp\Kabel\Kabel\winShell.prg:Zeile 34595. Stacktrace: PATH:LEGACYNORMALIZEPATH (Line: 0)  PATH:NORMALIZEPATH (Line: 0)  PATH:INTERNALGETDIRECTORYNAME (Line: 0)  _SPLITPATH (Line: 0)  __SPLITPATH (Line: 1796)  FILESPEC:SET_FULLPATH (Line: 821)  INIFILE:.CTOR (Line: 170)  EMAILSETUP:READINI (Line: 457)  DLGSETUPOPTIONS:.CTOR (Line: 284)  WINSHELL:ONBROWSEROPTIONS (Line: 34595)  OOPHELPERS:SENDHELPER (Line: 0)  OOPHELPERS:DOSEND (Line: 0)  SEND (Line: 0)  WINDOW:COMMANDFROMEVENT (Line: 493)  WINDOW:PREMENUCOMMAND (Line: 1067)  WINDOW:DISPATCH (Line: 449)  APPWINDOW:DISPATCH (Line: 180)  DATAWINDOW:DISPATCH (Line: 1998)  DTAWINDOW:DISPATCH (Line: 363)  STDBROWSER:DISPATCH (Line: 2137)  DOCAPP:DISPATCH (Line: 122)  WCDOCAPPWNDPROC (Line: 276)  CALLWINDOWPROC (Line: 0)  BEVENTHANDLER (Line: 0)  SENDMESSAGE (Line: 0)  SHELLWINDOW:DISPATCH (Line: 411)  WINSHELLABSTRACT:DISPATCH (Line: 98)  WINSHELL:DISPATCH (Line: 29092)  WCSHELLWNDPROC (Line: 869)  DISPATCHMESSAGE (Line: 0)  APP:EXEC (Line: 235)  XAPP:START (Line: 568)  START (Line: 23)

RobertvanderHulst commented 1 year ago

Which version of X#?

christianschmid200272 commented 1 year ago

Sorry, I forgot this information. The X# Version is XSharpSetup Fox 2.18.0.4. Windows 10 Version 19045.3570

RobertvanderHulst commented 1 year ago

We are using the System.IO.Path class internally to get to the various elements of the path. Apparently there is a problem with UNC paths. What is the exact path that you are sending into the constructor of the INIFILE class, and does this file exist?

christianschmid200272 commented 12 months ago

The path which is passed in the constructor consists only of the file name "emails.ini". I am not a VO specialist, but I think that if only the file name is specified, in the AppPath is searched for the file. The file "emails.ini" does not exist in the AppPath \mk-dbs-01\WWS_NET_Program. After the initialization of FileSpec, "FileSpec :Drive" and "FileSpec :Path" are called directly. You could of course check in advance whether the file exists and only load the file if this is the case, but the old VO application has no problem at this point, while the ported X# application does and it is not easy to determine how many places this could still occur.

cpyrgas commented 12 months ago

Christian, I think the error happens when assigning to the FullPath assign of the FileSpec class and that happens from the constructor of the IniFile class, which I assume is a class defined in your own library?

What is the value assigned to FullPath, in line 170 (in the constructor of the IniFile class)? Even better, can you please create a small standalone sample reproducing the problem?

christianschmid200272 commented 12 months ago

VOexample Here is an X# console application. If the compiled application is started from the UNC path and for comparison from a drive you will see the error. As already written, the error behavior in X# only occurs if the specified file does not exist. Surely we have to work on our code but as already written it is difficult to locate all affected places for sure so it is very important that the behavior is at the same place as in VO.

##################################################### USING System USING System.Collections.Generic USING System.Linq USING System.Text USING VO

/* Output if start from lokal drive: Hello Filespec test 14.11.2023 fullPath: D:\MyPgm\Kabel_XSharp\XSharp_BugDemos\Demo_SplitPath\bin\Debug\emails.ini Drive: D: Path: \MyPgm\Kabel_XSharp\XSharp_BugDemos\Demo_SplitPath\bin\Debug\

Output if start from UNC: Hello Filespec test 14.11.2023 Exception fullPath: emails.ini Exception Drive: Exception Path: fullPath: emails.ini

*/ FUNCTION Start() AS VOID STRICT ? "Hello Filespec test ",Today() LOCAL oIni AS IniFile

oIni := IniFile { "emails.ini" } TRY ? i"fullPath: {oIni:fullPath}" ? i"Drive: {oIni:Drive}" ? i"Path: {oIni:Path}" CATCH ex AS Exception ? ex:Message END TRY WAIT RETURN

CLASS IniFile INHERIT FileSpec CONSTRUCTOR (cFullPath) cFullPath := IIF (Instr (".", cFullPath), cFullPath, cFullPath + ".INI") SUPER(cFullPath) //In VO the SELF:Path is not empty when run the app from UNC path and the file not exists, SELF:Path is in VO the UNC app path. //In X# SELF:Drive and SELF:Path are empty hen run the app from UNC path and the file not exists. IF Empty (SELF:Drive) .AND. Empty (SELF:Path) TRY SELF:fullPath := DiskName() + ":\" + CurDir() + "\" + SELF:fullPath CATCH ex AS Exception ? i"Exception fullPath: {Self:fullPath}" ? i"Exception Drive: {Self:Drive}" ? i"Exception Path: {Self:Path}" END TRY ENDIF RETURN SELF END CLASS

cpyrgas commented 12 months ago

Thanks Christian, that helps a lot. Can you please also call (before the exception happens)

? DiskName() ? CurDir()

what do those functions return exactly, when you run the (test) app from the UNC path?

christianschmid200272 commented 12 months ago

Hello Chris, the return of the functions before the exception happens:

cpyrgas commented 12 months ago

Hi Christian,

OK, so you are effectively assigning the value ":\msb-azure-01\c$\Temp\Debug" to Fullpath, and that is when it fails, as this is indeed not a legal folder name.

Of course we can make it swallow the error and not throw an exception, to make it more compatible with VO, but just to make sure that this is where the difference exists compared to VO, or it is somewhere else, can you please check also in VO what the return values from DiskName() and CurDir() are in the same context? Do they return the same strings as in X#, or is there a difference there as well?

christianschmid200272 commented 11 months ago

Hello Chris,

the VO application returns the same strings as from X#

Actually, X# in FileSpec:Path should return the path in which the specified file was searched for, even if the file does not exist. From my point of view, VO does it this way.

RobertvanderHulst commented 11 months ago

Actually, X# in FileSpec:Path should return the path in which the specified file was searched for, even if the file does not exist. From my point of view, VO does it this way.

That is not so simple. We are searching the current directory and also all the locations specified in SetPath(). So which folder should we choose?

cpyrgas commented 11 months ago

Robert,

I have made several tests, and unfortunately VO allows all sorts of things in SplitPath(), even using characters like ? and * in the path/filename and does not complain about any of them. We will never make it VO-compatible in X#, while keeping using the .Net Path class. Do you mind if I completely rewrite the function, to do only regular string manipulation of the argument and get rid of the Path methods?

cpyrgas commented 11 months ago

Plus, VO for example for this path "c:\123\\45", returns "\123\\" as the dir name, while X# returns "\123\". Only with a custom function we can make them return the same thing...

RobertvanderHulst commented 11 months ago

Ok, go ahead and create a custom implementation. Please use the Directory and Path Separator properties of the Path class and do not hardcode a colon and backslash, so the code will also work in non Windows environments.

cpyrgas commented 11 months ago

OK, will do, but VO actually seems to handle both slash and backslash the same way..(both are considered folder delimiters)

cpyrgas commented 11 months ago

SplitPath() should be compatible to VO now, but I'm not sure if there are other functions used that may need similar adjustments..

Christian, can you please try this new dll and see if it completely fixes the problem in your app, or there's still an error somewhere else? You need to copy the dll file replacing the old one in the folder:

C:\Windows\Microsoft.NET\assembly\GAC_MSIL\XSharp.Core\v4.0_2.6.0.0__ed555a0467764586

You can return back to the original runtime by restoring the file from the \XSharp\Redist folder. You need to have installed X# build 2.18, in order to try this update.

XSharp.Core.zip

christianschmid200272 commented 11 months ago

Hello Chris, I have provided the new DLL and tested it with our ported application as well as my test program, the reported problem is solved, the values correspond to those of VO.

cpyrgas commented 11 months ago

That's great, thanks for your feedback Christian!