2

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.

Paul
  • 25,812
  • 38
  • 124
  • 247
  • iirc there are some builds of OpenSSL DLLs which have this dependency, while others have not. Did you download from indy.fulgan.com? – mjn42 Oct 22 '18 at 12:07
  • @mjn42: I just inherited them from previous developer. Do you mean that modal window call is just built in into SSL libraries? – Paul Oct 22 '18 at 12:09
  • This errormessage is caused by a dependency check for the DLLs. I'm no DLL expert but I assume that the DLLs itself tests for depencies, or it just declares that it requires that MSVCRT DLL and lets the operating system check & complain. – mjn42 Oct 22 '18 at 12:11
  • @mjn42: Ok, I understood. I would like to catch such messages, because they don't appear at the start, but on the first POST request, so that the app runs and has chance to intercept errors. – Paul Oct 22 '18 at 12:17
  • Why don't you deploy the necessary dependencies? It seems to me that if you are going to invest time it's best spent making sure the error never occurs. That way you don't need to worry about reporting it in a clean manner. Cure the disease not the symptoms. – David Heffernan Oct 22 '18 at 12:38
  • 1
    @David Heffernan: Who knows what else could be missing from some other Windows installation. I don't know ALL the dependencies. It took me one week to figure out what was going on on remote system, and there are planned 200 of installations, all of them are remote. – Paul Oct 22 '18 at 12:53
  • 1
    @Paul It's your job to know the dependencies. These files weren't missing from a Windows installation. They were missing from your deployment of your software. You absolutely need to understand the dependencies of your software. – David Heffernan Oct 22 '18 at 14:25
  • 5
    @Paul You are responsible for knowing the dependencies of the executables you deploy. This information is very easy to obtain before deployment. As for the question at hand, since Indy loads OpenSSL dynamically at runtime, you can disable the popup dialog by calling the Win32 API `Set(Thread)ErrorMode()` function before the DLLs are loaded. . – Remy Lebeau Oct 22 '18 at 16:21

2 Answers2

5

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.

mjn42
  • 830
  • 1
  • 8
  • 24
1

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.
Paul
  • 25,812
  • 38
  • 124
  • 247