0
votes

I want to create a DLL written in ADA that can be called from C++ or from ADA. I've compiled the DLL, and it exports my functions as well as Init and Final.

I now would like to call this DLL from Ada, using dynamic linking. The first half in the code below calls a C++ dll (without Init and Final). This works well. The second half tries to run Init before calling the DLL's function. But the line identified with lots of asterisks won't compile, instead I get error: missing operand.

Where am I going wrong?

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 SmallCode is
    -- Definitions for dynamic DLL interface
    type HANDLE is new Unsigned_32;
    function LoadLibrary (lpFileName : char_array) return HANDLE;
    pragma Import (stdcall, LoadLibrary, "LoadLibrary", "_LoadLibraryA@4"); -- Ada95 doesn't use @n

    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 AdaCallable.dll
    type fnAdaCallable is access function(val : Integer_32) return Integer_32;
    pragma Convention (Stdcall, fnAdaCallable);
    function To_fnAdaCallable is new Ada.Unchecked_Conversion (Address, fnAdaCallable);
    Pointer : Address;
    function To_AdaCallable is new Ada.Unchecked_Conversion (Address, fnAdaCallable);
    Pointer2 : Address;

    type fnInit is access procedure;
    pragma Convention (Stdcall, fnInit);
    function To_fnInit is new Ada.Unchecked_Conversion (Address, fnInit);
    PointerInit : Address;

    type fnFinal is access procedure;
    pragma Convention (Stdcall, fnFinal);
    function To_fnFinal is new Ada.Unchecked_Conversion (Address, fnFinal);
    PointerFinal : Address;

    Library : HANDLE;

begin
    Library := LoadLibrary (To_C ("AdaCallable.dll"));
    if Library /= 0 then

        Pointer := GetProcAddress(Library, To_C("_fnAdaCallable@4"));

        if Pointer /= Null_Address then
            declare
                result : Integer_32;
            begin

                result := To_fnAdaCallable(Pointer) (74);
                Put_Line("Returned result is " & Integer_32'Image(result));
            end;
        else
            Put_Line("GetProcAddress returned Null_Address");
        end if;
    else
        Put_Line("LoadLibrary returned 0");
    end if;
    Library := LoadLibrary (To_C ("libDllBuiltFromAda.dll"));
    if Library /= 0 then
        PointerInit := GetProcAddress (Library, To_C ("DllBuiltFromAdainit"));
      if Pointer /= Null_Address then
            Put_Line("Calling Init");
            To_fnInit (PointerInit);  -- ****************************************
            Put_Line("Returned from Init");

            Pointer2 := GetProcAddress(Library, To_C("AdaCallable@4"));
            if Pointer2 /= Null_Address then
                declare
                    result : Integer_32;
                begin

                    result := To_AdaCallable(Pointer2) (74);
                    Put_Line("Returned result is " & Integer_32'Image(result));
                end;
            else
                Put_Line("GetProcAddress returned Null_Address");
            end if;

            PointerFinal := GetProcAddress (Library, To_C ("DllBuiltFromAdafinal"));
         if Pointer /= Null_Address then
                Put_Line("Calling Final");
                To_fnFinal (PointerFinal);
                Put_Line("Returned from Final");
            else
                Put_Line ("GetProcAddress for final returned Null_Address");
            end if;
        else
            Put_Line ("GetProcAddress for Init returned Null_Address");
        end if;
    else
        Put_Line("LoadLibrary returned 0");
    end if;
   Put_Line ("Hello, World!");
end SmallCode;
1

1 Answers

3
votes

Given

type Proc_P is access procedure (X : Integer);
P : Proc_P;

you can write

P (42);

as a shorthand for

P.all (42);

but if there’s no argument list to trigger the shortcut you have to be explicit: given

type Parameterless_Proc_P is access procedure;
Q : Parameterless_Proc_P;

you have to call the procedure by writing

Q.all;

By the way, in the line two before your asterisked line, I think you mean PointerInit.