The PowerLIB - A Fusion of Libraries

The PowerLIB DeMystified
------------------------

This Gazette poses an interesting concept of hybrid libraries. They're simple and straightforward, but few have ever used them. Take a little tour with Tom Hanlin, PowerBASIC Engineer, and explore this methodology. It's perfect when you need one library, compatible with all types of client applications.

The sample code from this gazette may be downloaded here: http://powerbasic.com/support/downloads/gazette/gaz082.zip

The PowerLIB - A fusion of librariesby Tom Hanlin
We all know what a library is, right? It's just a collection of routines that we can call from our programs. With a traditional DLL, the routines are just ordinary SUBs and FUNCTIONs, with a little extra decoration to let the compiler know which SUBs and FUNCTIONs need to be made available for public use. The caller then has a list of DECLAREs that describe the SUBs and FUNCTIONs and the name of their DLL.

Let's start with a very simple DLL for reference purposes.

   #COMPILE DLL "DLL1"
   #DIM ALL

This is a standard DLL function that can be called directly. No COM needed.

   FUNCTION AddStrings ALIAS "AddStrings" (s1 AS STRING, s2 AS STRING) EXPORT AS STRING
       MSGBOX "AddStrings function"
       FUNCTION = FORMAT$(VAL(s1) + VAL(s2))
   END FUNCTION

Here, we have a perfectly ordinary PowerBASIC function to add a pair of strings as numbers. The only detail needed to make this function available to the outside world was the addition of the EXPORT keyword. We also added an ALIAS clause to specify the export name, which would otherwise be the function name in uppercase.

Calling this function from another program simply requires an appropriate DECLARE to describe the function. Our test program goes like so:

   #COMPILE EXE "Exe1"
   #DIM ALL
   ' The direct function call does not involve COM, so...
   ' we declare it manually here.
   DECLARE FUNCTION AddStrings LIB "Dll1.dll" ALIAS "AddStrings" (s1 AS STRING, s2 AS STRING) AS STRING
   FUNCTION PBMAIN () AS LONG
      MSGBOX AddStrings("11","12")
   END FUNCTION

All very short and sweet, isn't it? Standard DLLs are just that easy to use. They could last you forever. However, fashions in library formats come and go. Now, there's a fresher flavor that you may be less familiar with: the COM library. The COM approach offers a number of advantages over standard DLLs though, in truth, the key point is that it is simply a very popular format these days.

So, what's different about a COM library? First, there are a few header values that need to be defined through #COM metacommands: the name and version of the library, a GUID$ to uniquely identify the library, and the fact that we want a type library to be generated. Oh, a type library is like a set of DECLAREs so you can call the routines. The difference? It's in binary format rather than a text #include.

What else? Well, COM stands for Component Object Model so, as you might guess, the routines need to be objects rather than just SUBs and FUNCTIONs. Don't be too worried about the buzzwords, though, it's really just a matter of a slightly different syntax.

It's possible to combine standard DLL routines and COM routines in a single DLL, which can then be called using either approach. The following code does just that, building on the previous DLL example.

   #COMPILE DLL "Dll2"
   #DIM ALL

   ' YOU MUST PICK NEW GUIDS FOR EVERY NEW COM OBJECT, AS UNIQUE IDENTIFIERS.
   ' *** do not re-use the GUIDs from this example code in other programs ***

   #COM NAME "StringMath", 1.0
   #COM GUID GUID$("{952988DB-403E-41C2-B9E6-0342F4632B3C}")
   #COM TLIB ON

This is a standard DLL function that can be called directly. No COM needed.

   FUNCTION AddStrings ALIAS "AddStrings" (s1 AS STRING, s2 AS STRING) EXPORT AS STRING
      MSGBOX "AddStrings function"
      FUNCTION = FORMAT$(VAL(s1) + VAL(s2))
   END FUNCTION

This is a COM object that contains a single method. It can be called by any language that provides COM support.

   CLASS StringMathClass GUID$("{6D46AC9F-7D4A-4361-BE62-766BAA797161}") AS COM

       INTERFACE StringMath GUID$("{34363450-6B5D-4D14-B0BF-7371EDE1791D}")
           INHERIT IDISPATCH

           METHOD AddStrings ALIAS "AddStrings" (s1 AS STRING, s2 AS STRING) AS STRING
               MSGBOX "AddStrings method"
               ' We'll rely on the AddStrings function to get the work done.
               METHOD = AddStrings(s1, s2)
           END METHOD

       END INTERFACE
   END CLASS

On the calling end, you do not use DECLAREs for COM routines. Instead, you use the PowerBASIC COM Browser to create an #INCLUDE file for you. We'll just put that information directly in the code below, so you can see the whole thing:

   #COMPILE EXE "Exe2"
   #DIM ALL

   ' The COM definitions we want are supplied by the PowerBASIC COM Browser.
   ' Typically, you would place these definitions in an #include file.

   ' Generated by: PowerBASIC COM Browser v.2.00.0076
   ' Date & Time : 12/31/2009 at 12:09 PM
   ' ------------------------------------------------
   ' Library Name: StringMath
   ' Library File: C:\proj\gaz\lib\DLL2.tlb
   ' Description : COM Library
   ' GUID : {952988DB-403E-41C2-B9E6-0342F4632B3C}
   ' LCID : 0
   ' Version : 1.0

   ' Class Identifiers
   $CLSID_StringMath_STRINGMATHCLASS = GUID$("{6D46AC9F-7D4A-4361-BE62-766BAA797161}")

   ' Interface Identifiers
   $IID_StringMath_StringMath = GUID$("{34363450-6B5D-4D14-B0BF-7371EDE1791D}")

   ' Interface Name  : StringMath
   ' Description     : STRINGMATH is a dual interface with VTable/Dispatch access.
   ' Class Name      : STRINGMATHCLASS
   ' ClassID         : $CLSID_StringMath_STRINGMATHCLASS
   INTERFACE StringMath $IID_StringMath_StringMath
       INHERIT IDISPATCH

       METHOD AddStrings <257> (BYREF INOUT S1 AS STRING, BYREF INOUT S2 AS STRING) AS STRING
   END INTERFACE
   '-------------------------- end of COM definitions

The direct function call does not involve COM, so... we declare it manually here.

   DECLARE FUNCTION AddStrings LIB "Dll2.dll" ALIAS "AddStrings" (s1 AS STRING, s2 AS STRING) AS STRING

   FUNCTION PBMAIN () AS LONG

       DIM MyMath AS StringMath

       MyMath = NEWCOM CLSID $CLSID_StringMath_STRINGMATHCLASS LIB "Dll2.dll"

       ' here, we're calling the DLL version of AddStrings
       MSGBOX AddStrings("11","12")

       ' here, we're calling the COM version of AddStrings
       MSGBOX MyMath.AddStrings("11","12")

   END FUNCTION

That's what we call a PowerLIB! A single, hybrid DLL, which offers the best of both concepts. Some programming langauges only support standard DLLs, and some only support COM DLLs (COM Objects / COM Components). With a PowerLIB, you present both in a single component.

The PowerLIB can be easily created with PowerBASIC 9 for Windows, our flagship compiler. It offers state-of-the-art features and performance, at a very attractive price. Complete details on this compiler cna be found at https://www.powerbasic.com/class_pbwin.php/