Show how to call a function in a shared library (without dynamically linking to it at compile-time). In particular, show how to call the shared library function if the library is available, otherwise use an internal equivalent function.

This is a special case of calling a foreign language function where the focus is close to the ABI level and not at the normal API level.



Related task

 OpenGL -- OpenGL is usually maintained as a shared library.


with Ada.Text_IO;   use Ada.Text_IO;
with Interfaces;    use Interfaces;
with Interfaces.C;  use Interfaces.C;
with System;        use System;
 
with Ada.Unchecked_Conversion;
 
procedure Shared_Library_Call is
   --
   -- Interface to kernel32.dll which is responsible for loading DLLs under Windows.
   -- There are ready to use Win32 bindings. We don't want to use them here.
   --
   type HANDLE is new Unsigned_32; -- on x64 system, replace by Unsigned_64 to make it work
   function LoadLibrary (lpFileName : char_array) return HANDLE;
   pragma Import (stdcall, LoadLibrary, "LoadLibrary", "_LoadLibraryA"); -- Ada95 does not have the @n suffix.
 
   function GetProcAddress (hModule : HANDLE; lpProcName : char_array)
      return Address;
   pragma Import (stdcall, GetProcAddress, "GetProcAddress", "_GetProcAddress"); --
   --
   -- The interface of the function we want to call. It is a pointer (access type)
   -- because we will link it dynamically. The function is from User32.dll
   --
   type MessageBox is access function 
        (  hWnd      : Address     := Null_Address;
           lpText    : char_array;
           lpCaption : char_array  := To_C ("Greeting");
           uType     : Unsigned_16 := 0
        )  return Integer_16;
   pragma Convention (Stdcall, MessageBox);
   function To_MessageBox is new Ada.Unchecked_Conversion (Address, MessageBox);
 
   Library : HANDLE  := LoadLibrary (To_C ("user32.dll"));
   Pointer : Address := GetProcAddress (Library, To_C ("MessageBoxA"));
begin
   if Pointer /= Null_Address then
      declare
         Result : Integer_16;
      begin
         Result := To_MessageBox (Pointer) (lpText => To_C ("Hello!"));
      end;
   else
      Put_Line ("Unable to load the library " & HANDLE'Image (Library));
   end if;
end Shared_Library_Call;