Software solutions and questions blog
RSS icon Email icon Home icon
  • Een modale messagebox

    Posted on September 7th, 2009 Christophe No comments

    De msgbox functie in Visual Basic is modaal.
    Uw programma zal niet verder gaan zolang de gebruiker geen interactie had met het programma dmv het antwoord te geven.

    Niet handig dus als je bvb met timers werkt die tijdsgebonden zijn.
    Stel dat in dit geval de msgbox niet weggeklikt wordt dan blijft het programma gewoon hangen.

    De oplossing die ik hiervoor gebruik is om de msgbox op een nieuw form te laten verschijnen. Retourwaarden van de msgboxfunctie kunnen makkelijk aan het oproepende formulier doorgegeven worden. O ja, en zo kun je eventueel zelf de layout van je msgbox gaan bepalen. Design maar eens een form met enkele buttons (bvb ja/nee) en een label erop waarop de vraag ingevuld werd.

  • XSD en XML

    Posted on December 4th, 2008 Christophe No comments

    Ik zit al een tijdje te zwoegen op het inlezen van een XML bestand dat moet voldoen aan de normen van een XSD bestand.
    Ik doe dit in VB6.0

    Als ik mijn variabelen als volgt declareer :


    ' maak een referentie naar microsoft xml4.0 (project - references)
    ' declareer variabelen
    Dim sSchemaFile As String
    Dim sWorkFile As String
    sSchemaFile = txtSchemaPath.Text
    sWorkFile = txtPath.Text
    Dim schemaCache As MSXML2.XMLSchemaCache40
    Set schemaCache = New MSXML2.XMLSchemaCache40
    ' toevoegen van de namespace aan de schemacache
    schemaCache.Add "http://mijnnamespace.be/xml", sSchemaFile
    Dim xml_document As MSXML2.DOMDocument40
    Set xml_document = New MSXML2.DOMDocument40
    Set xml_document.Schemas = schemaCache

    Dan wordt de XML file getoetst door
    Set xml_document.Schemas = schemaCache

    Inlezen van het bestand in onze variabele:
    xml_document.async = False
    If Not xml_document.Load(sWorkFile) Then
    MsgBox "Error - : " & xml_document.parseError.reason
    Exit Sub
    End If

    Maar als ik nu een enkele node of een reeks nodes in een nodeobject wens in te lezen dan krijg ik steeds een ‘Nothing’ als return waarde.


    ' declareer node objecten
    Dim values_node As IXMLDOMNode ' single node
    Dim values_nodelist As IXMLDOMNodeList ' nodelijst (array)

    Set values_node = xml_document.SelectSingleNode("form//contactperson/name") --> Nothing
    Set values_node = xml_document.SelectSingleNode("form//contactperson/name") --> Nothing

    Ik heb de namespace dan toegevoegd aan de eigenschappen van het xml object (xml_document in mijn geval)

    xml_document.validateOnParse = True 'nodig vooraleer we de namespace property instellen
    xml_document.setProperty "SelectionNamespaces", "xmlns:x='http://mijnnamespace.be/xml'"

    We gebruiken x als prefix.

    Uitlezen:
    Set values_node = xml_document.SelectSingleNode("x:form//contactperson/nom") --> Nothing
    ' Attributen uitlezen:
    Set values_nodelist = xml_document.SelectNodes("x:form//@bedrag") --> array van bedragen

    (Tijdelijke) Work around om ook die single node uit te lezen.

    ' in plaats van naar domdocument40 te refereren:
    'Set xml_document.Schemas = schemaCache
    Set xml_document = New MSXML2.DOMDocument
    'Het xml_document valideren dmv de validate functie
    Validate sWorkFile, sSchemaFile

    Private Function Validate(ByVal strXMLPath As String, _
    ByVal strXSDPath As String) As Boolean

    Dim objSchemas As MSXML2.XMLSchemaCache40
    Dim objXML As MSXML2.DOMDocument40
    Dim objXSD As MSXML2.DOMDocument40
    Dim strNamespace As String
    Dim objErr As MSXML2.IXMLDOMParseError

    ' load XSD as DOM to populate in Schema Cache
    Set objXSD = New MSXML2.DOMDocument40
    objXSD.async = False
    If Not objXSD.Load(strXSDPath) Then
    Err.Raise 1, "Validate", "Load XSD failed: " & objXSD.parseError.reason
    Else
    ' get namespace name from XSD targetNamespace attribute
    strNamespace = objXSD.documentElement.getAttribute("targetNamespace")
    End If

    ' populate schema cache
    Set objSchemas = New MSXML2.XMLSchemaCache40
    objSchemas.Add strNamespace, objXSD

    ' load XML file (without validation - that comes later)
    Set objXML = New MSXML2.DOMDocument40
    objXML.async = False
    objXML.validateOnParse = False
    objXML.resolveExternals = False

    ' load XML, without any validation
    If Not objXML.Load(strXMLPath) Then
    Err.Raise 1, "Validate", "Load XML failed: " & objXML.parseError.reason
    End If

    ' bind Schema Cache to DOM
    Set objXML.Schemas = objSchemas

    ' does this XML measure up?
    Set objErr = objXML.Validate()

    ' any good?
    Validate = (objErr.errorCode = 0)
    If objErr.errorCode <> 0 Then
    Err.Raise 1, "Validate", objErr.reason
    End If

    End Function

    En dit werkt dus wel. Ook al vind ik het maar een beetje viesjes.

  • Openen van een visual basic project

    Posted on November 27th, 2008 Christophe No comments

    Als je een Visual Basic project opent, is de kans groot dat al de forms die je de laatste keer bezoek bewerkt hebt, zich openen in de Editor.

    Ik ben voorstander om een project te openen in een cleane werkomgeving.
    Om dat te doen volstaat het om het vbw (Visual Basic Workspace) bestand van het project read only te maken.
    Open het vbw bestand met een externe editor (vb notepad). Verwijder al de tekst die in het bestand staat en maak er een read only bestand van.

    Als je nu de volgende keer jou visual basic project opstart, zal de editor geen forms meer openen.

  • Werken met een inifile

    Posted on October 31st, 2008 Christophe 1 comment

    In het ‘oude’ visual basic werkte ik regelmatig met een inifile waarin veel settings stonden.
    Omdat ik af en toe wel bezoek over de vloer krijg met als zoektermen visual basic6 of bestanden + visual basic geef ik hier graag de werkwijze weer om gegevens van en naar een inifile te schrijven.

    Declaratie van functies:
    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
    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

    Gegevens uit een inifile halen:

    Public Function sGetINI(sINIfile As String, sSection As String, sKey _
    As String, sDefault As String) As String

    Dim sTemp As String * 256
    Dim nLength As Integer

    sTemp = Space$(256)

    nLength = GetPrivateProfileString(sSection, sKey, sDefault, sTemp, _
    255, sINIfile)
    sGetINI = Left$(sTemp, nLength)

    End Function

    Gegevens naar een inifile schrijven
    Public Sub writeINI(sINIfile As String, sSection As String, sKey _
    As String, sValue As String)

    Dim n As Integer
    Dim sTemp As String

    sTemp = sValue

    'Replace any CR/LF characters with spaces
    For n = 1 To Len(sValue)
    If Mid$(sValue, n, 1) = vbCr Or Mid$(sValue, n, 1) = vbLf _
    Then Mid$(sValue, n) = " "
    Next n

    n = WritePrivateProfileString(sSection, sKey, sTemp, sINIfile)

    End Sub

  • Een recordset snel naar excel exporteren

    Posted on September 24th, 2008 Christophe No comments

    Met visual basic kan je natuurlijk door een ganse recordset loopen en record per record naar excel gaan wegschrijven.
    Gemakkelijker gaat het als je de recordset in één keer, in zijn geheel exporteert naar excel.

    Dim RS As New ADODB.Recordset
    CREATERECORDSETONSERVER RS, dbOCMW ' function to create a recordset on the serverside

    RS.Open "select * from MyQuery where jaar = " & cmbJaar.Text

    'Start a new workbook in Excel
    Dim oApp As New Excel.Application
    Dim oBook As Excel.Workbook
    Dim oSheet As Excel.Worksheet

    Set oBook = oApp.Workbooks.Add
    Set oSheet = oBook.Worksheets(1)

    'Add the field names in row 1
    Dim i As Integer
    Dim iNumCols As Integer

    iNumCols = RS.Fields.Count
    For i = 1 To iNumCols
    oSheet.Cells(1, i).Value = RS.Fields(i - 1).Name
    Next

    'Add the data starting at cell A2
    oSheet.Range("A2").CopyFromRecordset RS

    'Format the header row as bold and autofit the columns
    With oSheet.Range("a1").Resize(1, iNumCols)
    .Font.Bold = True
    .EntireColumn.AutoFit
    End With

    oApp.Visible = True
    oApp.UserControl = True

    'Close the Database and Recordset
    RS.Close

    In a module we have
    Sub CREATERECORDSETONSERVER(rs)
    Set rs = New ADODB.Recordset
    rs.ActiveConnection = db ' is the active connection with the database
    rs.CursorLocation = adUseServer
    rs.CursorType = adOpenStatic
    rs.LockType = adLockReadOnly
    End Sub

    [tags]visual basic, excell, microsoft office[/tags]

  • Aantal rijen te weten komen in excel via visual basic6

    Posted on September 5th, 2008 Christophe No comments

    Een gebruiker van een programma weet altijd graag of het programma met een actie bezig is. Handig om het verloop van een proces aan te duiden is natuurlijk een progressiebar. Maar die progressiebar moet waarden hebben om enigszins een juiste weergave van een proces weer te geven.

    Stel je wil een excel sheet importeren in een database. In die excel sheet staan er x aantal rijen ingevuld.
    Hoe kan je nu de maximumwaarde aan de progressiebar geven (zijnde het aantal ingevulde rijen in de excel sheet);
    Je zou natuurlijk een for next (zolang cell(i,1) <> “”) kunnen gebruiken maar op zich heb je hier dan ook een progressiebar nodig omdat een grote excel sheet wel eventjes kan loopen.

    Ik maak gebruik van het volgende
    dim cnt as double
    Dim xlTmp As Excel.Application
    Set xlTmp = New Excel.Application
    cnt = xlTmp.ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row

    [tags]visual basic, excel[/tags]

  • Hoe om te gaan met een bit vector?

    Posted on July 11th, 2008 Christophe No comments

    Een bit vector is een return status van een routine waarbij nul, één of meer bits gezet worden.
    Normaliter handel ik alle routines (pollings) af met een select case – end select instructie.

    Maar indien de return waarde van een routine of een polling naar een aangesloten apparaat een bit vector is, dan bestaat de mogelijkheid dat de select case – end select de return waarde niet juist detecteert.
    Ook een if – then – elseif – endif zal deze niet detecteren.

    We dienen voor elke mogelijke respons, gebruik te maken van een if – then – endif instructie.
    Ook al zijn er 100 verschillende responses mogelijk vanuit de routine.

  • Schermresolutie

    Posted on June 4th, 2008 Christophe No comments

    Soms is het wel handig om te weten welke de schermresolutie van de computergebruiker is.
    In Visual Basic 6 deed ik dat via een eenvoudige functie.

    Public Function ScreenResolution()
    Dim iW As Integer
    Dim iH As Integer

    iW = Screen.Width / Screen.TwipsPerPixelX
    iH = Screen.Height / Screen.TwipsPerPixelY
    ScreenResolution = iW & " x " & iH
    End Function

    In het form_load event van het formulier dat u wilt openen plaats je dan gewoon een if then constructie.

    Bijvoorveeld:

    If ScreenResolution = "1024 x 768" Then
    Me.WindowState = vbMaximized
    Else
    Me.Width = 16290
    Me.Height = 10545
    End If

  • Beveiliging

    Posted on June 2nd, 2008 Christophe No comments

    Als we een programma hebben waarbij paswoorden of waarbij licentiessleutels gebruikt worden dienen we die paswoorden of sleutels te beveiligen.
    Paswoorden dienen niet onbeveiligd over het netwerk gestuurd te worden.

    Een voorbeeld om paswoorden in visual basic te encryperen en terug te decryperen geef ik hieronder mee.

    Encoderen:
    Public Function encode(str As String) As String
    Dim i As Long
    Dim r As String
    For i = 1 To Len(str)
    r = r & Chr(255 - Asc(str))
    str = Right$(str, Len(str) - 1)
    Next
    encode = r
    End Function

    Decoderen:

    Public Function decode(str As String) As String
    Dim i As Long
    Dim r As String
    For i = 1 To Len(str)
    r = r & Chr(255 - Asc(str))
    str = Right$(str, Len(str) - 1)
    Next
    decode = r
    End Function

    Update:
    Serge kwam me meldden dat dit niet echt encryperen is maar een reversible hash.

  • ADO Connections

    Posted on May 29th, 2008 Christophe 2 comments

    Normaal leg ik de connectie naar een database via ODBC-gegevensbronbeheer. Zo voeg ik een DSN toe via mijn installatieprogramma (wise installmaster). Een probleem stelt zich echter wanneer de gebruiker van de pc niet voldoende rechten heeft om naar het register te schrijven.

    Ik los dit dan op aan de hand van een inifile. De datasource wordt uit de inifile gelezen en de connectie kan gemaakt worden.
    Maar wat als je nu een ado connectie wil maken naar een access database die met een paswoord beveiligd is?

    Dan moeten we het paswoord natuurlijk in onze connectiestring opnemen. En dat werkt als volgt:

    db.Open "PROVIDER=Microsoft.Jet.OLEDB.4.0;data source=" & strDSN & ";Jet OLEDB:Database Password=paswoord"

    strDSN is dan het path naar waar de database zich bevindt en welk dus in de inifile vermeld staat.

    dim strDSN as string
    strDSN = sGetINI(sINIfile, "Data", "MijnDatabase", "")