proffs.nu    Supportbasen

Lathund om Visual Basic

Copyright © Mats Hindhede 2000 - 2010. All rights reserved.

Uppdaterad 2010-11-06.

Lathunden skapades ursprungligen för deltagarna på en Visual Basic-kurs som jag höll
under sommaren 2000. Sedan dess har lathunden stegvis förbättrats. Den omfattar nu det mesta
en programmerare behöver kunna om själva programmeringsspråket Visual Basic.

 

   Klicka här för att ladda ner lathunden som hjälpfil

 

Grundläggande syntax
Namngivning av variabler och konstanter
Deklaration av variabler och konstanter
Arrayer, egna datatyper och numreringar
Typkonvertering
Variablers och konstanters räckvidd
Variablers livslängd
Procedurer och deras räckvidd
Vanliga operatorer, slingor och inbyggda funktioner
Spara, öppna och skriva ut filer
Kopiera och klistra in
Felhantering och avlusning
Klassmoduler
Databaser
Prefix för några vanliga kontroller
Kortkommandon
Historik

 

 

  Grundläggande syntax

Denna lathund är en snabbkurs i Visual Basic för ambitiösa nybörjare och en hjälpreda för dig som redan kan språket. Uppgifterna i lathunden gäller Visual Basic 6.0, om inget annat anges. Det mesta i lathunden kan även tillämpas i Visual Basic 4.0 och 5.0. Lathunden beskriver inte hur man använder formulär och kontroller, utan bara själva programmeringsspråket. Resten är lätt att lära sig själv. Eftersom lathunden inte beskriver kontroller beskriver den heller inte ActiveX-kontroller. Den tekniken är också lätt att lära sig själv när man väl kan själva programmeringsspråket.

Visual Basic .NET då? Vore det inte bra med en lathund för Visual Basic .NET?

Visst vore det bra, men det finns många som fortsätter att arbeta i Visual Basic 6.0. Behovet av bra undervisningsmaterial på svenska är lika stort idag som 1998, när Visual Basic 6.0 lanserades.

Visual Basic 6.0 används även som programmeringsspråk i Office 2000 - 2010 under namnet Visual Basic for Applications (VBA). Versionsnumret höjdes till 6.3 i Office XP, 6.5 i Office 2003 och 7.0 i Office 2010, men språket är detsamma. Många kommer att skriva makron i Office i många år till.

Vi börjar med språkets grundläggande syntax.

Att välja mellan stora och små bokstäver är inget bekymmer. Visual Basic ändrar automatiskt till stor eller liten bokstav när det behövs. Vid namngivning av procedurer, variabler och konstanter skiljer man inte på stora och små bokstäver. I Visual Basic kan man inte ha en variabel som heter X och en annan som heter x i en och samma procedur, vilket man kan i andra programmeringsspråk, t ex Java. I Visual Basic anses X och x vara ett och samma namn. Blanksteg kan man inte göra för många, för onödiga blanksteg tas bort automatiskt.

Man radbryter koden om och endast om satsen är slut, med följande undantag:

  • En sats kan delas upp på två rader med ett understreck ( _ )
  • Flera satser kan skrivas på samma rad om man skriver ett kolon ( : ) mellan varje sats
  • Man kan infoga en tom rad före eller efter en sats för att göra koden mera lättläst

Normalt skulle man skriva

Select Case intA
  Case 1
    MsgBox "Yes"
  Case 0
    MsgBox "No"
End Select

men man kan också skriva

Select Case intA
  Case 1
    MsgBox _
    "Yes"
  Case 0
    MsgBox _
    "No"
End Select

eller

Select Case intA
  Case 1: MsgBox "Yes"
  Case 0: MsgBox "No"
End Select

Man kan t o m skriva

Select Case intA: Case 1: MsgBox "Yes": Case 0: MsgBox "No": End Select

fast det är nog lite svårare att läsa.

 

VARNING!
Undvik att göra raderna så långa att de inte får plats på skärmen! Det är visserligen ingen risk att det uppstår fel i det färdiga programmet bara för att raderna i koden är för långa. Visual Basic låter dig högst skriva 1023 tecken per rad, sedan är det stopp, men 80 tecken per rad anses vara en övre gräns om läsbarheten inte ska bli lidande. Teckenstorleken i Visual Basics kodfönster är normalt 10 punkter. Många bryr sig inte om att ändra. Om man klickar på Options... på menyn Tools och väljer fliken Editor Format kan man pröva andra teckenstorlekar. Pröva att sänka till 9 eller 8 punkter och se vad du tycker.

 

VARNING!
Det är obekvämt att arbeta med Visual Basic 6.0 om bildskärmens upplösning är lägre än 1024x768 bildpunkter. Går det inte att lösa problemet på något annat sätt bör du skaffa bättre utrustning.

 

Indrag på lämpliga rader gör koden lättare att förstå. Ett exempel:

If blnOK = False Then
  For lngX = 1 To 10
    intNumbers(lngX) = intNumbers(lngX) + 5
  Next lngX
  blnOK = True
Else
  MsgBox "Alla har redan ökat med 5"
End If

Lägg märke till att Visual Basic kan öka eller minska indraget på flera rader samtidigt. Det är bara att markera raderna och trycka på Tab eller Shift+Tab. Hur många blanksteg ett tryck på Tab motsvarar kan man själv bestämma om man klickar på Options... på menyn Tools och väljer fliken Editor. Standardvärdet är 4. Många tycker att 2 är mera lagom.

På fliken Editor finns även avbockningsrutan Auto Syntax Check. Ta bort bocken i den rutan! Då slipper du alla tjatiga meddelanden om dina syntaxfel. Du blir ändå påmind om syntaxfelen. De får automatiskt en avvikande färg.

Options

Kommentarer inleds med en apostrof ('). Man kan skriva en kommentar till höger om koden på samma rad eller på en egen rad. Alternativt kan man inleda kommentarer med uttrycket Rem. Om man skriver kommentaren till höger om koden på samma rad måste man dessutom infoga ett kolon mellan koden och uttrycket Rem.

Om man vill infoga en kommentar som är flera rader lång måste man tyvärr skriva en apostrof eller uttrycket Rem i början av varje rad. T o m HTML är smartare än Visual Basic i det fallet och det är svårt att förstå varför Microsoft inte har hittat en bättre lösning. Det är en viss tröst att man kan lägga till och ta bort apostrofer i början av flera rader samtidigt. Markera raderna och klicka på knapparna Comment Block och Uncomment Block på verktygsfältet Edit:

Comment and Uncomment buttons

Private Sub cmdDiff_Click()
Dim strToday As String
Dim strYesterday As String
Dim dblDiff As Double
  'Detta är en kommentar
  strToday = InputBox("Skriv dagens aktiekurs. Använd punkt, inte komma.")
  Rem Detta är också en kommentar
  strYesterday = InputBox("Skriv gårdagens aktiekurs") 'En till kommentar
  dblDiff = Val(strToday) - Val(strYesterday): Rem Och en till
  MsgBox "Skillnaden är " & dblDiff
End Sub

 

VARNING!
Som decimaltecken i koden används alltid punkt, inte komma! Man skriver t ex 3.5 i koden, inte 3,5. Användarens decimaltecken i det färdiga programmet beror på användarens inställningar i Kontrollpanelen i Windows.

 

 

VARNING!
Man bör vara försiktig med den inbyggda funktionen Val, som används i exemplet närmast ovan. Microsofts avsikt med denna funktion var att förse programmeraren med en snabb metod att omvandla en textsträng till ett numeriskt värde och samtidigt bli av med "dollar", "kronor", blanksteg, tabbsteg, radmatningar och andra onödiga saker som kan dyka upp i slutet av textsträngen. Tyvärr har Val flera nackdelar. Funktionen är oförmögen att tolka ett komma som ett decimaltecken. Val kräver att argumentet använder en punkt som decimaltecken. Även om man uppfyller detta krav kan man få problem. Ett fel uppstår om argumentet är ett decimaltal som följs av ett procenttecken, t ex "6.5 %". Val är dessutom långsam jämfört med typkonverteringsfunktionerna CDbl, CSng, CLng, CInt och CCur. Se upp med funktionen Val.

Typkonverteringsfunktionerna CDbl, CSng och CCur kan ge ett annat returvärde om användarens inställningar i Windows innebär att decimaltecknet är punkt istället för komma. I Sverige används komma. I USA används punkt. Ditt program kan därför behöva kontrollera den aktuella användarens inställningar när det gäller decimaltecknet. Hur ditt program kan kontrollera den saken förklaras i avsnittet Procedurer och deras räckvidd.

 

 

  Namngivning av variabler och konstanter

  • Namn på procedurer, variabler och konstanter består av högst 255 bokstäver eller siffror.
    (I Visual Basic 3.0 och äldre versioner gick gränsen vid 40.)
  • Blanksteg och punkt är inte tillåtna i namnet. Understreck ( _ ) tillåts som ersättning för blanksteg, men blanksteg kan även ersättas av Pascalnotation (VersalInlederAlla) eller kamelnotation (versalInlederAllaEfterInledningen).
  • Det första tecknet i namnet får inte vara en siffra.
  • Procedurer, variabler och konstanter får inte namnges med reserverade ord som End, If, Else, Sub, Function, Public och Private.

Välj namn som upplyser om procedurens, variabelns eller konstantens användning. Om en variabel tilldelas namn på olika företag bör den inte heta strMyLittleString, utan strCompany eller något liknande. Variabelnamn som intA, intB och intC bör användas sparsamt. De är visserligen korta, men säger inget om variabelns användning, vilket gör koden svårare att förstå.

 

VARNING!
Visual Basic 6.0 finns inte bara i amerikansk version, utan även i tysk, fransk, italiensk och spansk version. Däremot inte i svensk version. Ändå är det tillåtet att använda bokstäver som Å, Ä och Ö, vilket inte är tillåtet i programmeringsspråk som C++ och Java. Undvik Å, Ä och Ö vid namngivning av procedurer, variabler och konstanter! Använd engelska namn. Då blir koden lättare att tolka för människor i andra länder och lättare att arbeta med i utländska språkversioner av Windows.

 

 

  Deklaration av variabler och konstanter

Explicit variabeldeklaration är ett måste i Visual Basic. Man använder explicit variabeldeklaration genom att skriva Option Explicit överst i modulens huvud. Det betyder att alla variabler och konstanter som förekommer i modulen måste deklareras. Observera att denna sats måste skrivas överst i varje modul där man vill att regeln ska gälla.

Om man använder explicit variabeldeklaration gör det inte så mycket om man råkar felstava namnet på en redan deklarerad variabel eller konstant. Om man inte använder explicit variabeldeklaration tror Visual Basic att den felstavade variabeln är en ny och odeklarerad variabel. Vilket i sin tur kan leda till en mängd följdfel. Man hamnar inte i den situationen om man skriver Option Explicit överst i modulens huvud.

Då får man istället ett felmeddelande när man försöker kompilera eller när man försöker köra det aktuella kodavsnittet:

Variable not defined

Om man klickar på Options... på menyn Tools och väljer fliken Editor finner man avbockningsrutan Require Variable Declaration. Sätt en bock i den rutan! Då skriver Visual Basic automatiskt Option Explicit i huvudet av alla nya moduler. Man slipper att skriva det själv.

Så här kan det se ut när man deklarerar tre variabler i huvudet av en procedur:

Private Sub cmdMyButton_Click()
Dim strCompany As String
Dim strLastName As String
Dim intNumber As Integer

Uttrycket Dim är en förkortning av det engelska verbet dimension, som betyder dimensionera. Man kan även skriva så här:

Private Sub cmdMyButton_Click()
Dim strCompany As String, strLastName As String, intNumber As Integer

 

VARNING!
Du som är van vid andra programmeringsspråk, t ex Pascal, tror kanske att man kan skriva så här:

Private Sub cmdMyButton_Click()
Dim strCompany, strLastName As String, intNumber As Integer

I Visual Basic .NET är det inga problem att deklarera variabler som i exemplet närmast ovan. Både strCompany och strLastName får datatypen String.

I Visual Basic bör man däremot inte deklarera variabler som i exemplet närmast ovan. Variabeln strCompany får inte datatypen String, utan datatypen Variant, som alla variabler får när man struntar i att ange datatyp eller struntar i att deklarera överhuvudtaget.

Dessa regler gäller inte om man använder uttryck som DefStr och DefInt (vilket inte många gör). Antag t ex att man skriver DefStr S i huvudet av en modul. Då får alla variabler och konstanter datatypen String i den modulen om man ger dem namn som börjar på S och deklarerar dem utan att ange datatyp. Författaren rekommenderar inte uttryck som DefStr och DefInt. I Visual Basic .NET har de avskaffats.

 

Variabler med datatypen String kan deklareras med fast längd:

Private Sub cmdMyButton_Click()
Dim strCompany As String * 8

I detta exempel kommer variabeln strCompany alltid att innehålla åtta tecken. Om den tilldelas en kortare text kommer kvarstående positioner att fyllas med blanksteg. Om den tilldelas en längre text kommer överskjutande tecken att försvinna.

I hjälptexterna skriver Microsoft att en String med fast längd kan innehålla "ungefär" 65536 tecken. Om man kontrollerar själv verkar den exakta gränsen vara 65526.

Från början fanns det sju datatyper i Visual Basic:

Datatyp Användningsområde Startvärde Prefix Suffix Antal byte
Integer Heltal från -32768 till 32767 0 int % 2
Long Heltal från -2147483648 till 2147483647 0 lng & 4
Single Decimaltal från -3,402823x1E38 till
-1,401298x1E-45 och från
1,401298x1E-45 till 3,402823x1E38,
samt 0
0 sng ! 4
Double Decimaltal från
-1,79769313486231x1E308 till
-4,94065645841247x1E-324 och från 4,94065645841247x1E-324 till 1,79769313486232x1E308, samt 0
0 dbl # 8
Currency Penningbelopp från
-922337203685477,5808 till 922337203685477,5807
0 cur @ 8
String Text som kan bestå av 2147483648 tecken eller "ungefär" 65536 tecken om variabeln deklareras med fast längd "" str $ Olika
Variant Används istället för vilken datatyp som helst utom en String med fast längd Empty vnt Saknas Olika

I Visual Basic 4.0 kom det fyra nya datatyper:

Datatyp Användningsområde Startvärde Prefix Suffix Antal byte
Boolean Variabler som kan innehålla värdena True eller False False bln Saknas 2
Byte Heltal från 0 till 255 0 byt Saknas 1
Date Datum från 100-01-01 till 9999-12-31 0
(1899-12-30)
dte Saknas 8
Object En referens till ett godtyckligt objekt Saknas obj Saknas 4

I Visual Basic 6.0 kom det ytterligare en datatyp:

Datatyp Användningsområde Startvärde Prefix Suffix Antal byte
Decimal Decimaltal inom följande gränser:
+/-79228162514264337593543950335
utan decimaler
+/-7,9228162514264337593543950335
med 28 decimaler
Minsta tal skiljt från 0 är
+/-0,0000000000000000000000000001
Empty dec Saknas 14

Med startvärde menas variabelns värde när den har deklarerats, men ännu inte tilldelats något värde. En del programmerare tycks tro att variabler då är "tomma" eller på något sätt "opålitliga". Så är inte fallet. De är mycket pålitliga. En Boolean har värdet False. En String innehåller en "nollängdssträng", alltså "". En Byte, Integer, Long, Single och Double har alla värdet 0. En Date har också värdet 0, vilket motsvarar 1899-12-30. (Se avsnittet Typkonvertering.)

Empty är ett speciellt "värde" som en variabel med datatypen Variant har innan den tilldelas något värde. Man kan även tilldela en sådan variabel "värdet" Null för att visa att variabeln avsiktligen är "tom". Av samma orsak kan man tilldela en variabel med datatypen Object "värdet" Nothing.

En Decimal kan inte deklareras på vanligt sätt i Visual Basic 6.0, utan deklareras först som en Variant och omvandlas sedan till en Decimal med typkonverteringsfunktionen CDec. Datatypen Decimal bör inte användas i onödan. Single och Double bör heller inte användas i onödan. Dessa datatyper tar mera plats i datorns arbetsminne. Datatypen Variant bör i möjligaste mån undvikas, för den tar mest plats.

Använd gärna ovannämnda prefix (int, lng, sng, dbl, cur, str, vnt, bln, byt, dte, obj och dec) i början av variabelnamn. Att använda prefix i början av variabelnamn kallas ungersk notation efter den ungerske programmeraren Charles Simonyi på Microsoft. Ska man använda ungersk notation bör man göra det konsekvent.

Många tycker att ungersk notation gör koden lättare att förstå. Varför? Jo, för det första ser man på variabelnamnet vilken datatyp det är frågan om, vilket är bra i ett programmeringsspråk med automatisk typkonvertering (se avsnittet med samma namn). För det andra ser man lättare vilka ord som är namn på variabler och vilka ord som är andra ord i koden. Det finns ett tredje skäl, som ofta glöms bort. Om man använder ungersk notation kan man använda samma namn till olika variabler genom att kalla en för strNamn, en annan för intNamn, en tredje för lngNamn osv. Det kan vara praktiskt. Tyvärr har inte Microsoft själva varit konsekventa under årens lopp. I de tre första versionerna av Visual Basic förespråkades enställiga prefix som s (för String), i (för Integer) och l (för Long). När det gäller API-anrop (se avsnittet Procedurer och deras räckvidd) har man haft för vana att använda exotiska prefix som lp och dw. En C-programmerare förstår innebörden av dessa prefix. En Visual Basic-programmerare gör det inte. Använd gärna ungersk notation, men ta inte saken alltför högtidligt.

Konstanter deklareras med uttrycket Const enligt följande exempel:

Private Sub cmdMyButton_Click()
Dim strCompany As String
Dim strLastName As String
Dim intNumber As Integer
Const intBonus As Integer = 500
Const strEmployer As String = "Microsoft"
Const dteStart As Date = #1981-08-12#

Observera att man använder tecknet " på ömse sidor när man tilldelar ett värde till en variabel eller konstant med datatypen String.

Observera även att man använder tecknet # på ömse sidor när man tilldelar ett värde till en variabel eller konstant med datatypen Date.

I kod från äldre versioner av Visual Basic ser man ofta att programmerare har deklarerat konstanternas namn med stora bokstäver, utan prefix och utan att ange datatyp, vilket numera inte rekommenderas. Att man gjorde så berodde delvis på att man inte fick ange datatyp när man deklarerade konstanter i Visual Basic 3.0 och äldre versioner. Stora bokstäver tycker somliga är bra att använda för att man ska se på namnet att det är frågan om en konstant, men i Visual Basic är det viktigare att se på namnet vilken datatyp det är frågan om. Det går inte att ta den här saken alltför högtidligt heller. Namnen på alla hundratals systemkonstanter som förekommer i API-anrop (se avsnittet Procedurer och deras räckvidd) har av tradition alltid skrivits med stora bokstäver och det är inte lätt att ändra på.

Suffixen % (Integer), & (Long), ! (Single), # (Double), @ (Currency) och $ (String) kan användas för att deklarera variabler och konstanter på ett snabbare sätt:

Private Sub cmdMyButton_Click()
Dim strCompany$, strLastName$, intNumber%
Const intBonus% = 500
Const strEmployer$ = "Microsoft"

I detta exempel får variablerna strCompany och strLastName datatypen String, liksom konstanten strEmployer. Variabeln intNumber får datatypen Integer, liksom konstanten intBonus. Visual Basic tillåter suffix när det gäller sex av de sju ursprungliga datatyperna. Somliga tycker att detta skrivsätt är svårtolkat och inkonsekvent, eftersom det inte kan tillämpas på alla datatyper.

Även vissa funktioner som ingår i själva programmeringsspråket är försedda med suffix, t ex Format$, Left$, Right$, Mid$, Trim$ osv. Microsoft ville på detta sätt poängtera att returvärdet har datatypen String. Tyvärr är det många som inte använder dessa funktioner. Istället använder man funktionen utan suffix. Returvärdet får då datatypen Variant. Funktionerna med suffix kan ge programmet en viss prestandaförbättring.

Man kan sätta suffix på sina egna funktioner också. Följande funktion fungerar utmärkt och har ett returvärde med datatypen Long:

Public Function Summa&(A&, B&)
  Summa = A + B
End Function

Skriv inte svårtolkad kod i Visual Basic! Skriv istället

Public Function Summa(lngA As Long, lngB As Long) As Long
  Summa = lngA + lngB
End Function

Det är också bra att känna till prefixet &H, som används i koden framför tal i hexadecimal form, och prefixet &O, som används i koden framför tal i oktal form. 15 i decimala talsystemet är samma sak som F i hexadecimala talsystemet. I koden går det inte att bara skriva F. Man måste skriva &HF. Man kan lägga till ett &-tecken efter talet också, men det är frivilligt.

Om ett tal i koden är ett heltal och absolutbeloppet är mindre än 32768 tillåter kompilatorn att man skriver ett &-tecken efter talet. Är heltalets absolutbelopp större än 2147483647 lägger Visual Basic till ett #-tecken automatiskt. Det är även tillåtet att lägga till ett @-tecken eller ett !-tecken efter ett tal i koden, om talets absolutbelopp inte är för stort. Effekten blir att man ändrar undertypen för en Variant. & ändrar undertypen till Long, @ till Currency, ! till Single och # till Double. Ett exempel:

Private Sub cmdTypeTest_Click()
Dim vntX As Variant
  vntX = 7
  MsgBox TypeName(vntX)
  vntX = 7&
  MsgBox TypeName(vntX)
End Sub

Det första meddelandet blir "Integer", medan det andra blir "Long". En Variant med undertypen Long är inte samma sak som en vanlig Long. Det är t ex effektivare att använda en vanlig Long som räknare i en slinga.

 

Visual Basic-programmerarens viktigaste kortkommandon

Kortkommandona Shift+F2 och Ctrl+Shift+F2 är viktiga för en Visual Basic-programmerare. Utan dem är det svårt att orientera sig i koden. Placera den blinkande markören någonstans i namnet på en procedur, variabel eller konstant. Tryck på Shift+F2. Vips hamnar du på den plats i koden där proceduren, variabeln eller konstanten deklareras. På så sätt kan du snabbt kontrollera datatyp, räckvidd, returvärde eller något annat du behöver veta. Tryck sedan på Ctrl+Shift+F2. Vips är du tillbaka där du var förut.

 

Objektvariabler

Objektvariabler deklareras med tidig bindning ("early binding") eller sen bindning ("late binding"). Tidig bindning är ofta att föredra. Programmets prestanda kan i viss mån förbättras när man använder tidig bindning. Ett undantag är en ActiveX EXE. (Se avsnittet Historik.) Ett sådant objekt kan tjäna på sen bindning.

Med "tidig" menas att man i ett tidigt skede (redan när man deklarerar objektvariabeln) specificerar vilket slags objekt det är frågan om.

Med "sen" menas att man först i ett senare skede (när objektvariabeln för första gången tilldelas ett objekt) specificerar vilket slags objekt det är frågan om.

När man tilldelar ett objekt till en objektvariabel kan man använda uttrycket Set och ordet New.

Ett exempel på tidig bindning:

Private Sub cmdStartExcel_Click()
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
  Set xlApp = New Excel.Application
  xlApp.Visible = True
  Set xlBook = xlApp.Workbooks.Add
End Sub

Objekt kan ha metoder ("methods") och egenskaper ("properties"). Ibland grupperas ett antal objekt i en samling ("collection").

Excel är ett objekt. Detta objekt har egenskapen Application. Egenskapen Application returnerar i sin tur ett objekt, en instans av programmet Microsoft Excel. Detta objekt har egenskapen Visible, som kan vara True eller False, och egenskapen Workbooks, som returnerar samlingen Workbooks. Denna samling består av alla öppna arbetsböcker i den aktuella instansen av Microsoft Excel. Samlingen Workbooks har i sin tur metoden Add, som öppnar en ny arbetsbok. Så där håller det på.

Detta och mycket annat beskrivs i Excels objektmodell. Allt man kan göra för hand i Word och Excel kan automatiseras med hjälp av Visual Basic. Program som Access och Project kan också automatiseras med hjälp av Visual Basic, liksom de senaste versionerna av Outlook, PowerPoint, Publisher och Visio. Eftersom dessa program har vitt skilda ändamål är objektmodellerna och tillvägagångssätten olika, men själva programmeringsspråket är detsamma. En rad program från andra företag än Microsoft kan numera också automatiseras med hjälp av Visual Basic. De mest kända är CorelDRAW, WordPerfect och AutoCAD.

Man kan använda ordet New redan när objektvariabeln deklareras:

Private Sub cmdStartExcel_Click()
Dim xlApp As New Excel.Application
Dim xlBook As Excel.Workbook
  xlApp.Visible = True
  Set xlBook = xlApp.Workbooks.Add
End Sub

I detta exempel används ordet New redan när objektvariabeln xlApp deklareras. Objektvariabeln xlBook deklareras och tilldelas ett objekt utan att ordet New används överhuvudtaget. Istället tilldelas objektvariabeln xlBook ett objekt med hjälp av metoden Add.

Tidig bindning ger tillgång till IntelliSense, vilket är en stor hjälp när man ska orientera sig i objektmodellerna i Word och Excel:

IntelliSense

För att tidig bindning ska fungera krävs i ovanstående exempel en referens till Microsoft Excel i dialogrutan References, som visas om man klickar på References... på menyn Project:

Reference to Excel

Naturligtvis förutsätter detta att du har installerat Excel på din dator.

Ett exempel på sen bindning:

Private Sub cmdStartExcel_Click()
Dim xlApp As Object
Dim xlBook As Object
  Set xlApp = CreateObject("Excel.Application")
  xlApp.Visible = True
  Set xlBook = xlApp.Workbooks.Add
End Sub

När man använder sen bindning deklarerar man objektvariabler As Object.

Det är viktigt att förstå att en objektvariabel egentligen inte tilldelas ett objekt, utan en referens till ett objekt. Två olika objektvariabler kan referera till samma objekt. När man ändrar en egenskap hos den ena ändras denna egenskap även hos den andra.

 

 

  Arrayer, egna datatyper och numreringar

Arrayer

Att använda arrayer (kallas vektorer eller matriser på svenska) är effektivt. Arrayer hanteras mycket snabbt av Visual Basic, särskilt om du använder optimeringstipsen i slutet av denna lathund.

Några exempel på hur man deklarerar och använder arrayer:

Dim strMyFriends(2) As String
strMyFriends(0) = "Kalle"
strMyFriends(1) = "Pelle"
strMyFriends(2) = "Lisa"

Dim intMyLuckyNumbers(1 To 3) As Integer
intMyLuckyNumbers(1) = 4
intMyLuckyNumbers(2) = 7
intMyLuckyNumbers(3) = 8

Index för en array börjar alltid med 0 om man inte deklarerar något annat. Det kan man ändra genom att skriva

Option Base 1

i huvudet av en modul. Då kommer index alltid att börja med 1 om man inte deklarerar något annat. Observera att detta endast gäller den aktuella modulen.

Om man inte vet hur många element som behövs i en array kan man börja med att deklarera den utan att ange antalet element. Man brukar säga att man skapar en dynamisk array:

Dim strMyFriends() As String

Senare i koden kan man ändra antalet element med uttrycket ReDim:

ReDim strMyFriends(1 To 20)

Om man inte vill att innehållet ska försvinna när man ändrar antalet element använder man uttrycket ReDim Preserve:

ReDim Preserve strMyFriends(1 To 50)

Upp till 60 dimensioner kan man använda i arrayer. En tredimensionell array skulle kunna deklareras så här:

Dim strMulti(1 To 10, 1 To 50, 1 To 30) As String

Om man använder uttrycket ReDim Preserve kan man endast ändra antalet element i den sista dimensionen i en flerdimensionell dynamisk array. Varken ReDim eller ReDim Preserve kan ändra antalet dimensioner i en dynamisk array när den väl har fått ett visst antal dimensioner.

ReDim kan inte ändra datatypen för en dynamisk array, om den inte var deklarerad som Variant från början. När man använder uttrycket ReDim är det alltså inte nödvändigt att på nytt ange datatyp, om man inte ändrar från Variant till en annan datatyp och då kan man inte använda ReDim Preserve, bara ReDim.

 

VARNING!
Man bör använda ReDim Preserve med viss försiktighet, annars kan det färdiga programmets prestanda försämras. I stället för att öka antalet element med ett i taget kan man öka med tusen i taget eller något annat lämpligt antal.

 

Funktionerna LBound och UBound är mycket användbara. Dessa funktioner returnerar lägsta respektive högsta index för en array. Man kan även tillämpa dessa funktioner på flerdimensionella arrayer. Antag att variabeln lngSecondLimit ska tilldelas det tal som är högsta index i den andra dimensionen av en tredimensionell array som heter strMulti. Då kan man skriva

lngSecondLimit = UBound(strMulti, 2)

 

VARNING!
Om lägsta index är 1, så är högsta index lika med antalet element och funktionen UBound returnerar i så fall antalet element, men om lägsta index inte är 1 returnerar funktionen UBound inte antalet element!

 

VARNING!
Använd 0 som lägsta index om du vill underlätta övergången till Visual Basic .NET.

 

VARNING!
Det är en god vana att tömma arrayer med uttrycket Erase när innehållet inte längre behövs, men om Erase tömmer en dynamisk array drabbas den av total minnesförlust och kommer inte ens ihåg hur många element den innehöll. Du måste på nytt ange antalet element med ReDim när du återanvänder en dynamisk array som har tömts med Erase.

 

Antag att man deklarerar en array så här:

Dim strMyArray(0) As String

Vad får man? En array? Nej, i praktiken får man bara en variabel med datatypen String, för denna array kan endast rymma ett element.

Antag att man deklarerar en array så här:

Dim strMyArray(4, 0) As String

Vad får man? En tvådimensionell array? Nej, i praktiken får man bara en endimensionell array med fem element, för "på andra ledden" kan denna array endast rymma ett element.

 

Kopiering av arrayer

I Visual Basic 5.0 kan man inte tilldela en array till en annan array. Däremot kan man tilldela en array till en variabel med datatypen Variant. På så sätt kan man kopiera en array. Ett exempel:

Private Sub cmdCopyArray_Click()
Dim strOriginal(1 To 4) As String
Dim vntCopy As Variant
Dim lngX As Long
  strOriginal(1) = "spring"
  strOriginal(2) = "summer"
  strOriginal(3) = "autumn"
  strOriginal(4) = "winter"
  vntCopy = strOriginal
  For lngX = LBound(vntCopy) To UBound(vntCopy)
    MsgBox "Season number " & lngX & " is " & vntCopy(lngX)
  Next lngX
End Sub

Observera att elementen i vntCopy inte får datatypen String. De får datatypen Variant med undertypen String. Den skillnaden kan medföra en försämring av det färdiga programmets prestanda.

I Visual Basic 5.0 kan det vara bättre att kopiera arrayen element för element till en annan array med datatypen String:

Private Sub cmdCopyArray_Click()
Dim strOriginal(1 To 4) As String
Dim strCopy() As String
Dim lngX As Long
  strOriginal(1) = "spring"
  strOriginal(2) = "summer"
  strOriginal(3) = "autumn"
  strOriginal(4) = "winter"
  ReDim strCopy(LBound(strOriginal) To UBound(strOriginal))
  For lngX = LBound(strOriginal) To UBound(strOriginal)
    strCopy(lngX) = strOriginal(lngX)
  Next lngX
  For lngX = LBound(strCopy) To UBound(strCopy)
    MsgBox "Season number " & lngX & " is " & strCopy(lngX)
  Next lngX
End Sub

I Visual Basic 6.0 kan man tilldela en array till en annan array om den senare deklarerades som en dynamisk array och båda arrayerna har samma datatyp. Ett exempel:

Private Sub cmdCopyArray_Click()
Dim strOriginal(1 To 4) As String
Dim strCopy() As String
Dim lngX As Long
  strOriginal(1) = "spring"
  strOriginal(2) = "summer"
  strOriginal(3) = "autumn"
  strOriginal(4) = "winter"
  strCopy = strOriginal
  For lngX = LBound(strCopy) To UBound(strCopy)
    MsgBox "Season number " & lngX & " is " & strCopy(lngX)
  Next lngX
End Sub

 

Ett snabbare sätt att fylla en array

Det finns Visual Basic-programmerare som känner sig tvingade att skriva som i följande exempel när de tilldelar värden till elementen i en array. Koden kan bli lång. Väldigt lång.

Public Sub GetCapitals()
Dim strCapitals As String
  strCapitals(0) = "London"
  strCapitals(1) = "Paris"
  strCapitals(2) = "Rome"
  strCapitals(3) = "Berlin"
  strCapitals(4) = "Brussels"
  strCapitals(5) = "Hague"
  strCapitals(6) = "Luxembourg"
  strCapitals(7) = "Madrid"
  strCapitals(8) = "Lisbon"
  strCapitals(9) = "Athens"
  strCapitals(10) = "Vienna"
  strCapitals(11) = "Dublin"
  strCapitals(12) = "Copenhagen"
  strCapitals(13) = "Stockholm"
  strCapitals(14) = "Helsinki"
  strCapitals(15) = "Warsaw"
  strCapitals(16) = "Tallinn"
  strCapitals(17) = "Riga"
  strCapitals(18) = "Vilnius"
  strCapitals(19) = "Prague"
  strCapitals(20) = "Bratislava"
  strCapitals(21) = "Budapest"
  strCapitals(22) = "Ljubljana"
  strCapitals(23) = "Valletta"
  strCapitals(24) = "Nicosia"
  strCapitals(25) = "Bucharest"
  strCapitals(26) = "Sofia"
  strCapitals(27) = "Ankara"
End Sub

Ju fler element, desto snyggare blir det att skriva så här istället:

Public Sub GetCapitals()
Dim vntTemp As Variant
Dim strCapitals() As String
Dim lngX As Long
  vntTemp = Array("London", "Paris", "Rome", "Berlin", "Brussels", _
  "Hague", "Luxembourg", "Madrid", "Lisbon", "Athens", "Vienna", _
  "Dublin", "Copenhagen", "Stockholm", "Helsinki", "Warsaw", "Tallinn", _
  "Riga", "Vilnius", "Prague", "Bratislava", "Budapest", "Ljubljana", _
  "Valletta", "Nicosia", "Bucharest", "Sofia", "Ankara")
  ReDim strCapitals(LBound(vntTemp) To UBound(vntTemp))
  For lngX = LBound(vntTemp) To UBound(vntTemp)
    strCapitals(lngX) = vntTemp(lngX)
  Next lngX
End Sub

Den inbyggda funktionen Array returnerar en array med datatypen Variant, i detta fall med undertypen String. Lägsta index är alltid 0. For-slingan tilldelar elementens värden till elementen i en array med datatypen String, som ger bättre prestanda.

 

Arrayer och procedurer

Man kan använda en array som argument i en procedur:

Private Sub cmdMyButton_Click()
Dim strMembers(1 To 3) As String
  strMembers(1) = "Kalle"
  strMembers(2) = "Pelle"
  strMembers(3) = "Lisa"
  Talk "Hej ", strMembers
End Sub

Private Sub Talk(strIntro As String, strNames() As String)
Dim lngX As Long
  For lngX = LBound(strNames) To UBound(strNames)
    MsgBox strIntro & strNames(lngX)
  Next lngX
End Sub

Lägg märke till att man måste skriva argumentet strNames() med parenteser i procedurens argumentlista, för att visa att endast en array accepteras. Däremot spelar det ingen roll om man använder dessa parenteser när man anropar en procedur. I exemplet ovan kan man skriva strMembers eller strMembers(), det spelar ingen roll.

När man vill skapa en procedur med ett varierande antal argument skriver man som i detta exempel:

Private Sub TalkMore(strIntro As String, ParamArray vntNames() As Variant)
Dim lngX As Long
  For lngX = 0 To UBound(vntNames)
    MsgBox strIntro & vntNames(lngX)
  Next lngX
End Sub

Subrutinen TalkMore kan säga hej till hur många vänner som helst, så länge du inte har fler än 2147483648. Det högsta index man kan använda i en array är nämligen 2147483647, men det kräver mycket arbetsminne! Lägg märke till att det argument som är ParamArray alltid placeras sist bland argumenten. Datatypen för en ParamArray är alltid Variant och index börjar alltid med 0.

En funktion kan även returnera en array. Det kan man åstadkomma på två olika sätt. Dels kan man låta funktionen returnera en Variant som innehåller en array och dels kan man låta funktionen returnera själva arrayen. Det senare kräver Visual Basic 6.0.

Här returneras en Variant som innehåller en array (observera att det även är en Variant som tilldelas funktionens returvärde):

Private Sub TalkDays()
Dim vntMyArray As Variant
Dim lngX As Long
  vntMyArray = DayArray
  For lngX = LBound(vntMyArray) To UBound(vntMyArray)
    MsgBox vntMyArray(lngX)
  Next lngX
End Sub

Private Function DayArray() As Variant
Dim strDays(1 To 7) As String
  strDays(1) = "Monday"
  strDays(2) = "Tuesday"
  strDays(3) = "Wednesday"
  strDays(4) = "Thursday"
  strDays(5) = "Friday"
  strDays(6) = "Saturday"
  strDays(7) = "Sunday"
  DayArray = strDays
End Function

Här returneras själva arrayen (observera att det är en dynamisk array med rätt datatyp som tilldelas funktionens returvärde):

Private Sub TalkDays()
Dim strMyArray() As String
Dim lngX As Long
  strMyArray = DayArray
  For lngX = LBound(strMyArray) To UBound(strMyArray)
    MsgBox strMyArray(lngX)
  Next lngX
End Sub

Private Function DayArray() As String()
Dim strDays(1 To 7) As String
  strDays(1) = "Monday"
  strDays(2) = "Tuesday"
  strDays(3) = "Wednesday"
  strDays(4) = "Thursday"
  strDays(5) = "Friday"
  strDays(6) = "Saturday"
  strDays(7) = "Sunday"
  DayArray = strDays
End Function

 

Hur man snabbast överför data mellan tvådimensionella arrayer och cellområden i Excel

Man kan inte överföra data från ett cellområde i Excel till vilken tvådimensionell array som helst, bara till en Variant:

Function GetData(strRange As String) As Variant
  GetData = Range(strRange).Value
End Function

Argumentet strRange anger vilket cellområde som avses, t ex "C8:E12".

När man överför data i motsatt riktning, från en tvådimensionell array till ett cellområde i Excel, ger Range-objektets Resize-egenskap bäst prestanda:

Sub SetData(strUpperLeft As String, vntData As Variant)
Dim lngRows As Long
Dim lngColumns As Long
  lngRows = UBound(vntData, 1) - LBound(vntData, 1) + 1
  lngColumns = UBound(vntData, 2) - LBound(vntData, 2) + 1
  Range(strUpperLeft).Resize(lngRows, lngColumns) = vntData
End Sub

Argumentet strUpperLeft anger referensen till cellen överst till vänster i cellområdet, t ex "B2".

Resize-egenskapen kan även tilldelas tvådimensionella arrayer med andra datatyper än Variant.

Om Resize-egenskapen tilldelas en endimensionell array måste elementen placeras på en rad i kalkylbladet i Excel, inte i en kolumn:

Sub RowOfCapitals()
Dim vntTemp As Variant
Dim strCapitals() As String
Dim lngX As Long
  vntTemp = Array("London", "Paris", "Rome", "Berlin", "Brussels", _
  "Hague", "Luxembourg", "Madrid", "Lisbon", "Athens", "Vienna", _
  "Dublin", "Copenhagen", "Stockholm", "Helsinki", "Warsaw", "Tallinn", _
  "Riga", "Vilnius", "Prague", "Bratislava", "Budapest", "Ljubljana", _
  "Valletta", "Nicosia", "Bucharest", "Sofia", "Ankara")
  ReDim strCapitals(LBound(vntTemp) To UBound(vntTemp))
  For lngX = LBound(vntTemp) To UBound(vntTemp)
    strCapitals(lngX) = vntTemp(lngX)
  Next lngX
  Range("A1").Resize(1, UBound(vntTemp) + 1) = strCapitals
End Sub

Låt oss därför förbättra subrutinen SetData ovan, så att den även kan hantera en endimensionell array och placera den i en kolumn i kalkylbladet, inte bara på en rad. Även om Excel 2007 har lika många kolumner som Excel 95 hade rader (16384) är antalet rader i Excel 2007 mycket större (1048576) än antalet kolumner. Den förbättrade subrutinen har även felhantering (se avsnittet Felhantering och avlusning):

Sub SetAnyData(strUpperLeft As String, vntData As Variant, _
  Optional blnRow As Boolean)
Dim lngX As Long
Dim lngRows As Long
Dim lngColumns As Long
Dim vntTemp As Variant
  On Error GoTo Catch
  vntTemp = vntData
  On Error GoTo OneDimensional
  lngRows = UBound(vntTemp, 1) - LBound(vntTemp, 1) + 1
  lngColumns = UBound(vntTemp, 2) - LBound(vntTemp, 2) + 1
Fill:
  On Error GoTo Catch
  Range(strUpperLeft).Resize(lngRows, lngColumns) = vntTemp
  Exit Sub
OneDimensional:
  On Error GoTo Catch
  If blnRow = True Then
    lngRows = 1
    lngColumns = UBound(vntData) - LBound(vntData) + 1
    ReDim vntTemp(0, UBound(vntData))
    For lngX = 0 To UBound(vntData)
      vntTemp(0, lngX) = vntData(lngX)
    Next lngX
  Else
    lngRows = UBound(vntData) - LBound(vntData) + 1
    lngColumns = 1
    ReDim vntTemp(UBound(vntData), 0)
    For lngX = 0 To UBound(vntData)
      vntTemp(lngX, 0) = vntData(lngX)
    Next lngX
  End If
  Resume Fill
Catch:
  MsgBox "There was an unexpected error"
End Sub

 

Samlingar

Samlingar (kallas collections på engelska) har vissa fördelar som arrayer saknar.  Man kan använda en slinga av typen For Each (se avsnittet Operatorer, slingor och inbyggda funktioner) för att nå alla medlemmarna i en samling. Att nå alla elementen i en array på detta sätt är inte möjligt om inte datatypen är Variant. Om man vill öka eller minska antalet element i en array måste den omdimensioneras. Samlingar omdimensioneras inte, antalet medlemmar går att öka eller minska ändå. Att nå en viss medlem i en samling är dessutom lättare än att nå ett visst element i en array.

 

VARNING!
Även om en samling har vissa fördelar kan en array ge bättre prestanda. Testa och jämför.

 

En samling deklareras på samma sätt som ett objekt:

Dim colCapitals As Collection
Set colCapitals = New Collection

En samling har fyra metoder. Add, Item, Remove och Count.

Metoden Add har fyra argument. Det första argumentet är den nya medlemmens värde. Det kan vara ett numeriskt värde eller en textsträng inom citationstecken. Det andra argumentet är en frivillig nyckel som kan användas om man senare vill läsa medlemmens värde med hjälp av metoden Item eller ta bort medlemmen med hjälp av metoden Remove. Nyckeln måste vara en textsträng inom citationstecken. Tredje och fjärde argumentet är också frivilliga. De kan användas för att ange var i samlingen den nya medlemmen ska placeras.

colCapitals.Add "London", "Great Britain"
colCapitals.Add "Paris", "France"
colCapitals.Add "Rome", "Italy"

Metoden Item har bara ett argument.

strCapital = colCapitals.Item("Italy")

och

strCapital = colCapitals.Item(3)

ger samma resultat. Variabeln strCapital tilldelas värdet av den tredje medlemmen i samlingen colCapitals, alltså "Rome". Samlingar har alltid ett index som börjar med 1.

Metoden Remove har också bara ett argument.

colCapitals.Remove("Italy")

och

colCapitals.Remove(3)

ger samma resultat. Den tredje medlemmen i samlingen colCapitals tas bort.

Metoden Count returnerar det aktuella antalet medlemmar i samlingen. Ett exempel:

MsgBox "Samlingen colCapitals har " & colCapitals.Count & " medlemmar"

 

Egna datatyper

Om man vill kan man använda egna datatyper i Visual Basic. De kallas även "användardefinierade typer" ("user-defined types" på engelska). Dessa mindre lyckade benämningar började Microsoft använda i föregångaren QuickBasic på 80-talet.

I C++ och Java säger man structure. I Pascal säger man record.

Egentligen är det lätt. Man hittar på ett gemensamt namn för ett antal variabler med de gamla vanliga datatyperna. Ibland kan det vara praktiskt att hantera vissa variabler tillsammans, istället för att hantera dem var för sig.

I huvudet av en standardmodul kan man t ex skriva

Public Type Member
  MemberID As Long
  FirstName As String
  LastName As String
  PhoneNumber As String
End Type

I en procedur i samma projekt kan man sedan skriva

Dim udtNewMember As Member
Dim udtEmptyMember As Member

och senare i samma procedur

udtNewMember.MemberID = 1234
udtNewMember.FirstName = "Lisa"
udtNewMember.LastName = "Karlsson"
udtNewMember.PhoneNumber = "123456"

udtEmptyMember då? Vad är den variabeln till för? Jo, det är bra att ha en tom variabel med samma egna datatyp. Då kan man lätt tömma innehållet i andra variabler med samma egna datatyp. Skriv bara så här:

udtNewMember = udtEmptyMember

Det är förstås lättare än att skriva så här:

udtNewMember.MemberID = 0
udtNewMember.FirstName = ""
udtNewMember.LastName = ""
udtNewMember.PhoneNumber = ""

Om man deklarerar en egen datatyp i huvudet av en formulärmodul måste man använda ordet Private. Då kan den egna datatypen bara användas för att deklarera lokala eller modulära variabler i den aktuella formulärmodulen. (Se avsnittet Variablers och konstanters räckvidd.)

Vill man kunna deklarera variabler med egen datatyp i vilken modul som helst måste den egna datatypen deklareras i huvudet av en standardmodul. Man kan utelämna ordet Public, men för tydlighets skull bör det vara med.

För att få global räckvidd måste variabler med egen datatyp också deklareras i huvudet av en standardmodul. Ordet Public måste användas.

Det går bra att använda en variabel med egen datatyp som argument i en procedur.

När det passar dina syften kan du även göra en array av en variabel med egen datatyp:

Dim udtAllMembers(1 To 10) As Member
udtAllMembers(1).MemberID = 1234
udtAllMembers(1).FirstName = "Lisa"
udtAllMembers(1).LastName = "Karlsson"
udtAllMembers(1).PhoneNumber = "123456"

 

VARNING!
Gör gärna en array av en variabel med egen datatyp, men använd inte en array i en egen datatyp om du vill underlätta övergången till Visual Basic .NET. Av samma skäl bör du inte använda en String med fast längd i en egen datatyp.

 

Numreringar

Med uttrycket Enum kan man skapa något som påminner om egna datatyper, fast man grupperar inte ett antal variabler med olika datatyper, utan ett antal konstanter med datatypen Long. Det kallas numreringar. En del säger enumeratorer.

En numrering passar bra som datatyp för en variabel vars tillåtna värden är ett begränsat antal heltal, eller rättare sagt ett begränsat antal alternativ som vart och ett representeras av ett heltal.

Som följande exempel visar kan en numrering vara bra att använda som argument i en procedur. När proceduren anropas får man som synes en praktisk lista över argumentets tillåtna värden.

Enum

Numreringar har samma begränsningar som datatypen Long, så alla heltal mellan -2147483648 och 2147483647 kan användas, även i hexadecimal form.

I en numrering behöver inte alternativen numreras i ordning. Om man struntar i att numrera alternativen får de automatiskt en numrering som börjar med 0.

 

 

  Typkonvertering

En programmerare vill ofta tilldela variabeln A till variabeln B. Om A och B är deklarerade med olika datatyper kan tilldelningen vara begränsad av olika regler eller helt förbjuden. Visual Basic är ett mycket snällt språk i den situationen och tillåter det mesta.

I Visual Basic kan man alltid tilldela en Byte, Integer, Long, Currency, Single, Double, Date eller Boolean till en String, utan att använda typkonverteringsfunktionen CStr.

Man kan till och med konkatenera (sammanfoga) en Byte med en Integer och en Long och en Currency och en Single och en Double och en Date och en Boolean och tilldela resultatet till en String.

Motsatsen, att tilldela en String till en Byte, Integer, Long, Currency, Single, Double, Date eller Boolean går också bra, under förutsättning att värdet av variabeln med datatypen String är "lämpligt" för den andra variabelns datatyp.

Variabler med de numeriska datatyperna Byte, Integer, Long, Currency, Single, Double, Date och Boolean kan även tilldelas varandra om de har "lämpliga" värden.

Följande kod fungerar:

Private Sub Test()
Dim lngX As Long
Dim blnY As Boolean
  lngX = -1
  blnY = lngX
End Sub

Följande kod fungerar inte:

Private Sub Test()
Dim lngX As Long
Dim intY As Integer
  lngX = 750000
  intY = lngX
End Sub

I det andra exemplet har variabeln lngX ett värde som är för stort för datatypen Integer.

När det gäller datatypen Date är det bra att veta att alla datum sedan år 1900 numreras med positiva heltal. Den 25 januari 2001 numreras 36916. Den dagen hade det gått 36916 dagar sedan förrförra sekelskiftet. (Så gör kalkylprogrammet Excel också, men det finns en skillnad: Visual Basic 6.0 räknar konstigt nog inte år 1900 som ett skottår, vilket Excel gör, men den 1 januari 1900 numreras 1 i Excel och 2 i Visual Basic 6.0, så det uppstår inte någon förskjutning mellan Excel och Visual Basic 6.0 efter skottdagen 1900.)

Visual Basic kan hantera alla datum mellan år 100 och år 9999.

När det gäller datatypen Boolean är det bra att veta att False kan bytas ut mot 0 och True kan bytas ut mot -1.

Nu kommer en hemlighet om datatypen Boolean. Det är inte bara -1 som motsvarar True. Alla tal överhuvudtaget motsvarar True, utom 0, som motsvarar False! Faktum är att alla textsträngar också motsvarar True! Utom "0" och "False", som motsvarar False! Vad motsvarar 1899-12-30? Rätt gissat! False! Alla andra datum motsvarar True! Låt oss säga att vi har en variabel med datatypen Integer. Variabeln heter intX. Vi vill kontrollera om intX = 0 och meddela resultatet av kontrollen. Då kan vi kort och gott skriva

If intX Then
  MsgBox "Den är inte 0!"
Else
  MsgBox "Den är 0!"
End If

Skriv inte svårtolkad kod i Visual Basic! Skriv istället

If intX <> 0 Then
  MsgBox "Den är inte 0!"
Else
  MsgBox "Den är 0!"
End If

Vid anrop av procedurer är Visual Basic strängare. Ofta kräver Visual Basic att de variabler som den anropande proceduren skickar som argument har rätt datatyp. Då kan man bli tvungen att använda typkonverteringsfunktionerna CStr, CByte, CInt, CLng, CCur, CSng, CDbl, CDate, CBool, CDec och CVar för att undvika "type mismatch" och följande välkända felmeddelande:

Type mismatch

Kravet på rätt datatyp gäller inte när det står ByVal eller As Any i den anropade procedurens argumentlista. As Any kan bara användas vid API-anrop. (Se avsnittet Procedurer och deras räckvidd.)

 

 

  Variablers och konstanters räckvidd

Räckvidden för variabler och konstanter beror på två saker:

  • Om man deklarerar i huvudet av en procedur, formulärmodul eller standardmodul
  • Om man skriver Public och Public Const istället för Dim och Const

Om man vill skapa en lokal variabel eller konstant, som bara kan användas i en viss procedur, så deklarerar man variabeln eller konstanten som vanligt i procedurens huvud och använder uttrycken Dim eller Const.

Om man vill skapa en modulär variabel eller konstant, som kan användas i alla procedurer i en viss modul, så deklarerar man i modulens huvud och skriver Private eller Private Const. Man kan även använda de vanliga uttrycken Dim eller Const, men då syns det inte lika tydligt att räckvidden är begränsad till den aktuella modulen. Det är tydligare att skriva Private eller Private Const.

Exempel:

Private m_strCompany As String
Private Const m_strCity As String = "Stockholm"

Ibland vill man skapa en global variabel eller konstant, som kan användas i alla moduler i hela projektet. Då deklarerar man i huvudet av en standardmodul och skriver Public eller Public Const istället för Dim eller Const. (I Visual Basic 3.0 och äldre versioner använde man inte ordet Public, utan Global. Det fungerar fortfarande, men rekommenderas inte.)

Exempel:

Public p_strCompany As String
Public Const p_intBonus As Integer = 500

Man brukar hänga på ett m_ (för modular) och ett p_ (för public) framför namnet på modulära och globala variabler och konstanter. Dessa prefix rekommenderas, särskilt i större projekt med många moduler. Det är bra att kunna se på namnet vilken räckvidd som gäller. (I Visual Basic 3.0 och äldre versioner brukade man använda bokstaven g istället för p.)

Globala variabler kan även deklareras i klassmoduler (se avsnittet med samma namn).

Det är inte förbjudet att deklarera globala variabler i formulärmoduler, men formulärmodulens namn måste i så fall anges när variablerna används i andra moduler, vilket är en nackdel:

intX = frmTestForm.p_intTestVariable

Globala konstanter måste deklareras i standardmoduler. Det gäller även arrayer och variabler med  egna datatyper om räckvidden ska vara global. En String med fast längd måste också deklareras i en standardmodul om variabeln ska vara global.

Numreringar har inte dessa begränsningar. De kan deklareras i vilken modul som helst, även om räckvidden ska vara global. Det gäller både numreringarna själva och de variabler som använder dem som datatyp.

 

VARNING!
Använd inte för många globala variabler, särskilt inte i större projekt med många moduler. Annars blir det mycket hoppande fram och tillbaka med Shift+F2 och Ctrl+Shift+F2 för att kontrollera vad den och den globala variabeln heter.

I princip har globala variabler varit onödiga sedan Visual Basic 4.0, då klassmoduler började användas. Istället för att använda globala variabler kan man skapa en klass, vars egenskaper ersätter de globala variablerna. (Se avsnittet Klassmoduler.) Det har flera fördelar. Sedan skapar man en global instans av klassen, så egenskaperna kan nås från alla moduler i projektet.

Ett annat alternativ är att deklarera en egen datatyp som innehåller alla globala variabler och sedan deklarera en enda global variabel med denna egna datatyp. Skriv alltså inte så här:

Public p_strA As String
Public p_intB As Integer
Public p_lngC As Long
Public p_sngD As Single
Public p_dblE As Double

Skriv så här istället i huvudet av en standardmodul:

Private Type ExPublics
  A As String
  B As Integer
  C As Long
  D As Single
  E As Double
End Type

Public p_Pub As ExPublics

Nu slipper du hoppa fram och tillbaka med Shift+F2 och Ctrl+Shift+F2 för att kontrollera vad den och den globala variabeln heter. Så fort du skriver p_Pub följt av en punkt visas en lista över alla dina (före detta) globala variabler!

Som framgår av detta exempel behöver inte en egen datatyp vara global bara för att en variabel med den egna datatypen ska vara global.

 

Onödig räckvidd

"Excess scope" är ett vanligt misstag i Visual Basic. På svenska kan man säga "onödig räckvidd". Vad det handlar om är globala variabler som lika gärna kan vara modulära, eftersom de bara används i en enda modul, eller lokala, eftersom de bara används i en enda procedur. Programmeraren trodde kanske att variabeln skulle komma till användning i flera moduler, men glömde att kontrollera om så verkligen blev fallet.

Onödig räckvidd kan försämra programmets prestanda och bör därför undvikas. Även procedurer kan ha onödig räckvidd.

 

Döda procedurer, variabler och konstanter

Döda variabler och konstanter är variabler och konstanter som deklareras utan att användas. Naturligtvis bör de undvikas, eftersom de komplicerar koden i onödan. När det gäller döda variabler försämrar de även programmets prestanda. Döda konstanter sållas bort av kompilatorn.

Det finns kanske hela procedurer som aldrig anropas i ditt projekt. Även de komplicerar koden i onödan och försämrar programmets prestanda.

Att försöka hitta alla döda procedurer, variabler och konstanter i ett projekt kan vara tidsödande. Att försöka hitta alla som har onödig räckvidd är också besvärligt. Därför är det bra att det finns program som gör jobbet automatiskt, t ex Project Analyzer från Aivosto.

 

Inbyggda konstanter

I Visual Basic finns det hundratals inbyggda konstanter för alla möjliga ändamål. Deras namn brukar börja med bokstäverna vb och deras datatyp är ofta Long eller Integer.

Det finns t ex två inbyggda konstanter som heter vbYes och vbNo. Båda har datatypen Integer. Värdet av vbYes är 6. Värdet av vbNo är 7. Vad är vitsen med detta? Jo, den inbyggda funktionen MsgBox, som visar en meddelanderuta, har returvärdet 6 om användaren klickar på knappen Ja i meddelanderutan. Om användaren klickar på knappen Nej har funktionen returvärdet 7. För att slippa komma ihåg talen 6 och 7 kan man använda konstanterna vbYes och vbNo. Det finns en annan konstant som heter vbYesNo. Den används som argument i funktionen MsgBox när man vill visa en meddelanderuta med två knappar, en för Ja och en för Nej. Vill man visa en knapp för OK och en för Avbryt använder man konstanten vbOKCancel.

Ett exempel:

Public Function IsSmart() As Boolean
Dim intReturn As Integer
  intReturn = MsgBox("Can you write VB code?", vbYesNo)
  If intReturn = vbYes Then
    IsSmart = True
  Else
    IsSmart = False
  End If
End Function

Ännu smartare är att skriva så här:

Public Function IsSmart() As Boolean
  If MsgBox("Can you write VB code?", vbYesNo) = vbYes Then
    IsSmart = True
  Else
    IsSmart = False
  End If
End Function

Allra smartast är att skriva så här:

Public Function IsSmart() As Boolean
  If MsgBox("Can you write VB code?", vbYesNo) = vbYes Then IsSmart = True
End Function

Man behöver inte skriva att funktionen ska returnera False om användaren klickar på Nej. Om en funktion ska ha ett returvärde med en viss datatyp och inte tilldelas något returvärde returnerar funktionen startvärdet för en variabel med samma datatyp. För en variabel med datatypen Boolean är startvärdet False. Om en funktion ska ha ett returvärde med datatypen Boolean och inte tilldelas något returvärde blir alltså konsekvensen att funktionen returnerar False.

 

 

  Variablers livslängd

Variablers livslängd beror på deras räckvidd.

Lokala variabler förlorar sitt värde när proceduren avslutas.

Om man ersätter uttrycket Dim med ordet Static behåller variabeln sitt värde när proceduren avslutas, men är fortfarande lokal. En sådan lokal variabel brukar kallas en statisk variabel.

Modulära variabler förlorar sitt värde när programmet avslutas eller när man använder satsen

Set frmMyForm = Nothing

om den modulära variabeln har deklarerats i formulärmodulen frmMyForm. Observera att det inte räcker att ladda ur formuläret.

Globala variabler förlorar aldrig sitt värde förrän programmet avslutas.

Även procedurer kan förses med ordet Static framför uttrycken Function och Sub. Detta är en intressant men sällan använd finess i Visual Basic:

Private Static Sub cmdTest_Click()
Dim lngClicks As Long
Dim dteStart As Date
  lngClicks = lngClicks + 1
  If lngClicks = 1 Then
    dteStart = Now
    MsgBox "Det var första klicket"
  Else
    MsgBox "Nu har du klickat " & lngClicks & " gånger" & _
    vbCrLf & vbCrLf & "Tid sedan första klicket: " & _
    FormatDateTime(Now - dteStart)
  End If
End Sub

Vad blir effekten av detta? Jo, alla lokala variabler i den aktuella proceduren blir statiska och behåller sina värden när proceduren avslutas. Man kan alltså lika gärna skriva så här:

Private Sub cmdTest_Click()
Static lngClicks As Long
Static dteStart As Date
  lngClicks = lngClicks + 1
  If lngClicks = 1 Then
    dteStart = Now
    MsgBox "Det var första klicket"
  Else
    MsgBox "Nu har du klickat " & lngClicks & " gånger" & _
    vbCrLf & vbCrLf & "Tid sedan första klicket: " & _
    FormatDateTime(Now - dteStart)
  End If
End Sub

Statiska variabler kan användas istället för modulära variabler. Visual Basics hjälptexter påstår dock att modulära variabler ger bättre prestanda än statiska.

 

 

  Procedurer och deras räckvidd

Från början fanns det två sorters procedurer i Visual Basic: funktioner, som anges med uttrycket Function, och subrutiner, som anges med uttrycket Sub. (Denna terminologi används inte i alla programmeringsspråk. I Pascal kallas subrutiner för procedurer, medan procedurer kallas för subprogram.)

I Visual Basic 4.0 började man använda en tredje sorts procedurer, som kallas egenskapsprocedurer. (Se avsnittet Klassmoduler.)

Händelseprocedurer är subrutiner som körs när en viss händelse inträffar för ett formulär eller en kontroll som man har placerat på formuläret, t ex när användaren klickar på en knapp. Liksom andra subrutiner kan händelseprocedurer anropas från andra procedurer.

Det vanligaste sättet att skapa en händelseprocedur för ett formulär eller en kontroll är att dubbelklicka på formuläret eller kontrollen.

Button event

Om man t ex dubbelklickar på en knapp öppnas kodfönstret och den blinkande markören placeras i händelseproceduren för knappens standardhändelse, Click. Om denna händelseprocedur inte finns skapas automatiskt den första och sista raden i händelseproceduren.

Namnet på en händelseprocedur består alltid av namnet på kontrollen och namnet på händelsen, förenade med ett understreck.

Button code

 

VARNING!
Ett vanligt misstag är att skriva händelseprocedurer för fel händelser. Ett annat vanligt misstag är att skriva händelseprocedurer för rätt händelser, men i fel ordning.

När man skriver händelseprocedurer i Visual Basic är det viktigt att förstå vilka händelser som kan inträffa för ett formulär eller en kontroll. När händelserna inträffar är också viktigt att förstå. Det är lätt att förstå när händelsen Click inträffar, men alla händelser är inte lika självklara. Ibland måste man även veta i vilken inbördes ordning händelserna inträffar. När man t ex laddar ett formulär inträffar händelserna Initialize, Load och Activate för formuläret, i den ordningen. När man laddar ur ett formulär inträffar händelserna QueryUnload, Unload och Terminate för formuläret, i den ordningen.

 

Det finns en viktig skillnad mellan funktioner och subrutiner. Funktioner kan ha både argument och returvärde. Subrutiner kan bara ha argument. Man sätter argumenten inom parentes när man anropar funktioner. När man anropar subrutiner sätter man inte argumenten inom parentes. (Om man anropar subrutinen med uttrycket Call eller om subrutinen endast har ett argument tillåter Visual Basic att man sätter argumenten inom parentes när man anropar subrutinen.)

Ett exempel på hur man skriver en funktion:

Public Function Add(intA As Integer, Optional intB As Integer) As Long
  Add = intA + intB
End Function

Vad händer om man skriver

lngNumber = Add(3)

och utelämnar det frivilliga argumentet intB? Kraschar programmet? Nej, kom ihåg vad du läste om variablers startvärden i avsnittet Deklaration av variabler och konstanter ovan. Startvärdet för variabler med datatypen Integer är 0. Eftersom intB inte tilldelas något värde i exemplet närmast ovan gäller att intB = 0.

I Visual Basic kan man även anropa procedurer så här:

lngNumber = Add(intB:=7, intA:=4)

Man säger att man använder namngivna argument ("named arguments" på engelska). När man använder namngivna argument kan man som synes skriva dem i vilken ordning man vill. Detta skrivsätt används mest i makron i Word och Excel. Många inbyggda funktioner och uttryck i Visual Basic tillåter inte att man använder namngivna argument. Till undantagen hör t ex funktionerna MsgBox och InputBox. Lägg märke till att man skriver ett kolon till vänster om likhetstecknet när man använder namngivna argument, precis som man gör när man tilldelar ett värde till en variabel i programmeringsspråket Pascal.

Om man vill att det frivilliga argumentet intB ska få ett annat värde än 0 när argumentet utelämnas, t ex 5, kan man skriva

Public Function Add(intA As Integer, Optional intB As Integer = 5) As Long
  Add = intA + intB
End Function

När ett frivilligt argument har datatypen Variant kan man använda funktionen IsMissing för att kontrollera om argumentet har utelämnats:

Public Sub SayHello(Optional vntName As Variant)
  If IsMissing(vntName) = True Then
    MsgBox "Var hälsad, främling!"
  Else
    MsgBox "Var hälsad, " & vntName & "!"
  End If
End Function

Argument med ordet Optional framför sig måste stå sist i argumentlistan. Optional kan inte användas om argumentet är en array eller en variabel med en egen datatyp. Man kan heller inte använda Optional om det finns en ParamArray bland argumenten.

Funktioner kan avbrytas i förtid med satsen Exit Function, subrutiner med Exit Sub.

 

VARNING!
Om man glömmer funktionen DoEvents kan programmets utseende försämras. DoEvents pausar programmet en bråkdel av en sekund, så att operativsystemet hinner med allt som programmet hittills har bett om. Sådana pauser är sällan nödvändiga och det finns ingen anledning att använda funktionen DoEvents i onödan, men ibland kan det vara befogat, t ex när texten på en kontroll inte uppdateras lika snabbt som man önskar.

 

VARNING!
Undersökningar har visat att procedurer som är längre än 500 rader medför en kraftigt ökad risk för missförstånd. Skriv inte så långa procedurer, utan dela dem i flera mindre procedurer.

 

Sanningen om procedurernas räckvidd

Om man vill skapa en global procedur, som kan anropas från alla moduler i projektet, är det nödvändigt att placera proceduren i en standardmodul eller klassmodul. (Se avsnittet Klassmoduler.) En formulärmodul duger inte, om inte formulärmodulens namn anges när man anropar proceduren från en annan modul:

intX = frmTestForm.TestFunction(intArgument As Integer)

Man behöver inte använda ordet Public när man skapar globala procedurer i standardmoduler och klassmoduler, men det är en god vana att ändå göra det, för tydlighets skull.

Om man istället använder ordet Private begränsas räckvidden till den aktuella modulen.

 

Sanningen om parenteserna

Det händer att man vill anropa en funktion, fast man inte är intresserad av returvärdet. Då märker man vilket snällt språk Visual Basic är! Det är bara att slopa parenteserna runt argumenten när man anropar funktionen, så slipper man ta hand om returvärdet!

MsgBox "Returvärdet är 1 och det struntar vi i"

Alternativt kan man använda uttrycket Call:

Call MsgBox("Returvärdet är 1 och det struntar vi i")

När man anropar en procedur med uttrycket Call måste man alltid sätta argumenten inom parentes och man får aldrig något returvärde, varken från funktioner eller subrutiner.

Det finns inga fördelar med uttrycket Call och det finns inga tillfällen när detta uttryck måste användas. Microsoft påstår i hjälptexterna att uttrycket Call kan förbättra kodens läsbarhet. Det låter osannolikt. Eftersom uttrycket inte används konsekvent kan det snarare försämra läsbarheten.

 

Sanningen om ByVal och ByRef

När man skapar en procedur kan man skriva ByVal eller ByRef framför vart och ett av argumenten i argumentlistan. Om man skriver ByVal kan proceduren inte påverka värdet av den variabel som den anropande proceduren skickar som argument. Så blir dock fallet om man skriver ByRef:

Public Sub VisaKubiken(ByRef lngHeltal As Long)
  MsgBox "Du vill veta vad " & lngHeltal & " i kubik är"
  lngHeltal = lngHeltal ^ 3
  MsgBox "Svaret är " & lngHeltal
End Sub

Att varken skriva ByVal eller ByRef är samma sak som att skriva ByRef. (Den som använder Pascal eller Visual Basic .NET får vänja sig vid motsatsen. I Pascal skriver man inte ByRef, utan var. Istället för ByVal skriver man ingenting. Det är bra att Visual Basic .NET har fått liknande regler.)

För tydlighets skull kan man uttryckligen skriva ByRef när man avsiktligen låter en procedur påverka värdet av en variabel som den anropande proceduren skickar som argument.

Läroböcker i Visual Basic 6.0 brukar missa ett undantag. Om en subrutin har exakt ett argument är det konstigt nog tillåtet att sätta parenteser runt argumentet när man anropar subrutinen utan att använda uttrycket Call. Då tror Visual Basic att man har skrivit ByVal, oavsett om man har skrivit ByRef, ByVal eller ingenting. Testa följande tre varianter, så får du se:

Private Sub cmdVisaKubikenAvTre_Click()
Dim lngX As Long
  lngX = 3
  VisaKubiken(lngX)
  MsgBox "Konstigt att lngX fortfarande har värdet " & lngX
End Sub

Private Sub cmdVisaKubikenAvTre_Click()
Dim lngX As Long
  lngX = 3
  VisaKubiken lngX
  MsgBox "Som väntat har värdet av lngX ändrats till " & lngX
End Sub

Private Sub cmdVisaKubikenAvTre_Click()
Dim lngX As Long
  lngX = 3
  Call VisaKubiken(lngX)
  MsgBox "Som väntat har värdet av lngX ändrats till " & lngX
End Sub

Läroböcker i Visual Basic 6.0 brukar även missa ett annat undantag. Om en funktion har exakt ett argument är det konstigt nog tillåtet att sätta parenteser runt argumentet när man anropar funktionen utan att ta hand om returvärdet och utan att använda uttrycket Call. Även då tror Visual Basic att man har skrivit ByVal, oavsett om man har skrivit ByRef, ByVal eller ingenting.

Microsoft har aldrig rättat till dessa brister, vilket är synd. Det är inte svårt att föreställa sig hur förvirrade många nybörjare har blivit. I konsekvensens namn borde parenteser vara förbjudna vid alla anrop av subrutiner och vid alla funktionsanrop som inte tar hand om returvärdet, även om den aktuella subrutinen eller funktionen endast har ett argument. Det är god programmeringssed i Visual Basic att införa dessa förbud själv.

Om man använder en array eller en variabel med en egen datatyp som argument kan man inte skriva ByVal framför. Däremot kan man skriva ByRef. Det är ju samma sak som att skriva ingenting.

Att använda ByRef är ett sätt att skapa en funktion som indirekt returnerar flera värden. Om man inte är intresserad av det (och det är man för det mesta inte) har man knappast någon anledning att använda ByRef.

Många har frågat sig vilket alternativ som ger bäst prestanda, ByVal eller ByRef. Visual Basics hjälptexter påstår att ByVal ger bättre prestanda. Noggranna undersökningar har dock visat att prestandaskillnaden är ytterst liten, utom när datatypen är String och variabelns värde är en lång textsträng. Då är faktiskt ByRef mycket snabbare. Om långa textsträngar inte förekommer är det bättre att hålla sig till ByVal. Det ger ingen nämnvärd prestandavinst, men det minskar risken att man av misstag påverkar värdena av den anropande procedurens variabler. Att man uttryckligen skriver ByRef istället för ingenting har ingen som helst betydelse för prestandan.

 

VARNING!
När en variabel används som argument vid ett proceduranrop är det naturligtvis dumt att ge argumentet samma namn i den anropade proceduren och den anropande proceduren. Om man gör det blir koden svårtolkad, det borde alla begripa. Det blir svårare att se var den ena proceduren slutar och den andra börjar.

Sådana Visual Basic-programmerare borde inte få komma i närheten av ett tangentbord, för att inte tala om sådana människor som ger en lokal variabel samma namn som en modulär variabel i samma modul, eller samma namn som en global variabel i samma projekt. Man kan undra hur deras hjärnor ser ut.

Visual Basic har tyvärr inget försvar mot dessa virriga människor. Koden blir svårtolkad, men fungerar ändå. Visual Basic prioriterar alltid den lokala variabeln eller konstanten om en sådan har deklarerats. Annars tror Visual Basic att man syftar på en modulär eller global variabel om det finns en sådan med samma namn.

Å andra sidan, om du vill göra din arbetsgivare beroende av dig genom att göra koden obegriplig för alla utom dig själv, så har du nu lärt dig några av de absolut bästa knepen. Om du sedan använder tillräckligt många virriga variabelnamn, tillräckligt många onödiga anrop till procedurer med lika virriga namn och krånglar till dina For-slingor och If-satser så mycket det går, så ska du se att det biter.

 

Att starta ett program

I Visual Basic kan ett program starta på två olika sätt.

Det ena sättet går ut på att man laddar ett av de formulär som ingår i projektet.

Det andra sättet går ut på att man har en subrutin som heter Main i en standardmodul (en formulärmodul eller klassmodul duger inte). Denna subrutin körs när programmet startar. Eventuella formulär som ska laddas måste i så fall laddas med hjälp av koden i subrutinen Main:

Public Sub Main()
  frmMittVanligaFormulär.Show
End Sub

Start program

Man kan välja hur programmet ska starta i listrutan Startup Object på fliken General i dialogrutan Project Properties, som visas om man klickar längst ner på menyn Project. Om man väljer Sub Main kommer programmet att köra subrutinen Main vid start. Om man väljer namnet på ett formulär kommer programmet att ladda detta formulär vid start.

 

Att kompilera ett program

Klicka på Make... på menyn File när du vill kompilera ditt program till en färdig EXE- eller DLL-fil.

Compile program

I bakgrunden sköts kompileringen av programmen c2.exe och link.exe.

Se optimeringstipsen i slutet av denna lathund.

 

API-anrop

Det är en fördel att kunna anropa procedurer i sådana DLL-filer som ingår i själva operativsystemet Windows. Då måste man först deklarera proceduren genom att använda uttrycket Declare framför Function eller Sub. Ett exempel:

Public Declare Function Beep Lib "Kernel32.dll" _
  (ByVal lngFrequency As Long, ByVal lngDuration As Long) As Long

Man kan skriva detta i huvudet av en standardmodul. Filändelsen .dll kan utelämnas. Ordet Public kan också utelämnas, men bör vara med, för tydlighets skull. Att skriva i huvudet av en formulärmodul eller klassmodul går också bra, men då måste man ersätta ordet Public med Private. Därmed begränsas räckvidden till den aktuella modulen.

I exemplet närmast ovan deklarerades en funktion som heter Beep. Funktionen Beep finns i filen Kernel32.dll och har två argument med datatypen Long. Argumenten kan man kalla vad man vill. I exemplet kallas de lngFrequency och lngDuration. Funktionen har ett returvärde med datatypen Long.

På en annan plats i projektet kan man sedan deklarera en lokal variabel med datatypen Long, den kan t ex heta lngReturnValue, och anropa funktionen Beep genom att skriva

lngReturnValue = Beep(3000, 5000)

om man vill höra ett 5000 millisekunder långt pip med frekvensen 3000 Hz. Detta fungerar i Windows NT 4.0, 2000 och XP, samt i 32-bitarsversionerna av Windows Vista och 7. I Windows 95, 98 och Me hörs bara ett av standardljuden i Windows, oavsett vilka värden man ger funktionens argument. Returvärdet är ointressant, så man kan lika gärna skriva

Beep 3000, 5000

Ovan beskrivna teknik kallas API-anrop. (API betyder Application Programming Interface.) Som synes kan man inte räkna med att alla API-anrop fungerar lika bra i alla versioner av Windows.

Om en procedur har deklarerats med uttrycket Declare gäller ett särskilt undantag för argument med datatypen String. Även om man skriver ByVal framför argumentet kan proceduren ändå påverka värdena av de strängvariabler som anropande procedurer skickar som argument. Detta undantag beror på att strängvariabler hanteras annorlunda i programmeringsspråken C och C++, som Microsoft har använt för att skapa DLL-filerna i Windows.

I Visual Basic använder man främst anrop till procedurer i filerna User32.dll, Kernel32.dll, Gdi32.dll, Shell32.dll, Advapi32.dll, Comdlg32.dll och Winmm.dll. På så sätt kan man komma åt många finesser som är inbyggda i Windows. Hur kan man veta vilka procedurer som finns i olika DLL-filer, vilka argument och returvärden procedurerna har och vad de kan användas till? Den hjälp som Microsoft erbjuder programmerare på det här området är dålig. AllAPI Network är däremot en mycket bra webbplats för dig som vill veta mera om API-anrop.

Här kommer ett annat exempel. Skriv detta längst upp i en standardmodul...

Public Declare Function GetLocaleInfo Lib "Kernel32" _
Alias "GetLocaleInfoA" (ByVal Locale As Long, ByVal LCType As Long, _
ByVal lpLCData As String, ByVal cchData As Long) As Long
Public Declare Function GetUserDefaultLCID Lib "Kernel32" () As Integer

Public Const LOCALE_SDECIMAL = &HE

...och detta längst ner:

Public Function GetDecimalSeparator() As String
Dim strSymbol As String
Dim lngLocale As Long
Dim lngPos As Long
Dim lngR As Long
  lngLocale = GetUserDefaultLCID()
  lngR = GetLocaleInfo(lngLocale, LOCALE_SDECIMAL, strSymbol, 0)
  strSymbol = String$(lngR, 0)
  GetLocaleInfo lngLocale, LOCALE_SDECIMAL, strSymbol, lngR
  lngPos = InStr(strSymbol, vbNullChar)
  If lngPos > 0 Then
    GetDecimalSeparator = Left$(strSymbol, lngPos - 1)
  End If
End Function

Funktionen GetDecimalSeparator returnerar ett komma eller en punkt. Returvärdet beror på valet av decimaltecken i Kontrollpanelen i Windows. Med hjälp av denna funktion kan du kontrollera om användarens inmatningar är giltiga. Antag att ditt program innehåller en textruta. I textrutan får användaren skriva ett tal mellan 0,01 och 0,99. Ditt program måste kunna validera användarens inmatning, alltså kontrollera om den är giltig. Om ditt program ska klara den uppgiften måste programmet veta om decimaltecknet är komma eller punkt. I Sverige används komma. I USA används punkt. Om ditt program ska bli en storsäljare i både Sverige och USA måste programmet veta vilket decimaltecken som gäller, oavsett var programmet används.

Funktionen GetLocaleInfo heter egentligen GetLocaleInfoA i filen Kernel32.dll. Som synes får funktionen ett nytt namn med hjälp av ordet Alias. När du använder ett API-anrop kan ordet Alias döpa om en procedur till vad du vill.

Det finns faktiskt ett mycket enklare sätt att ta reda på decimaltecknet:

Public Function GetDecimalSeparator() As String
  GetDecimalSeparator = Format$(0, ".")
End Function

 

VARNING!
Använd inte den inbyggda funktionen IsNumeric för att kontrollera om ett inmatat värde verkligen är ett tal. Denna funktion kan inte avgöra om rätt decimaltecken används och godkänner alltför lättvindigt användarens inmatning som ett tal. Här är en bättre funktion som verkligen klarar jobbet:

Public Function IsReallyNumeric(ByVal strValue As String, _
Optional blnAllowNegative As Boolean = False, _
Optional blnCurrency As Boolean = False) As Boolean
Dim strDP As String
  strDP = Format$(0, ".")
  If Left$(strValue, 1) = "-" And blnAllowNegative = True Then
    strValue = Mid$(strValue, 2)
  End If
  IsReallyNumeric = Not strValue Like "*[!0-9" & strDP & "]*" And _
  Not strValue Like "*" & strDP & "*" & strDP & "*" And _
  Len(strValue) > 0 And _
  strValue <> strDP And _
  strValue <> vbNullString
  If InStr(strValue, strDP) > 0 And blnCurrency = True Then
    If (Len(strValue) - InStr(strValue, strDP)) > 2 Then
      IsReallyNumeric = False
    End If
  End If
  If strDP = "," And Left$(strValue, 1) = "," Then IsReallyNumeric = False
  If Right$(strValue, 1) = strDP Then IsReallyNumeric = False
End Function

Jämförande operatorer som Like och logiska operatorer som Not förklaras i nästa avsnitt.

 

Här kommer ett exempel som visar hur man öppnar en webbsida eller påbörjar ett mail till en viss mailadress. Skriv detta längst upp i en standardmodul...

Public Declare Function ShellExecute Lib "Shell32" Alias _
"ShellExecuteA" (ByVal hWnd As Long, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, _
ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

...och detta längst ner:

Public Sub NewPage(ByVal strURL As String)
  ShellExecute 0&, vbNullString, strURL, vbNullString, _
  "C:\", SW_SHOWNORMAL
End Sub

Public Sub NewMessage(ByVal strEmailAddress As String)
  ShellExecute 0&, vbNullString, "mailto:" & strEmailAddress, _
  vbNullString, "C:\", SW_SHOWNORMAL
End Sub

Här kommer ett exempel som visar hur man laddar ner en fil. Skriv detta längst upp i en standardmodul...

Public Declare Function URLDownloadToFile Lib "Urlmon" Alias _
"URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, _
ByVal szFileName As String, ByVal dwReserved As Long, _
ByVal lpfnCB As Long) As Long

...och detta längst ner:

Public Function DownloadFile(ByVal strURL As String, _
  ByVal strLocalFile As String) As Boolean
Dim lngReturnValue As Long
  lngReturnValue = URLDownloadToFile(0&, strURL, strLocalFile, 0&, 0&)
  If lngReturnValue = 0 Then DownloadFile = True
End Function

Funktionen DownloadFile returnerar True om nerladdningen gick bra, annars False.

Om man vill skriva eller läsa i Registret, där Windows lagrar mängder av inställningar för operativsystemet och andra program, kan man använda API-anrop till funktioner i filen Advapi.dll, t ex RegQueryValueExString och RegSetValueEx.

 

Egna kalkylbladsfunktioner i Excel

Att skapa egna kalkylbladsfunktioner i Excel är praktiskt. Här kommer ett bra exempel.

Den inbyggda kalkylbladsfunktionen för veckonummer i Excel, WEEKNUM (VECKONR på svenska), är inte så lätt att använda om man vill ha svenska veckonummer. Låt oss bygga en bättre.

Starta Excel, använd kortkommandot Alt+F11 för att öppna Visual Basic Editor och välj Modul (Module) på menyn Infoga (Insert).

Skriv

Public Function WEEKNUMSWEDEN(dteDate As Date) As Integer
Dim lngNumber As Long
  lngNumber = DateSerial(Year(dteDate - Weekday(dteDate - 1) + 4), 1, 3)
  WEEKNUMSWEDEN = Int((dteDate - lngNumber + Weekday(lngNumber) + 5) / 7)
End Function

Stäng sedan Visual Basic Editor med samma kortkommando.

Skriv nu ett datum, t ex 2010-12-24, i en cell, t ex A1, och använd formeln =WEEKNUMSWEDEN(A1) i en annan cell. Praktiskt, eller hur? Observera att du måste ange datum i Excel med ett datumformat som överensstämmer med inställningarna i Kontrollpanelen i Windows.

 

Makron i Excel

Man kan spela in makron i Word och Excel. Sedan kan man öppna Visual Basic Editor och studera den källkod som automatiskt skapades när man spelade in makrot. Det är ett bra sätt att lära sig hur Visual Basic for Applications (VBA) kan användas i Word och Excel.

En del makron är dock omöjliga att spela in, de måste skrivas för hand. Säg t ex att du behöver ett makro som tar bort alla tomma rader i vilket markerat cellområde som helst. Gör så här:

Starta Excel, använd kortkommandot Alt+F11 för att öppna Visual Basic Editor och välj Modul (Module) på menyn Infoga (Insert).

Skriv

Public Sub DeleteBlankRows()
Dim lngX As Long
  Application.Calculation = xlCalculationManual
  Application.ScreenUpdating = False
  For lngX = Selection.Rows.Count To 1 Step -1
    If WorksheetFunction.CountA(Selection.Rows(lngX)) = 0 Then
      Selection.Rows(lngX).EntireRow.Delete
    End If
  Next lngX
  Application.Calculation = xlCalculationAutomatic
  Application.ScreenUpdating = True
End Sub

Stäng sedan Visual Basic Editor med samma kortkommando.

Nu kan du markera ett cellområde där några av raderna är tomma, men inte alla. Använd sedan kortkommandot Alt+F8 för att öppna dialogrutan Makron (Macros).

Markera makrot DeleteBlankRows och klicka på knappen Kör (Run). Dina tomma rader försvinner.

Makrot ovan innehåller ett trick som ofta ökar prestandan i makron i Excel. Automatiska beräkningar och skärmuppdateringar inaktiveras i början av makrot och aktiveras i slutet.

Här är ett makro som skapar hyperlänkar av alla cellvärden i ett markerat cellområde:

Public Sub CreateLinks()
  Application.Calculation = xlCalculationManual
  Application.ScreenUpdating = False
  For Each X In Selection.Cells
    ActiveSheet.Hyperlinks.Add ActiveSheet.Range(X.Address), X.Value
  Next
  Application.Calculation = xlCalculationAutomatic
  Application.ScreenUpdating = True
End Sub

Detta makro är användbart om du har klistrat in ett lång lista av webbadresser i ett kalkylblad och snabbt vill göra alla adresserna klickbara.

 

VBScript

Skriptspråket VBScript är en förenklad version av Visual Basic. Detta skriptspråk kan användas för att snabbt skapa små program för olika ändamål. Stöd för VBScript finns i alla versioner av Windows sedan Windows 98.

VBScript förtjänar egentligen en egen lathund, men låt oss pröva ett enkelt exempel:

Starta programmet Anteckningar (Notepad på engelska), som ingår i Windows.

Skriv

Today = Now
Number = DateSerial(Year(Today - Weekday(Today - 1) + 4), 1, 3)
Week = Int((Today - Number + Weekday(Number) + 5) / 7)
MsgBox "Nu är det vecka " & Week

och spara filen med filnamnet Vecka.vbs på Skrivbordet (filändelsen måste vara vbs). Dubbelklicka på filen och se vad som händer. (Om inget händer använder du förmodligen inte standardinställningarna för VBScript i Windows.)

 

 

  Vanliga operatorer, slingor och funktioner

 

Aritmetiska operatorer
Operator Användning Exempel Resultat
+ Addition 14 + 5 19
- Subtraktion 14 - 5 9
* Multiplikation 14 * 5 70
/ Division 14 / 5 2,8
^ Exponentiering 14 ^ 5 537824
\ Heltalsdivision 14 \ 5 2
Mod Modulus 14 Mod 5 4
& Konkatenering "Hej " & "då" "Hej då"

De aritmetiska operatorerna prioriteras på samma sätt som i matematiken. Exponentiering tillämpas först. Sedan multiplikation och division. Sist addition och subtraktion. Parenteser kan därför behöva användas på samma sätt som i matematiken.

Modulus betyder att man intresserar sig för restvärdet. Om man dividerar 14 med 5 blir resultatet 2 och restvärdet 4.

Konkatenera, sammanfoga textsträngar, kan man även göra med +-tecknet. Det kan leda till misstag. &-tecknet rekommenderas.

 

Jämförande operatorer
Operator Användning
> Större än
< Mindre än
>= Större än eller lika med
<= Mindre än eller lika med
<> Inte lika med
Like Används när man jämför en String med en textsträng som innehåller jokertecken

Följande kod fungerar:

If UCase$(strName) Like "N*" Then
  MsgBox "Namnet börjar på N!"
Else
  MsgBox "Namnet börjar inte på N!"
End If

Följande kod fungerar inte:

If UCase$(strName) = "N*" Then
  MsgBox "Namnet börjar på N!"
Else
  MsgBox "Namnet börjar inte på N!"
End If

 

Logiska operatorer
Operator Användning Exempel Resultat
Not Gör falskt till sant och vice versa Not 4 = 5 True
And Båda sidor ska vara sanna 2 < 3 And 5 < 6 True
Or Minst en av sidorna ska vara sann 2 < 3 Or 6 > 7 True
Xor Endast en av sidorna ska vara sann 2 < 3 Xor 4 < 7 False

De fyra logiska operatorerna Not, And, Or och Xor prioriteras i den ordningen av Visual Basic.

Om de logiska, jämförande och aritmetiska operatorerna blandas i en och samma utsaga tillämpar Visual Basic de aritmetiska operatorerna först. Sedan de jämförande. Sist de logiska. Därför behövs inga parenteser i exemplen närmast ovan, om man inte vill använda...

 

Bitvis And, Or och Xor

Ibland ser man uttryck som

lngX = 3 And 5

Nybörjaren kliar sig i huvudet. Vad i hela världen är detta? Tja, det är något som kallas bitvis And. Det visar sig att resultatet blir 1. Nybörjaren kliar sig ännu mera i huvudet. Hur kan 3 "och" 5 bli 1?

Rent matematiskt betyder det att man utgår från 3 och 5 i binär form, alltså 011 och 101. Sedan jämför man siffrorna steg för steg.

Om båda siffrorna är 1 ger bitvis And 1, annars 0.

Resultatet blir alltså 001, med andra ord 1.

Man kan även använda bitvis Or och bitvis Xor, som fungerar på liknande sätt:

Om båda siffrorna är 0 ger bitvis Or 0, annars 1.

Om båda siffrorna är lika ger bitvis Xor 0, annars 1.

 

Ovanliga logiska operatorer
Operator Användning
Eqv Falsk om ena sidan är sann och andra sidan är falsk
Imp Endast falsk om vänstra sidan är sann och högra sidan är falsk

Eqv kan betraktas som en generösare variant av And.

Imp kan betraktas som en generösare variant av Eqv.

Om båda siffrorna är lika ger bitvis Eqv 1, annars 0.

Om första siffran är 1 och andra siffran är 0 ger bitvis Imp 0, annars 1.

 

Slingor av typen For ... Next

For lngCount = Första Talet To Sista Talet Step Steglängd
  Kod
Next lngCount

Även om det är mera svårtolkat är det tillåtet att bara skriva

For lngCount = Första Talet To Sista Talet Step Steglängd
  Kod
Next

Exit For avbryter slingan i förtid. Om man utelämnar Step Steglängd blir steglängden 1. Om Steglängd är ett negativt heltal stegar man baklänges. Då måste Första Talet vara större än Sista Talet.

Uttrycket Continue, som hoppar till nästa varv i slingan, har funnits länge i Java, men infördes inte i Visual Basic förrän 2005. I Visual Basic 6.0 och äldre versioner är det enkelt att åstadkomma samma sak genom att kombinera uttrycket GoTo med en radetikett som placeras i början av slingan.

Det är vanligt att man använder funktionerna LBound och UBound när man låter en For-slinga bearbeta en array. Programmets prestanda påverkas inte nämnvärt om man använder dessa funktioner direkt i For-slingan. Man behöver inte skriva så här:

lngLower = LBound(strMyArray)
lngUpper = UBound(strMyArray)
For lngCount = lngLower To lngUpper
  strMyArray(lngCount) = "This is element number " & lngCount
Next lngCount

Man kan lika gärna skriva så här:

For lngCount = LBound(strMyArray) To UBound(strMyArray)
  strMyArray(lngCount) = "This is element number " & lngCount
Next lngCount

 

Slingor av typen For Each

Denna typ av slinga kan man använda för att nå alla objekt i en samling ("collection"). I Visual Basic finns det många samlingar, t ex samlingen Forms, som består av alla laddade formulär.

For Each Objektvariabel In Samling
  Kod
Next Objektvariabel

Även om det är mera svårtolkat är det tillåtet att bara skriva

For Each Objektvariabel In Samling
  Kod
Next

Exempel:

Private Sub cmdCloseAll_Click()
Dim frm As Form
  For Each frm In Forms
    Unload frm
  Next frm
End Sub

Exit For avbryter slingan i förtid.

 

Slingor av typen Do ... While

Do While Villkor
  Kod
Loop

Exit Do avbryter slingan i förtid.

Man kan även skriva

Do
  Kod
Loop While Villkor

 

Slingor av typen Do ... Until

Do Until Villkor
  Kod
Loop

Exit Do avbryter slingan i förtid.

Man kan även skriva

Do
  Kod
Loop Until Villkor

 

Slingor av typen While ... Wend

While Villkor
  Kod
Wend

Slingor av typen While ... Wend kan inte avbrytas i förtid.

 

VARNING!
Använd aldrig en Variant eller en odeklarerad variabel som räknare i en slinga. En For-slinga kan ta flera gånger så lång tid om räknaren är en Variant istället för en Long! Dessutom ska man undvika onödiga proceduranrop, beräkningar och konkateneringar i slingor. Annars kan ditt program förlora mycket prestanda. Istället för att skriva

Do While intA < 100
  intB = 3 * intC
  intA = intA + intB
Loop

bör man naturligtvis skriva

intB = 3 * intC
Do While intA < 100
  intA = intA + intB
Loop

så att inte beräkningen intB = 3 * intC upprepas varje varv i slingan.

Varning för konkateneringar i slingor! Konkateneringar är det segaste som finns i Visual Basic. Att placera ett stort antal konkateneringar i en lång slinga kan medföra en allvarlig försämring av programmets prestanda. Undvik detta till varje pris! Den praktiska och snabba funktionen Join erbjuder ofta en bättre lösning än vanlig konkatenering med &-tecknet. Systerfunktionen Split är också mycket användbar.

 

Beslutsstrukturer av typen If ... Else

If Villkor Then
  Kod om villkor är sant
Else
  Kod om villkor är falskt
End If

If-satser kan vara utan Else och man kan även kapsla (en del säger nästla) dem inuti varandra:

If Villkor A Then
  Kod om villkor A är sant
Else
  If Villkor B Then
    Kod om villkor B är sant
  End If
End If

Med hjälp av ordet ElseIf kan detta skrivas kortare:

If Villkor A Then
  Kod om villkor A är sant
ElseIf Villkor B Then
  Kod om villkor B är sant
End If

En del tycker att den kortare varianten är mera svårtolkad.

När man använder And och Or i If-satser är det bra att veta att Visual Basic alltid evaluerar vad som står på båda sidorna om den logiska operatorn.

Antag att du har en mycket snabb funktion som heter QuickFunction och en mycket långsam funktion som heter SlowFunction. Båda returnerar en Boolean.

Då ger det bättre prestanda att skriva

If QuickFunction = True Then
  If SlowFunction = True Then
    MsgBox "Hello world"
  End If
End If

än att skriva

If QuickFunction = True And SlowFunction = True Then
  MsgBox "Hello world"
End If

I det andra exemplet får du nämligen alltid vänta på resultatet från SlowFunction, även när QuickFunction ger resultatet False.

I det första exemplet slipper du vänta på resultatet från SlowFunction när QuickFunction ger resultatet False. Man brukar säga att man kortsluter If-satsen.

I Visual Basic .NET finns den nya logiska operatorn AndAlso som ger samma effekt som det första exemplet. Som komplement till Or finns OrElse.

 

Beslutsstrukturer av typen Select Case

Select Case Variabeln
  Case Tänkbart värde, Tänkbart värde, Tänkbart värde ...
    Kod om variabeln har något av dessa värden
  Case Tänkbart värde, Tänkbart värde, Tänkbart värde ...
    Kod om variabeln har något av dessa värden
  Case Else
    Kod om variabeln har något annat värde
End Select

Tänkbart värde kan t ex vara något av dessa alternativ:

"Skåne"
Is <> "Stockholm"
5000
Is > 1000
Is >= 5000
1000 To 5000

Observera att den enda kod som körs är koden i den första matchande Case-satsen. Om man skriver samma värde i flera Case-satser uppstår inget fel bara för det. Endast koden i den första matchande Case-satsen kommer att köras. Här skiljer sig Visual Basic från andra programmeringsspråk. Motsvarande uttryck i Java heter switch och tillåter inte samma värde i flera Case-satser.

Det är inget krav att variabelns värde matchas av någon Case-sats och det är inget krav att ta med en Case Else-sats! Om man tar med en Case Else-sats måste den stå sist!

Prestandatips: Placera det mest sannolika värdet i den första Case-satsen.

 

With

Uttrycket With gör koden kortare att skriva och förbättrar programmets prestanda om man behöver ändra många egenskaper samtidigt för ett och samma objekt.

Istället för att skriva

frmMyForm.ScaleTop = 0
frmMyForm.ScaleLeft = 0
frmMyForm.ScaleWidth = 2000
frmMyForm.ScaleHeight = 2000

bör man skriva

With frmMyForm
  .ScaleTop = 0
  .ScaleLeft = 0
  .ScaleWidth = 2000
  .ScaleHeight = 2000
End With

 

En lista över de vanligaste inbyggda funktionerna i Visual Basic 6.0

Funktion Användning
Abs Returnerar absolutbeloppet av ett tal
Asc Returnerar ASCII-koden för angivet tecken
Array Returnerar en Variant som innehåller en array med angivna element
Atn Returnerar arcus tangens av ett tal (4 * Atn(1) returnerar pi)
CBool Omvandlar till ett värde för datatypen Boolean
CByte Omvandlar till ett värde för datatypen Byte
CCur Omvandlar till ett värde för datatypen Currency
CDate Omvandlar till ett värde för datatypen Date
CDbl Omvandlar till ett värde för datatypen Double
CDec Omvandlar till ett värde för datatypen Decimal
Choose Returnerar angiven sträng i en indexerad rad av strängar
Chr Returnerar ett tecken med angiven ASCII-kod
CInt Omvandlar till ett värde för datatypen Integer
CLng Omvandlar till ett värde för datatypen Long
Command Returnerar argumenten när programmet startas från en DOS-prompt
Cos Returnerar cosinus av ett värde i radianer
CreateObject Returnerar en referens till ett objekt
CSng Omvandlar till ett värde för datatypen Single
CStr Omvandlar till ett värde för datatypen String
CurDir Returnerar den aktuella mappen
CVar Omvandlar till ett värde för datatypen Variant
Date Returnerar aktuellt datum
DateAdd Returnerar ett datum ett visst tidsintervall från ett annat datum
DateDiff Returnerar tidsintervallet mellan två datum
DatePart Returnerar kvartalet, veckonumret och andra uppgifter om ett datum
DateSerial Returnerar ett datum enligt angivna tal för år, månad och dag
DateValue Returnerar ett datum enligt en angiven sträng
Day Returnerar dagen i ett datum
Dir Anger om en viss fil eller mapp existerar
DoEvents Pausar programmet en bråkdel av en sekund och låter operativsystemet utföra allt som programmet hittills har bett om
Environ Returnerar värdet av en angiven miljövariabel
EOF Returnerar True när man har nått slutet av en fil
Error Returnerar felmeddelandet som motsvarar ett visst felnummer
Exp Returnerar e upphöjt till ett tal
FileAttr Returnerar ett heltal som anger hur en fil har öppnats med uttrycket Open
FileDateTime Returnerar datumet och tiden då en fil skapades eller senast ändrades
FileLen Returnerar storleken av en fil i byte
Filter Returnerar en delmängd av en array enligt angivna urvalskriterier
Fix Returnerar heltalsdelen av ett tal med avrundning uppåt för negativa tal
Format Returnerar ett uttryck i valfritt format enligt angiven formatkod
FormatCurrency Returnerar ett uttryck i olika format för penningvärden
FormatDateTime Returnerar ett uttryck i olika format för datum och tid
FormatNumber Returnerar ett uttryck i olika numeriska format
FormatPercent Returnerar ett uttryck i olika procentformat
FreeFile Returnerar ett ledigt filnummer
GetAttr Returnerar ett heltal som anger attributen för en fil eller mapp
GetObject Returnerar en referens till ett objekt som finns i en viss fil
Hex Returnerar ett tal i hexadecimal form
Hour Returnerar timmarna i ett klockslag
IIf Returvärdet beror på om ett uttryck är sant eller falskt
Input Returnerar angivet antal tecken i en öppen fil
InputBox Visar en inmatningsruta och returnerar användarens inmatning (String)
InStr Returnerar positionen för första förekomsten av en delsträng i en sträng
InStrRev Returnerar positionen för sista förekomsten av en delsträng i en sträng
Int Returnerar heltalsdelen av ett tal med avrundning nedåt för negativa tal
IsArray Returnerar True om en variabel är en array
IsDate Returnerar True om en variabel innehåller ett datum
IsEmpty Returnerar True om en Variant innehåller värdet Empty
IsError Returnerar True om en variabel innehåller en felkod
IsMissing Returnerar True om om ett argument med datatypen Variant
har utelämnats
IsNull Returnerar True om en Variant innehåller värdet Null
IsNumeric Returnerar True om en variabel innehåller siffror, även om variabeln innehåller punkt och komma samtidigt
IsObject Returnerar True om en variabel innehåller ett objekt
Join Sammanfogar elementen i en array och returnerar en sträng
LBound Returnerar lägsta index i en array
LCase Omvandlar en sträng till små bokstäver
Left Returnerar ett antal tecken från vänster i en sträng
Len Returnerar antalet tecken i en sträng
LoadPicture Laddar en bild i en kontroll av typen Image eller Picture Box
LOF Returnerar antalet tecken i en fil som har öppnats med uttrycket Open
Log Returnerar den naturliga logaritmen av ett tal
LTrim Avlägsnar blanksteg till vänster i en sträng
Mid Returnerar en del av en sträng
Minute Returnerar minuterna i ett klockslag
Month Returnerar månaden i ett datum
MonthName Omvandlar siffrorna 1 till 12 till namnen på månaderna
MsgBox Visar en meddelanderuta och returnerar knappvalet (Integer)
Now Returnerar aktuellt datum och klockslag
Oct Returnerar ett tal i oktal form
QBColor Returnerar 16 olika färger
Replace Ersätter förekomster av en delsträng med en annan sträng
RGB Returnerar 16 miljoner olika färger
Right Returnerar ett antal tecken från höger i en sträng
Rnd Returnerar ett slumptal och används tillsammans med uttrycket Randomize
Round Avrundar ett numeriskt värde till valfritt antal decimaler
RTrim Avlägsnar blanksteg till höger i en sträng
Second Returnerar sekunderna i ett klockslag
Sgn Anger om ett värde är positivt eller negativt
Shell Startar ett program och returnerar dess Task ID (Variant)
Sin Returnerar sinus av ett värde i radianer
Space Fyller en sträng med angivet antal blanksteg
Split Delar upp en grupperad sträng i en array
Sqr Returnerar kvadratroten av ett tal
StrComp Jämför två strängar med varandra
String Fyller en sträng med angivet antal tecken med angiven ASCII-kod
StrReverse Returnerar en sträng med alla tecken i motsatt ordning
Switch Returnerar det värde som motsvarar den första sanna utsagan i en följd av sammanparade utsagor och värden
Tan Returnerar tangens av ett värde i radianer
Time Returnerar aktuellt klockslag
Timer Returnerar antalet sekunder sedan midnatt
TimeSerial Returnerar ett klockslag enligt angivna tal för
timmar, minuter och sekunder
TimeValue Returnerar ett klockslag enligt en angiven sträng
Trim Avlägsnar blanksteg till vänster och höger i en sträng
TypeName Returnerar datatypen för en variabel eller en array
UBound Returnerar högsta index i en array
UCase Omvandlar en sträng till stora bokstäver
Val Omvandlar en sträng till ett numeriskt värde, men accepterar endast punkt som decimaltecken
VarType Returnerar ett heltal som anger datatypen för en variabel eller array
Weekday Returnerar veckodagen av ett datum i form av en siffra från 1 till 7
WeekdayName Omvandlar siffrorna 1 till 7 till namnen på veckodagarna
Year Returnerar året i ett datum

 

En lista över några vanliga uttryck i Visual Basic 6.0

Uttryck Användning
AppActivate Aktiverar ett programfönster
ChDir Byter aktuell mapp
ChDrive Byter aktuell enhet
Close Stänger en fil som har öppnats med uttrycket Open
Date Ändrar datorns lokala datumangivelse
Erase Tömmer en array
FileCopy Kopierar en fil
GoTo Hoppar till en annan rad i koden
Kill Tar bort en fil
MkDir Skapar en mapp
Name Byter namn på en fil eller mapp
On Error Hanterar fel i koden
Open Öppnar en fil
Randomize Startar om slumptalsgeneratorn
Reset Stänger alla filer som har öppnats med uttrycket Open
RmDir Tar bort en tom mapp
SavePicture Sparar en bild
SendKeys Simulerar tangentnedtryckningar
SetAttr Ändrar attributen för en fil
Time Ändrar datorns lokala tidsangivelse

 

 

  Spara, öppna och skriva ut filer

I Visual Basic kan man arbeta med ASCII-filer (filer med oformaterad text) på tre olika sätt: sekventiellt, slumpmässigt och binärt. I denna lathund behandlas endast det sekventiella sättet. Det är mest användbart.

Exempel på sekventiell skrivning till fil:

Private Sub WriteToFile()
  Open "C:\Mina dokument\Min fil.txt" For Output As #1
  Print #1, "Goddag"
  Print #1, "Adjö"
  Close #1
End Sub

Istället för ettan kan man använda en Integer som man tilldelar ett värde med funktionen FreeFile. Då kan man vara säker på att numret inte redan är upptaget av en annan öppen fil:

Private Sub WriteToFile()
Dim intFree As Integer
  intFree = FreeFile
  Open "C:\Mina dokument\Min fil.txt" For Output As #intFree
  Print #intFree, "Goddag"
  Print #intFree, "Adjö"
  Close #intFree
End Sub

Om filen C:\Mina dokument\Min fil.txt inte finns i förväg skapas den. Om den finns i förväg skrivs den över. Om mappen C:\Mina dokument inte finns i förväg uppstår ett fel.

Om man vill lägga till text i slutet av en befintlig fil kan man skriva som i nästa exempel:

Private Sub AppendToFile()
  Open "C:\Mina dokument\Min fil.txt" For Append As #1
  Print #1,
  Print #1, "Vänta ett slag"
  Print #1, "Här kommer mera"
  Close #1
End Sub

Om man vill skapa en tom rad i filen skriver man endast Print #1,

Exempel på sekventiell läsning från fil:

Private Sub ReadFromFile()
Dim strLineOne As String
Dim strLineTwo As String
  Open "C:\Mina dokument\Min fil.txt" For Input As #1
  Line Input #1, strLineOne
  Line Input #1, strLineTwo
  Close #1
  MsgBox strLineOne
  MsgBox strLineTwo
End Sub

Variabeln strLineOne tilldelas det som står på första raden i filen och variabeln strLineTwo tilldelas det som står på andra raden. Om man inte vet hur många rader filen innehåller kan man göra en slinga:

Private Sub ReadFromLongFile()
Dim strAllText As String
Dim strCurrentLine As String
  Open "C:\Mina dokument\Min fil.txt" For Input As #1
  If LOF(1) > 1023 Then
    Close #1
    MsgBox "Texten är för lång för att visas i en Message Box."
    Exit Sub
  End If
  Do While Not EOF(1)
    Line Input #1, strCurrentLine
    strAllText = strAllText & strCurrentLine & vbCrLf
  Loop
  Close #1
  MsgBox strAllText
End Sub

Den inbyggda konstanten vbCrLf ger en radbrytning. Använd alltid denna konstant när du behöver radbrytningar i Visual Basic!

EOF(1) betyder slutet av filen. LOF(1) ger totala antalet tecken i filen.

Istället för Print #1 kan man skriva Write #1. Då kommer varje rad i filen att omges av citattecken, vilket kanske inte är önskvärt. Om man använder Print #1 för att skriva rekommenderar Microsoft att man använder Line Input #1 för att läsa. Om man däremot använder Write #1 för att skriva rekommenderas Input #1 för att läsa.

Ovanstående metoder är dock inte särskilt effektiva om man vill läsa hela texten i en fil och presentera den i en kontroll, t ex en vanlig textruta. Då är funktionen Input mycket bättre. Ett exempel:

Private Sub cmdView_Click()
  Open "C:\Mylongfile.txt" For Input As #1
  txtMyTextBox.Text = Input(LOF(1), #1)
  Close #1
End Sub

Textrutans egenskap MultiLine bör ha värdet True, annars hamnar all text på en enda rad.

Vissa filer kan vara bättre att läsa binärt:

Open "C:\Mylongfile.txt" For Binary As #1

Det kan vara bra att veta att App.Path ger sökvägen till det aktuella programmets EXE-fil.

Att göra en utskrift är enkelt. Man använder objektet Printer, som är systemets standardskrivare, och uttrycket Print. Det är viktigt att avsluta med metoden EndDoc. Metoden NewPage ger en sidbrytning, metoden Line ritar linjer och rektanglar, metoden Circle ritar cirklar och ellipser och metoden PaintPicture skriver ut en bild som man har placerat i en kontroll av typen PictureBox. Objektet Printer har dessutom ett stort antal egenskaper som kan styra teckenformat och textens placering. Ett exempel:

Private Sub TestPrinter()
  Printer.Print "Nu prövar vi att göra en utskrift!"
  Printer.Print
  Printer.Print "Förra raden blev tom..."
  Printer.NewPage
  Printer.Print "...och detta hamnade på sidan två!"
  Printer.Print "Nu är det slut."
  Printer.EndDoc
End Sub

 

VARNING!
Lustigt nog kan man inte skriva så här i Visual Basic:

Private Sub TestPrinter()
  With Printer
    .Print "Nu prövar vi att göra en utskrift!"
    .Print
    .Print "Förra raden blev tom..."
    .NewPage
    .Print "...och detta hamnade på sidan två!"
    .Print "Nu är det slut."
    .EndDoc
  End With
End Sub

Uttrycket With fungerar inte tillsammans med uttrycket Print.

 

Innan man skapar en fil kan det vara bra att kontrollera om den redan finns. Det kan också vara bra att kontrollera om mappen finns.

Dessa enkla API-anrop löser problemet:

Public Declare Function PathFileExists Lib "shlwapi.dll" _
  Alias "PathFileExistsA" (ByVal pszPath As String) As Long
Public Declare Function PathIsDirectory Lib "shlwapi.dll" _
  Alias "PathIsDirectoryA" (ByVal pszPath As String) As Long

Om filen eller mappen inte finns blir returvärdet 0. Windows 98 eller senare version krävs. Windows 95 och NT 4.0 duger om man installerar Internet Explorer 4.0 eller senare version.

Följande två funktioner kan också vara nyttiga. Dessa funktioner returnerar namnen på alla filer respektive undermappar i en viss mapp. Om mappen inte innehåller någon fil respektive undermapp returneras ett backslash.

Eftersom returvärdena är arrayer med datatypen String krävs Visual Basic 6.0 eller Office 2000. Visual Basic 5.0 eller Office 97 duger inte.

Public Function GetFiles(ByVal strPath As String) As String()
Dim strAllFiles() As String
Dim strFile As String
Dim lngI As Long
Dim lngJ As Long
Dim lngX As Long
  If Right$(strPath, 1) <> "\" Then strPath = strPath & "\"
  strFile = Dir$(strPath & "*.*", _
  
  vbNormal + vbReadOnly + vbSystem + vbHidden)
  Do While strFile <> ""
    lngJ = lngJ + 1
    lngX = lngJ * 1000
    ReDim Preserve strAllFiles(lngX)
    Do While strFile <> "" And lngI <= lngX
      strAllFiles(lngI) = strFile
      lngI = lngI + 1
      strFile = Dir$
    Loop
  Loop
  If lngI = 0 Then
    ReDim strAllFiles(0)
    strAllFiles(0) = "\"
  Else
    ReDim Preserve strAllFiles(lngI - 1)
  End If
  GetFiles = strAllFiles
End Function

Public Function GetFolders(ByVal strPath As String) As String()
Dim strAllFolders() As String
Dim strFolder As String
Dim lngI As Long
Dim lngJ As Long
Dim lngX As Long
  If Right$(strPath, 1) <> "\" Then strPath = strPath & "\"
  strFolder = Dir$(strPath, vbDirectory)
  Do While strFolder <> ""
    lngJ = lngJ + 1
    lngX = lngJ * 1000
    ReDim Preserve strAllFolders(lngX)
    Do While strFolder <> "" And lngI <= lngX
      If (GetAttr(strPath & strFolder) And vbDirectory) = vbDirectory Then
        If strFolder <> "." And strFolder <> ".." Then
          strAllFolders(lngI) = strFolder
          lngI = lngI + 1
        End If
      End If
      strFolder = Dir$
    Loop
  Loop
  If lngI = 0 Then
    ReDim strAllFolders(0)
    strAllFolders(0) = "\"
  Else
    ReDim Preserve strAllFolders(lngI - 1)
  End If
  GetFolders = strAllFolders
End Function

 

 

  Kopiera och klistra in

Man kan kopiera och klistra in text med hjälp av objektet Clipboard och dess tre metoder Clear, SetText och GetText. Observera att man ska använda metoden Clear före metoden SetText.

Så här kan man kopiera en text ...

Clipboard.Clear
Clipboard.SetText txtMyOldTextBox.Text

... och så här kan man klistra in samma text ...

txtMyNewTextBox.Text = Clipboard.GetText

Objektet Clipboard har även tre andra metoder: SetData, GetData och GetFormat. SetData och GetData kan användas för att kopiera och klistra in bilder. GetFormat kan användas för att undersöka vad som har kopierats eller klippts ut.

Man kan även kopiera och klistra in med hjälp av API-anrop.

 

 

  Felhantering och avlusning

Man kan förhindra att programmet avbryts på grund av fel genom att göra som i följande exempel:

Private Sub Test()
  On Error GoTo ErrorHandlerA
    Kod som kan tänkas orsaka fel A
  On Error GoTo ErrorHandlerB
    Kod som kan tänkas orsaka fel B
  On Error GoTo 0
    Kod som inte orsakar fel
  On Error GoTo ErrorHandlerC
    Kod som kan tänkas orsaka fel C
  Exit Sub
ErrorHandlerA:
    Kod som ska köras om fel A uppstår
  Exit Sub
ErrorHandlerB:
    Kod som ska köras om fel B uppstår
  Exit Sub
ErrorHandlerC:
    Kod som ska köras om fel C uppstår
End Sub

Om man skriver On Error Resume Next fortsätter programmet på nästa rad när ett fel uppstår.

Om man bara skriver On Error Resume fortsätter programmet på samma rad. Raden som orsakade felet körs alltså en gång till. Förutsättningarna har kanske ändrats efter ett antal försök och då slipper man kanske felet. Tyvärr sällsynt i verkligheten.

Resume Next kan även kombineras med felhantering:

Private Sub Test()
  On Error GoTo ErrorHandler
    Kod som kan tänkas orsaka fel
    Vid fel ska en viss kod köras och sedan ska programkörningen forsätta på nästa rad
  Exit Sub
ErrorHandler:
    Kod som ska köras om fel uppstår
  Resume Next
End Sub

Exemplet närmast ovan kan användas om du bara vill logga felet i en loggfil utan att avbryta programkörningen.

Strukturerad undantagshantering ("structured exception handling") av det slag som finns i Java finns egentligen inte i Visual Basic. Detta har dock förändrats i Visual Basic .NET.

Om man är finurlig kan man åstadkomma samma sak i Visual Basic 6.0:

Private Sub Try()
  On Error GoTo Catch
    Kod som kan tänkas orsaka fel
    Om fel uppstår ska åtgärd B utföras
    Antingen fel uppstår eller inte ska proceduren avslutas med åtgärd A
Finally:
    Kod som utför åtgärd A
  Exit Sub
Catch:
    Kod som utför åtgärd B
  Resume Finally
End Sub

Som synes kan både GoTo och Resume kombineras med en radetikett.

Enklare buggar kan upptäckas med hjälp av brytpunkter. Man kan placera en brytpunkt på en viss rad i koden genom att klicka på den gråa marginalen till vänster om raden. Brytpunkten visas som en röd punkt. Sedan startar man programkörningen, t ex med kortkommandot F5. Raden före brytpunkten kommer att köras. Sedan bryts programkörningen och man kan undersöka variablernas värden i den aktuella proceduren genom att peka på dem. Raden med brytpunkten kommer inte att köras förrän man kör vidare. Man kan ta bort brytpunkten genom att klicka på den. Om man har flera brytpunkter kan man ta bort alla på en gång med kortkommandot Ctrl+Shift+F9 eller genom att klicka på Clear All Breakpoints på menyn Debug.

Det går inte att spara brytpunkter. Alla brytpunkter försvinner när man stänger projektet. Du behöver inte oroa dig för att det finns brytpunkter kvar i den kompilerade EXE-filen. Man behöver man inte städa efter sig. Det gör Visual Basic automatiskt.

Break point

Om man vill spara brytpunkter kan man använda uttrycket Stop. Med uttrycket Stop skapar man så att säga en brytpunkt i själva koden. Med uttrycket End stoppar man också programkörningen med omedelbar verkan, men till skillnad från Stop gör inte End en paus i programkörningen, utan avslutar hela programmet. Uttrycket End bör endast användas i undantagsfall.

För effektiv avlusning av Visual Basic-program rekommenderas flitig användning av kortkommandona F8 och Shift+F8. Det senare är ofta bättre. Med F8 stegar man en rad i taget. Tryck på F8, så startar programkörningen och bryts omedelbart. Tryck på F8 en gång till, så körs första raden i koden. Tryck på F8 en gång till, så körs andra raden i koden. Det är bara att fortsätta trycka på F8 tills man kommer till en rad som behöver rättas. Om man istället använder kortkommandot Shift+F8 slipper man stega rad för rad i en anropad procedur. Istället körs en anropad procedur i ett enda svep. Skulle man råka slinka in i en anropad procedur med F8 och inte vill stega resten av proceduren rad för rad kan man använda kortkommandot Ctrl+Shift+F8 för att köra resten av proceduren i ett enda svep. Sedan kan man stega vidare rad för rad med F8 eller Shift+F8.

 

VARNING!
Vad gör man om man har stegat fram till en rad i koden där en lång For-slinga börjar? Sitter man då och trycker på F8 hundratals gånger för att stega igenom hela For-slingan rad för rad? Det finns säkert programmerare som inte har lärt sig kortkommandot Ctrl+F8. Du är väl inte en av dem? Placera den blinkande markören längst till vänster på den första raden efter For-slingan och tryck på Ctrl+F8, så kör du resten av For-slingan i ett enda svep. Efter For-slingan kan du sedan stega vidare rad för rad med F8 eller Shift+F8.

 

Locals Window och Watch Window är mycket användbara när man avlusar Visual Basic-program. I Locals Window kan man överblicka värdet av alla lokala variabler i den aktuella proceduren medan man stegar rad för rad med F8 eller Shift+F8. Dessutom visar Locals Window värdet av alla modulära och globala variabler som har deklarerats i den aktuella modulen. Gäller det en formulärmodul visas även värdet av alla egenskaper hos formuläret och alla dess kontroller. I Watch Window kan man skapa en watch (bevakning på svenska) som bryter programkörningen om och när ett visst villkor uppfylls. Alternativt kan man använda metoden Debug.Assert Villkor, som bryter programkörningen om Villkor är falskt. Med denna metod skapar man så att säga en watch i själva koden.

 

VARNING!
Satsen Debug.Assert Villkor bör inte vara kvar i det färdiga programmet om Villkor innehåller funktionsanrop. Programkörningen bryts inte i det färdiga programmet, men funktionsanropen drar ändå ner prestandan om man får tro hjälptexterna i Visual Basic.

 

Immediate Window, som många läroböcker tjatar om, är mindre intressant. Metoden Debug.Print skriver en viss variabels värde eller resultatet av ett visst uttryck i Immediate Window, men det är ofta bättre att skriva i en loggfil om man behöver testa eller avlusa program på detta sätt. Immediate Window, Locals Window och Watch Window kan man öppna genom att klicka på respektive menyval på menyn View.

Det finns en sak som man faktiskt kan använda Immediate Window till, nämligen att kontrollera värdet av en global variabel i brytläge. I Locals Window visas inte globala variabler om de inte råkar vara deklarerade i den aktuella modulen. Om p_intX är en godtycklig global variabel kan man i brytläge skriva

print p_intX

i Immediate Window och trycka på Enter, så visas det aktuella värdet av p_intX på nästa rad.

Om operativsystemet är Windows NT 4.0, 2000, XP, Vista eller 7 kan man även logga saker och ting under rubriken Program i Loggboken (Event Log). Det fungerar endast när man kör den färdiga EXE-filen. Ett exempel:

App.LogEvent "Nu skriver vi i Loggboken", vbLogEventTypeInformation

Det andra argumentet kan man ge värdet vbLogEventTypeError, vbLogEventTypeWarning eller vbLogEventTypeInformation beroende på vilken ikon man vill se vid meddelandet i Loggboken.

 

Villkorlig kompilering

Med villkorlig kompilering kan man "stänga av och sätta på" olika kodavsnitt, t ex felhantering. Det kan man även göra med hjälp av en vanlig global Boolean och vanliga If-satser, men fördelen med villkorlig kompilering är att de "avstängda" kodavsnitten inte kompileras. På så sätt minskar EXE-filens storlek.

För att kunna använda villkorlig kompilering måste man deklarera en eller flera kompileringskonstanter, som kan ha värdena 0 och -1. 0 står för False och -1 står för True. Kompileringskonstanter kan deklareras i huvudet av en procedur eller modul, precis som andra lokala och modulära konstanter, men det går inte att använda orden Public och Private och det går inte att ange datatyp. Man inleder raden med ett #-tecken:

#Const Catch = -1
#Const LogCaught = -1

En global kompileringskonstant kan inte deklareras i koden. Istället finns det två andra sätt.

Det ena sättet är att skriva den globala kompileringskonstanten och dess värde på fliken Make i dialogrutan Project Properties, som visas om man klickar längst ner på menyn Project:

Make

Vill man ha flera globala kompileringskonstanter skriver man ett kolon mellan varje.

Det andra sättet är att kompilera vid en DOS-prompt. Ge kommandot

"C:\Program\Microsoft Visual Studio\VB98\VB6.exe"
/make "D:\Mina projekt\Projekt1.vbp" /d Catch=-1:LogCaught=-1

om du sparade projektet i filen D:\Mina projekt\Projekt1.vbp och Visual Basic som vanligt installerades i mappen C:\Program\Microsoft Visual Studio\VB98.

Om du vill se alla växlar och parametrar som man kan använda vid DOS-prompten kan du använda kommandot

"C:\Program\Microsoft Visual Studio\VB98\VB6.exe" /?

Om du vill testa följande exempel behöver du ett nytt projekt med ett formulär och en knapp. Klistra in koden i formulärmodulen och kör.

Ändra sedan värdet av kompileringskonstanterna från -1 till 0 och kör igen.

Option Explicit

#Const Catch = -1
#Const LogCaught = -1

Private Sub Command1_Click()
Dim lngX As Long
Dim strMessage As String
Dim intFree As Integer

  #If Catch = -1 Then
    On Error GoTo Catcher
  #End If

  MsgBox "Soon there will be an error...", vbInformation

  lngX = 1 / 0

  MsgBox "There was an error a moment ago...", vbInformation

  Exit Sub

Catcher:

  strMessage = "Error time: " & Now & vbCrLf & _
    "Error number: " & Err.Number & vbCrLf & _
    "Error description: " & Err.Description
  
  #If LogCaught = -1 Then
    intFree = FreeFile
    Open "C:\Error.txt" For Append As #intFree
      Print #intFree, strMessage
    Close #intFree
  #Else
    MsgBox strMessage, vbExclamation
  #End If

  Resume Next

End Sub

Som du ser skriver man även #-tecken framför If, Else, ElseIf och End If när man använder kompileringskonstanterna i koden.

Objektet Err ger information om det senast inträffade felet. Detta objekt är inbyggt i Visual Basic och kan användas närsomhelst utan att först deklareras.

 

 

  Klassmoduler

Med en klassmodul skapar man en klass står det i läroböckerna. Jaha, det var ju en bra förklaring! Vad betyder det i praktiken? Jo, det betyder att koden i en klassmodul kan användas i många projekt, precis som koden i en standardmodul kan användas i många moduler i samma projekt. Det är bra!

Att skriva samma kod flera gånger är det värsta programmerare vet.

Klassmoduler förklaras bäst med ett exempel. Öppna ett nytt projekt och välj att skapa en ActiveX DLL. Ge projektet namnet Fordon (genom att klicka längst ner på menyn Project). Klassmodulen kan få namnet Bil. Skriv sedan följande kod i klassmodulen (för tydlighets skull används svenska namn):

Option Explicit

Private m_dblBensinvolym As Double
Private m_dblTankvolym As Double

Public Event Motorstopp()
Public Event Överfyllning()

Public Property Get Tankvolym() As Double
  Tankvolym = m_dblTankvolym
End Property

Public Property Let Bensinvolym(ByVal dblData As Double)
  m_dblBensinvolym = dblData
End Property

Public Property Get Bensinvolym() As Double
  Bensinvolym = m_dblBensinvolym
End Property

Public Sub Tanka(dblPåfyllningsvolym As Double)
  If dblPåfyllningsvolym < 0 Then Exit Sub
  m_dblBensinvolym = m_dblBensinvolym + dblPåfyllningsvolym
  If m_dblBensinvolym > m_dblTankvolym Then
    m_dblBensinvolym = m_dblTankvolym
    RaiseEvent Överfyllning
  End If
End Sub

Public Sub Kör(dblKörsträcka As Double)
  If dblKörsträcka < 0 Then Exit Sub
  m_dblBensinvolym = m_dblBensinvolym - 0.8 * dblKörsträcka
  If m_dblBensinvolym <= 0 Then
    m_dblBensinvolym = 0
    RaiseEvent Motorstopp
  End If
End Sub

Private Sub Class_Initialize()
  m_dblTankvolym = 70
  m_dblBensinvolym = 70
End Sub

Varsågod! Här har du en bil med full tank! Du kan använda klassen Bil i andra projekt om du kompilerar koden till en DLL-fil. Klassen Bil har två egenskaper (Tankvolym och Bensinvolym), två metoder (Kör och Tanka), samt två händelser (Motorstopp och Överfyllning). Egenskapen Tankvolym går endast att läsa, inte att ändra.

Det är inte mycket som skiljer koden i en klassmodul från koden i standardmoduler. Subrutiner och funktioner är klassens metoder. Egenskapsprocedurer är klassens egenskaper. Händelser deklareras med uttrycket Event (för tydlighets skull kan man skriva Public Event) i huvudet av en klassmodul och triggas i procedurerna i samma klassmodul med uttrycket RaiseEvent.

När du ska använda din DLL-fil i andra datorer kan du placera filen i systemmappen (C:\Windows\System32 om du kör Windows XP, Vista eller 7). Det är inget krav, men en god vana.

Sedan måste DLL-filen registreras i den andra datorn. Det betyder att uppgifter om något som kallas Interface ID (IID), Class ID (CLSID) och Type Library ID (LIBID) läggs till i Registret i Windows. Om man skapar ett installationsprogram med Package and Deployment Wizard sköter installationsprogrammet registreringen av DLL-filen i den andra datorn. Package and Deployment Wizard kan skapa installationsprogram som enbart installerar en DLL-fil, om man så önskar.

I datorn där man kompilerar DLL-filen registreras den automatiskt vid kompileringen, men i den andra datorn kan man bli tvungen att registrera DLL-filen manuellt. Det kan man göra med det lilla DOS-programmet regsvr32, som ingår i Windows.

Skriv så här vid en DOS-prompt och tryck på Enter (om vi förutsätter att Windows installerades i mappen Windows och att DLL-filen fordon.dll finns i undermappen System32):

regsvr32 c:\windows\system32\fordon.dll

Om man tvärtom vill avregistrera DLL-filen kan man göra det med hjälp av växeln /u:

regsvr32 /u c:\windows\system32\fordon.dll

 

VARNING!
I dialogrutan Project Properties, som visas om man klickar längst ner på menyn Project, finns fliken Component. Om det aktuella projektet är en ActiveX DLL kan man på denna flik välja mellan de tre inställningarna No Compatibility, Project Compatibility och Binary Compatibility. Om man inte känner till hur dessa inställningar fungerar kan det bli problem, ibland stora problem. Du kan lätt undvika dessa problem om du följer några enkla råd.

Component tab

Vid den första kompileringen och vid stora ändringar i koden kan du använda inställningen No Compatibility. Med denna inställning får DLL-filen nya Interface ID, Class ID och Type Library ID vid varje kompilering, även om ingenting ändras i koden mellan kompileringarna.

Det kan hända att du kompilerar DLL-filen många gånger innan du är nöjd. Då är det bäst att använda inställningen Project Compatibility. Detta är standardinställningen. När du använder inställningen Project Compatibility förnyas bara Interface ID vid kompileringarna.

Både No Compatibility och Project Compatibility tillåter att du fritt ändrar koden hur du vill.

Det viktiga är att du ändrar till Binary Compatibility och kompilerar med denna inställning när DLL-filen görs redo för distribution. När du kompilerar med inställningen Binary Compatibility förändras varken Interface ID, Class ID eller Type Library ID. Det ger dig stora fördelar. Antag att DLL-filen distribueras och börjar användas av tusentals användare. Efter en tid upptäcker du plötsligt en liten bugg. Låt oss säga att du har råkat skriva minus istället för plus någonstans. Du blir tvungen att rätta felet i koden. Sedan blir du tvungen att kompilera DLL-filen ännu en gång. Tack vare inställningen Binary Compatibility blir det lätt att distribuera den rättade versionen. Användarna kan helt enkelt ersätta den gamla DLL-filen med den nya. Den nya DLL-filen behöver inte registreras, eftersom Interface ID, Class ID och Type Library ID är oförändrade.

När du har ändrat till Binary Compatibility måste du följa vissa regler. Om du bryter mot reglerna blir du påmind vid nästa kompilering. Då blir du uppmanad att ångra ditt brott. Om du vägrar får DLL-filen nya Interface ID och du förlorar fördelarna med Binary Compatibility.

  • Projektets namn får inte ändras.
  • Klassernas namn i projektet får inte ändras.
  • Klasser får läggas till, men inte tas bort.
  • Namnen på exponerade egenskaper och globala variabler får inte ändras.
  • Datatyperna för exponerade egenskaper och globala variabler får inte ändras.
  • Exponerade egenskaper och globala variabler får läggas till, men inte tas bort.
  • Namnen på exponerade metoder får inte ändras.
  • Exponerade metoder får läggas till, men inte tas bort.
  • Antalet argument i en exponerad metod får inte ändras.
  • Namnen på globala enumeratorer får inte ändras.
  • Argumentens datatyp i en exponerad metod får inte ändras.
  • Användningen av orden ByVal och ByRef i en exponerad metod får
  • Nummer får läggas till i en global enumerator, men annars får innehållet inte ändras.
  • Globala enumeratorer får läggas till, men inte tas bort.
  • Användningen av uttrycket Implements får inte ändras.

Med exponerad menas tillgänglig för andra program.

 

VARNING!
Detta avsnitt började med att vi öppnade ett nytt projekt och skapade en ActiveX DLL. I ett sådant projekt har klassmodulerna en egenskap som klassmodulerna i en Standard EXE saknar, nämligen Instancing. Denna egenskap har standardvärdet MultiUse. Texten i detta avsnitt förutsätter att du inte ändrar värdet till något av de andra alternativen (Private, PublicNotCreatable eller GlobalMultiUse). Om du ändrar värdet till något annat än MultiUse gäller andra regler för klassmodulen och hur den kan användas i andra program. Klassmodulerna i en ActiveX EXE har ytterligare två alternativ (Single och GlobalSingle).

Single betyder att en ny instans av ActiveX-komponenten skapas för varje nytt objekt som skapas.

Global betyder att andra program kan anropa klassens metoder och egenskaper som om de vore inbyggda i Visual Basic, vilket inte enbart är en fördel, eftersom koden samtidigt blir mera svårtolkad.

Private betyder att andra program varken kan se klassen eller skapa objekt av klassen. Denna inställning är lämplig för klasser som bara ska betjäna andra klasser i samma ActiveX-komponent.

PublicNotCreatable betyder att andra program kan se klassen, men inte skapa objekt av klassen. I vissa fall är det bättre att den saken sköts av en annan klass i samma ActiveX-komponent.

 

Nu ska du få lön för mödan.

Öppna ett nytt projekt, välj References... på menyn Project och sätt en bock på rätt rad ...

References dialog

... så får du tillgång till klassen Bil genom att t ex skriva

Public WithEvents Kärran As Bil

i huvudet av en formulärmodul eller klassmodul i det nya projektet.

Ordet WithEvents kan utelämnas. Om ordet WithEvents utelämnas kan man även skriva i huvudet av en standardmodul, men då får man inte tillgång till händelserna Motorstopp och Överfyllning.

När du behöver en ny bil kan du skriva

Set Kärran = New Bil

och köra en sväng på stan:

Kärran.Kör 50

Man kan skriva

Set Kärran = Nothing

när man inte behöver bilen mera. Det är en god vana att alltid göra så med en objektvariabel i Visual Basic när man inte behöver den mera. På så sätt kan man omedelbart frigöra en del av det arbetsminne som objektvariabeln ockuperar. Dessutom kan man på detta sätt ange exakt när klassmodulens händelse Terminate ska äga rum.

Naturligtvis kan man skapa flera klassmoduler i projektet Fordon ovan. Man kan t ex skapa en klassmodul som heter Cykel, en som heter Moped osv. Om man vill att en procedur ska vara tillgänglig i alla moduler i projektet Fordon, men inte tillgänglig för andra program, kan man använda ordet Friend istället för Public. Ordet Friend används bara när man deklarerar procedurer i klassmoduler, inte när man deklarerar variabler och konstanter.

Kom ihåg att en konstant, array, variabel med egen datatyp eller string med fast längd måste deklareras i en standardmodul om räckvidden ska vara global. En klassmodul eller formulärmodul duger inte. Glöm inte att skriva ordet Public först.

Public Const p_intBonus As Integer = 500

 

VARNING FÖR FATTIGMANS-DLL:ER!
Stora lösningar i Visual Basic kan bestå av flera olika EXE-filer. Koden kan fördelas på flera olika projekt, kanske dussintals olika projekt. Den färdiga lösningen kan bestå av dussintals EXE-filer i samarbete. En stor del av koden kan vara gemensam för flera av projekten. Naturligtvis bör man placera den gemensamma koden i en eller flera DLL:er. Tyvärr gör inte alla programmerare på det viset.

Det finns programmerare som har en ful ovana. De skapar ett antal lösa moduler som inte ingår i något särskilt projekt. Sedan låter de flera projekt dela på dessa lösa moduler. Ett projekt kan på så sätt innehålla moduler som har sparats i helt andra mappar än den förväntade mappen. Du kan själv föreställa dig vad som händer när man ändrar en sådan modul på ett sätt som passar det ena projektet men inte det andra.

Fattigmans-DLL:er är vad det är. Ett bra sätt att skapa oreda i stora lösningar.

 

Samlingsklasser

En samlingsklass är en samling som alla andra samlingar. (Se avsnittet Arrayer, egna datatyper och numreringar.) Skillnaden är att medlemmarna är objekt av en viss klass och att man själv kan bestämma hur metoderna Add och Remove ska fungera. Man kan t ex kräva att vissa villkor ska vara uppfyllda när man lägger till eller tar bort en medlem.

Här är ett exempel på en enkel klass. Vi kan kalla den Player. Precis som i exemplet ovan skriver man denna kod i en egen klassmodul.

Option Explicit
Private m_lngNumber As Long
Private m_strFirstName As String
Private m_strLastName As String
Private m_lngGoals As Long

Public Sub AddGoal()
  m_lngGoals = m_lngGoals + 1
End Sub

Public Sub SubtractGoal()
  m_lngGoals = m_lngGoals - 1
End Sub

Public Property Let Number(lngData As Long)
  m_lngNumber = lngData
End Property

Public Property Get Number() As Long
  Number = m_lngNumber
End Property

Public Property Let FirstName(strData As String)
  m_strFirstName = strData
End Property

Public Property Get FirstName() As String
  FirstName = m_strFirstName
End Property

Public Property Let LastName(strData As String)
  m_strLastName = strData
End Property

Public Property Get LastName() As String
  LastName = m_strLastName
End Property

Public Property Get Goals() As Long
  Goals = m_lngGoals
End Property

 

Här är samlingsklassen. Vi kan kalla den Team. Denna kod skriver man också i en egen klassmodul.

Option Explicit
Private m_Col As Collection

Public Function Add(Number As Long, FirstName As String, _
  LastName As String, Optional strKey As String) As Player
Dim objNew As Player
  Set objNew = New Player
  objNew.Number = Number
  objNew.FirstName = FirstName
  objNew.LastName = LastName
  If Len(strKey) = 0 Then
    m_Col.Add objNew
  Else
    m_Col.Add objNew, strKey
  End If
  Set Add = objNew
  Set objNew = Nothing
End Function

Public Property Get Item(vntIndexKey As Variant) As Player
  Set Item = m_Col(vntIndexKey)
End Property

Public Sub Remove(vntIndexKey As Variant)
  m_Col.Remove vntIndexKey
End Sub

Public Property Get Count() As Long
  Count = m_Col.Count
End Property

Public Sub Clear()
  Set m_Col = New Collection
End Sub

Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"

  Set NewEnum = m_Col.[_NewEnum]
End Property

Private Sub Class_Initialize()
  Set m_Col = New Collection
End Sub

Private Sub Class_Terminate()
  Set m_Col = Nothing
End Sub

Som synes bygger samlingsklassen på en modulär samling. Namnet är förstås valfritt. I detta exempel heter den m_Col.

Metoden Clear finns inte i vanliga samlingar. Den kan användas för att ta bort alla medlemmar i samlingsklassen på en gång.

Metoden NewEnum innehåller en del hokus pokus som inte är vanlig Visual Basic-kod.

Den första röda raden, den med -4, gör det möjligt att använda slingor av typen For Each. Fråga inte vad -4 betyder. Det vet nog bara ett skelett i Microsofts källare.

Den andra röda raden, den med "40", döljer metoden NewEnum från IntelliSense-listorna. Denna rad är frivillig och har ingen effekt i en klassmodul i Word, Excel eller något annat Office-program.

Om man inte vill skriva de röda raderna för hand kan man använda dialogrutan Procedure Attributes. Den visas när man klickar på Procedure Attributes... på menyn Tools. Välj NewEnum som Name, skriv -4 som Procedure ID och bocka för Hide this member.

Dessa inställningar görs automatiskt om man låter Class Builder Utility skapa samlingsklassens kod. Class Builder Utility är ett Add-In som man kan lägga till på menyn Add-Ins med hjälp av Add-In Manager på samma meny.

Om man skriver de röda raderna för hand måste man spara, stänga och öppna projektet på nytt innan klassmodulen kan användas. Då blir de röda raderna osynliga.

Procedure Attributes dialog

I Word, Excel och de andra Office-programmen saknas dialogrutan Procedure Attributes. Man skriver den första röda raden för hand. Den andra röda raden kan man strunta i, för den har som sagt ingen effekt i Office-programmen. Sedan måste man i tur och ordning exportera, ta bort och importera klassmodulen för att den ska fungera. Då blir den röda raden osynlig. Knepigt, men det fungerar.

 

 

  Databaser

Om man använder DAO (Data Access Objects) kan man skapa databaser av samma typ som används i Microsoft Access. Databasmotorn heter Microsoft Jet. Namnet är något missvisande, för Jet är inte världens snabbaste databasmotor, men den duger bra för mindre databaser som endast har ett fåtal samtidiga användare. För att kunna använda DAO måste man skapa en referens i dialogrutan References, helst till den senaste versionen Microsoft DAO 3.6. Klicka på References... på menyn Project och sätt en bock på rätt rad:

Reference to DAO

DAO är en teknik som började användas 1993 i Visual Basic 3.0 (även om den inte kallades DAO förrän i Visual Basic 4.0) och har visst stöd för SQL (Structured Query Language) och transaktionshantering. Om man använder DAO kan man även koppla sitt program till andra databaser med hjälp av ODBC (Open Database Connectivity). När Visual Basic 6.0 lanserades 1998 var en av de största nyheterna ADO (ActiveX Data Objects), som är ett annat sätt att hantera databaser i Visual Basic. Man använder inte ADO för att skapa nya databaser, utan för att koppla ett program till redan befintliga databaser. Det är å andra sidan ADO mycket bra på.

Följande exempel skapar en databas med hjälp av DAO och sparar den i filen C:\Medlem.mdb. Databasen har endast en tabell och den heter Medlemmar. Tabellen Medlemmar har tre kolumner: Efternamn, Förnamn och Telefon. För tydlighets skull använder vi svenska namn ännu en gång, även om man egentligen bör hålla sig till engelska.

Private Sub cmdMakeMyDatabase_Click()
Dim MinPlats As Workspace
Dim MinDatabas As Database
Dim MinTabell As TableDef
Dim MinaFält(2) As Field
  Set MinPlats = DBEngine.Workspaces(0)
  Set MinDatabas = MinPlats.CreateDatabase("C:\Medlem.mdb", dbLangSwedFin)
  Set MinTabell = MinDatabas.CreateTableDef("Medlemmar")
  Set MinaFält(0) = MinTabell.CreateField("Efternamn", dbText)
  Set MinaFält(1) = MinTabell.CreateField("Förnamn", dbText)
  Set MinaFält(2) = MinTabell.CreateField("Telefon", dbText)
  MinTabell.Fields.Append MinaFält(0)
  MinTabell.Fields.Append MinaFält(1)
  MinTabell.Fields.Append MinaFält(2)
  MinDatabas.TableDefs.Append MinTabell
  Set MinaFält(0) = Nothing
  Set MinaFält(1) = Nothing
  Set MinaFält(2) = Nothing
  Set MinTabell = Nothing
  Set MinDatabas = Nothing
  Set MinPlats = Nothing
End Sub

Naturligtvis innehåller DAO mycket mer än detta enkla exempel. Så här ser objektmodellen ut i DAO 3.6:

DAO Object Model

Objektet Workspace styr transaktionshanteringen. Metoderna BeginTrans, CommitTrans och Rollback påverkar alla databaser inom samma Workspace.

 

 

  Prefix för några vanliga kontroller

Prefix Objekttyp Prefix Objekttyp
cbo Kombinationsruta (Combo Box) lin Linje (Line)
chk Kryssruta (Check Box) lst Listruta (List Box)
cmd Kommandoknapp (Command Button) mnu Meny (Menu)
dir Kataloglistruta (Directory List Box) mod Modul (Module)
drv Enhetslistruta (Drive List Box) ole OLE
dta Datakontroll (Data Control) opt Alternativknapp (Option Button)
fil Fillistruta (File List Box) pic Bildruta (Picture box)
fra Ram (Frame) shp Form (Shape)
frm Formulär (Form) tmr Stoppur (Timer)
hsb Vågrät rullningslist (Scrollbar) txt Textruta (Text Box)
img Bild (Image) udt Användardefinierad datatyp
lbl Etikett (Label) vsb Lodrät rullningslist (Scrollbar)

 

 

  Kortkommandon

Ctrl+n Nytt projekt
Ctrl+o Öppna projekt
Ctrl+s Spara
Ctrl+p Skriva ut
Alt+q Avsluta
Ctrl+z Ångra senaste åtgärd
Ctrl+a Markera allt
Ctrl+f Sök
F3 Sök nästa
Ctrl+h Ersätt
Ctrl+t Visa dialogrutan Components
Ctrl+e Visa dialogrutan Menu Editor
F5 Köra ett program
Ctrl+F5 Köra ett program med full kompilering
F8 Stega en kodrad i taget
Shift+F8 Stega en kodrad i taget utan att stega anropade procedurer
Ctrl+Shift+F8 Köra resterande rader av en procedur
Ctrl+F8 Köra till markörens position
Ctrl+F9 Forsätta körning från markörens position
Ctrl+Break Tvinga ett program till brytläge under pågående körning
Ctrl+l Visa dialogrutan Call Stack i brytläge
Ctrl+g Visa Immediate Window i brytläge
Shift+F9 Visa dialogrutan Quick Watch i brytläge
Ctrl+w Visa dialogrutan Edit Watch
F5 Fortsätta program från brytläge
Shift+F5 Starta om program från brytläge
Ctrl+d Lägga till fil
Ctrl+x Klippa ut
Ctrl+y Klippa ut aktuell rad
Ctrl+c Kopiera
Ctrl+v Klistra in
Delete Ta bort markerat objekt eller markerad kod
Ctrl+j Flytta kontroll längst fram
Ctrl+k Flytta kontroll längst bak
F7 Växla från objekt till kod
Shift+F7 Växla från kod till objekt
Ctrl+j Lista med egenskaper och metoder
Ctrl+Shift+j Lista med konstanter
Ctrl+i Quick Info
Ctrl+Shift+i Parameter Info
F2 Visa Object Browser
F4 Visa Properties Window
Shift+F4 Visa Property Pages
Ctrl+r Visa Project Explorer
Shift+F2 Gå till procedurens, variabelns eller konstantens deklaration
eller till aktuellt objekt i Object Browser
Ctrl+Shift+F2 Gå tillbaka till föregående position
F9 Lägga till eller ta bort brytpunkt på aktuell rad
Ctrl+Shift+F9 Ta bort alla brytpunkter
Ctrl+Blanksteg Komplettera ord
Ctrl+Enter Acceptera komplettering utan att radbryta
F1 Hjälp

 

Några användbara teckenkoder från ANSI-tabellen
Siffrorna måste skrivas på det numeriska tangentbordet med Num Lock på.

Dessa teckenkoder kan du använda för att skriva ovanliga tecken i Visual Basic, inte bara i koden, utan även på knappar, etiketter och andra kontroller.

æ (litet danskt ä) Alt+0230
Æ (stort danskt ä) Alt+0198
ø (litet danskt ö) Alt+0248
Ø (stort danskt ö) Alt+0216
þ (litet isländskt thorn) Alt+0254
Þ (stort isländskt thorn) Alt+0222
ð (litet isländskt eth) Alt+0240
Ð (stort isländskt eth) Alt+0208
ü (litet tyskt u) Alt+0252
Ü (stort tyskt u) Alt+0220
ä (litet svenskt ä) Alt+0228
Ä (stort svenskt ä) Alt+0196
ö (litet svenskt ö) Alt+0246
Ö (stort svenskt ö) Alt+0214
° (gradnolla) Alt+0176
± (plusminus) Alt+0177
· (multiplikationstecken) Alt+0183
‰ (promille) Alt+0137
µ (my) Alt+0181
¹ (upphöjd etta) Alt+0185
² (upphöjd tvåa) Alt+0178
³ (upphöjd trea) Alt+0179
¼ (en fjärdedel) Alt+0188
¾ (tre fjärdedelar) Alt+0190
© (copyright) Alt+0169
® (registrerat varumärke) Alt+0174
™ (trade mark) Alt+0153
€ (euro) Alt+0128
¥ (yen) Alt+0165

Om du är ute efter något annat tecken är det bra att använda ordbehandlingsprogrammet Word. Klicka på Symbol... på menyn Infoga i Word, så kan du infoga mängder av ovanliga tecken, som du sedan kan kopiera och klistra in i Visual Basic.

Det är bra att veta att funktionen Chr(x) ger följande resultat vid olika värden på talet x:

x Chr(x)
9 Tab (istället för Chr(9) kan man skriva konstanten vbTab)
34 " (citattecken)
38 & (skriv Chr(38) & Chr(38) för att undvika understreck)

Använd alltid konstanten vbCrLf (motsvarar Chr(13) & Chr(10)) för att göra en radbrytning programmatiskt.

 

 

  Historik

Årtal Version Största nyheter
1991 Visual Basic 1.0 Allt.
1992 Visual Basic 2.0 ODBC (Open DataBase Connectivity) och MDI-formulär.
1993 Visual Basic 3.0 Databasmotorn Jet.
1995 Visual Basic 4.0 Klassmoduler.
1997 Visual Basic 5.0 ActiveX-kontroller och klassmoduler med händelser.
1998 Visual Basic 6.0 ADO (ActiveX Data Objects).
2002 Visual Basic .NET 2002 Ett nytt språk med arv, åsidosättning och överlagring.
2003 Visual Basic .NET 2003 Utveckling för handdatorer.
2005 Visual Basic 2005 Generiska datatyper och partiella klasser.
2007 Visual Basic 2008 LINQ (Language Integrated Query).
2010 Visual Basic 2010 Lambda-utryck och samlings-initialiseringar.

 

Till sist några tips:

För att kunna köra program som har kompilerats i Visual Basic 6.0 (utan några extra komponenter eller referenser) behöver man filen MSVBVM60.DLL. Som tur är ingår denna fil i Windows Me, 2000, XP, Vista och 7. Den ingår även i Windows Server 2003, 2008 och 2008 R2.

De flesta användare kan alltså köra EXE-filen fristående. Dock inte användare som kör Windows 98 eller äldre versioner, om de inte har skaffat sig MSVBVM60.DLL på något annat sätt, t ex här.

För att kunna köra program som har kompilerats i Visual Basic 5.0 (utan några extra komponenter eller referenser) behöver man filen MSVBVM50.DLL. Den ingår i Windows 98, Me, 2000 och XP, men inte i Windows Vista och 7.

Skriptspråket VBScript använder filen SCRRUN.DLL. I dialogrutan References (som visas när man klickar på References... på menyn Project) kallas den Microsoft Scripting Runtime. En referens till denna fil ger ditt program tillgång till objektet Dictionary (en förbättrad variant av objektet Collection) och objektet FileSystemObject (ett bättre sätt att hantera filer och mappar). En referens till Windows Script Host Object Model (filen heter WSHOM.OCX) ger ditt program möjlighet att skapa genvägar och hantera Registret i Windows på ett enklare sätt. SCRRUN.DLL och WSHOM.OCX ingår i Windows 2000 och senare versioner.

Vissa avancerade tekniker beskrivs inte i detalj i denna lathund. Det kan vara lärorikt att pröva dessa tekniker på egen hand. När du har tränat ett tag på API-anrop kan du testa en teknik som kallas subclassing. Då använder man API-anrop för att påverka sådana egenskaper hos ett formulär eller en kontroll som i vanliga fall inte kan påverkas. Man kan t ex ändra textfärgen i en listruta eller skapa ett formulär med runda hörn. Hooking är en teknik som kan användas när man vill påverka andra program, t ex vad som ska hända när man trycker på en viss tangent eller högerklickar med musen i Windows eller vilket program som helst.

Callback-funktioner och ActiveX EXE-projekt kan användas för att skapa Visual Basic-program som ger sken av att göra flera saker samtidigt. I Visual Basic .NET bjuder Microsoft på fullt stöd för trådar ("threads"), vilket är mycket bättre. Det bästa med ActiveX EXE-projekt är att man kan skapa samverkande EXE-filer som anropar och utväxlar data med varandra.

I Visual Basic 6.0 bör du lära dig att använda dessa tre Add-Ins på menyn Add-Ins: Package and Deployment Wizard, ActiveX Control Interface Wizard och Class Builder Utility. Om du saknar någon av dem väljer du Add-In Manager... på samma meny.

Med Package and Deployment Wizard kan du lätt skapa installationsprogram.

Med ActiveX Control Interface Wizard kan du snabbare bygga ActiveX-kontroller. När du har tränat ett tag på det kan du läsa om objektet PropertyBag och hur det fungerar.

Med Class Builder Utility kan du lätt bygga klasser och samlingsklasser utan att skriva kod. Det kan verkligen effektivisera din programmering i Visual Basic!

Arv ("inheritance"), åsidosättning ("overriding") och överlagring ("overloading") är viktiga begrepp i andra objektorienterade programmeringsspråk, t ex Java. Dessa begrepp finns inte i Visual Basic, men däremot i Visual Basic .NET.

När du har lärt dig att bygga klassmoduler kan du lära dig uttrycket Implements, som ger tillgång till gränssnitt. Ett gränssnitt ("interface" på engelska) är helt enkelt en klassmodul i vilken man har deklarerat ett antal globala variabler och procedurer utan att skriva någon kod i procedurerna. I andra klassmoduler kan man sedan använda uttrycket Implements för att skapa olika varianter av samma klass. Ett gränssnitt är en klass som andra klasser kan ärva från, den enda form av arv som finns i Visual Basic 6.0.

Till sist några prestandatips. Öppna dialogrutan med det aktuella projektets egenskaper genom att klicka längst ner på menyn Project. Välj fliken Compile. Se till att du har valt Compile to Native Code och Optimize for Fast Code.

Alternativet till native code, P-Code, betyder pseudo code. P-Code är varken källkod eller kompilerad kod, utan ett mellanting. När man väljer P-Code brukar kompileringen gå lite snabbare och EXE-filen brukar bli lite mindre, men det färdiga programmet får sämre prestanda. Därför är native code ett bättre val. Detta alternativ finns i Visual Basic 5.0 och 6.0, men inte i äldre versioner.

Compiler optimization

Om man har valt Compile to Native Code kan man förbättra prestandan ytterligare genom att välja Favor Pentium Pro, under förutsättning att användarna har en Pentium Pro, Pentium II eller ännu bättre processor (en rimlig förutsättning idag).

Klicka sedan på knappen Advanced Optimizations..., så ser du denna dialogruta:

Advanced Optimizations dialog

Alla sex alternativen kan förbättra det färdiga programmets prestanda.

Det översta alternativet, Assume No Aliasing, får du inte bocka för om du

  • använder en global variabel i en procedur till vilken du skickar samma globala variabel som ett argument ByRef
  • skickar en och samma globala variabel ByRef som minst två olika argument till en och samma procedur

Är du säker på att ditt program inte försöker tilldela ett otillåtet värde till ett arrayindex eller en heltalsvariabel (det bör du vara säker på om du har programmerat ordentligt) kan du tjäna på att bocka för Remove Array Bounds Check och Remove Integer Overflow Check. Ett program som använder arrayer i stor omfattning kan bli mycket snabbare då.

Om ditt program gör många räkneoperationer med decimaltal kan du även tjäna på att bocka för Remove Floating Point Error Checks och Allow Unrounded Floating Point Operations. Det förutsätter att ditt program inte försöker tilldela otillåtna värden till variabler med datatyperna Single och Double. Det förutsätter också att det inte blir några avrundningsfel när värdena av två sådana variabler jämförs.

Det sista optimeringsalternativet, Remove Safe Pentium FDIV Checks, kan du bocka för om ingen kör det färdiga programmet i en dator med en av de felaktiga 60 MHz-processorerna som såldes under 1994. Dessa processorer fick problem när de skulle dividera stora heltal med varandra och kunde t ex påstå att 4 195 835 - 3 145 727 * 4 195 835 / 3 145 727 är 256 istället för 0. Om du talar om för användarna att en Pentium II-processor är ett minimikrav är du på den säkra sidan.

 

Lycka till med programmeringen!