Friday, November 23, 2007

[Ada (GNAT/GCC)] Creating DLLs for VB6

And finally, after much prayer and perspiration, the GNAT/GCC version. Again, thanks to Roger Pearse for The Noddy Guide to using ADA code with Visual Basic. I'm sure there was someone else [This space set aside for an attribution.]

First up, api.ads, which declares the functions and exports them.
  • function Factorial, which accepts a Win32.LONG and returns a Win32.LONG (I gave up on C.int as it was too small for a Factorial of 16)
  • function GetCount, which returns the value of the global Count (another Win32.LONG)
  • procedure Mangle, which accepts a Win32.LPWSTR and attempts the same dangerous stuff that Bob6 does in the ObjectAda version.
  • function Pattern, which returns a long pointer to some string data
  • procedures Initialize_API, and Finalize_API, which I understand are mandatory. (If someone knows better, please tell me.)


Next, api.adb, where the declarations are explained.

I'm still working through the issue of what to do with Mangle. Perhaps two routines are needed. The first to ask the DLL how much space is needed, with VB the allocating it, and the second then actually poking the data into the allocated space.

Pattern returns a pointer to the string data. I rediscovered the technique for reading it out and that's in the VB code below. It also seems that, for as long as the DLL is loaded, the data stored in foo is available for transfer.



api.def lists the symbols exported, and is needed by gnatdll.



Now, pulling it all together requires some handwaving on the commandline. From one of the demos I modified the make.bat to look like this:



The output from a run of these is as follows:



Now the VB code. Take note of a few things:
  • Exporting as DLL generates decorated names, but dlltool was able to resolve the decorated ones with the undecorated ones specified in api.def
  • For reasons I remember reading somewhere, initialize_api and finalize_api are mandatory, and must be the first and last calls to the DLL
  • Seeing as woof woof woof woof is longer than foo man chew, s ends up containing foo man chew f woof
  • As mentioned before, I rediscovered some code for getting data from a pointer and put that in. It's the PointerToString function at the bottom.


Finally, a sample run under VB6



Next? Well, there's the issue of how to export overloaded functions and procedures. And there's the question of how to pass in complex data types, like records and the like. I'll keep you posted.

(By the way, I'm not doing this merely for the fun of it, but also in pursuit of the fulfillment of my employer's expectations. So more will follow.)


© Copyright Bruce M. Axtens, 2007

No comments: