Showing posts with label VB6. Show all posts
Showing posts with label VB6. Show all posts
Thursday, August 16, 2012
VB6 IsMissing() and optional arguments
In VB6/VBA the IsMissing function is used to test for optional arguments passed to user-defined function procedures as variants. Default values were not required for optional arguments; if no value was passed then IsMissing returned true. It was also possible to specify a default value of a primitive type to pass to the Variant argument.
The important point is that IsMissing only work for optional argurment of Variant Type.
If the optional argument is not of variant type, you should not use the IsMissing() function.
In this case always supply a default value, even if the compiler does not require it.
Monday, August 13, 2012
VBA / VB6 Interface implementation
Few months ago I blogged about interface implementation in VB6. You can find the post here
However, I discovered that the code had a memory leak caused by a circulare reference.
You can find a solution here.
The Keyword Implements in VBA/VB6 allows you to do Interface Implementation, which in turns allows for Polymorphism. This is indeed a great capability of the VB6 language that is often overlooked.
While the VB6 version of interface implementation is not so elegant as the one from .NET environment, it still allows you to implement most of the pattern of the GoF books
I will show you a very easy example on how to use it in VBA.
The Idea is to create an interface called IInstrumet with just one property "Id", and have a Security class that implements its interface. You could also have a Fund, Porftolio or a Security Class that implements this interface. This wil allow for polymorphism.
Dim inst as IInstrument
Dim sec as Security
Dim fn as Fund
Set sec = new Security
Set fn = new Fund
Set inst = sec
Set inst = fn
As you can see, bot a security and a fund can be assigned to an Instruments object!
We first define a Class called IInstrument. The code is here
We now create a new Class called Security that Implements the IInstrument one. This is a bit more tricky.
Once we implement an Interface, the Class that implements it in VB6 will declare those method as Private like that.
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
This is a kind of unsual behaviour, because if I know that the Security class implements the IInstrument interface, I expect to have access to the same methods and property made available by the interface obejcts. For this reason, I usually expose as public member the same properties and functions that are available in the interface. When I implement them, I delegate the job to the interface method
3) I implement the interface methods as I normally do. a declare a module level variable mId
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
Private Property Let IInstrument_Id(value As String)
mId =value
End Property
4) I crate public properties / methods mirroring the interface delegating their implementation to the
mInstrument object
Public Property Get Id() As String
Id =IInstrument_Id
End Property
Public Property Let Id(value As String)
IInstrument_Id = value
End Property
Here you can find the Security Class Code
However, I discovered that the code had a memory leak caused by a circulare reference.
You can find a solution here.
The Keyword Implements in VBA/VB6 allows you to do Interface Implementation, which in turns allows for Polymorphism. This is indeed a great capability of the VB6 language that is often overlooked.
While the VB6 version of interface implementation is not so elegant as the one from .NET environment, it still allows you to implement most of the pattern of the GoF books
I will show you a very easy example on how to use it in VBA.
The Idea is to create an interface called IInstrumet with just one property "Id", and have a Security class that implements its interface. You could also have a Fund, Porftolio or a Security Class that implements this interface. This wil allow for polymorphism.
Dim inst as IInstrument
Dim sec as Security
Dim fn as Fund
Set sec = new Security
Set fn = new Fund
Set inst = sec
Set inst = fn
As you can see, bot a security and a fund can be assigned to an Instruments object!
We first define a Class called IInstrument. The code is here
'This is an Interface for the Generic Financial Instrument Public Property Get Id() As String 'Only Signature End Property Public Property Let Id(value As String) 'Only Signature End Property
We now create a new Class called Security that Implements the IInstrument one. This is a bit more tricky.
Once we implement an Interface, the Class that implements it in VB6 will declare those method as Private like that.
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
This is a kind of unsual behaviour, because if I know that the Security class implements the IInstrument interface, I expect to have access to the same methods and property made available by the interface obejcts. For this reason, I usually expose as public member the same properties and functions that are available in the interface. When I implement them, I delegate the job to the interface method
3) I implement the interface methods as I normally do. a declare a module level variable mId
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
Private Property Let IInstrument_Id(value As String)
mId =value
End Property
4) I crate public properties / methods mirroring the interface delegating their implementation to the
mInstrument object
Public Property Get Id() As String
Id =IInstrument_Id
End Property
Public Property Let Id(value As String)
IInstrument_Id = value
End Property
Here you can find the Security Class Code
Implements IInstrument Private mId As String Public Ticker as String Private Sub Class_Initialize() End Sub Private Property Get IInstrument_Id() As String IInstrument_Id = mId End Property Private Property Let IInstrument_Id(value As String) mId = value End Property 'Public Interface Public Property Get Id() As String Id = IInstrument_Id End Property Public Property Let Id(value As String) IInstrument_Id = value End PropertyWe can now test the code
Sub TestSecurity() Dim Sec1 As Security Dim Inst As IInstrument Dim Sec2 As Security Set Sec1 = New Security Sec1.Id = 10 Sec1.Ticker = "MXEU" Set Inst = Sec1 'Upcast: A Security in an Instruments Debug.Print Inst.Id 'DownCast, this should have been done explicit, but VBA does not support CType. 'VB6 does. So instead of CType(Inst, "Security") we can do If TypeName(Inst) = "Security" Then Set Sec2 = Inst End If Set Sec2 = Inst Debug.Print Sec2.Id Debug.Print Sec2.Ticker End Sub
Thursday, June 28, 2012
VBA and VB6 Debugging Options
In this blog post I will explore the VBA Debugging options.
If you go to
Tools - Options - General
You will see the Error Trapping Options
1) Break on All Errors
2) Break in Class Modlue
3) Bread on Unhandled Errors
Depeding on whether you have an error hanler active or not, or if you call the a class of modue function you will get different behavious. Let's test them out.
1) Break on all errors.
Caller is a Sub of Function
It stops at all errors as soon as they occur: ex division by zero or Err.Raise
Caller is an Excel UDF.
The code will NOT STOP. It will just end execution at the point where the error is caused
Excel will Return #VALUE!
2) Break in Class Module
Caller is a Sub or Function
It stops only on Unhandled errors. If it meets an Err.Raise in a Class module it will stop
in any case.
Caller is an Excel UDF
It terminate only on Unhandled errors. If it meets an Err.Raise in a Class modue it will raise
Err.num 440, irrespective or the error number raised. VERY STRANGE
3) Break on Unhandled Errors
Caller is a Sub or Functin or UDF.
It stops only on Unhandler errors.
As you can see Opton number 3 is the one that gives the most consistency, followed by option number 1 and
finally option number 2.
I would recommend to use always "Break on Unhandled Errors" and switch to any of the other two options only if you are debugging difficult code.
Option 2 is interesting especially when you are developing an ActiveX component and you want to stop the debugger in the class.
Again, use "Break on Unhandled Errors" and you will save a lot of time trying to put up with the inconsistency between on how the debbuger behaves in case you are using an Excel UDF or just simply a sub or function.
If you go to
Tools - Options - General
You will see the Error Trapping Options
1) Break on All Errors
2) Break in Class Modlue
3) Bread on Unhandled Errors
Depeding on whether you have an error hanler active or not, or if you call the a class of modue function you will get different behavious. Let's test them out.
1) Break on all errors.
Caller is a Sub of Function
It stops at all errors as soon as they occur: ex division by zero or Err.Raise
Caller is an Excel UDF.
The code will NOT STOP. It will just end execution at the point where the error is caused
Excel will Return #VALUE!
2) Break in Class Module
Caller is a Sub or Function
It stops only on Unhandled errors. If it meets an Err.Raise in a Class module it will stop
in any case.
Caller is an Excel UDF
It terminate only on Unhandled errors. If it meets an Err.Raise in a Class modue it will raise
Err.num 440, irrespective or the error number raised. VERY STRANGE
3) Break on Unhandled Errors
Caller is a Sub or Functin or UDF.
It stops only on Unhandler errors.
As you can see Opton number 3 is the one that gives the most consistency, followed by option number 1 and
finally option number 2.
I would recommend to use always "Break on Unhandled Errors" and switch to any of the other two options only if you are debugging difficult code.
Option 2 is interesting especially when you are developing an ActiveX component and you want to stop the debugger in the class.
Again, use "Break on Unhandled Errors" and you will save a lot of time trying to put up with the inconsistency between on how the debbuger behaves in case you are using an Excel UDF or just simply a sub or function.
Friday, April 27, 2012
Interface Implementation in VBA and VB6
WARNING THIS CODE HAS A MEMORY LEAK: check UPDATE HERE
I have realized that setting Set mInstruments = Me in the Class inizialize method create a circular reference and so a memory leak. The new code is much better.
The Keyworkd Implements in VBA/VB6 allows you to Interface Implementation in VB6, which in turns allows for Polymorfism. This is indeed a great capabilites on VB6 language that is often overlooked.
While the VB6 version of interface implementation is not so elegant as the one from .NET environment, it still allows you to implement some nice pattern like the strategy or the abstract facotory one.
I will show you a very easy example on how to use it in VBA."
The Idea is to create an interface calle IInstrumets with just one property "Id", and have a Security class that implements its interface. You could also have a Fund, Porftolio or a Security Class that implements its interface. This wil allow for polymorfism.
Dim inst as IInstrument
Dim sec as Security
Dim fn as Fund
Set sec = new Security
Set fn = new Fund
Set inst = sec
Set inst = fn
As you can see, bot a security and a fund can be assigned to an Instruments object!
We first define a Class called IInstrument. The code is here
We now create a new Class called Security that Implements the IInstrument one. This is a bit more tricky.
Once we implement an Interface, the Class that implements it in VB6 will declare those method as Private like that.
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
This is a kind of unsual behaviour, because if I know that the Security class implements the IInstrument interface, I expect to have access to the same methods and property made available by the interface obejcts. For this reason, I usually code the Class using this rules
1) In the Class that implements the interface I declare at Class level a private object of the interface type
Private mInstrument As IInstrument
2) In the constructor I assing the Obj to this instance. This will allow me to call the interface methods of my class
Private Sub Class_Initialize()
'I need to Access the IInstruments Methods
Set mInstrument = Me
End Sub
3) I implement the interface methods as I normally do.
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
Private Property Let IInstrument_Id(strId As String)
mId = strId
End Property
4) I crate public properties / methods mirroring the interface delegating their implementation to the
mInstrument object
Public Property Get Id() As String
Id = mInstrument.Id
End Property
Public Property Let Id(strId As String)
mInstrument.Id = strId
End Property
Here you can find the Security Class Code
I have realized that setting Set mInstruments = Me in the Class inizialize method create a circular reference and so a memory leak. The new code is much better.
The Keyworkd Implements in VBA/VB6 allows you to Interface Implementation in VB6, which in turns allows for Polymorfism. This is indeed a great capabilites on VB6 language that is often overlooked.
While the VB6 version of interface implementation is not so elegant as the one from .NET environment, it still allows you to implement some nice pattern like the strategy or the abstract facotory one.
I will show you a very easy example on how to use it in VBA."
The Idea is to create an interface calle IInstrumets with just one property "Id", and have a Security class that implements its interface. You could also have a Fund, Porftolio or a Security Class that implements its interface. This wil allow for polymorfism.
Dim inst as IInstrument
Dim sec as Security
Dim fn as Fund
Set sec = new Security
Set fn = new Fund
Set inst = sec
Set inst = fn
As you can see, bot a security and a fund can be assigned to an Instruments object!
We first define a Class called IInstrument. The code is here
'This is an Interface for the Generic Financial Instrument Public Property Get Id() As String 'Only Signature End Property Public Property Let Id(strId As String) 'Only Signature End Property
We now create a new Class called Security that Implements the IInstrument one. This is a bit more tricky.
Once we implement an Interface, the Class that implements it in VB6 will declare those method as Private like that.
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
This is a kind of unsual behaviour, because if I know that the Security class implements the IInstrument interface, I expect to have access to the same methods and property made available by the interface obejcts. For this reason, I usually code the Class using this rules
1) In the Class that implements the interface I declare at Class level a private object of the interface type
Private mInstrument As IInstrument
2) In the constructor I assing the Obj to this instance. This will allow me to call the interface methods of my class
Private Sub Class_Initialize()
'I need to Access the IInstruments Methods
Set mInstrument = Me
End Sub
3) I implement the interface methods as I normally do.
Private Property Get IInstrument_Id() As String
IInstrument_Id = mId
End Property
Private Property Let IInstrument_Id(strId As String)
mId = strId
End Property
4) I crate public properties / methods mirroring the interface delegating their implementation to the
mInstrument object
Public Property Get Id() As String
Id = mInstrument.Id
End Property
Public Property Let Id(strId As String)
mInstrument.Id = strId
End Property
Here you can find the Security Class Code
Implements IInstrument Private mId As String Private mInstrument As IInstrument Public Ticker As String Private Sub Class_Initialize() 'I need to Access the IInstruments Methods Set mInstrument = Me End Sub Private Property Get IInstrument_Id() As String IInstrument_Id = mId End Property Private Property Let IInstrument_Id(strId As String) mId = strId End Property 'Public Interface Public Property Get Id() As String Id = mInstrument.Id End Property Public Property Let Id(strId As String) mInstrument.Id = strId End PropertyWe can now test the code
Sub TestSecurity() Dim Sec1 As Security Dim Inst As IInstrument Dim Sec2 As Security Set Sec1 = New Security Sec1.Id = 10 Sec1.Ticker = "MXEU" Set Inst = Sec1 'Upcast: A Security in an Instruments Debug.Print Inst.Id 'DownCast, this should have been done explicit, but VBA does not support CType. 'VB6 does. So instead of CType(Inst, "Security") we can do If TypeName(Inst) = "Security" Then Set Sec2 = Inst End If Set Sec2 = Inst Debug.Print Sec2.Id Debug.Print Sec2.Ticker End Sub
VB6 and VBA Enumerations
An Enumeration in VBA/VB6 is a special type of long Variable.
A great resource can be found here on cpearson.com
The [_First] and [_Last] are not necessary but they can be used to validate the Enumerated variables.
The _ makes the Enumrated variable hidden to the intellisense, while the [ makes it a valid character for the VB6 interpreter.
This is an example on how to Validate Enumerations
A great resource can be found here on cpearson.com
Enum Position [_First] = -1 RelativeDynamic = 0 RelativeStatic = 1 Absolute = 2 [_Last] = 3 End Enum Enum FactorEngine [_First] = -1 AA = 0 [_Last] = 1 End EnumThe code above specify two kind of Enumerations, Position and FactorEngine.
The [_First] and [_Last] are not necessary but they can be used to validate the Enumerated variables.
The _ makes the Enumrated variable hidden to the intellisense, while the [ makes it a valid character for the VB6 interpreter.
This is an example on how to Validate Enumerations
Sub TestEnum()
Dim Fac As FactorEngine
Dim i As Long
Dim IsValid As Boolean
Fac = AA
IsValid = False
For i = FactorEngine.[_First] To FactorEngine.[_Last]
If Fac = i Then
IsValid = True
Exit For
End If
Next i
If IsValid = True Then
Debug.Print Fac & " Is a valid Engine"
Else
Debug.Print Fac & " Is NOT a valid Engine"
End If
End Sub
Thursday, September 9, 2010
How to access .Net library from VBA and VB 6.0
Download Example from Microsoft here
Here you can find a couple of links that will explain you how to access the .Net Framework Class Libray (FCL) from VB6.0 and VBA.
This link contains a series of articles on COM and .NET
Link 1
This one shows you to use some .NET library withoug writing any line of code Link 2
In a netshell
path=%path%;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft.NET\SDK\v1.1\Bin;C:\Program Files\Microsoft.NET\SDK\v1.1\Bin;C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322;
regasm "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\system.dll"
regasm "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\system.dll"
pause
as you can see it use the regasm utilty to register as a COM object the system.dll file.
More interestingly:
The FCL also ships with a number of powerful collection classes, which include:
a reference to either C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorlib.tlb or C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorlib.tlb, depending on the version of the framework that you want to use. Mscorlib is part of the Microsoft .NET Framework, and contains the collection classes.
and you are ready to go.
The are few caveats though
1) Intellisense will not work!!!. To sort this out you need to write your own COM wrapper (I will tell you how to do it)
2) To use the For Each loop to run through the collection you need to define a variable as IEnumerable and assign the list to this interface. This is because the For Each loop need an explicit GetEnumerable (equal to NewEnum) method to work
Dim objSortedList As mscorlib.SortedList
Dim Enum As mscorlib.IEnumerable
Set Enum = objSortedList
3) If you follow step 2 instruction you will have the For Each loop work, however the single object returned for an HashTable or a SortedList is a DictionaryEntry. This means tha VB 6.0 will not be able to access anyway its properties
All of these problems can be solved coding your own COM class in C#.
This is explained on this Link3 you can also find some info on my blog here and I will soon post some sample projects
Here you can find a couple of links that will explain you how to access the .Net Framework Class Libray (FCL) from VB6.0 and VBA.
This link contains a series of articles on COM and .NET
Link 1
This one shows you to use some .NET library withoug writing any line of code Link 2
In a netshell
- Download and install either version 1.1 or version 2.0 of the .NET Framework. If you have installed Visual Studio .NET 2003 or Visual Studio 2005, or any of the Express products, then the .NET framework is already installed.
- Execute Register.bat, which is included in the code download for this article. This registers the .NET framework System.dll so that it can be called as a COM object.
- Start Visual Basic 6.
- In the New Project dialog, select Standard EXE, and click OK.
- Add a CommandButton and Image control to the form.
- Set the Stretch property of the Image to true.
- Select the Project | References menu command.
- Click Browse.
- For v1.1 of the .NET Framework, select C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\system.tlb. For v2.0 of the .NET framework, select C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\system.tlb.
- Click OK.
path=%path%;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft.NET\SDK\v1.1\Bin;C:\Program Files\Microsoft.NET\SDK\v1.1\Bin;C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322;
regasm "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\system.dll"
regasm "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\system.dll"
pause
as you can see it use the regasm utilty to register as a COM object the system.dll file.
More interestingly:
The FCL also ships with a number of powerful collection classes, which include:
- ArrayList—An array class that doesn't have a fixed size. You can just keep adding items to it.
- Hashtable—This class is similar to the Scripting.Dictionary class. You can add items and look them up by key.
- Queue—This is a first in, first out (FIFO) collection. You push items in, and then read them out at a later time in the same order.
- Stack—A first-in, last out (FILO) collection. You push items onto the stack, and then pop them off in reverse order.
- SortedList—Similar to the Hashtable, except when you iterate through the items, they're always sorted by the key.
a reference to either C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorlib.tlb or C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorlib.tlb, depending on the version of the framework that you want to use. Mscorlib is part of the Microsoft .NET Framework, and contains the collection classes.
and you are ready to go.
The are few caveats though
1) Intellisense will not work!!!. To sort this out you need to write your own COM wrapper (I will tell you how to do it)
2) To use the For Each loop to run through the collection you need to define a variable as IEnumerable and assign the list to this interface. This is because the For Each loop need an explicit GetEnumerable (equal to NewEnum) method to work
Dim objSortedList As mscorlib.SortedList
Dim Enum As mscorlib.IEnumerable
Set Enum = objSortedList
3) If you follow step 2 instruction you will have the For Each loop work, however the single object returned for an HashTable or a SortedList is a DictionaryEntry. This means tha VB 6.0 will not be able to access anyway its properties
All of these problems can be solved coding your own COM class in C#.
This is explained on this Link3 you can also find some info on my blog here and I will soon post some sample projects
Subscribe to:
Posts (Atom)