VBA uitbreiden met de mogelijkheden van API's.

Niettegenstaande VBA over veel functies beschikt komt men in bepaalde situaties waar VBA functies niet volstaan of waar bepaalde bewerkingen in VBA niet mogelijk zijn. Windows beschikt over uitgebreide bibliotheken van functies waarop mijn via VBA beroep kan doen.
Men spreekt van Windows API (application programming interface). Beroep doen op API in VBA is niet echt gebruiksvriendelijk, en de datatypes die er gebruikt worden verschillen van deze in VBA.
De Windows API bestaat uit verschillende DLL's (Dynamically Linked Library).Alle toepassingen onder Windows interacteren op één of andere wij met de DLL's.

Om beter te begrijpen in de VBA editor kan men via het menu Tools, Referenties een link leggen naar vb ADO-bibliotheek, Microsoft Scripting Runtime...enz. Het gebruik maken van API's komt in feite op het zelfde neer, maar kan echter niet via het Tools menu gerealiseerd worden.

Hier moet men aanduiden welke DLL men wil gebruiken en bovendien specifiëren welke functie ervan. Dit doet men door het declaren van API's. Daartoe moet men gebruik maken van het Declare statement,in de declaratie sectie van een module indien nodig op module niveau. De syntax :

  • Public of Private Declare Sub Naam(die men kiest) Lib "naambibliotheek" Alias "aliasnaam" (is naam in DLL) argumenten
  • Public of Private Declare Function Naam(die men kiest) Lib "naambibliotheek" Alias "aliasnaam" (is naam in DLL) argumenten As Type

Het Declare Sleutelwoord betekent dat VBA beroep wil doen op een functie in een DLL en bepaalt tevens indien het gaat over een functie of een sub. In een Class-module moet het Declare statement steeds Private zijn.

Opgepast :

  • De aliasnaam, die de naam is van de functie of sub in de DLL is hoofdletter gevoelig dit in tegenstelling tot VBA
  • Bij de argumenten, let er op de datatypes te respecteren (VBA controleert dit niet), verkeerde datatypes kunnen allerlei nare gevolgen hebben tot het computer crash toe.
  • Betreffende het string dataype zowel ANSI- of Unicode zijn mogelijk. De functie die ANSI code nemen hebben een A op het einde van de alias naam een W voor unicode.
  • Het Lib sleutelwoord specifiërt de naam van de DLL.

Functies en Sub's in de Windows API zijn in de taal C of C++ geschreven en aanvaarden argumenten net zoals functies en sub's in VBA.
Echter de datatype's verschillen van de vertrouwde VBA datatype's, bovendien kunnen sub-routines, opnieuw in tegenstelling met VBA, wel waarden teruggeven.
En om het nog verwarrender te maken de verwijzingingen ByVal en ByRef worden anders geïnterpreteerd dan in VBA.Volgens de nagelezen literatuur en artikelen zou VBA daaromtrent inconsistent zijn.

Bij VBA is het zo dat :
ByRef geeft een verwijzing (pointer) door naar de locatie in het geheugen waar de variabele opgeslagen wordt, maar die toelaat dat de waarde zelf gewijzigd wordt.
ByVal by ByVal wordt de waarde van de variabele wordt doorgegeven en eventuele wijzigingen in de waarde lokaal blijven in de aangeroepen routine en niet terug gegeven worden aan de aanroepende routine.
Dat is zo voor zowel string als numerieke waarden.
Het voorbeeld hierna verduidelijkt dit :

Private Sub sWijzigByRef(ByRef intEenwaarde As Integer)
                    intEenwaarde = 100
                End Sub
                
                Private Sub sWijzigByVal(ByVal intEenwaarde As Integer)
                    intEenwaarde = 1000
                End Sub
                Private Sub sWijzigStringByRef(ByRef strEenstring As String)
                    strEenstring = "Slecht bier!"
                End Sub
                
                Private Sub sWijzigStringByVal(ByVal strEenstring As String)
                    strEenstring = "Slechte wijn!"
                End Sub
                
                Public Sub sTestByRef_ByVal()
                Dim intWaarde_1 As Integer
                Dim intWaarde_2 As Integer
                Dim strString_1 As String
                Dim strString_2 As String
                
                intWaarde_1 = 333
                intWaarde_2 = 444
                strString_1 = "Lekker biertje"
                strString_2 = "Lekker wijntje"
                
                Call sWijzigByRef(intWaarde_1)
                Debug.Print "de waarde was 333 en is na ByRef " & intWaarde_1
                
                Call sWijzigByVal(intWaarde_2)
                Debug.Print "de waarde was 444 en is na ByVal " & intWaarde_2
                
                Call sWijzigStringByRef(strString_1)
                Debug.Print "Lekker biertje is na ByRef " & strString_1
                
                Call sWijzigStringByVal(strString_2)
                Debug.Print "Lekker wijntje is na ByVal " & strString_2
                
                End Sub
                

Laat men bovenstaande routine lopen dan is het resultaat:

de waarde was 333 en is na ByRef 100
                de waarde was 444 en is na ByVal 444
                Lekker biertje is na ByRef Slecht bier!
                Lekker wijntje is na ByVal Lekker wijntje
                

Stringwaarden in DLL's zijn in C-taal gekend als LPSTR objecten. De DLL's kunnen de grootte van een string niet wijzigen eens die gecreëerd is, wat erop neerkomt dat de opgegeven string voldoende groot moet zijn om de door de DLL geretourneerde waarde te kunnen bevatten en bovendien moet de string eindigen met een ANSI nulwaarde.
In VBA kan men dit via de Space en Chr functies : strEen String = Space(255) & Chr(0) indien ook de grootte als argument moet gegeven worden :
lngGroot = 256

Het probleem met API functies is dat men hun functionaliteit moet kennen, wat voor mij althans niet altijd evident is. Als Access ontwikkelaar heb ik hier en daar voorbeelden gevonden, en sommige heb ik in mijn eigen projecten ook toegepast.
Ik geef daar ook enkele voorbeelden van. Het is vooral handig API Functies in te kapselen in Class-modules, onder deze rubriek ook enkele voorbeelden.

Begin