Public Const waarde geven vanuit een *.ini file (Excel)

  • Onderwerp starter Onderwerp starter dprod
  • Startdatum Startdatum
Status
Niet open voor verdere reacties.

dprod

Gebruiker
Lid geworden
2 jun 2010
Berichten
80
Beste mede-forum leden,

Ik ben erg benieuwd of ik iets wil wat misschien niet kan (ik zoek namelijk al 3uur op google naar de oplossing).
Ik wil wanneer mijn Excel bestand start, dat er constanten in hangen die hun waarde uit een ini file ophalen.
Nou lukt het me wel om informatie uit een ini file te lezen middels een functie(ReadIniFileString), maar dit werkt blijkbaar niet bij constanten?!

Code:
Public Const DATABASE_FILE As String = ReadIniFileString("config", "DatabaseFile")
geeft dus een error...

Code:
Public Const DATABASE_FILE As String = "database-bestand.test"
werkt bijvoorbeeld wel maaaaar....
al mijn informatie staat netjes in een ini file die ik d.m.v. options kan veranderen.
Daarom wil ik graag ook mijn constanten vanuit een ini file lezen en deze gebruiken in mijn excel bestand!

Alvast bedankt, ik hoop dat iemand een oplossing hiervoor heeft??

Gr,
dprod
 
Als je er eens publieke variabelen van maakt?
 
Uhmmm zou misschien kunnen...
Hoe declareer ik deze dan in public, zodat ik niet in elke procedure opnieuw deze variabele een waarde vanuit de ini hoef te geven?
 
Code:
Public DATABASE_FILE As String

Sub SetVariables()
DATABASE_FILE = "database-bestand.test"
'etc.
End Sub
 
Ik neem aan dat ik deze:
Code:
Sub SetVariables()
DATABASE_FILE = "database-bestand.test"
'etc.
End Sub
...moet oproepen in me workbook_open, zodat deze bij het openen een waarde krijgen?
En behouden deze variabelen ook hun waarde als ik later een hele andere sub aanroep?
Ik dacht namelijk dat publieke variabelen alleen tijdens het aanroepen van procedures Hun waarde behielden?
Misschien zit ik er dan naast...

Gr,
dprod
 
Alleen in dezelfde module:
Dim DATABASE_FILE As String
of
Private DATABASE_FILE As String

Door heel het werkboek:
Public DATABASE_FILE As String

Bovenaan in een module zetten.

De Sub SetVariables inderdaad ergens aanroepen op het moment waar jij wilt dat ze worden geiniteerd. (Dus open-event)

Wellicht handig om 1 Publieke variabele extra op te nemen om indien (om wat voor reden dan ook jouw variabelen weer leeg zijn, te resetten)
Code:
Public DATABASE_FILE As String
[COLOR="darkred"]Public VariabeleAan As Boolean[/COLOR]
Sub SetVariables()
[COLOR="darkred"]VariabeleAan = True[/COLOR]
DATABASE_FILE = "database-bestand.test"
'etc.
End Sub

Vervolgens zet je in andere subs (Ergens in het begin van de code) die rechtstreeks door de gebruiker worden aangeroepen:
Code:
If VariabeleAan = False Then SetVariables
 
Laatst bewerkt:
Duidelijk!
Als ik vandaag of morgen meer tijd heb, en het gelukt is deel ik mijn ervaring en gaat hij op opgelost.
Alvast bedankt...

Gr,
dprod
 
Je kunt ook een Property of Function gebruiken

Bijvoorbeeld zo:
Code:
Public Property Get DATABASE_FILE() As String
        DATABASE_FILE = ReadIniFileString("config", "DatabaseFile")
End Property

Sub Kijk()
    MsgBox DATABASE_FILE
End Sub

of als de variabele constant moet blijven gedurende de sessie:
Code:
Option Explicit
Private mstrDBFile As String

Public Property Get DATABASE_FILE() As String
    If mstrDBFile = "" Then
        mstrDBFile = ReadIniFileString("config", "DatabaseFile")
    End If
    DATABASE_FILE = mstrDBFile
End Property

Sub Kijk()
    MsgBox DATABASE_FILE
End Sub
 
Laatst bewerkt:
Juist... ik denk dat ik property get moet gaan gebruiken...
Alleen welke van de twee?

Ik wil dat deze constanten gedurende alle sessies/procedures hetzelfde zijn.
Net zoals een public const ook werkt.

Morgen op me werk ga ik gelijk het e.e.a. proberen!

Gr,
dprod
 
als je je gegevens uit een inifile leest, maak het niet uit, of je de informatie opslaat in en variabele, of constant opnieuw uitleest.

het punt is, dat als je inifile kan worden aangepast je voor de consistentie moet zorgen dat je variabele gedurende de huidige sessie hetzelfde blijft.

in dat geval gebruik je dus een Private variable die je opvraagt met je property get. deze wordt opgeslagen buiten de procedure, en blijft de waarde vasthouden, totdat je programmacode aanpast of de werkmap afsluit. (methode 2)

als je inifile niet verandert, kun je de eerste methode gebruiken. tenzij je de waarde 100x moet opvragen, dan is het wellicht ook efficienter om de waarde op te slaan in de variabele (methode 2).

je kunt overigens ook in elke subprocedure de waarde uit je inifile toewijzen aan een public variabele, maar daar word je code niet netter van. Het is dan beter om een property of function aan te roepen als je deze nodig hebt
 
Laatst bewerkt:
hmmmm...
nu krijg ik de melding "onvoldoende stack ruimte".

Code:
'+=======================================================================
'+-------------------------------------------------PUBLIC PROPERTY GET...
'+
Public Property Get DATABASE_FILE() As String
        DATABASE_FILE = ReadIniFileString("config", "DatabaseFile")
End Property
Public Property Get SERVER_FILE_LOCATION() As String
        SERVER_FILE_LOCATION = ReadIniFileString("config", "ServerFileLocation")
End Property
Public Property Get LOCAL_FILE_LOCATION() As String
        LOCAL_FILE_LOCATION = ReadIniFileString("config", "LocalFileLocation")
End Property
Public Property Get LOG_FILE() As String
        LOG_FILE = ReadIniFileString("config", "LogFile")
End Property
Public Property Get BIN_FOLDER() As String
        BIN_FOLDER = ReadIniFileString("config", "BinFolder")
End Property
Public Property Get AANTAL_CHEFS() As String
        AANTAL_CHEFS = ReadIniFileString("chefs", "AantalChefs")
End Property
Public Property Get AANTAL_PICS() As String
        AANTAL_PICS = ReadIniFileString("pictures", "AantalPics")
End Property
Public Property Get CHEFS_FOLDER() As String
        CHEFS_FOLDER = ReadIniFileString("chefs", "ChefsFolder")
End Property
Public Property Get PICS_FOLDER() As String
        PICS_FOLDER = ReadIniFileString("pictures", "PicsFolder")
End Property

Toch vreemd dat je een waarde voor een constante niet zonder rare omwegen kan inlezen vanuit een ander bestand (bijvoorbeeld ini).
Iemand DE oplossing?

Gr,
dprod
 
Een constante is een vooraf gedefinieerde waarde die nooit wijzigt. deze waarde ligt vast in je programmacode
Wat jij wilt is een waarde toewijzen aan een variabele, en dat is geen constante, en niet mogelijk om toe te wijzen buiten procedures(sub, function,property) om.

Dus zul je deze waarde moeten ophalen dmv een function of property. of in al je modules als eerste regel een waarde aan een variabele toewijzen.

wat je foutmelding betreft, die zal ergens anders in je programmacode kunnen ontstaan. weet je waar?
en heb je de oude constanten al verwijderd?
 
Laatst bewerkt:
Je kunt het ook oplossen met een klassenmodule

Maak een klassenmodule aan, en geef deze de naam "Inifile"

Plak deze code in de klassenmodule
Code:
Option Explicit

Private mstrDATABASE_FILE As String
Private mstrSERVER_FILE_LOCATION As String
Private mstrLOCAL_FILE_LOCATION As String
Private mstrLOG_FILE As String
Private mstrBIN_FOLDER As String
Private mstrAANTAL_CHEFS As String
Private mstrAANTAL_PICS As String
Private mstrCHEFS_FOLDER As String
Private mstrPICS_FOLDER As String

Private Sub class_initialize()
    mstrDATABASE_FILE = ReadIniFileString("config", "DatabaseFile")
    mstrSERVER_FILE_LOCATION = ReadIniFileString("config", "ServerFileLocation")
    mstrLOCAL_FILE_LOCATION = ReadIniFileString("config", "LocalFileLocation")
    mstrLOG_FILE = ReadIniFileString("config", "LogFile")
    mstrBIN_FOLDER = ReadIniFileString("config", "BinFolder")
    mstrAANTAL_CHEFS = ReadIniFileString("chefs", "AantalChefs")
    mstrAANTAL_PICS = ReadIniFileString("pictures", "AantalPics")
    mstrCHEFS_FOLDER = ReadIniFileString("chefs", "ChefsFolder")
    mstrPICS_FOLDER = ReadIniFileString("pictures", "PicsFolder")
End Sub

Public Property Get DATABASE_FILE() As String
    DATABASE_FILE = mstrDATABASE_FILE
End Property
Public Property Get SERVER_FILE_LOCATION() As String
    SERVER_FILE_LOCATION = mstrSERVER_FILE_LOCATION
End Property
Public Property Get LOCAL_FILE_LOCATION() As String
    LOCAL_FILE_LOCATION = mstrLOCAL_FILE_LOCATION
End Property
Public Property Get LOG_FILE() As String
    LOG_FILE = mstrLOG_FILE
End Property
Public Property Get BIN_FOLDER() As String
    BIN_FOLDER = mstrBIN_FOLDER
End Property
Public Property Get AANTAL_CHEFS() As String
    AANTAL_CHEFS = mstrAANTAL_CHEFS
End Property
Public Property Get AANTAL_PICS() As String
    AANTAL_PICS = mstrAANTAL_PICS
End Property
Public Property Get CHEFS_FOLDER() As String
    CHEFS_FOLDER = mstrCHEFS_FOLDER
End Property
Public Property Get PICS_FOLDER() As String
    PICS_FOLDER = mstrPICS_FOLDER
End Property

Vervolgens plaats je in een GEWONE module de volgende code
en zo lees je voortaan je ini uit.

is dat al beter?

Code:
Option Explicit
Public clsIni As New Inifile   'initialiseert je klasse, dit is vereist om hem te laten werken. 
'ook kan: Dim abc as New Inifile op procedure niveau

Sub InifileTest()
'zo lees je waarden uit je klasse uit

    Debug.Print clsIni.AANTAL_CHEFS
    Debug.Print clsIni.AANTAL_PICS
    Debug.Print clsIni.BIN_FOLDER
    Debug.Print clsIni.CHEFS_FOLDER
    Debug.Print clsIni.DATABASE_FILE
    Debug.Print clsIni.LOCAL_FILE_LOCATION
    Debug.Print clsIni.LOG_FILE
    Debug.Print clsIni.PICS_FOLDER
    Debug.Print clsIni.SERVER_FILE_LOCATION

End Sub
 
Laatst bewerkt:
Dat is 'm!
Ik heb de code exact zo gebruikt zoals je deze hebt gegeven en dat werkt perfect.
Gelijk weer wat geleerd m.b.t klassenmodules!

Rest mij alleen nog maar één vraag.
Het pad EN de naam van het "config.ini" bestand welke ik gebruik, heb ik wel vast gelegd als constanten in de programmeercode.
Dit omdat anders de ReadIniFileString functie uiteraard niet werkt.
Stel dat ik nu de config.ini file op een andere plek installeer, dan moet ik steeds de hardgecodeerde constanten van het pad + naam veranderen in de code.
Is het ook mogelijk deze variabel te maken zodat ik deze kan wijzigen vanuit een userform??

(als ik dit in de config.ini file op sla heeft het geen nut, omdat ik eerst het pad + naam van de iniFile moet gebruiken om überhaubt hieruit te kunnen lezen :-)

ik hoop dat mijn vraag een beetje duidelijk is!
bedankt iedergeval...

Gr,
dprod
 
Je kunt wel code aanpassen met code, maar dat raad ik af

wat je misschien kan doen is het inifile opslaan in dezelfde map als het excel bestand
en dan een variabele vullen met het huidige pad van het bestand + de inifile
bijv:
Code:
inipath = Thisworkbook.path & "\testfile.ini"

Je kunt deze ook in je inifile klassenmodule plaatsen dan, maar dan moet ook je readinifilestring procedure daarin worden gezet, zodat je in die procedure kan verwijzen naar de variabele inipath, die je eerst vult.

als je zoiets ziet zitten, kun je als je wilt de functie readinifilestring posten, dan kan ik een voorzetje geven voor de opzet van de uitgebreide klassenmodule Inifile.

edit: misschien kun je deze onderstaande verder afmaken: (leuk om te kijken of je het al snapt)

Code:
Option Explicit

Private mstrDATABASE_FILE As String
Private mstrSERVER_FILE_LOCATION As String
Private mstrLOCAL_FILE_LOCATION As String
Private mstrLOG_FILE As String
Private mstrBIN_FOLDER As String
Private mstrAANTAL_CHEFS As String
Private mstrAANTAL_PICS As String
Private mstrCHEFS_FOLDER As String
Private mstrPICS_FOLDER As String

Private mstrINI_FILE As String

Private Sub class_initialize()

    mstrINI_FILE = ThisWorkbook.Path & "\config.ini"
    
    mstrDATABASE_FILE = ReadIniFileString("config", "DatabaseFile")
    mstrSERVER_FILE_LOCATION = ReadIniFileString("config", "ServerFileLocation")
    mstrLOCAL_FILE_LOCATION = ReadIniFileString("config", "LocalFileLocation")
    mstrLOG_FILE = ReadIniFileString("config", "LogFile")
    mstrBIN_FOLDER = ReadIniFileString("config", "BinFolder")
    mstrAANTAL_CHEFS = ReadIniFileString("chefs", "AantalChefs")
    mstrAANTAL_PICS = ReadIniFileString("pictures", "AantalPics")
    mstrCHEFS_FOLDER = ReadIniFileString("chefs", "ChefsFolder")
    mstrPICS_FOLDER = ReadIniFileString("pictures", "PicsFolder")
End Sub

Public Property Get DATABASE_FILE() As String
    DATABASE_FILE = mstrDATABASE_FILE
End Property
Public Property Get SERVER_FILE_LOCATION() As String
    SERVER_FILE_LOCATION = mstrSERVER_FILE_LOCATION
End Property
Public Property Get LOCAL_FILE_LOCATION() As String
    LOCAL_FILE_LOCATION = mstrLOCAL_FILE_LOCATION
End Property
Public Property Get LOG_FILE() As String
    LOG_FILE = mstrLOG_FILE
End Property
Public Property Get BIN_FOLDER() As String
    BIN_FOLDER = mstrBIN_FOLDER
End Property
Public Property Get AANTAL_CHEFS() As String
    AANTAL_CHEFS = mstrAANTAL_CHEFS
End Property
Public Property Get AANTAL_PICS() As String
    AANTAL_PICS = mstrAANTAL_PICS
End Property
Public Property Get CHEFS_FOLDER() As String
    CHEFS_FOLDER = mstrCHEFS_FOLDER
End Property
Public Property Get PICS_FOLDER() As String
    PICS_FOLDER = mstrPICS_FOLDER
End Property

Private Function ReadIniFileString(ByVal file As String, _
                                    ByVal Lookfor As String) As String
    'mstrINI_FILE  bevat nu het pad van de inifile


End Function
 
Laatst bewerkt:
ja code vervangen voor code vind ik zelf ook niet prettig.

echter gebruik ik nu al ThisWorkbook.Path, als volgt:
Code:
Public Const C_INI_FILE_NAME As String = "config.ini"
Public Const BIN_FOLDER As String = "bin\"
Code:
Public Function ReadIniFileString( _
        ByVal Sect As String, _
        ByVal Keyname As String) As String
Dim worked As Long
Dim RetStr As String * 128
Dim StrSize As Long
    
    c_ini_no_of_chars = 0
    c_ini_string = ""
    
    If Sect = "" Or Keyname = "" Then
        MsgBox "Section Or Key To Read Not Specified !!!", vbExclamation, "INI"
    Else
        c_profile_string = ""
        RetStr = Space(128)
        StrSize = Len(RetStr)
        'eerst kijken of de iniFile in ThisWorkbook.Path staat...!!
        worked = GetPrivateProfileString(Sect, Keyname, "", RetStr, StrSize, _
            ThisWorkbook.Path & "\" & BIN_FOLDER & C_INI_FILE_NAME)
        If Not worked Then 'zo niet dan kijken op de server locatie voor de iniFile...!!
            worked = GetPrivateProfileString(Sect, Keyname, "", RetStr, StrSize, _
                clsIni.SERVER_FILE_LOCATION & BIN_FOLDER & C_INI_FILE_NAME)
        End If

        If worked Then
            c_ini_no_of_chars = worked
            c_ini_string = Left$(RetStr, worked)
        End If
    End If
    ReadIniFileString = c_ini_string
End Function

Echter wil ik dit losse excel bestand via de mail kunnen versturen zodat deze overal te gebruiken is (zonder overige mapjes/ini-files mee te struren).
ThisWorkbook.Path heeft dus (behalve voor thuisgebruik dan vanuit een *.zip) niet veel nut.
Oplossing is om de iniFile op de server_locatie te zetten, en 'm in de code vanuit daar op te roepen (SERVER_FILE_LOCATION constante).
Maar ik wil dus juist dat deze variabel blijft omdat de server_locatie nog wel eens wil wijzigen (per bedrijfsonderdeel krijgen we verschillende volumes toegewezen, e.g. G:\ of H:\ of Z:\ ...)
Ik wil dus voorkomen om de code per bedrijfsonderdeel aan te passen aan de locatie, terwijl de ini file dus weldegelijk op een andere locatie uitgelezen dient te worden.
Vandaar dat ik het liefst in een userform de paden wijzig, niet iedereen is zo handig met VBA ^^

Gr,
dprod
 
Laatst bewerkt:
ik snap je wel denk ik ^^
Code:
Option Explicit

Private mstrDATABASE_FILE As String
Private mstrSERVER_FILE_LOCATION As String
Private mstrLOCAL_FILE_LOCATION As String
Private mstrLOG_FILE As String
Private mstrBIN_FOLDER As String
Private mstrAANTAL_CHEFS As String
Private mstrAANTAL_PICS As String
Private mstrCHEFS_FOLDER As String
Private mstrPICS_FOLDER As String

    Private mstrINI_FILE As String

Private Sub class_initialize()

        mstrINI_FILE = ThisWorkbook.Path & "\config.ini"
    
    mstrDATABASE_FILE = ReadIniFileString("config", "DatabaseFile")
    mstrSERVER_FILE_LOCATION = ReadIniFileString("config", "ServerFileLocation")
    mstrLOCAL_FILE_LOCATION = ReadIniFileString("config", "LocalFileLocation")
    mstrLOG_FILE = ReadIniFileString("config", "LogFile")
    mstrBIN_FOLDER = ReadIniFileString("config", "BinFolder")
    mstrAANTAL_CHEFS = ReadIniFileString("chefs", "AantalChefs")
    mstrAANTAL_PICS = ReadIniFileString("pictures", "AantalPics")
    mstrCHEFS_FOLDER = ReadIniFileString("chefs", "ChefsFolder")
    mstrPICS_FOLDER = ReadIniFileString("pictures", "PicsFolder")
End Sub

Public Property Get DATABASE_FILE() As String
    DATABASE_FILE = mstrDATABASE_FILE
End Property
Public Property Get SERVER_FILE_LOCATION() As String
    SERVER_FILE_LOCATION = mstrSERVER_FILE_LOCATION
End Property
Public Property Get LOCAL_FILE_LOCATION() As String
    LOCAL_FILE_LOCATION = mstrLOCAL_FILE_LOCATION
End Property
Public Property Get LOG_FILE() As String
    LOG_FILE = mstrLOG_FILE
End Property
Public Property Get BIN_FOLDER() As String
    BIN_FOLDER = mstrBIN_FOLDER
End Property
Public Property Get AANTAL_CHEFS() As String
    AANTAL_CHEFS = mstrAANTAL_CHEFS
End Property
Public Property Get AANTAL_PICS() As String
    AANTAL_PICS = mstrAANTAL_PICS
End Property
Public Property Get CHEFS_FOLDER() As String
    CHEFS_FOLDER = mstrCHEFS_FOLDER
End Property
Public Property Get PICS_FOLDER() As String
    PICS_FOLDER = mstrPICS_FOLDER
End Property

    Public Property Get INI_FILE() As String
        INI_FILE = mstrINI_FILE
    End Property


'declaratie voor afhandeling van lezen iniFile
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias _
    "GetPrivateProfileStringA" ( _
        ByVal lpApplicationName As String, _
        ByVal lpKeyName As Any, _
        ByVal lpDefault As String, _
        ByVal lpReturnedString As String, _
        ByVal nSize As Long, _
        ByVal lpFileName As String) As Long
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias _
    "WritePrivateProfileStringA" ( _
        ByVal lpApplicationName As String, _
        ByVal lpKeyName As Any, _
        ByVal lpString As Any, _
        ByVal lpFileName As String) As Long
Private c_WinDir As String
Private c_profile_string As String
Private c_ini_string As String
Private c_ini_no_of_chars As Integer

Private Function ReadIniFileString( _
        ByVal Sect As String, _
        ByVal Keyname As String) As String
Dim worked As Long
Dim RetStr As String * 128
Dim StrSize As Long
    
    c_ini_no_of_chars = 0
    c_ini_string = ""
    
    If Sect = "" Or Keyname = "" Then
        MsgBox "Section Or Key To Read Not Specified !!!", vbExclamation, "INI"
    Else
        c_profile_string = ""
        RetStr = Space(128)
        StrSize = Len(RetStr)
        worked = GetPrivateProfileString(Sect, Keyname, "", RetStr, StrSize, _
            INI_FILE)

        If worked Then
            c_ini_no_of_chars = worked
            c_ini_string = Left$(RetStr, worked)
        End If
    End If
    ReadIniFileString = c_ini_string
End Function

alleen bied dit dus geen oplossing voor bovenstaand probleem...
 
Laatst bewerkt:
Ik kan natuurlijk nietzomaar een drive letter tevoorschijn toveren, als echter je bestand op dezelfde drive staat als je inifile,
heb je zo alvast de driveletter:

Code:
Private Function GetDrive() As String
    On Error Resume Next
    'de drive bestaat toch niet als het bestand niet is opgeslagen
    GetDrive = Split(ThisWorkbook.Path, "\")(0) & "\"
End Function

Maak daar de map en het bestand aan vast en je bent er.

Maak het ook niet te ingewikkeld trouwens, of bedenk hoe het beter kan :P
ik hoop je in elk geval een paar nieuwe inzichten te geven

je bent op de goede weg. probeer ook zoveel mogelijk constanten etc mbt tot je inifile in je klassenmodule teplaatsen, (als private)
en je mist nog de GetPrivateProfileString API, deze zou je ook in je klassenmodule moeten plaatsen. dat houdt het geheel overzichtelijk
 
Laatst bewerkt:
Je hebt gelijk...
Ik denk dat mijn wens erg lastig te realiseren is.
Het probleem zit 'm ook dat ik gebonden ben aan alleen excel.
Als je met een *.exe bestand zou werken welke een installatie doet, kan je het pad van de installatie in het register planten.
Vervolgens in excel-code verwijzen naar deze register waarde en je bent er (lijkt me).
Maar elke gebruiker een installatie procedure te laten doorlopen is ook niet ideaal.

Helaas (of gelukkig? :rolleyes:) denkt een computer niet zoals een mens!
En logisch nadenken zoals een computer doet, is voor een mens soms best lastig ^^
We blijven lekker puzzelen...
Bedankt voor de feedback

Gr,
dprod
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan