VBA Encryption Method - vba

I have written a very simple Ceaser Cipher encryption algorithm on VBA. It takes a string value and applies x shift.
Quite happy with it. However, would like to take it to the next step, but I am not sure if it is doable.
I would like to call this encryption function in another module and pass a string value to encrypt.
I.e. What I am trying to do is something like this
Private Sub Encryption()
'Encryption method of string Var
End Sub
---- and in another sub ----
Private Sub function()
Dim Text as String
Text = "Hello"
Encryption(Text)
End Sub
So in this example, I have defined a method to encrypt any string variable. In the other function, I defined a string and initialised it as "Hello". Then called Encryption function on it... Not sure if this is doable in VBA?
I am not sure how I could pass in a variable when I am calling a function within a function. Any advise please?

You would need to change the Sub Routine to a Function. Also, get rid of the Private keyword as this will not allow you to call it across different modules.
So Change this:
Private Sub Encryption()
'Encryption method of string Var
End Sub
to this:
Function Encryption(ByVal inputString as String) As String
'Encryption method of string Var
End Sub
Now, inside your function you need to change whatever variable holds the first string (the one to be encrypted) to the newly created variable, inputString. It's hard to help you in this area as you did not provide the full code for Sub Encryption().
Also, ensure that you set the Function name itself to the newly encrypted text within the function. So your function would essentially look as follows:
Function Encryption(ByVal inputString as String) As String
'Encryption method of string Var
Encryption = 'the value to return from this function
End Sub
Now, your second sub would look like this:
Private Sub test()
Dim Text as String, encryptedText as String
Text = "Hello"
encryptedText = Encryption(Text)
End Sub
You will just make the new variable encryptedText equal to the new function, Encryption.
So, the major difference between a Sub and a Function is that a Function will return values. They both essentially process code the same way.
METHOD 2 (Edit)
After rethinking your question, I believe that you were using your Sub to obtain your encrypted text from passing the variable as ByRef, and you may just be having difficulties with calling the Sub because of the Private keyword.
If this what was going on, then you can simply remove the Private keyword and it should work as intended.
So your Sub should look like:
Sub Encryption() '<-- Notice, no Private scope
'Encryption method of string Var
End Sub
or
Public Sub Encryption()
'Encryption method of string Var
End Sub
You should take a look at this for additional reading regarding scope.

Related

Using a delegate for thread start inside another Sub

What I've got is something like this:
Private Sub GiantLegacySub()
... lots of variables and legacy code...
Dim somethingNew = New Func(of String, Boolean)(
Function(stringy as String) As Boolean
... new code that uses the legacy variables ...
End Function)
Dim t = New Thread(AddressOf somethingNew)
End Sub
I am getting an error indicating that somethingNew is being seen as variable name and not a method name and is thus unacceptable by AddressOf. ( I know that somethingNew is a variable, just one that happens to contain a pointer to a method).
Is there a way to do this? I need to leave it inside of GiantLegacySub because of the shear volume of variables in its scope.
Based on Craig's guidance, this was the answer:
Private Sub GiantLegacySub()
... lots of variables and legacy code...
Dim somethingNew = Sub(stringy as String)
... new code that uses the legacy variables ...
End Sub
Dim t = New Thread(somethingNew)
t.Start(someStringForStringy)
End Sub

How can I assign a value to a number of different variables in a collection using loops?

I have a problem that has been bugging me for a while now. Consider this code:
Public Class Class1
Dim VariableList as New List(of Object) From {MainForm.X, MainForm.Y,
SettingsForm.Z, SettingsForm.Textbox1.Text} '...etc.
Sub SetToZero()
For Each Element in VariableList
Element = 0
Next
End Sub
Sub SetToCustomValue(value As Double)
For Each Element in VariableList
Element = value
Next
End Sub
Sub LoadValuesFromFile()
Dim path As String = MainForm.GetPath()
For Each Element in VariableList
Element = File.Readline()
Next
End Sub
Sub SaveValuesToFile()
Dim path As String = MainForm.GetPath()
For Each Element in VariableList
Element = File.Writeline()
Next
End Sub
'and more similar functions/subs
As you can see, what this class does is that it takes lot of different variables from different places into a collection, and then various functions read or write values to every variable in that collection using loops. In this example, I have just a few variables, but most of the time there are dozens.
Reading the values is not a problem. Writing them, is, because when I declare that VariableList at the top of my class, that List just makes a copy of each variable, rather than maintaining a reference to it. Meaning that if, say, one of the functions modifies the MainForm.X in that List, the actual variable MainForm.X is not modified. To work with references, I would have to forgo loops, and assign every single variable manually, in every function. Which is obviously a lot of bad code. I want to declare that list of variables only once, and then use loops, like in this example code that I wrote above. My question is, how can I make such a container (List, Array, whatever) that would retain the references to the original variables in it, and make the code above possible?
There is no easy way to store pointers to variables in VB.NET. As a workaround, you can use a class to store your variables, as a class is always used as a pointer.
Here's an example of a way to achieve this with a ContainerClass which own a Dictionary of integers. One interest of this method would be that you can declare and name "variables" dynamically. In reality, they will be managed KeyValuePair. Once you have instantiated a copy of this class, you can use it to "manage" your variables by using this class as your pointer.
I included a loop which set all the integers to the same number just for fun, and to demonstrate the kind of manipulation which would end up having an effect similar to one of those described in your question.
Public Class Form2
'This is the container class which will be used to bypass the lack of pointers
'if you wanted to change a property, like the window width, it would be more difficult, but simples variables will be no trouble
Private variableContainer As New VariableContainer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
variableContainer.AddVar("X", 5)
variableContainer.AddVar("Y", 15)
Debug.Print(variableContainer.GetVar("X"))
Debug.Print(variableContainer.GetVar("Y"))
variableContainer.SetAllVar(42)
Debug.Print("Next line will print 42")
Debug.Print(variableContainer.GetVar("X"))
End Sub
End Class
Public Class VariableContainer
'I know a public variable wouldn't need the fancy functions down there, but it's usually better to encapsulate, especially if you're working with a team
'and "future you" count as a teammate, never forget that...
Private list As New Dictionary(Of String, Integer)
Public Sub AddVar(ByVal name As String, ByVal value As Integer)
list.Add(name, value)
End Sub
Public Function GetVar(ByVal name As String) As Integer
If list.ContainsKey(name) Then
Return list(name)
Else
'I choose -1 arbitrarily, don't put too much thinking into this detail
Return -1
End If
End Function
Public Sub SetVar(ByVal name As String, ByVal num As Integer)
If list.ContainsKey(name) Then
list(name) = num
End If
End Sub
Public Sub SetAllVar(ByVal num As Integer)
Dim dict As New Dictionary(Of String, Integer)
For Each item As KeyValuePair(Of String, Integer) In list
dict.Add(item.Key, num)
Next
list = dict
End Sub
End Class
Have fun!

Identify form the method is being called from

I have a global method (in a module) that multiple forms are calling. I can't figure out how to pass/identify the calling form so that it's controls are recognised when referenced in the method:
Public Sub SomeFunction(callingForm As Form)
callingForm.ErrorProvider.SetError(TextBox1, "Faux pas!")
End Sub
Public Sub SomeOtherFunction(callingForm As Form)
SomeFunction(Me)
End Sub
I the above example, I've attempted passing the form as a parameter but I'm being told:
ErrorProvider is not a member of System.Windows.Forms.Form.
This is pretty common, to want to treat all your forms the same, yet different. You will want to create another class that each form can implement. This allows you to do something specific... generically.
Create a class similar to this, call it and the function whatever you want:
Public Interface IErrorForm
Sub MyValidate
End Interface
Implement it in your forms:
Public Class Form1
Implements IErrorForm
Public Sub MyValidate() Implements IErrorForm.MyValidate
'...Your code here
'TextBox1.Text = "Faux pas!"
End Sub
Now, wherever you want to call the function, you could do something like this:
Public Sub SomeFunction(callingForm As Form)
If GetType(IErrorForm).IsAssignableFrom(xFrm.GetType) Then
CType(xFrm, IErrorForm).MyValidate()
End If
End Sub
Another approach with returning value from Validate function
As you mentioned in the comments
...one of the key purposes of my method is to avoid having to set the
errors outside of the method, to reduce duplicitous code
As I understand you want Validate function check, given control as parameter, for errors and show error message through ErrorProvider.
My suggestion will be shared Validate function return string value, which contains error message generated after validating control
If no error then function return Nothing or String.Empty
Public Function Validate(ctrl As Object, formats As String) As String
Dim errorMessage As String = Nothing 'or String.Empty
' Your validating code here
' If no error errorMessage = Nothing
Return errorMessage
End Function
Then in the form (possible in the Validated event handler)
'....
Me.MyErrorprovider.SetError(Me.MyTextBox,
MyGlobalFunctions.Validate(Me.MyTextBox, "formats"))

To dimension an incoming variable or to not

What is the difference between doing this:
Public Sub MySub(ByVal MyString as String)
Dim TheString as String = MyString
myFunction(TheString)
'Some more code...
End Sub
Compared to this:
Public Sub MySub(ByVal MyString as String)
MyFunction(MyString)
'Some more code
End Sub
That is, is there a good reason to dimension a variable in a function/sub again before using it from the argument line? Or does it not matter?
Hope this makes sense, I wasn't sure how to word this question.
If it's a value based Type (e.g: string or integer, double etc.), unless it's passed using the reference (ByRef) instead of the value (ByVal), you shouldn't need to worry about storing it in another variable (unless you wish to have 2 copies)
If the function required a modified string, so you were changing it to fit that, the first code block would make some sense.
However--since it's equal, the only case I can think of you needing the first block of code is if you're needing to keep myString the same within that sub...but I would think if you were doing something like that, most of the time you would just have a totally different sub.
Because you used ByVal-- once you exit that sub, myString will once again be whatever it was initially set to before you entered the sub, because the mystring you're working with inside of the sub is just a copy of the value.
In contrast, if you used ByRef the changes made to the variable would be taken back to the main code and actually change the value of mystring.
You can read about the difference between ByVal and ByRef here: http://social.msdn.microsoft.com/Forums/vstudio/en-US/07b9d3b9-5658-49ed-9218-005564e8209e/what-is-the-difference-between-byval-and-byref
You can take all these concepts and play with how it works in a simple console program to further your understanding. That's what I did, here's some of the code I toyed with to double check what I was saying. Try changing where ByVal & ByRef is used, and maybe printing to the screen after you make a change to see what sticks and what doesn't.
Sub Main()
Dim someString As String = "This is some string."
MySub(someString)
Console.WriteLine(someString)
MyOtherSub(someString)
Console.WriteLine(someString)
Console.ReadLine()
End Sub
Public Sub MySub(ByVal myString As String)
Dim theString As String = myString
MyFunction(theString)
' First line printed in console.
Console.WriteLine(theString)
theString = "Hello."
Console.WriteLine(theString)
Console.WriteLine(myString)
myString = "I'm mystring."
Console.WriteLine(myString)
End Sub
Public Sub MyOtherSub(ByVal MyString As String)
MyFunction(MyString)
End Sub
Public Function MyFunction(ByRef mystring As String)
mystring += "myFunction is acting on this string."
End Function

Type of variable scoping in vba language

I try to understand the VBA scope type, it's impossible to make this such of thing in VBA, but it's possible in other language (java,scala,etc):
public sub try()
dim myVar as String
myvar = "hello world"
Call displayVar()
end sub
public sub displayVar()
msgbox (myvar)
end sub
Can you give me some information about this type of limited scoping ? It's dynamical or lexical, i don't really understand the difference :/
Franck Leveque has provided a clear and simple demonstratation of the difference between local and global declarations.
However, like most languages, VBA allows you to pass parameters to subroutines. Sometimes a global variable is the only choice or the only sensible choice. But normally it it is better to declare myVar within try and pass it as a parameter to displayVar. This prevents displayVar from accidentally changing myVar because, by default, parameters are passed as values. If you want a subroutine to change the value of a parameter you must explicitly pass the parameter as a reference. This is true of most modern programming languages.
Note also that Public means these subroutines are visible to subroutines in other modules. If Public was omitted or replaced by Private, try and displayVar would only be visible within their module.
In the code below I have passed the value of myVar as a parameter to displayVar.
Public Sub try()
Dim myVar As String
myvar = "hello world"
Call displayVar(myVar)
End Sub
Public Sub displayVar(Stg As String)
Call Msgbox(Stg, VBOKOnly)
End Sub
Variable myVar is declared in the function try()
As such, you can only use it in the try() function scope.
By try() function scope, I mean all the instruction written between public sub try() and end sub.
You try to call your variable from another function (displayVar). Which define it's own scope and is not inside the try function scope.
If you want this, you have to declare your variable in the global scope (outside any function)
For example :
dim myVar as String
public sub try()
myvar = "hello world"
Call displayVar()
end sub
public sub displayVar()
msgbox (myvar)
end sub