Catch MSVCR120 missing error message in Delphi

599 Views Asked by At

I wrote an unattended HTTPS upload client which shouldn't require user interaction.

Everything was flawless until I deployed it blindly to a remote system that I do not have a remote desktop access to. The tool reported in logs that SSL libraries are missing.

Ok, I deployed LIBEAY32.dll and SSLEAY32.dll to the application folder on the remote system, but then the tool hung and I couldn't figure out what was going on until I wrote a tool which makes a remote screenshot.

On the screenshot I see a modal window from csrss.exe process with a message:

The program can't start because MSVCR120.dll is missing from your computer.

The window appeared despite of having a lot of try except blocks and Application.OnException handler.

I would like that in such cases application would not be hold up so it can report failure to it's log.

How to achieve this?

In a current implementation TIdHttp.Post call just hangs.

P.S. I solved the absence of DLL by copying it to app folder, but my question is about catching such errors.

2

There are 2 best solutions below

0
mjn42 On BEST ANSWER

To avoid this error, you can use the OpenSSL DLLs available on https://indy.fulgan.com/SSL/

They do not have this dependency on MSVCRT.

Or, use TNetHTTPClient.

From this answer:

TNetHTTPClient was introduced in Delphi XE8.

The most important benefit of TNetHTTPClient is that it allows your application to support HTTPS without having to provide your own support for SSL/TLS. TNetHTTPClient relies on the SSL/TLS support provided by the operating system.

0
Paul On

Using the information from Remy Lebeau's comment, I experimented with SetErrorMode function in Delphi 6.

The setup consists of three projects:

  • Host application, that links caller DLL dynamically,
  • caller DLL, that links worker DLL statically,
  • and a worker DLL.

At first I place both DLLs in host app folder, test that everything works, and then delete worker DLL and test without it.

Here is some code:

Host application

program MyHost;

uses
  Windows, SysUtils;

var
  hLib: HMODULE;

procedure Box(msg: WideString);
begin
  MessageBoxW(0, PWideChar(msg), 'MyHost Message', 0);
end;

procedure ShowLastError();
begin
  Box('LastError: ' + SysErrorMessage(GetLastError()));
end;

type
  TDoWork = procedure();

var
  DoWork: TDoWork;

begin
  SetErrorMode(SEM_FAILCRITICALERRORS);
  try
    {Without SetErrorMode it displays modal dialog.
     No exception is generated.
     After clicking at [Ok], it goes to "if hLib = 0".
     With SetErrorMode it just goes to "if hLib = 0"}
    hLib := LoadLibrary('CallerLib.dll');
    if hLib = 0 then begin
      ShowLastError();
      Halt(1);
    end;
    try
      @DoWork := GetProcAddress(hLib, 'DoWork');
      if @DoWork <> nil then DoWork();
    finally
      FreeLibrary(hLib);
    end;
  except
    on ex: Exception do Box(ex.ClassName + ': ' + ex.Message);
  end;
end.

Caller DLL

library CallerLib;

uses
  Windows;

//Static linking
procedure Function1(); stdcall; external 'MyLib.dll';
procedure Function2(); stdcall; external 'MyLib.dll';

//To be dynamically linked
procedure DoWork(); stdcall; export;
begin
  Function1();
  Function2();
end;

exports
  DoWork;

end.

Worker DLL

library MyLib;

uses
  Windows;

procedure Function1(); stdcall; export;
begin
  MessageBox(0, 'MyDLL.Function1', 'MyDLL', 0);
end;

procedure Function2(); stdcall; export;
begin
  MessageBox(0, 'MyDLL.Function2', 'MyDLL', 0);
end;

exports
  Function1, Function2;

end.