From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,e314bcfae26d60a X-Google-Attributes: gid103376,public From: Wiljan Derks Subject: Re: gnat and dlls Date: 1996/05/20 Message-ID: <31A0D559.712F@nl.cis.philips.com> X-Deja-AN: 155804256 references: <4no2nu$60g@cville-srv.wam.umd.edu> content-type: text/plain; charset=us-ascii organization: Philips mime-version: 1.0 newsgroups: comp.lang.ada x-mailer: Mozilla 2.0 (WinNT; I) Date: 1996-05-20T00:00:00+00:00 List-Id: Eric Anthony Spear wrote: > > Is there any way I can write procedures in Ada, compile with gnat, and > end up with a dll, which could then be accessed by a windows program, > like visual basic? > I wanted the same thing and I actually managed to do this. Finally I had a piece of ada code (with tasking stuff inside) and I could call procedure in it from visual basic. I encountered several problem however: - The first think I tried was using the dlltool from cygnus. I run into trouble becuase you must also use the cygnus linker to link the dll. Trouble with that is that it is not able to link to MS libraries as the ld from labtek. so finally it meant it was not usable. The ld from labtek can also not link a dll. For that reason I switched to the MS linker. You can setup gnat on NT so that it uses that linker. - Finally I made an ada package with a task inside. To link it I first made a program that calls a procedure from that package using the ms linker. This gives you an .gp file that contains a link script for that program. Then you can use gnatbind to generate a c file that just does an initialisation. (use gnatbind with -n option). You can the edit the .gp file and remove the obj for the main program you originally had and add the object for the generated c bind code. That code contains an adainit procedure that initializes the ada environment. The you can link using the addapted .gp file and use the same options and arguments that are normally used when linking with the ms linker. (just try -v options and you will see them when you normally link a program.) Beside those you must also specify the -dll option and the -def:dll.def option. In my case the dll.def file contained: LIBRARY dll EXPORTS _addint@8 _dll_entry@12 _trydll_init@0 The MS linker then generates the the dll in one step. You can find the ms linker on ftp.microsoft.com somewhere. It is a bugfix for an old linker and it actually works. You will not get decent error messages from it when there is an error however bcuase it is incomplete. Up to now I had not change to try it with msvc. Using NT 4.0 is easy because it allows you to peek inside .dll and .exe files using the explorer right mouse button. It will show you the entry points that are in there. The code that I use to try this is attached at the end of this message. I just put in a task that increments a variable periodically. This allows you to show all features from the visual basic program. In visual basic I declare the functions as: Private Declare Function addint Lib "\users\wiljan\ada\trydll\dll" Alias "_addint@8" (ByVal a As Long, ByVal b As Long) As Long Private Declare Sub initdll Lib "\users\wiljan\ada\trydll\dll" Alias "_trydll_init@0" () I had to put a few extra procedure in my package it to make the linker happy: - Routine main and main_priotity. This are required when you want to link ada code. - dll_entry. I linked this in the dll as the entry point for the dll. (more on that one later) - two routine which I called later from visual basic: addint and trydll_init I originally wanted to make a dll which initialises itself automatically. This is done on NT becuase the entry point is called when a process attaches to a dll. In that case b=1. This however did not work. Probably some deadlock arizes becuase of the tasking inside the ada code. It looks like: - Because of the dll load the initialisation creates a task and waits on it. - Probably the taks needs to wait for the dll initialisation before it can be run, hence the deadlock that occurs in this situation. everything works fine when not using tasking in the package. I know it is a big hack, but when first calling the init function once from visual basic everything worked fine. A last problem that I had was when exiting the visual basic program. It simply does not apear form the system (the form did). This is becuase of the tasking still some threads are running which causes the program not to exit. This is a general problem when using ada programs with tasking. I think it is best to simply call exitprocess (i do not know if that is the right name) directly. Lets hope Labtek addapt the linker a bit so that things will get much simpler in the near future. For visual basic it is a must that you link packages into a dll, but also for the run time it whould be nice to be able to put stuff into a dll somehow. To make a general solution for this is not that trival however. Wiljan package trydll is function addint(a,b:integer) return integer; function dll_entry(a,b,c:integer) return integer; procedure trydll_init; pragma convention(stdcall,addint); pragma convention(stdcall,dll_entry); pragma convention(stdcall,trydll_init); pragma export(C,addint,"addint"); pragma export(C,dll_entry,"dll_entry"); pragma export(C,trydll_init,"trydll_init"); end trydll; package body trydll is glob:integer:=0; function addint(a,b:integer) return integer is begin return a+b+glob; end addint; procedure adainit; pragma import(C,adainit,"adainit"); procedure trydll_init is begin adainit; end trydll_init; adainit_done:boolean:=false; function dll_entry(a,b,c:integer) return integer is begin if b=1 and not adainit_done then -- adainit; adainit_done:=true; end if; return 1; end dll_entry; task increment; task body increment is begin loop delay 1.0; glob:=glob+1; end loop; end increment; procedure main; pragma export(C,main,"main"); procedure main is begin null; end main; function main_priority return integer; pragma export(C,main_priority,"__main_priority"); function main_priority return integer is begin return -1; end main_priority; end trydll;