Welcome, Guest
Username: Password: Remember me
Please use this forum for suggestions to the XSharp Development Team
  • Page:
  • 1
  • 2

TOPIC:

Possibly error message when starting program with missing included DLL 18 Mar 2020 15:20 #13761

  • ArneOrtlinghaus
  • ArneOrtlinghaus's Avatar
  • Topic Author


  • Posts: 339
  • I had now the case, that an EXE program did not start because of a missing DLL. The program started and stopped without a message. In the event log I found the following entry:
    System.IO.FileNotFoundException
    bei <Module>.$AppInit()
    bei RadixDN.Exe.Functions.Start()

    I looked into $AppInit() with ILSpy and I saw an exception handling. Is it probably possible that in case of an EXE file you open a windows message box with the exception? When having Win32-programs with a missing DLL normally the Runtime shows such a message.
    Thanks
    Arne

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 15:28 #13762

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3298
  • Hi Arne,
    that is a problem I had several times, but I don't thing the devteam can do anything here as it is the .NET Runtime that loads the DLLs.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 15:30 #13763

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3298
  • Hi Arne,
    I have looked better - maybe there couid be a solution:
    social.msdn.microsoft.com/Forums/office/...s-dll-file?forum=wpf
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 17:09 #13765

    • robert
    • robert's Avatar


  • Posts: 3448
  • Arne,

    Adding a message box should be possible, however that will add a dependency to System.Windows.Forms to all apps. Or we need to add a _DLL FUNCTION in the generated code for MessageBox in user32.dll.
    And that would make our programs incompatible with non windows platforms...


    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 17:16 #13767

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3298
  • Hi Robert,
    and write an error log?
    I suspect this check must be executed before any user code is executed, so there is no possibility to register a handler.... Or would it be possible to call a function with a fixed name in the exe, when it exist?
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 17:19 #13768

    • robert
    • robert's Avatar


  • Posts: 3448
  • Wolfgang,

    I think that calling a function in the EXE should be possible, as long as that function does not depend on any of the initializers that are called from $AppInit() ( init procedures).
    I could pass the exception object to that function.
    Do you have a suggestion for a function name ?

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 17:24 #13769

    • mainhatten
    • mainhatten's Avatar


  • Posts: 199
  • wriedmann wrote: I have looked better - maybe there couid be a solution:
    social.msdn.microsoft.com/Forums/office/...s-dll-file?forum=wpf


    If Arne has a similar customer-PEBCAC problem as the original poster of the linked thread, another option is to rename the .exe
    Whatever_StartOptimized.exe
    and to add another program (depending on nothing but itself, perhaps a JSON or dbf data store and perhaps the GAC) first verifying all dll are in expected place and fit expected CRC-value, either showing nice error msg or starting "Whatever_StartOptimized.exe" if all is ok.

    Sometimes going the long way is easier than to confront PEBCAC customers head on...

    regards
    thomas

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 17:24 #13770

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3298
  • Hi Robert,
    that would be great, thank you!
    As function name I could suggest "XSharpInitError()", but I'm not really good inventing names <g>.
    The important thing is that a sample for such a funtion would be added by XPorter and also in the sample applications in both XIDE and VS, so people sees it and uses it also in own applications.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 18:08 #13771

    • Karl-Heinz
    • Karl-Heinz's Avatar


  • Posts: 774
  • Guys
    ,
    i think the first question should be how Arne is currently catching exceptions ? Is he really using a WPF app, where it seems there is a catch problem when i follow Wolfgang´s link ?

    i´m using a global Exception handler, and til now i see all errors using the X# buildin ErrorDialog. Maybe Arne can give a sample when exactely such a exception handling fails ?
    [STAThread];
    FUNCTION Start() AS INT 
    LOCAL oDlg AS ErrorDialog 
    LOCAL oXApp AS XApp
    
    	TRY
    		oXApp := XApp{}
    		oXApp:Start() 
    				  
    	CATCH e AS Exception 
    		oDlg := ErrorDialog { e }
    		oDlg:showDialog() 
    		
    	END TRY
    	
    RETURN 0  
    
    
    CLASS XApp INHERIT App
    
    METHOD Start() 
    
    .. open the first Window 
    
    RETURN 0
    
    END CLASS 
    

    regards
    Karl-Heinz

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 18 Mar 2020 18:47 #13772

    • Karl-Heinz
    • Karl-Heinz's Avatar


  • Posts: 774
  • Hi Arne

    Would be interesting to know. When you add this init proc to your app do you see the debout() content before your app closes ?
    PROCEDURE AppInit1 _INIT1
    	
    	DebOut( "AppInit1" )
    	
    	RETURN NIL
    

    regards
    Karl-Heinz

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 08:58 #13775

    • ArneOrtlinghaus
    • ArneOrtlinghaus's Avatar
    • Topic Author


  • Posts: 339
  • Hi all,
    thank you for responding.
    I understand that a messagebox in general can disturb usage of different GUIs. Having the possibility for a callback function for trapping such an error could be a solution. The name Wolfgang proposed would be ok.
    Of course normally it should not happen, that a Dll is missing and in the last years at our customer sites this happens only randomly. Possible reasons can be for example an Antivirus, that blocks reading, copying files or deletes them (or an admin that tries to clean an infected fileserver). For this case such an error message simplifies diagnose time. Unfortunately the event log entry currently does not give an indication which file could have generated the exception. Using Process Monitor from Sysinternals showed the missing file, but it takes much time using such a tool and analyzing it.

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 09:49 #13777

    • robert
    • robert's Avatar


  • Posts: 3448
  • Guys,
    I have given this some thought and a special function name will not be the way to go.
    This function will become part of the compiler generated static functions class and that means that the static constructor for this class will have to be called before the code in the special function can be executed. This static constructor contains code to initialize defines that do not have a compile time constant (such as defines that have a symbol as value, eg DEFINE SomeValue := #SomeSymbol) and the code to initialize globals that are declared with an initializer (GLOBAL aValues[0] AS ARRAY).
    There is a big risk that some of this initialization code will depend on external DLLs that may or may not be correctly initialized.

    However there is a better way to do this and it is already built into the compiler.
    This is the compiler option -Main.

    Consider the following code:
    GLOBAL x AS INT
    GLOBAL y := 1 / x AS INT
       
    FUNCTION Start AS VOID
    	? "Function Start"
        RETURN

    This code will generate an exception at startup:

    Unhandled Exception: System.TypeInitializationException: The type initializer for 'Application1.Exe.Functions' threw an exception. ---> System.DivideByZeroException: Attempted to divide by zero.
    at Application1.Exe.Functions..cctor() in C:\XIDE\Projects\Default\Applications\Application1\Prg\Start.prg:line 4
    --- End of inner exception stack trace ---
    at Application1.Exe.Functions.Start()

    And you cannot intercept this.

    Now add the following code:
    CLASS MyStartupCode
    	STATIC METHOD Start AS VOID  
    		TRY
                            // Note that in the following line the name before .Exe must 
                            // match the file name of your EXE. In my case I am generating Application1.exe
    			Application1.Exe.Functions.Start()
    		CATCH e AS Exception   
                    // We should probably log this to disk as well !
     		Console.WriteLine("An unhandled exception has occurred")
    		Console.WriteLine("===================================")
    		DO WHILE e != NULL         
    			Console.WriteLine("Exception: "+e:Message)                             
    			Console.WriteLine("Callstack:")
    			Console.WriteLine(e:StackTrace)
    			Console.WriteLine()
    			e := e:InnerException
    		ENDDO             
    		Console.WriteLine("===================================")
    		Console.WriteLine("Press any to close the application")
    		Console.ReadLine()				
                   END TRY
    		RETURN		
    END CLASS

    You may have to change the call to Application1.Exe.Functions.Start() into something that matches your EXE name.
    Now goto the General page in the application properties in VS and at the entry "Startup Object" set the value MyStartupCode (in XIDE add the command line option -main:MyStartupCode)

    and run the code again

    Of course you can also register an UnHandledException handler in the AppDomain class inside the new startup code. Change the code to:
    CLASS MyStartupCode
    	STATIC METHOD Start AS VOID           
    		TRY
    			System.AppDomain.CurrentDomain:UnhandledException += ExceptionHandler
    			Application1.Exe.Functions.Start()
    		CATCH e AS Exception
    			ExceptionHandler(NULL, UnhandledExceptionEventArgs{e, TRUE})
    		END TRY
    		RETURN		
    	STATIC METHOD ExceptionHandler( sender AS OBJECT, args AS UnhandledExceptionEventArgs) AS VOID
    		LOCAL e AS Exception
    		e := (Exception) args:ExceptionObject
                   // We should probably log this to disk as well !
    		Console.WriteLine("An unhandled exception has occurred")
    		Console.WriteLine("===================================")
    		DO WHILE e != NULL 
    		        Console.WriteLine("Exception: "+e:Message) 
    			Console.WriteLine("Callstack:")
    		        Console.WriteLine(e:StackTrace)
    			Console.WriteLine()
    			e := e:InnerException
    		ENDDO             
    		Console.WriteLine("===================================")
    		Console.WriteLine("Press any to close the application")
    		Console.ReadLine()				
    				
    END CLASS

    One remark:
    Do NOT use or call any Xbase types and or functions in the exception handler, since you can't be sure that the runtime was initialized properly. If you use classes written by yourself make sure that everything is strongly typed and uses native types only. So no USUAL, FLOAT, SYMBOL etc.

    I hope this helps.

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Last edit: by robert.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 10:02 #13778

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3298
  • Hi Robert,
    thank you very much - this is great!
    I will build a sample later today.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 10:27 #13779

    • ArneOrtlinghaus
    • ArneOrtlinghaus's Avatar
    • Topic Author


  • Posts: 339
  • Great, it works as I have hoped and this without having to wait for updates, thank you!
    I had to modify the code a little bit as below (adding the word strict and using a message box, because the console window did not appear on the screen.


    CLASS MyStartupCode
    STATIC METHOD Start AS VOID strict
    local c as string
    TRY
    // Note that in the following line the name before .Exe must
    // match the file name of your EXE. In my case I am generating Application1.exe
    radixdn.exe.Functions.Start()
    CATCH e AS Exception

    c := "An unhandled exception has occurred"+crlf
    c += "==================================="+crlf
    DO WHILE e != NULL
    c += "Exception: "+e:Message+crlf
    c += "Callstack:"+crlf
    c += e:StackTrace+crlf
    e := e:InnerException
    ENDDO
    c += "==================================="+crlf

    MessageBox (null_ptr,string2psz(c), string2psz("RADIX"), MB_OK + MB_ICONSTOP+ MB_DEFAULT_DESKTOP_ONLY + MB_TOPMOST)
    // We should probably log this to disk as well !
    END TRY
    RETURN
    END CLASS
    Attachments:

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 10:40 #13780

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3298
  • Hi Arne,
    if you like to open a console window from a non-console application (WPF, Windows Forms, VO GUI) you need that here:
    stackoverflow.com/questions/4362111/how-...-a-forms-application
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 12:20 #13781

    • robert
    • robert's Avatar


  • Posts: 3448
  • Arne,

    Adding Strict() is needed because you have enabled the compiler option /vo5 (implicit Clipper calling convention).
    My sample did not have that.

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 12:29 #13782

    • robert
    • robert's Avatar


  • Posts: 3448
  • Arne,

    One more thing:
    you are using String2Psz() in your exception handler.
    I would not recommend that, since this relies on the runtime and this will fail when one of the X# runtime DLLs is missing.
    To avoid that declare MessageBox yourself without PSZ type and add it as method to your MyStartupCode class
    // add this line to the start of your PRG
    USING System.Runtime.InteropServices
    // add this to your MyStartupCode class
    [DllImport("user32.dll", CharSet := CharSet.Ansi)];
    STATIC METHOD MessageBox(hwnd AS IntPtr, lpText AS STRING, lpCaption AS STRING, uType AS DWORD) AS INT PASCAL

    Do not make this a function, because that will again fail when the type initializer of the Functions class fails...



    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 15:56 #13790

    • ArneOrtlinghaus
    • ArneOrtlinghaus's Avatar
    • Topic Author


  • Posts: 339
  • Robert,
    this is something interesting, which I do not understand, why it can work.
    The MessageBox in user32 surely is the C-base function with pointers to 0-terminated C-Strings. Here you declare the parameters using the Dotnet-Variable type "STRING" which is an object. Who cares for the conversion of this object when even with this interface you give the compiler hints that seem not to fit?
    STATIC METHOD MessageBox(hwnd AS IntPtr, lpText AS STRING, lpCaption AS STRING, uType AS DWORD) AS INT PASCAL
    int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 19 Mar 2020 16:37 #13792

    • robert
    • robert's Avatar


  • Posts: 3448
  • Arne,

    The method is marked with the [DllImport] attribute. This tells the runtime that it is a native DLL.
    The runtime "knows" that it needs to do some work on the strings.
    The CharSet := CharSet.Ansi tells the .Net runtime that the managed strings need to be converted from Unicode to Ansi.
    This is all managed "magically" by the .Net runtime.
    You can also control this behavior by using a MarshalAs attribute
    You could therefore also write

    [DllImport("user32.dll"];
    STATIC METHOD MessageBox(hwnd AS IntPtr, [MarshalAs(UnmanagedType.LPStr)] lpText AS STRING, [MarshalAs(UnmanagedType.LPStr)] lpCaption AS STRING, uType AS DWORD) AS INT PASCAL

    LIkewise you can also pass a stringbuilder to methods in the win32 api that return strings (such as GetWindowText)
    See docs.microsoft.com/en-us/dotnet/framewor...rshaling-for-strings

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Possibly error message when starting program with missing included DLL 20 Mar 2020 09:39 #13798

    • ArneOrtlinghaus
    • ArneOrtlinghaus's Avatar
    • Topic Author


  • Posts: 339
  • If someone needs the [STAThread] attribute for Internet Explorer control/Olecontrols, it is important to position it before the first method called, in this case the new Start method and not the start function.
    CLASS MyStartupCode
    [STAThread] ;
    STATIC METHOD Start AS VOID strict

    Please Log in or Create an account to join the conversation.

    • Page:
    • 1
    • 2