In the last post we saw how to create a UDF in Excel DNA, now let’s look at how to convert an existing UDF into DNA one. Obviously every UDF is different, but hopefully this example will show the process needed, and help you get started in converting your own.
Having worked through this UDF to write the post, I’ve come to the conclusion that its not a brilliant example, so if you have a UDF you’d like to convert why not post the code in the comments and if it looks like a good candidate for conversion I’ll do a post on it.
The UDF we will use is taken from J-walks site [here], I’m using this function because although its not very useful it was a) around at the time (I used this at the UK Excel Dev Con earlier this year), and B) it has some aspects that require a change from VBA to dot Net.
This is the code that John used:
Sub TimeTest()
'100 million random numbers, tests, and math operations
Dim x As Long
Dim StartTime As Single
Dim i As Long
x = 0 StartTime = Timer For i = 1 To 100000000
If Rnd <= 0.5 Then x = x + 1 Else x = x - 1
Next i
MsgBox Timer - StartTime & " seconds"
End Sub
As you can see this is not actually a UDF, so we’re off to a good start! No matter lets convert the above to a VBA UDF:
Public Function RandomWalkVBA()
'100 million random numbers, tests, and math operations
Dim x As Long Dim i As Long
x = 0
For i = 1 To 100000000
If Rnd <= 0.5 Then x = x + 1 Else x = x - 1
Next i
RandomWalkVBA = x
End Function
So now this function will spit out some number after a given amount of time – that is the time it takes to do 100,000000 loops!
Now let’s make this a DNA function, building on the last blog post lets swap out the “My First Function” code and drop in the VBA code and see what happens, the DNA file should contain the following:
<DnaLibrary> <![CDATA[ Public Module Mod1 Public Function RandomWalkVBA() '100 million random numbers, tests, and math operations Dim x As Long Dim i As Long x = 0 For i = 1 To 100000000 If Rnd <= 0.5 Then x = x + 1 Else x = x - 1 Next i RandomWalkVBA = x End Function End Module ]]> </DnaLibrary>
When the function is done it returns a #VALUE! error, why is this? First thing is that the code has compiled OK, and loaded in to Excel, so it’s unlikely to be any of the XML tags or module declarations. Likewise the function is in the wizard so the function declaration is OK. “Dim X as Long” is fairly straight forward, as are loops; so possible causes of the error, but unlikely. That only really leaves:
If Rnd <= 0.5 Then x = x + 1 Else x = x – 1
Looking at this it is conceivable that this could be a problem. If we look at the code we see the Rnd function, which is a VBA method. Also the Then, Else, on one line might not work in VB.Net? Lets comment out that line and get the function to return a string to test our theory.
Close Excel, open the text file, comment out the “IF Rnd” line and change “RandomWalkVBA = x” to “ RandomWalkVBA = “The Function Worked” ”, the DNA file should look like this:
<DnaLibrary> <![CDATA[ Public Module Mod1 Public Function RandomWalkVBA() '100 million random numbers, tests, and math operations Dim x As Long Dim i As Long x = 0 For i = 1 To 100000000 'If Rnd <= 0.5 Then x = x + 1 Else x = x - 1 Next i RandomWalkVBA = "The Function Worked" End Function End Module ]]> </DnaLibrary>
Close the DNA file and load the XLL again, then enter the function. Bingo, the text is displayed, we have found the error. So what to do about it? We can test to see if “Then If” will work, just by changing Rnd to a number, if we do then the function should return the text again, you can test it it you like, but I can tell you it will work ;-). So that just leave the Rnd Function. Lets try it with the rnd function in and the text as the result to check that it’s causing the error, – hun, it worked! So the problem is not in fact the Rnd function, it must be the returning call.
Why do return calls fail? Our experience would tell us its either some bug in the code, or the thing you’re returning at the end of the code is not correct. The variable X is declared as a Long, that seems to be working when the code is run, but not when it gets returned. Strings are returned OK, could it be that the issue is with the long type?
I’m going to save you the heart ache, but when VB went to dot Net, the types changed a bit, this was to make all the common languages (C++ dot Net, C#, F#, VB.Net etc.) work on the same level. Consequently a Long in VB.Net* is no longer the same as a Long it VBA. (Also Variant is gone, use Object instead), so now a long is an Int, but an Int is still and Int… see here for a list of types: http://www.thescarms.com/vbasic/VB6vsVBNet.aspx. Lets convert that Long into an Integer and see what happens!
<DnaLibrary> <![CDATA[ Public Module Mod1 Public Function RandomWalkVBA() '100 million random numbers, tests, and math operations Dim x As Integer Dim i As Long x = 0 For i = 1 To 100000000 If rnd <= 0.5 Then x = x + 1 Else x = x - 1 Next i RandomWalkVBA = x End Function End Module ]]> </DnaLibrary>
Bingo (again) it’s worked, we now have a fully function DNA port of the original VBA function and all we really needed to do was change the longs to Integers – amazing. But I didn’t waste your time, your functions may well be different and you might have to debug them along the way. In later instalments we’ll look at how to use the IDE to debug things, which if you have a large and complex function might be a batter way to go.
Get coding!
*VB.Net still has Long as a type but its 64 bits big, in VB6 a Long is 32 bits big, in dot Net an Integer is 32 bits big – that’s progress!






