Showing posts with label VBA. Show all posts
Showing posts with label VBA. Show all posts

Thursday, November 7, 2019

Download files from urls in Excel sheet

If you’d need to download several files based on some concatenated url’s it can be useful to build the url’s with Excel.

This little macro can then be used to download all the url’s found on the active sheet and store the files in a folder.

The target folder where the files need to be stored will be requested upon running the macro.

Based on some example VBA found online.

Sub DownloadUrlsOnSheet()
      Dim iRow, iColumn As Long

      Dim FileNum As Long

      Dim FileData() As Byte

       Dim MyFile As String

      Dim WHTTP As Object

          On Error Resume Next

          Set WHTTP = CreateObject("WinHTTP.WinHTTPrequest.5")

          If Err.Number <> 0 Then

              Set WHTTP = CreateObject("WinHTTP.WinHTTPrequest.5.1")

          End If

      On Error GoTo 0

          targetDir = BrowseForFolder

      If (targetDir = False) Then

          Exit Sub

      End If

          If Dir(targetDir, vbDirectory) = Empty Then MkDir targetDir

          Set rngRange = Nothing

      Set rngRange = Worksheets(ActiveCell.Worksheet.Name).Cells.Find("*", Worksheets(ActiveCell.Worksheet.Name).Cells(1, 1), xlFormulas, xlWhole, xlByRows, xlPrevious)

      If Not rngRange Is Nothing Then

          'if found then assign last non-empty cell row and colum index to the variable

          lngMaxColumIndex = rngRange.Column

          lngMaxRowIndex = rngRange.Row

      Else

          MsgBox ("Error clearing data, please check logs")

          Exit Sub

      End If

          For iRow = 1 To lngMaxRowIndex

          For iColumn = 1 To lngMaxColumIndex

              currValue = Trim(Worksheets(ActiveCell.Worksheet.Name).Cells(iRow, iColumn).Text)

               If CheckURL(currValue) Then

                  TempFile = Right(currValue, InStr(1, StrReverse(currValue), "/") - 1)

                   WHTTP.Open "GET", currValue, False

                  WHTTP.Send

                  FileData = WHTTP.ResponseBody

                   FileNum = FreeFile

                  Open targetDir & "\" & TempFile For Binary Access Write As #FileNum

                       Put #FileNum, 1, FileData

                  Close #FileNum

                   FileNum = FreeFile

                  Open targetDir & "\LogFile.txt" For Append As #FileNum

                  Print #FileNum, currValue & " --- Dowmloaded ----"

                  Close #FileNum

              Else

                  FileNum = FreeFile

                   Open targetDir & "\LogFile.txt" For Append As #FileNum

                  Print #FileNum, currValue & " !!! File Not Found !!!"

                  Close #FileNum

              End If

           Next

      Next

      Set WHTTP = Nothing

      MsgBox "Open the folder " & targetDir & " for the downloaded files..."

      Shell "C:\WINDOWS\explorer.exe """ & targetDir & "", vbNormalFocus

   End Sub   Function BrowseForFolder(Optional OpenAt As Variant) As Variant

       'Function purpose:  To Browser for a user selected folder.

       'If the "OpenAt" path is provided, open the browser at that directory

       'NOTE:  If invalid, it will open at the Desktop level

           Dim ShellApp As Object

            'Create a file browser window at the default folder

      Set ShellApp = CreateObject("Shell.Application"). _

      BrowseForFolder(0, "Please choose a folder", 0, OpenAt)

       'Set the folder to that selected.  (On error in case cancelled)

      On Error Resume Next

      BrowseForFolder = ShellApp.self.Path

      On Error GoTo 0

             'Destroy the Shell Application

      Set ShellApp = Nothing

             'Check for invalid or non-entries and send to the Invalid error

       'handler if found

       'Valid selections can begin L: (where L is a letter) or

       '\\ (as in \\servername\sharename.  All others are invalid

      Select Case Mid(BrowseForFolder, 2, 1)

      Case Is = ":"

          If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid

      Case Is = "\"

          If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid

      Case Else

          GoTo Invalid

      End Select

           Exit Function

        Invalid:

       'If it was determined that the selection was invalid, set to False

      BrowseForFolder = False

        End Function

   '

   Function CheckURL(URL) As Boolean

      Dim W As Object

      On Error Resume Next

          Set W = CreateObject("winhttp.winhttprequest.5")

          If Err.Number <> 0 Then

              Set W = CreateObject("winhttp.winhttprequest.5.1")

          End If

      On Error GoTo 0

          If (Len(URL) < 4 Or Left(URL, 4) <> "http") Then

           CheckURL = False

          Exit Function

      End If

              On Error Resume Next

      W.Open "HEAD", URL, False

      W.Send

      If W.Status = 200 Then

          CheckURL = True

      Else

           CheckURL = False

      End If

   End Function

Saturday, September 29, 2012

My Excel macro selection

Some easy to use Excel macro’s. All explained below are available in one Excel Macro Example.

All macro’s are combined in one example Excel sheet template to test the usage of it.

Password Generation

Function RndPassword(vLength)
'This function will generate a random strong password of variable
'length.
'This script is provided under the Creative Commons license located
'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
'be used for commercial purposes with out the expressed written consent
'of NateRice.com

For x = 1 To vLength
Randomize
vChar = Int(89 * Rnd) + 33
If vChar = 34 Then 'this is quote character, replace it with a single quote
vChar = 39
End If
RndPassword = RndPassword & Chr(vChar)
Next
End Function








An example usage of this Password generation function: I have a list with on each row a button to generate a password in the cell next to the button. Each button is linked to the same macro (for easy copy paste of the row). The cell to fill with the new password is automatically detected based on the cell in which the button is drawn. Before setting the new generated password, a warning is shown in a message box.









ExcelMacroPasswordGeenration









Sub Process_GenNewPassword()
Dim LRange As String
Dim RowOffset As Integer
Dim ColumnOffset As Integer
Dim newGenPassword As String
'Find cell that button resides in
LName = Application.Caller
Set bBox = ActiveSheet.Buttons(LName)
LRange = bBox.TopLeftCell.Address
RowOffset = 0 ' relative location of the row in which to work, same row used
FirstNameColumnOffset = -5 ' relative location of firstname column in row to show in warning message box
LastNameColumnOffset = -4 ' relative location of lastname column in row to show in warning message box
PasswordColumnOffset = 2 ' relative location of column in row where the generated password should be set
sResult = MsgBox("The password for user '" & Range(LRange).Offset(RowOffset, FirstNameColumnOffset).Value & " " & Range(LRange).Offset(RowOffset, LastNameColumnOffset).Value & "' will be replaced with a new random password!", vbExclamation + vbOKCancel, "New password generation")
If (sResult <> 1) Then
Exit Sub
End If
newGenPassword = RndPassword(10)
Range(LRange).Offset(RowOffset, PasswordColumnOffset).Value = newGenPassword
End Sub








Checkboxes









Checkbox LinkedCell









Whenever you need many checkboxes in your sheet, you'll probably need each checkbox to be linked to the cell it is residing on.




When copy-pasting rows or columns, the checkboxes will be copied as well, but they will still be linked to the same cell as the checkbox you started to copy-paste. The little macro shown below, will update each Checkbox on the active sheet and set it's linked cell to the cell on which the Checkbox is drawn.









Sub setCheckBoxLinkedCell()
'Loop through all Checkboxes in the active sheet
'Set for each Checkbox it's "LinkedCell" value to the cell on which the Checkbox is drawn
Application.ScreenUpdating = False
' turns off screen updating
Application.DisplayStatusBar = True
' makes sure that the statusbar is visible
Application.StatusBar = "Updating linked cells of all Checkboxes in this sheet."
For Each chk In ActiveSheet.Checkboxes
LRow = ActiveSheet.Checkboxes(chk.Name).TopLeftCell.Row
LColumn = ActiveSheet.Checkboxes(chk.Name).TopLeftCell.Column
cA1 = Application.ConvertFormula("R" & LRow & "C" & LColumn, xlR1C1, xlA1)

ActiveSheet.Shapes.Range(Array(chk.Name)).Select
With Selection
.Value = xlOff
.LinkedCell = cA1
.Display3DShading = False
End With
Next chk
Application.StatusBar = "Linked cells of all Checkboxes in this sheet are updated."
Application.ScreenUpdating = True
End Sub








Save date on Checkbox check









The macro below will set the date in the cell next to the Checkbox whenever the checkbox is checked. All checkboxes are linked to the same macro, for easy copy-pasting. The cell in which to save the date will be detected based on the checkbox location.









ExcelMacroCheckboxDate









Sub Process_CheckBox()
Dim cBox As CheckBox
Dim LRow As Integer
Dim LRange As String

LName = Application.Caller
Set cBox = ActiveSheet.Checkboxes(LName)

'Find address that checkbox resides in
LRange = cBox.TopLeftCell.Address
DateRowOffset = 0 ' row offset (relative to the checkbox location) in which the date should be set
DateColumnOffset = 1 ' column offset (relative to the checkbox location) in which the date should be set

'Change date if checkbox is checked
If cBox.Value > 0 Then
Range(LRange).Offset(DateRowOffset, DateColumnOffset).Value = Date

'Clear date if checkbox is unchecked
Else
Range(LRange).Offset(DateRowOffset, DateColumnOffset).Value = Null
End If
End Sub








Create Folder Structure









I copied my previously explained 'Create Folder Structure' in this Excel Macros Example. For all details, see my previous blog post. An import of an existing system folder structure is now added in there as well.









ExcelMacroCreateFolderStructure









Run macro upon opening a workbook




To run a macro whenever the workbook Excel sheet is opened, the Sub Workbook_Open in 'ThisWorkbook' can be used. This is needed if you want to link some keyboard keys to specific macro's.







Link keys to macro




To link a keyboard key to a specific macro action, the Application.OnKey "..." can be used in the auto startup macro. The keys must be unlinked before closing the workbook. I used this functionality in my Exam Point Counter workbook, described in this previous blog post. In 'ThisWorkbook':







'startup macro
Private Sub Workbook_Open()
Application.OnKey "t", "tKeyPressed"
Application.OnKey "e", "eKeyPressed"
Application.OnKey "s", "sKeyPressed"
Application.OnKey "t", "tKeyPressed"
End Sub
Private Sub Workbook_BeforeClose()
Application.OnKey "t"
Application.OnKey "e"
Application.OnKey "s"
Application.OnKey "t"
End Sub



In any module, for example KeyboardAction:







Sub tKeyPressed()
Application.DisplayStatusBar = True
Application.StatusBar = "t key linked to special action in KeyboardAction module"
End Sub
Sub eKeyPressed()
Application.DisplayStatusBar = True
Application.StatusBar = "e key linked to special action in KeyboardAction module"
End Sub
Sub sKeyPressed()
Application.DisplayStatusBar = True
Application.StatusBar = "s key linked to special action in KeyboardAction module"
End Sub








Search Lookup









The search lookup functionality has also been described in details in this previous blog post. The macro is included in this Excel Macro Example as well.









The formula for E9 below looks like:









 ExcelMacroSearchLookupFomula









ExcelMacroSearchLookup









Open Save









A button with linked macro to navigate to a folder is shown in the module 'OpenSave'.








A basic example of the resource exporter I showed in a previous post, is included as well. It will export the example data set into a text file, and while doing so, all special characters will be converted (eg &#233). For rows in the list of AlternativeEncoding, an alternative encoding for special characters will be used (eg \u00E9). To make the sheet readable, the special characters can be converted back into readable special characters. The conversion is based on a hex2ascii converter, unicode encoding, html encoding and decoding.









When you would reuse this code, please note, in order to support FileSystemObject, you’ll need to add reference to Microsoft scripting runtime in your Excel workbook VBA. In order to do so, open the Visual Basic environment in Excel (ALT+F11) > Menu ‘Tools’ > ‘Reference’ > Enable ‘Microsoft Scripting Runtime’. If this isn’t done in the workbook, the error ‘User defined type not defined’ will appear when writing an export file on ‘Dim fso As New FileSystemObject’.









ExcelMacroOpenSave









When the special characters are encoded using the macro, they will look like this:









ExcelMacroOpenSaveEncoded









PhoneBook vCard export



A sheet in which all phonebook data can be added (can be exported from any other application) is now available. Once all contact information is set, it can be exported into a vCard format which is supported by many address and contact management applications. More details can be found in this specific blog post.



image



All code is available in the Excel Macro Example.

Tuesday, November 2, 2010

Excel lookups in formulas

Different solutions exist to work with looked up data in Excel formulas: LOOKUP, VLOOKUP, HLOOKUP.

  • LOOKUP(value, lookup_range, result_range): searches for value in the lookup_range and returns the value in the result_range that is in the same position
  • VLOOKUP(value, table_array, index_number, not_exact_match ): searches for value in the left-most column of table_array and returns the value in the same row based on the index_number.
  • HLOOKUP(value, table_array, index_number, not_exact_match ): searches for value in the top row of table_array and returns the value in the same column based on the index_number.

But I needed yet some other lookup functionality, something like SEARCHHLOOKUP(search_in_text, lookup_range, result_range) where values from the lookup_range are searched in the text of search_in_text and if found the value of the result_range with the same column as were it was found is returned.

I wanted to be able to define some categories, with keywords linked. If a keyword occurs in a sentence, I wanted the category name as result. and I wanted to easily add new keywords for each category, without changing the formula. For example sheet CATEGORIES:

A B
Fruit Food
1 2
1 apple chocolate
2 banana milk






Next I have a cell with value: "Apple belongs to category" In another cell I want a formula (no VBS) that would result in the category name: "Fruit". For example sheet EXAMPLE:

A B
1 Apple belongs to category Fruit
2 Chocolate belongs to category Food




(Example SearchLookup.xlsm)

Since I need to search for the keyword in a sentence, I use the SEARCH(search_text, search_in_text, start_position ) function. If the result is bigger than 0, the keyword was found (not case sensitive). But if the keyword was not found, an error value #VALUE will be returned. To catch this error value, the function IFERROR(value, value_if_error) can be used. So I get this function: {=IFERROR(IF(SEARCH(CATEGORIES!$A$2:$A$5;EXAMPLE!$A1)>0;CATEGORIES!A$1);"")}

But this will only lookup keywords in my first column of Categories, while I want many more. I solved this by attaching a weight to each category and using the formula CHOOSE(position, value1, value2, ... value_n ) to select the category name corresponding it's weight. To ignore the error values when the keyword is not found, I return 0 if an error occurs and the category weight when the keyword was found, so a MAX on that array will result in the matching category weight. To make sure that 0 is returned, only when the keyword is not found, I add any single character (µ in this case) in front of the text to search in, else 0 could be returned if the text to search in starts with the text we are searching. Now the search has to be bigger than 1 when the keyword is found.

The result is this formula: {=CHOOSE(MAX(IFERROR(IF(SEARCH(Categories!$A$3:$A$6;"µ"&Example!$A1)>1;Categories!$A$2;0);0);IFERROR(IF(SEARCH(Categories!$B$3:$B$6;"µ"&Example!$A1)>1;Categories!$B$2;0);0))+1;"";Categories!$A$1;Categories!$B$1)}

Since we apply the SEARCH function on an array, the complete formula has to be an array formula, so don't forget to press CTRL+SHIFT+ENTER to save as an array function and get the "{=...}" signs around the formula.

So using a combination of CHOOSE, MAX, IFERROR, IF and SEARCH functions I can lookup category names base on keywords and the keywords can be added dynamically. The only "problem" left is that I need to change my formulas when a new category is added, but at least not when adding keywords in a category.

To solve this last problem, I ended up creating a 'User defined function' SEARCHHLOOKUP(search_in_text, lookup_range, result_range, (result_range_index)):

Function SearchHLookup(Search_in_text As Variant, Lookup_range As Range, Optional Result_range As Range, Optional Result_range_index As Integer)
'''''''''''''''''''''''''''''''''''''''
'Written by myT - http://myTselection.blogspot.com
'Values from the lookup_range are searched in the text of search_in_text
'If a match is found, the value of Result_range in the same column and top row (or result_range_index) is returned
'Example:
'A B
'1 2
'3 4
'if 2 or 4 is found in Search_in_text, B will be returned
'if 1 or 3 is found in Search_in_text, A will be returned
'if none is found, empty string will be returned
'''''''''''''''''''''''''''''''''''''''
Dim iRow, startRow As Integer
Dim iColumn, startColumn As Integer
If Result_range Is Nothing Then
startRow = 2
Else
startRow = 1
End If
startColumn = 1
For iColumn = startColumn To Lookup_range.Columns.Count
For iRow = startRow To Lookup_range.Rows.Count
If Not (Lookup_range(iRow, iColumn) = "") Then
If (InStr(1, Search_in_text, Lookup_range(iRow, iColumn), 1) > 0) Then
If Result_range Is Nothing Then
SearchHLookup = Lookup_range(1, iColumn)
ElseIf Not (Result_range_index = 0) Then
SearchHLookup = Result_range(Result_range_index, iColumn)
Else
SearchHLookup = Result_range(1, iColumn)
End If

Exit Function
End If
End If
Next iRow
Next iColumn
SearchHLookup = ""
End Function


So in my example, the function I use now has been simplified to:



=SearchHLookup(A1;Categories!$A$3:$B$4;Categories!$A$1:$B$1;1)



Of course, a SearchVLookup could be made easily as well:



Function SearchVLookup(Search_in_text As Variant, Lookup_range As Range, Optional Result_range As Range, Optional Result_range_index As Integer)
'''''''''''''''''''''''''''''''''''''''
'Written by myT - http://myTselection.blogspot.com
'Values from the lookup_range are searched in the text of search_in_text
'If a match is found, the value of Result_range in the same column and top row (or result_range_index) is returned
'Example:
'A 1 2
'B 3 4
'if 1 or 2 is found in Search_in_text, A will be returned
'if 3 or 4 is found in Search_in_text, B will be returned
'if none is found, empty string will be returned
'''''''''''''''''''''''''''''''''''''''
Dim iRow, startRow As Integer
Dim iColumn, startColumn As Integer
If Result_range Is Nothing Then
startColumn = 2
Else
startColumn = 1
End If
startRow = 1
For iRow = startRow To Lookup_range.Rows.Count
For iColumn = startColumn To Lookup_range.Columns.Count
If Not (Lookup_range(iRow, iColumn) = "") Then
If (InStr(1, Search_in_text, Lookup_range(iRow, iColumn), 1) > 0) Then
If Result_range Is Nothing Then
SearchVLookup = Lookup_range(iRow, 1)
ElseIf Not (Result_range_index = 0) Then
SearchVLookup = Result_range(iRow, Result_range_index)
Else
SearchVLookup = Result_range(iRow, 1)
End If

Exit Function
End If
End If
Next iColumn
Next iRow
SearchVLookup = ""
End Function


The user defined function needs to be defined in a module. Example: SearchLookup.xlsm)

Friday, April 3, 2009

Excel resource exporter – special characters (Unicode) convertor

Excel_2007On many project I worked, we often keep some program resources in an Excel sheet (labels, translations, static data,  etc.). Excel makes it easy to get an overview of all language translations next to each other and we can easily export this data to text files to be used by our applications.

In one sheet, we also wanted to convert all special characters (e.g. é, ü, etc) to their special notation that will be threaded correctly into our Java application (e.g. è becomes &#232;). And we even used some labels inside JavaScript popup where we wanted a Unicode representation for special characters and some escaped characters (e.g. é becomes \u00E9).

To export all this data, but also make the Excel sheet readable, I implemented some VBS to convert and export the data of the sheet. I even added some extras, for example to make an archive of the exported data, to easily select a folder with a navigator, make the complete sheet readable (convert special characters) etc. All settings can easily be configured.

I suppose parts of the VBS and the look-and-feel can be reused in some other projects, the Excel sheet can be downloaded here.

Wednesday, February 18, 2009

Babylon - Contacts


I'm a big fan of Babylon to easily translate or explain something. I also use it a lot with my own created "dictionaries". For example: I made some script to easily export all my Microsoft Outlook contacts and create a Babylon dictionary out of it. Whenever I need a name, email, phone number, ... of some contact, I just have to provide a name, company, phone number,... to immediately popup my contacts details with just a click.

Follow these steps if you want to be able to export your own Outlook contacts to Babylon.


  1. Export MS Outlook contacts to Excel file: Menu 'File' -> 'Import and export' -> 'Export to file' -> 'Microsoft Excel 97-2003' -> 'Contacts' -> chose some location to save the file
  2. Open the generated Excel file
  3. Add a new macro in the Excel file: Menu 'Developer' -> 'Visual Basic' -> Sheet1 -> Copy-paste my macro from here :
  4. Private Declare Function GetDesktopWindow Lib "user32" () As Long
    Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
      "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
    Private Type OPENFILENAME
      lStructSize As Long
      hwndOwner As Long
      hInstance As Long
      lpstrFilter As String
      lpstrCustomFilter As String
      nMaxCustFilter As Long
      nFilterIndex As Long
      lpstrFile As String
      nMaxFile As Long
      lpstrFileTitle As String
      nMaxFileTitle As Long
      lpstrInitialDir As String
      lpstrTitle As String
      flags As Long
      nFileOffset As Integer
      nFileExtension As Integer
      lpstrDefExt As String
      lCustData As Long
      lpfnHook As Long
      lpTemplateName As String
    End Type
    Sub ConvertOutlookContactsToBabylon()
        sFile = "C:\Contacts.gls"
        
        Application.ScreenUpdating = False
        ' turns off screen updating
        Application.DisplayStatusBar = True
        ' makes sure that the statusbar is visible
        Application.StatusBar = "Preparing babylon file in " + sFile
        
        '--------------------------------------------------------------------------
        'Create export file
        '--------------------------------------------------------------------------
        Set fs = CreateObject("Scripting.FileSystemObject")
        Set f = fs.CreateTextFile(sFile, True)
        f.writeline ("### Glossary title:Contacts")
        f.writeline ("### Author:")
        f.writeline ("### Description:Contacts")
        f.writeline ("### Source language:Dutch")
        f.writeline ("### Source alphabet:Latin")
        f.writeline ("### Target language:Dutch")
        f.writeline ("### Target alphabet:Latin")
        f.writeline ("### Icon:")
        f.writeline ("### Icon2:")
        f.writeline ("### Browsing enabled?Yes")
        
        f.writeline ("### Type of glossary:00000000")
        f.writeline ("### Case sensitive words?0")
        f.writeline ("; DO NOT EDIT THE NEXT **SIX** LINES  - Babylon-Builder generated text !!!!!!")
        f.writeline ("### Glossary id:029f645f6877899f836e9c869d8a89447c6e8e9e8271769a9d659559957889978372869c8477772a9693897f5d89526e7c458944648127444854575a428a9244977c946e5b524147584c559fcc23264eac62515a414f4b8b279a224f5a42474f5f555638993bd86e5b524147584c559f908e2d60475e5a4b597e66833a32294d48429a4d5955")
        f.writeline ("### Confirmation string:7C221QRF")
        f.writeline ("### File build number:01292D7C")
        f.writeline ("### Build:")
        f.writeline ("### Glossary settings:00000000")
        f.writeline ("### Gls type:00000001")
        f.writeline ("; DO NOT EDIT THE PREVIOUS **SIX** LINES  - Babylon-Builder generated text !!!!!!")
        f.writeline ("### Part of speech table:")
        f.writeline ("### Private label id:")
        f.writeline ("### Min version:0")
        f.writeline ("### Regular expression:")
        f.writeline ("### Glossary section:")
        'Find a free column to fill with copy
        ' and find the column to copy from
        For iColumn = 1 To 65000
            'Empty column, stop loop
            colName = CStr(Worksheets(1).Cells(1, iColumn).Value)
            If colName = Empty Then
              lastColumn = iColumn
                Exit For
            End If
            
            'Columns to remove
            If colName = "E-mail Type" Or colName = "E-mail Display Name" Or colName = "E-mail 2 Type" Or colName = "E-mail 2 Type" Or colName = "E-mail 2 Display Name" Or colName = "E-mail 3 Type" Or colName = "E-mail 3 Display Name" Or colName = "Gender" Or colName = "Priority" Or colName = "Private" Or colName = "Sensitivity" Then
              Worksheets(1).Columns(iColumn).Delete (xlShiftToLeft)
              iColumn = iColumn - 1
            End If
            
        Next iColumn
        
        
        'go thru all rows
        For iRow = 2 To 65000
        
            'check if last row to do
            If Worksheets(1).Cells(iRow, 2).Value = Empty And Worksheets(1).Cells(iRow, 4).Value = Empty And Worksheets(1).Cells(iRow + 1, 2).Value = Empty And Worksheets(1).Cells(iRow + 1, 4).Value = Empty Then
                Exit For
            End If
            
            'start new line for babylon display data
            Worksheets(1).Rows(iRow + 1).Insert (xlShiftDown)
            'insert empty row between each contact
            Worksheets(1).Rows(iRow + 2).Insert (xlShiftDown)
            
            'output line, will be written to file
            sLine = ""
            
            'babylon subject
            sSubject = ""
            FullName = CStr(Worksheets(1).Cells(iRow, 2).Value) + " " + CStr(Worksheets(1).Cells(iRow, 4).Value) + "|" + CStr(Worksheets(1).Cells(iRow, 4).Value) + " " + CStr(Worksheets(1).Cells(iRow, 2).Value) + "|"
            
            'keep track of column working in, since cells will be deleted but not in header row
            iColumn = 1
            For headerColumn = 1 To (lastColumn - 1)
                If Worksheets(1).Cells(iRow, iColumn).Value <> Empty Then
                    
                    'convert value to string
                    elementValue = CStr(Worksheets(1).Cells(iRow, iColumn).Value)
                    
                    
                    'eleminiate empty birthday dates
                    If elementValue = "0/0/00" Then
                        Worksheets(1).Cells(iRow, iColumn).Value = ""
                    Else
                        'insert babylon display data
                        displayData = elementValue
                        
                        'convert email addresses to links
                        If InStr(displayData, "@") And (Not InStr(displayData, " ")) Then
                            displayData = "<a href='mailto:" + elementValue + "'>" + elementValue + "</a>"
                        End If
                        
                        'convert web links
                        If Worksheets(1).Cells(1, headerColumn).Value = "WebPage" Then
                            If Not InStr(elementValue, "http://") Then
                                displayData = "<a href='http://" + elementValue + "'>" + elementValue + "</a>"
                            Else
                                displayData = "<a href='" + elementValue + "'>" + elementValue + "</a>"
                            End If
                        End If
                        
                        'convert phone numbers
                        If InStr(Worksheets(1).Cells(1, headerColumn).Value, "Phone") Or InStr(Worksheets(1).Cells(1, headerColumn).Value, "Fax") Then
                            displayData = Replace(Replace(Replace(elementValue, "+31", "+31."), "+33", "+33."), "+32", "+32.")
                        End If
                        
                        
                        'convert categories
                        If Worksheets(1).Cells(1, headerColumn).Value = "Categories" Then
                            displayArray = Split(displayData, ";")
                            displayData = ""
                            For Each sArrayElement In displayArray
                                displayData = displayData + "<a href='bword://" + sArrayElement + "'>" + sArrayElement + "</a> "
                            Next
                        End If
                            
                            
                        'Put display data in sheet
                        Worksheets(1).Cells(iRow + 1, 1).Value = Worksheets(1).Cells(iRow + 1, 1).Value + "<b>" + Worksheets(1).Cells(1, headerColumn).Value + "</b>: " + Replace(Replace(Replace(displayData, vbCrLf, "<br>"), vbCr, "<br>"), ";", ",") + "<br>"
                        
                        
                        'replace vbCrLf vbCr ; with |
                        elementValue = Replace(Replace(Replace(Replace(elementValue, vbCrLf, "|"), vbCr, "|"), ";", "|"), "||", "|")
                        'replace all special character for babylon search data
                        replacedChars = Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(elementValue, " ", "|"), ".", "|"), "@", "|"), ":", "|"), ";", "|"), "-", "|"), "/", "|"), "||", "|"), "||", "|"), "|&|", "|"), "|-|", "|"), "|.|", "|"), "|~|", "|"), "|=|", "|")
                        replacedChars = Replace(Replace(Replace(replacedChars, "+31", "0"), "+33", "0"), "+32", "0")
                        
                        If replacedChars <> elementValue Then
                            Worksheets(1).Cells(iRow, iColumn).Value = elementValue + "|" + replacedChars + "|"
                        Else
                            Worksheets(1).Cells(iRow, iColumn).Value = elementValue + "|"
                        End If
                        
                        If headerColumn = 1 Or headerColumn = 2 Or headerColumn = 3 Or headerColumn = 4 Then
                            If sSubject = "" Then
                                sSubject = elementValue
                            Else
                                sSubject = sSubject + " " + elementValue
                            End If
                        End If
                        
                    End If
                    
                    If Worksheets(1).Cells(1, headerColumn).Value <> "Notes" Then
                        sLine = sLine + Worksheets(1).Cells(iRow, iColumn).Value
                    End If
                    'handle next cell in next loop of For
                    iColumn = iColumn + 1
                Else
                    'empty column: remove cell and shift other cells left
                    'keep track of original cell location to get the heading name of the cell
                    'deleting cells is very slow!
                    'Worksheets(1).Cells(iRow, iColumn).Delete (xlShiftToLeft)
                    
                    'handle next cell in next loop of For, not needed if cells are deleted
                    iColumn = iColumn + 1
                End If
            Next headerColumn
            
            sSubject = Replace(sSubject, "|", " ")
            
            'writing to file
            
            f.writeline (Replace(sSubject + "|" + FullName + sLine, "||", "|"))
            f.writeline (Replace(CStr(Worksheets(1).Cells(iRow + 1, 1).Value), vbTab, " "))
            f.writeline ("")
            iRow = iRow + 2
        Next iRow
        
        'Close export file
        f.Close
        
        Application.ScreenUpdating = True
        ' turns off screen updating
        Application.DisplayStatusBar = True
        ' makes sure that the statusbar is visible
        MsgBox "Babylon file prepared in " + sFile
    End Sub


  5. Close Visual Basic editor

  6. Run the created Macro: Menu 'Developer' -> 'Macro' –> 'ConvertOutlookContactsToBabylon'

  7. A file called 'c:\Contacts.gls' will be created on your C: drive

  8. Open BabylonBuilder.exe and open the gls file 'c:\Contacts.gls': Menu 'File' -> 'Open' (The new version of BabylonBuilder can also be used to compile .gls to .bgl)

  9. Press 'Edit screen'

  10. Press 'Build screen'

  11. Press 'Build'

  12. A file called 'Contacts.bgl' file will be created, this is the compile Babylon dictionary.

  13. Double click the 'Contacts.bgl' file to load it into Babylon

  14. Use Babylon to search on any contact and immediately see all contact details.