Meaningful error message when program start fails

Here you can propose new features, make suggestions etc.

Moderators: white, Hacker, petermad, Stefan2

User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Meaningful error message when program start fails

Post by *Dalai »

Hi,

This recent thread reminded me again that TC doesn't show a meaningful error message when the launch of an executable fails. One has to start the program again via context menu to make Explorer execute this program to learn the reason why the program launch failed. This is really annoying!

Please make TC show a meaningful error when a program fails to start. In Delphi there's even a group of functions that can help to do so. I use something like this:

Code: Select all

MessageBox(Self.Handle, PChar(SysErrorMessage(GetLastError)), PLUGINNAME, MB_OK or MB_ICONHAND);
This makes the system translate the error code into an error message and also translates this to the current OS language, so there's no need to change TC's language files.

I'm not sure whether or not Delphi 2 has SysErrorMessage function, but I'm sure that there's a way to deal with that if that's the case. Of course instead of GetLastError you could use any other approriate variable, e.g. the return code of a function or something. Maybe even RaiseLastOsError/RaiseLastWin32Error could help in this situation.

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

It doesn't but there seems to be a Windows function:
FormatMessage

The only problem would be that the message language would differ from the language chosen within Total Commander. Maybe I will show a combined error (the one I show now and the windows error).
Author of Total Commander
https://www.ghisler.com
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

ghisler(Author) wrote:It doesn't but there seems to be a Windows function:
FormatMessage
Yes, that's the one that SysErrorMessage uses, too.
The only problem would be that the message language would differ from the language chosen within Total Commander.
Well, that's better than it is now, isn't it? No matter which language the current "Access denied" message is shown, it's meaningless. As I see it, FormatMessage has a dwLanguageId parameter which might help with that.
Maybe I will show a combined error (the one I show now and the windows error).
Yes, that could be a solution, too.

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Thanks for implementing this. Unfortunately I don't know if it really works. I just did the following: Downloaded FB-Traffic and tried to start it on a Windows XP system in TC 9.12. TC just said

Code: Select all

---------------------------
Total Commander
---------------------------
Zugriff verweigert!
---------------------------
OK   
---------------------------
(which translates to "Access denied") which is just as meaningless as before. Changing TC's language to English just adds the translation to the message which then reads

Code: Select all

---------------------------
Total Commander
---------------------------
Access denied!

"Zugriff verweigert"
---------------------------
OK   
---------------------------
Launching the EXE via context menu tells me the real reason:

Code: Select all

---------------------------
C:\FB-Traffic\FB-Traffic.exe
---------------------------
C:\FB-Traffic\FB-Traffic.exe ist keine zulässige Win32-Anwendung.

---------------------------
OK   
---------------------------
(FB-Traffic.exe is not a valid Win32 application).

How come TC doesn't tell as much? You can try this yourself with FB-Traffic on XP, even if you don't have a Fritz!Box since the program doesn't run on XP anyway (which I was trying to find out).

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Out of curiosity, I made a quick and dirty implementation of a small Delphi program to find out whether or not I can get the reason from the OS. Turns out: in Delphi 5 calling SysErrorMessage() function returns just an empty string while RaiseLastWin32Error() tells at least the error code 193, but also with an empty string for the message :(. In Delphi XE2 SysErrorMessage() returns the real reason:

Code: Select all

---------------------------
Project1
---------------------------
%1 ist keine zulässige Win32-Anwendung.
---------------------------
OK   
---------------------------
(%1 is not a valid Win32 application). Then, I copied the SysErrorMessage() function from XE2 to Delphi 5, renamed it to avoid confusion and voilà, I got the error message string :). Next, I dug a little deeper to find out why this is, and it turns out that specifying FORMAT_MESSAGE_IGNORE_INSERTS flag in FormatMessage() function call makes the difference. If the flag is not specified, the returned string is empty. If the flag is set, the message is OK. Note the literal %1 in the returned message.

Conclusion: Please add FORMAT_MESSAGE_IGNORE_INSERTS flag to the FormatMessage() call. It might be a good idea to replace the %1 in the message (or let the FormatMessage() do it, but I don't know how that would work). Also, please add the error code to the message TC shows when something fails, so the user at least has the option to look up the error code to see what the system was trying to tell.

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Thanks for the analysis! I didn't know about that parameter.
Author of Total Commander
https://www.ghisler.com
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

It looks like TC 9.20 still behaves the same. Any chance this flag gets added to TC 9.20 before its final release? This might also help with SmartScreen mentioned in this thread (although I'm totally unsure about this).

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

OK, I will add it to beta 5.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I just found some description of the problem with ERROR_BAD_EXE_FORMAT / FORMAT_MESSAGE_IGNORE_INSERTS here: https://blogs.msdn.microsoft.com/oldnewthing/20071128-00/?p=24353

Regards
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Although history.txt claims that the flag is set in TC 9.20 beta5, I still only get "Access denied" when trying to start FB-Traffic on XP, while my test program shows the error message "%1 is not a valid Win32 application". Don't know what's different/wrong in TC but I hope you can take a look at it.

Here's my test program:

Code: Select all

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ShellAPI;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function MySysErrorMessage(ErrorCode: Cardinal): string;
var
  Buffer: PChar;
  Len: Integer;
begin
  Len := FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM or
    FORMAT_MESSAGE_IGNORE_INSERTS or
    FORMAT_MESSAGE_ARGUMENT_ARRAY or
    FORMAT_MESSAGE_ALLOCATE_BUFFER, nil, ErrorCode, 0, @Buffer, 0, nil);

  try
    while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
    SetString(Result, Buffer, Len);
  finally
    LocalFree(HLOCAL(Buffer));
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var a: TShellExecuteInfo;
    b: DWORD;
begin
    if OpenDialog1.Execute then begin
        ZeroMemory(@a, SizeOf(a));
//        a.Wnd:= Self.Handle;
        a.fMask:= SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;
        a.lpFile:= PChar(OpenDialog1.FileName);
        a.cbSize:= SizeOf(TShellExecuteInfo);
        if NOT ShellExecuteEx(@a) then begin
            b:= GetLastError;
//            RaiseLastWin32Error;
            raise Exception.Create(MySysErrorMessage(b));
        end;
    end;
end;

end.
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I'm setting the following parameters:
FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS or
FORMAT_MESSAGE_ARGUMENT_ARRAY
Author of Total Commander
https://www.ghisler.com
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

So the flag FORMAT_MESSAGE_ALLOCATE_BUFFER isn't used in TC. As per my tests, it doesn't matter if you manage the buffer yourself or leave that to Windows. The following code works fine too, meaning I get the error message:

Code: Select all

function MySysErrorMessage(ErrorCode: Cardinal): string;
var
  Buffer: array[0..8191] of Char;
  Len, Lsize: Integer;
begin
  Lsize:= SizeOf(Buffer) * SizeOf(Char) - 1;
  ZeroMemory(@Buffer, Lsize);
  Len := FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM or
    FORMAT_MESSAGE_IGNORE_INSERTS or
    FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, ErrorCode, 0, @Buffer, Lsize, nil);

  try
    while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
    SetString(Result, Buffer, Len);
  finally
  end;
end;
Conclusion: Something else must be wrong. I don't know what else I could test :| - if you do, please let me know.

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

What error text do you get? I use a buffer length of 256 characters, maybe it's too short?
Author of Total Commander
https://www.ghisler.com
User avatar
Dalai
Power Member
Power Member
Posts: 9352
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

ghisler(Author) wrote:What error text do you get?

Code: Select all

%1 ist eine unzulässige Win32-Anwendung
(%1 is not a valid Win32 application) The length returned by FormatMessage is 41 in my case, so your buffer of 256 characters should be enough for this message. But I'm pretty sure there are much longer error texts in Windows, so I think it's a good idea to use a larger buffer.

Do you get this text with the FormatMessage function? Do you have some executable that you can test with to get this error text? If you can debug on XP, use the linked FB-Traffic mentioned and linked above; it doesn't run on XP so it's a perfect candidate to provoke this error message.

Regards
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Maybe it's because I'm no longer showing my own error dialog when launching EXE files on Windows 10 fall creators update or newer? I had to switch to the Windows error dialog, because otherwise nothing would happen for files caught in Windows smart screen.
Author of Total Commander
https://www.ghisler.com
Post Reply