Securely store password in a VBA project - vba

I built a file used by various people in one of my company service.
Each sheet is protected by a password and all users entries are handled with a VBA user form. All sheets are protected by the same password and my code protect/unprotect sheet when users modify data.
The problem is I'm storing the password in clear text in the VBA project so as to call the ActiveSheet.Protect password method. The VBA project is also protected by this password.
Is there a secure way to store that password in the VBA project ?
Anyone who knows how to search a bit would find a code to crack that VBA project password and be able to read it.
EDIT :
I have thought of computing a new password each time the file is open by adding some randomness in it. This way one could read the code without knowing the password. Adding a msgbox could reveal it but only until the file is reopenend. The problem is I cannot manually unprotect/protect sheet with that method as I won't be aware of the password.

Summarising the useful info from comments:
if your code has access to the password (even directly or through obfuscation) anybody having access to the code have access to the password too
password protection of Excel VBA is very weak, it's a trivial job to crack it
Conclusion : there is no way securely storing password in Excel VBA

This should do the trick. The password is smp2smp2, which you will get when running GetPassword, but that actual value is not stored in the project. It is stored using the code 30555112012321187051111661144119, which will be converted to the actual password (human readable) by using CreatePasswordFromCode. By the way, I have no idea how to easily get the code that belongs to a certain password. And in this way, it is always 8 characters long, no room for changes unless you adjust the code. I have found this somewhere in an old project of somebody else, no source mentioned unfortunately.
Option Explicit
Function GetPassword() As String
'the password is stored as codes, so the real password is not stored in this project
GetPassword = CreatePasswordFromCode("30555112012321187051111661144119")
End Function
Function CreatePasswordFromCode(ByVal pstrPasswordCode As String) As String
Dim intChar As Integer
Dim intCode As Integer
Dim arrintShifts(0 To 7) As Integer
Dim arrlngCharCode(0 To 7) As Long
Dim strMessage As String
intChar = 0
intCode = 0
For intCode = 0 To 7
'store -8 to -1 into 0-7
arrintShifts(intCode) = intCode - 8
Next intCode
'the code is stored by using the number of the letter of the password in the 4th character.
'the real code of the character is directly behind that.
'so the code 30555112012321187051111661144119
'has on position 3, 055, 5, 112, 0, 123, 2, 118, 7, 051, 1, 116, 6, 114 and 4, 119
'so sorted this is 0, 123, 1, 116, 2, 118, 3, 055, 4, 119, 5, 112, 6, 114, 7, 051
'then there is also the part where those charcode are shifted by adding -8 to -1 to them.
'leading to the real charactercodes:
'0, 123-8, 1, 116-7, 2, 118-6, 3, 055-5, 4, 119-4, 5, 112-3, 6, 114-2, 7, 051-1
'0, 115, 1, 109, 2, 112, 3, 050, 4, 115, 5, 109, 6, 112, 7, 050
For intChar = 0 To 7
If Mid(pstrPasswordCode, 1, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 2, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 5, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 6, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 9, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 10, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 13, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 14, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 17, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 18, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 21, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 22, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 25, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 26, 3) + arrintShifts(intChar))
ElseIf Mid(pstrPasswordCode, 29, 1) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, 30, 3) + arrintShifts(intChar))
End If
Next intChar
'by getting the charcodes of these values, you create the password
CreatePasswordFromCode = Chr(arrlngCharCode(0)) & Chr(arrlngCharCode(1)) & Chr(arrlngCharCode(2)) & Chr(arrlngCharCode(3)) & Chr(arrlngCharCode(4)) & Chr(arrlngCharCode(5)) & Chr(arrlngCharCode(6)) & Chr(arrlngCharCode(7))
End Function

Modified the code for use with up to 99 characters. Added Password generator.
But still: this all is just an obfuscation of the real password.
Function CreatePasswordFromCode(ByVal pstrPasswordCode As String) As String
' Original Code https://stackoverflow.com/questions/47990187/securely-store-password-in-a-vba-project?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
' Modified to extend password length
' Modifications free to use
Dim codeLen As Integer
Dim intChar As Integer
Dim intCode As Integer
Dim arrintShifts() As Integer
Dim arrlngCharCode() As Long
Dim icp As Integer
' Initialise Arrays
icp = IIf(Right(pstrPasswordCode, 1) Mod 2 = 0, 5, 4)
pstrPasswordCode = Left(pstrPasswordCode, Len(pstrPasswordCode) - IIf(Right(pstrPasswordCode, 1) Mod 2 = 0, 1, 1))
codeLen = Len(pstrPasswordCode) / icp - 1 ' Array Index starts with 0
ReDim arrintShifts(codeLen)
ReDim arrlngCharCode(codeLen)
intChar = 0
intCode = 0
For intCode = 0 To codeLen
'store -8 to -1 into 0-7
arrintShifts(intCode) = intCode - (codeLen + 1)
Next intCode
'the code is stored by using the number of the letter of the password in the 4th character.
'the real code of the character is directly behind that.
'so the code 30555112012321187051111661144119
'has on position 3, 055, 5, 112, 0, 123, 2, 118, 7, 051, 1, 116, 6, 114 and 4, 119
'so sorted this is 0, 123, 1, 116, 2, 118, 3, 055, 4, 119, 5, 112, 6, 114, 7, 051
'then there is also the part where those charcode are shifted by adding -8 to -1 to them.
'leading to the real charactercodes:
'0, 123-8, 1, 116-7, 2, 118-6, 3, 055-5, 4, 119-4, 5, 112-3, 6, 114-2, 7, 051-1
'0, 115, 1, 109, 2, 112, 3, 050, 4, 115, 5, 109, 6, 112, 7, 050
For intChar = 0 To codeLen
For intCode = 0 To codeLen
If CInt(Mid(pstrPasswordCode, intCode * icp + 1, icp - 3)) = intChar Then
arrlngCharCode(intChar) = (Mid(pstrPasswordCode, (intCode + 1) * icp - 2, 3) + arrintShifts(intChar))
Exit For
End If
Next intCode
Next intChar
'by getting the charcodes of these values, you create the password
CreatePasswordFromCode = ""
For intChar = 0 To codeLen
CreatePasswordFromCode = CreatePasswordFromCode & Chr(arrlngCharCode(intChar))
Next intChar
End Function
Function CreateCodeFromPassword(ByVal pstrPasswordCode As String) As String
' Generator free to use
Dim pwLen As Integer
Dim scp As String ' String Code Position, for formatting "0" or "00"
Dim icp As Integer ' marker if pwLen < 10 or > 10
Dim intCode As Integer
Dim arrintShifts() As Integer
Dim arrlngCharCode() As Long
Dim pw() As String
Dim Temp As Variant
Dim arnd() As Variant
Dim irnd As Variant
Randomize
' Initialise Arrays
pwLen = Len(pstrPasswordCode) - 1 ' Array Index starts with 0
scp = IIf(pwLen < 10, "0", "00")
' Create odd/even marker if we have 1 (odd) or 2 (even) byte index digits (scp), values between 0 and 9
icp = IIf(pwLen < 10, Int(Rnd() * 5 + 1) * 2 - 1, Int(Rnd() * 5 + 1) * 2)
ReDim arrintShifts(pwLen)
ReDim arrlngCharCode(pwLen)
ReDim pw(pwLen)
ReDim arnd(pwLen)
For intCode = 0 To pwLen
arnd(intCode) = intCode
Next intCode
' randomize the indizes to bring the code into a random order
For intCode = LBound(arnd) To UBound(arnd)
irnd = CLng(((UBound(arnd) - intCode) * Rnd) + intCode)
If intCode <> irnd Then
Temp = arnd(intCode)
arnd(intCode) = arnd(irnd)
arnd(irnd) = Temp
End If
Next intCode
'by getting the charcodes of these values, you create the password
For intCode = 0 To pwLen
'get characters
pw(intCode) = Mid(pstrPasswordCode, intCode + 1, 1)
'and store -8 to -1 into 0-7 (for additional obfuscation)
arrintShifts(intCode) = intCode - (pwLen + 1)
Next intCode
' Search for the random index and throw the shifted code at this position
For intCode = 0 To pwLen
arrlngCharCode(Application.Match(intCode, arnd, False) - 1) = AscB(pw(intCode)) - arrintShifts(intCode)
Next intCode
' Chain All Codes, combination of arnd(intcode) and arrlngCharCode(intcode) gives the random order
CreateCodeFromPassword = ""
For intCode = 0 To pwLen
CreateCodeFromPassword = CreateCodeFromPassword & Format(arnd(intCode), scp) & Format(arrlngCharCode(intCode), "000")
Next intCode
CreateCodeFromPassword = CreateCodeFromPassword & icp
End Function
Obfuscated version
'VBA code protection using: www.excel-pratique.com/en/vba_tricks/vba-obfuscator.php
Function CreatePasswordFromCode(ByVal z4891679d877f1da36647b21d6197fbfd As String) As String
Dim b2da54ddb60c93bf346493d7e08bc6d08 As Integer
Dim bf56f94eb6ed9a658e82e88591237324d As Integer
Dim bec732ae8e18b7b2ff2e9ccd058f3e8fc As Integer
Dim m06993036154505accc9ce092bdb57b17() As Integer
Dim b8026f9f8f7fe86372be0799d8c9c6691() As Long
Dim q24471047c7a6e466b78de3c6ae66f20f As String
Dim t5f443e88a552a3f943275f985dde03ca As Integer
t5f443e88a552a3f943275f985dde03ca = IIf(Right(z4891679d877f1da36647b21d6197fbfd, 1) Mod 2 = 0, 5, 4)
z4891679d877f1da36647b21d6197fbfd = Left(z4891679d877f1da36647b21d6197fbfd, Len(z4891679d877f1da36647b21d6197fbfd) - IIf(Right(z4891679d877f1da36647b21d6197fbfd, 1) Mod 2 = 0, 1, 1))
b2da54ddb60c93bf346493d7e08bc6d08 = Len(z4891679d877f1da36647b21d6197fbfd) / t5f443e88a552a3f943275f985dde03ca - 1
ReDim m06993036154505accc9ce092bdb57b17(b2da54ddb60c93bf346493d7e08bc6d08)
ReDim b8026f9f8f7fe86372be0799d8c9c6691(b2da54ddb60c93bf346493d7e08bc6d08)
bf56f94eb6ed9a658e82e88591237324d = 0
bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0 To b2da54ddb60c93bf346493d7e08bc6d08
m06993036154505accc9ce092bdb57b17(bec732ae8e18b7b2ff2e9ccd058f3e8fc) = bec732ae8e18b7b2ff2e9ccd058f3e8fc - (b2da54ddb60c93bf346493d7e08bc6d08 + 1)
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
For bf56f94eb6ed9a658e82e88591237324d = 0 To b2da54ddb60c93bf346493d7e08bc6d08
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0 To b2da54ddb60c93bf346493d7e08bc6d08
If CInt(Mid(z4891679d877f1da36647b21d6197fbfd, bec732ae8e18b7b2ff2e9ccd058f3e8fc * t5f443e88a552a3f943275f985dde03ca + 1, t5f443e88a552a3f943275f985dde03ca - 3)) = bf56f94eb6ed9a658e82e88591237324d Then
b8026f9f8f7fe86372be0799d8c9c6691(bf56f94eb6ed9a658e82e88591237324d) = (Mid(z4891679d877f1da36647b21d6197fbfd, (bec732ae8e18b7b2ff2e9ccd058f3e8fc + 1) * t5f443e88a552a3f943275f985dde03ca - 2, 3) + m06993036154505accc9ce092bdb57b17(bf56f94eb6ed9a658e82e88591237324d))
Exit For
End If
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
Next bf56f94eb6ed9a658e82e88591237324d
CreatePasswordFromCode = ""
For bf56f94eb6ed9a658e82e88591237324d = 0 To b2da54ddb60c93bf346493d7e08bc6d08
CreatePasswordFromCode = CreatePasswordFromCode & Chr(b8026f9f8f7fe86372be0799d8c9c6691(bf56f94eb6ed9a658e82e88591237324d))
Next bf56f94eb6ed9a658e82e88591237324d
End Function
Function CreateCodeFromPassword(ByVal z4891679d877f1da36647b21d6197fbfd As String) As String
Dim qe564274d6cab7b91a3393ef092dac78f As Integer
Dim b330c8da5472f3c36b801671ef5a54797 As String
Dim t5f443e88a552a3f943275f985dde03ca As Integer
Dim bec732ae8e18b7b2ff2e9ccd058f3e8fc As Integer
Dim m06993036154505accc9ce092bdb57b17() As Integer
Dim b8026f9f8f7fe86372be0799d8c9c6691() As Long
Dim b343223dcae485b35af2792c7dd91f92b() As String
Dim e0d4cf763c9da42470a729a29b30d7d50 As Variant
Dim b41d8f2e79c0e09113beb7629aa0d8c48() As Variant
Dim b42a57d0c121b9fe34a74143aa279157c As Variant
Randomize
qe564274d6cab7b91a3393ef092dac78f = Len(z4891679d877f1da36647b21d6197fbfd) - 1
b330c8da5472f3c36b801671ef5a54797 = IIf(qe564274d6cab7b91a3393ef092dac78f < 10, "0", "00")
t5f443e88a552a3f943275f985dde03ca = IIf(qe564274d6cab7b91a3393ef092dac78f < 10, Int(Rnd() * 5 + 1) * 2 - 1, Int(Rnd() * 5 + 1) * 2)
ReDim m06993036154505accc9ce092bdb57b17(qe564274d6cab7b91a3393ef092dac78f)
ReDim b8026f9f8f7fe86372be0799d8c9c6691(qe564274d6cab7b91a3393ef092dac78f)
ReDim b343223dcae485b35af2792c7dd91f92b(qe564274d6cab7b91a3393ef092dac78f)
ReDim b41d8f2e79c0e09113beb7629aa0d8c48(qe564274d6cab7b91a3393ef092dac78f)
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0 To qe564274d6cab7b91a3393ef092dac78f
b41d8f2e79c0e09113beb7629aa0d8c48(bec732ae8e18b7b2ff2e9ccd058f3e8fc) = bec732ae8e18b7b2ff2e9ccd058f3e8fc
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = LBound(b41d8f2e79c0e09113beb7629aa0d8c48) To UBound(b41d8f2e79c0e09113beb7629aa0d8c48)
b42a57d0c121b9fe34a74143aa279157c = CLng(((UBound(b41d8f2e79c0e09113beb7629aa0d8c48) - bec732ae8e18b7b2ff2e9ccd058f3e8fc) * Rnd) + bec732ae8e18b7b2ff2e9ccd058f3e8fc)
If bec732ae8e18b7b2ff2e9ccd058f3e8fc <> b42a57d0c121b9fe34a74143aa279157c Then
e0d4cf763c9da42470a729a29b30d7d50 = b41d8f2e79c0e09113beb7629aa0d8c48(bec732ae8e18b7b2ff2e9ccd058f3e8fc)
b41d8f2e79c0e09113beb7629aa0d8c48(bec732ae8e18b7b2ff2e9ccd058f3e8fc) = b41d8f2e79c0e09113beb7629aa0d8c48(b42a57d0c121b9fe34a74143aa279157c)
b41d8f2e79c0e09113beb7629aa0d8c48(b42a57d0c121b9fe34a74143aa279157c) = e0d4cf763c9da42470a729a29b30d7d50
End If
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0 To qe564274d6cab7b91a3393ef092dac78f
b343223dcae485b35af2792c7dd91f92b(bec732ae8e18b7b2ff2e9ccd058f3e8fc) = Mid(z4891679d877f1da36647b21d6197fbfd, bec732ae8e18b7b2ff2e9ccd058f3e8fc + 1, 1)
m06993036154505accc9ce092bdb57b17(bec732ae8e18b7b2ff2e9ccd058f3e8fc) = bec732ae8e18b7b2ff2e9ccd058f3e8fc - (qe564274d6cab7b91a3393ef092dac78f + 1)
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0 To qe564274d6cab7b91a3393ef092dac78f
b8026f9f8f7fe86372be0799d8c9c6691(Application.Match(bec732ae8e18b7b2ff2e9ccd058f3e8fc, b41d8f2e79c0e09113beb7629aa0d8c48, False) - 1) = AscB(b343223dcae485b35af2792c7dd91f92b(bec732ae8e18b7b2ff2e9ccd058f3e8fc)) - m06993036154505accc9ce092bdb57b17(bec732ae8e18b7b2ff2e9ccd058f3e8fc)
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
CreateCodeFromPassword = ""
For bec732ae8e18b7b2ff2e9ccd058f3e8fc = 0 To qe564274d6cab7b91a3393ef092dac78f
CreateCodeFromPassword = CreateCodeFromPassword & Format(b41d8f2e79c0e09113beb7629aa0d8c48(bec732ae8e18b7b2ff2e9ccd058f3e8fc), b330c8da5472f3c36b801671ef5a54797) & Format(b8026f9f8f7fe86372be0799d8c9c6691(bec732ae8e18b7b2ff2e9ccd058f3e8fc), "000")
Next bec732ae8e18b7b2ff2e9ccd058f3e8fc
CreateCodeFromPassword = CreateCodeFromPassword & t5f443e88a552a3f943275f985dde03ca
End Function

Related

Collection of list of integer changing number to access the different variable names

Public p1 = New List(Of Integer)({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
Public p2 = New List(Of Integer)({5, 4, 6, 7, 3, 8, 9, 10, 2, 11})
Public p3 = New List(Of Integer)({11, 8, 10, 9, 7, 12, 6, 13, 14, 15})
I want to display the list p depending on how much is A. if a is 1 then it will be p1, if a is 2 then it will be p2. how can i access the list using this loop without having to manually write the code so many times.
For a As Integer = 1 To 20
If strDigit(str) = a Then
If a = 1 Then
Dim astr As Integer = 0
For Each num In p1
astr = Val(astr) + 1
If num + 1 >= 1 AndAlso num + 1 <= 1000 Then
If pos < 5 Then
Else
End If
End If
Next
ElseIf a = 2 Then
For Each num In p2
Dim astr As Integer = 0
If num + 1 >= 1 AndAlso num + 1 <= 1000 Then
If pos < 5 Then
Else
End If
End If
Next
ElseIf a = 3 Then
For Each num In p3
Dim astr As Integer = 0
astr = Val(astr) + 1
If num + 1 >= 1 AndAlso num + 1 <= 1000 Then
If pos < 5 Then
Else
End If
Next
This should normally be the case, but it doesn't work that way.
For a As Integer = 1 To 20
If strDigit(str) = a Then
If a = 1 Then ' remove line
Dim astr As Integer = 0
For Each num In p(a) ' here
astr = Val(astr) + 1
If num + 1 >= 1 AndAlso num + 1 <= 1000 Then
If pos < 5 Then
Else
End If
End If
Next
End If
Try this one with sorted list
Dim slist As New SortedList(Of Integer, List(Of Integer))
Dim p1 = New List(Of Integer)({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
slist.Add(1, p1)
Dim p2 = New List(Of Integer)({5, 4, 6, 7, 3, 8, 9, 10, 2, 11})
slist.Add(2, p2)
Dim p3 = New List(Of Integer)({11, 8, 10, 9, 7, 12, 6, 13, 14, 15})
slist.Add(3, p3)
Dim p4 = New List(Of Integer)({9, 16, 2, 43, 12, 11, 21, 22, 23})
slist.Add(4, p4)
Dim tmpList As List(Of Integer)
For Each a In slist.Keys
If slist.ContainsKey(a) = True Then
tmpList = slist.Item(a)
For Each num In tmpList
astr = Val(astr) + 1
If num + 1 >= 1 AndAlso num + 1 <= 1000 Then
If pos < 5 Then
Else
End If
End If
Next
End If
Next
LINQ is a great way to make code that would normally involve a loop more succinct.
Dim lists = {p1, p2, p3}
Dim list = lists.First(Function(l) l.Contains(A))
If more than one list contains the specified number, that code will return the first one in which it is found, so that would depend on the order you search them.

Excel VBA sum all cells with matching criteria

I've been trying to do an Overall Equipment Effectiveness (OEE), and for that I need to be able to sum all the good produced items and divide over the total production. So i get a quality índex...
The criteria are "today" , shift (1 or 2 or 3 ) , piece number
So far I've done this...
Private Sub CommandButton1_Click()
Dim last, i As Integer
Dim ref As String, turno As String, dia As String, estado As String, pecasap As String, pecaspr As String
'Sheets("analisegeral").Select
folha = estadoform.Label1.Caption
last = Application.ThisWorkbook.Worksheets(folha).Range("A65536").End(xlUp).Row
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 5) = fimturnoform.ComboBox1 'peça
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 6) = "FIM TURNO"
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 7) = "FINALIZADO" 'estado trabalho (A DECORRER/FINALIZADO)
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 9) = fimturnoform.TextBox1.Text 'fase
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 12) = Now() 'HORA FIM TURNO
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 14) = fimturnoform.TextBox3.Text 'peças aprovadas
Application.ThisWorkbook.Worksheets(folha).Cells(last + 1, 15) = fimturnoform.TextBox2.Text 'peças produzidas
'' Day (Now)
For i = 2 To last
dia = Cells(i, 3)
turno = Cells(i, 4)
ref = Cells(i, 5)
estado = Cells(i, 6)
pecasap
pecaspr
If (Day(Now) = dia And ComboBox2 = turno And ComboBox1 = ref And (estado = "FIM LOTE" Or estado = "FIM TURNO")) Then
End If
Next i
GoTo fim
fim:
End Sub

Macro returns #REF! in excel

I don't know if this is the place to ask such a question, but since it was regarding some VBA scripting, I thought it might.
I have been writing this Macro function:
Function Mod10(tl As String) As Byte
Dim c(13) As Integer
Dim er As Integer
c(13) = Mid(tl, 14, 1) * 2
c(12) = Mid(tl, 13, 1)
c(11) = Mid(tl, 12, 1) * 2
c(10) = Mid(tl, 11, 1)
c(9) = Mid(tl, 10, 1) * 2
c(8) = Mid(tl, 9, 1)
c(7) = Mid(tl, 8, 1) * 2
c(6) = Mid(tl, 7, 1)
c(5) = Mid(tl, 6, 1) * 2
c(4) = Mid(tl, 5, 1)
c(3) = Mid(tl, 4, 1) * 2
c(2) = Mid(tl, 3, 1)
c(1) = Mid(tl, 2, 1) * 2
c(0) = Mid(tl, 1, 1)
For i = 0 To 13
If c(i) > 9 Then
c(i) = CInt(Left(c(i), 1)) + CInt(Right(c(i), 1))
End If
Next
er = 0
For i = 0 To 13
er = er + c(i)
Next
Mod10 = 10 - er Mod 10
End Function
But as you can see here in this picture:
it returns an error saying #REF!. i am writing this in the fx: =Mod10(a1).
The script is found here: http://kronsell.net/fikkontrol.htm (a danish site)
It is used to calculate the final digit to a string. A bit like when calculating the EAN-13 code, just another kind of calculation.
If anybody with VBA or EXCEL knowledge could tell me what to do, I'd really appreciate it.
Not sure why, but it looks like Mod10 is a reserved keyword. I tried renaming the function to Mod_10 and it worked.
You may need to declare some variables if you hold Option Explicit at the top of your module.
Try this and call it from a cell with =MOD_10(A1)
Function MOD_10(tl As String) As Byte
Dim i As Long
Dim c(13) As Integer
Dim er As Integer
c(13) = Mid(tl, 14, 1) * 2
c(12) = Mid(tl, 13, 1)
c(11) = Mid(tl, 12, 1) * 2
c(10) = Mid(tl, 11, 1)
c(9) = Mid(tl, 10, 1) * 2
c(8) = Mid(tl, 9, 1)
c(7) = Mid(tl, 8, 1) * 2
c(6) = Mid(tl, 7, 1)
c(5) = Mid(tl, 6, 1) * 2
c(4) = Mid(tl, 5, 1)
c(3) = Mid(tl, 4, 1) * 2
c(2) = Mid(tl, 3, 1)
c(1) = Mid(tl, 2, 1) * 2
c(0) = Mid(tl, 1, 1)
For i = 0 To 13
If c(i) > 9 Then
c(i) = CInt(Left(c(i), 1)) + CInt(Right(c(i), 1))
End If
Next
er = 0
For i = 0 To 13
er = er + c(i)
Next
MOD_10 = 10 - er Mod 10
End Function

Getting an error Run time erro 9, Subscript Out of Range [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am getting this run-time error 9 , Subscript Out of range in Excel VBA 2003 while creating charts,
Somewhere in the code, Public Chrt_color As Variant and also
'Assigning the chart colors
Chrt_color = Array(4, 7, 9, 10, 11, 12, 13, 14, 17, 18, 21, 22, 23, 3, 43, 51, 50, 39, 47, 52, 56)
Public Sub label_creation_Chart5(ByRef wksht As Excel.Worksheet)
Dim i As Integer
Dim j As Integer
Dim iTemp As Integer
Dim cht_Num As Integer
Dim iTextBoxLoc As Integer
Dim dbTemp As Double
Dim vSeriesValues As Variant
Dim dbSeriesLastValue() As Double
Application.ScreenUpdating = False
cht_Num = 5
wksht.ChartObjects("Chart 5").Activate
wksht.ChartObjects("Chart 5").Select
Do While ActiveChart.TextBoxes.Count > 0
ActiveChart.TextBoxes(1).Delete
Loop
If ActiveChart.SeriesCollection.Count < 1 Then GoTo Sub_end
ReDim dbSeriesLastValue(1 To ActiveChart.SeriesCollection.Count) As Double
ReDim iSeriesIndex(1 To ActiveChart.SeriesCollection.Count) As Integer
For i = 1 To ActiveChart.SeriesCollection.Count
vSeriesValues = ActiveChart.SeriesCollection(i).Values
If wksht.Range("AJ" & (i + 52)).Value = "Yes" Or _
(prdName = "" And InStr(wksht.Range("A" & (i + 52)).Value, corpName) > 2) Then
ActiveChart.SeriesCollection(i).Border.ColorIndex = 5
wksht.Range("Z" & (i + 52) & ":AH" & (i + 52)).Font.ColorIndex = 5
Else
ActiveChart.SeriesCollection(i).Border.ColorIndex = Chrt_color(i)
wksht.Range("Z" & (i + 52) & ":AH" & (i + 52)).Font.ColorIndex = Chrt_color(i)
End If
dbSeriesLastValue(i) = vSeriesValues(UBound(vSeriesValues, 1))
iSeriesIndex(i) = i
iTextBoxLoc = 12 + 202 * (1 - (vSeriesValues(UBound(vSeriesValues, 1)) / (ActiveChart.Axes(xlValue).MaximumScale - ActiveChart.Axes(xlValue).MinimumScale)))
With ActiveChart.TextBoxes.Add(195, iTextBoxLoc, 100, 13)
.AutoSize = True
.Text = ActiveChart.SeriesCollection(i).Name
With .Font
.Name = "Arial"
.Size = 7
.ColorIndex = ActiveChart.SeriesCollection(i).Border.ColorIndex
End With
End With
Next i
For i = 1 To (ActiveChart.SeriesCollection.Count - 1)
For j = i + 1 To ActiveChart.SeriesCollection.Count
If dbSeriesLastValue(j) < dbSeriesLastValue(i) Then
dbTemp = dbSeriesLastValue(j)
dbSeriesLastValue(j) = dbSeriesLastValue(i)
dbSeriesLastValue(i) = dbTemp
iTemp = iSeriesIndex(j)
iSeriesIndex(j) = iSeriesIndex(i)
iSeriesIndex(i) = iTemp
End If
Next j
Next i
I am getting the error at ActiveChart.SeriesCollection(i).Border.ColorIndex = Chrt_color(i)
Also value of ActiveChart.SeriesCollection(i).Border.ColorIndex = -4105 is showing in intermediate window when the error occurs.
Please help!
I'd look at the value of i when you get the error message. Your code iterates i from to the number of series. Say you had more series than the elements of Chtr_color, then Chrt_color(i) doesn't evaluate beyond.
Another problem might be the series index goes from 1 to N while the array index goes from 0 to N-1.
Looking at the original question and comments, everything looks perfect. I have a couple of suggestions and questions tho:
It seems that ActiveChart.SeriesCollection does conatin an element.
1.Are you not sure? Have you not checked in the watch window?
*'Assigning the chart colors Chrt_color = Array(4, 7, 9, 10, 11, 12, 13, 14, 17, 18, 21, 22, 23, 3, 43, 51, 50, 39, 47, 52, 56)*
2.This most likely may not be the reason but do check if the single quote is active and if so, this line becomes commented out rendering the array empty.

Descrypt SagePay string vb.net

I have been having some problems trying to decrypt the string returned back from SagePay.
I used their asp.net kit which included the encrypt and decrypt functions using base64 - sending the information to SagePay is not a problem but I am having a number of problems trying to descrypt the string.
Here is the function I am using to descypt:
Private Function base64Decode(ByVal strEncoded As String) As String
Dim iRealLength As Integer
Dim strReturn As String
Dim iBy4 As Integer
Dim iIndex As Integer
Dim iFirst As Integer
Dim iSecond As Integer
Dim iThird As Integer
Dim iFourth As Integer
If Len(strEncoded) = 0 Then
base64Decode = ""
Exit Function
End If
'** Base 64 encoded strings are right padded to 3 character multiples using = signs **
'** Work out the actual length of data without the padding here **
iRealLength = Len(strEncoded)
Do While Mid(strEncoded, iRealLength, 1) = "="
iRealLength = iRealLength - 1
Loop
'** Non standard extension to Base 64 decode to allow for + sign to space character substitution by **
'** some web servers. Base 64 expects a +, not a space, so convert vack to + if space is found **
Do While InStr(strEncoded, " ") <> 0
strEncoded = Left(strEncoded, InStr(strEncoded, " ") - 1) & "+" & Mid(strEncoded, InStr(strEncoded, " ") + 1)
Loop
strReturn = ""
'** Convert the base 64 4x6 byte values into 3x8 byte real values by reading 4 chars at a time **
iBy4 = (iRealLength \ 4) * 4
iIndex = 1
Do While iIndex <= iBy4
iFirst = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 0, 1)))
'iFirst = CType(System.Convert.ToByte(CType(Mid(strEncoded, iIndex + 0, 1), Char)), Integer)
iSecond = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 1, 1)))
'iSecond = CType(System.Convert.ToByte(CType(Mid(strEncoded, iIndex + 1, 1), Char)), Integer)
iThird = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 2, 1)))
'iThird = CType(System.Convert.ToByte(CType(Mid(strEncoded, iIndex + 2, 1), Char)), Integer)
iFourth = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 3, 1)))
'iFourth = CType(System.Convert.ToByte(CType(Mid(strEncoded, iIndex + 3, 1), Char)), Integer)
strReturn = strReturn + CType(System.Convert.ToChar(((iFirst * 4) And 255) + ((iSecond \ 16) And 3)), String) 'Chr(((iFirst * 4) And 255) + ((iSecond \ 16) And 3))
strReturn = strReturn + CType(System.Convert.ToChar(((iSecond * 16) And 255) + ((iThird \ 4) And 15)), String) 'Chr(((iSecond * 16) And 255) + ((iThird \ 4) And 15))
strReturn = strReturn + CType(System.Convert.ToChar(((iThird * 64) And 255) + (iFourth And 63)), String) 'Chr(((iThird * 64) And 255) + (iFourth And 63))
iIndex = iIndex + 4
Loop
'** For non multiples of 4 characters, handle the = padding **
If iIndex < iRealLength Then
iFirst = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 0, 1)))
iSecond = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 1, 1)))
strReturn = strReturn & Chr(((iFirst * 4) And 255) + ((iSecond \ 16) And 3))
If iRealLength Mod 4 = 3 Then
iThird = arrBase64DecMap(Asc(Mid(strEncoded, iIndex + 2, 1)))
strReturn = strReturn & Chr(((iSecond * 16) And 255) + ((iThird \ 4) And 15))
End If
End If
base64Decode = strReturn
End Function
I don't think the web server is trying to encode anything as there are no + symbols within the url string and I have just glanced over the two to compair they are the same.
This returns a blank string whereas when I use the sections commented out in the first loop i get a really weired string back and when I use their simpleXor function it just returns complete nonsense.
There support is a bit useless as they "are not programmers"! So I am hoping someone can help me out who has used SagePay before.
Thanks in advance.
Managed to get it working:
Private Function base64Decode(ByVal strEncoded As String) As String
Dim output As String = ""
Dim bt64 As Byte() = System.Convert.FromBase64String(strEncoded)
For i As Integer = 0 To (bt64.Length - 1)
output &= System.Convert.ToChar(CInt(bt64(i))).ToString()
Next
Return output
End Function