Is there any IsDouble() function in VB6? If I'm not mistaken, Double data type in VB6 is equivalent to float in SQL Server 2000.
Your advice would be much appreciated.
Actually you are much better off using the Vartype function.
Private Function IsDouble(ByVal value As Variant) As Boolean
IsDouble = (VarType(value) = vbDouble)
End Function
Function IsDouble(ByVal varValue As Variant) As Boolean
Dim dblTest As Double
On Error Resume Next
dblTest = CDbl(varValue)
IsDouble = Err.Number = 0
End Function
IsNumeric() is fine, it will only accept values that fit into Doubles. It is regionally aware, i.e. for French regional settings the decimal separator is a comma.
I just tried this in the Immediate window.
Debug.Print IsNumeric("4e308")
False
The definition of a VB6 Double in the manual is "VB6 Double variables are stored as IEEE 64-bit (8-byte) floating-point numbers ranging in value from -1.79769313486232E308 to -4.94065645841247E-324 for negative values and from 4.94065645841247E-324 to 1.79769313486232E308 for positive values".
I think that's the same as a SQL Server float, going by the online docs. "Floating precision number data with the following valid values: -1.79E + 308 through -2.23E - 308, 0 and 2.23E + 308 through 1.79E + 308."
There is no inbuilt IsDouble function available in VB6 instead you can use inbuilt IsNumeric Function. Otherwise you can use following User Defined Function to achieve the same:
Function IsDouble(ByVal value As Variant) As Boolean
Dim convertedValue As Double
On Error Goto EH
convertedValue = CDbl(value)
IsDouble = True
Exit Function
EH:
IsDouble = False
End Function
There's an IsNumeric() function that should work well enough. If that is inadequate for your needs can you also explain in what ways?
Related
In VB6, the function Mid(string, start, [length]) has an optional parameter length. If omitted, the whole characters after the start bound will be passed.
Say I want this default behaviour only in a certain condition:
s = Mid(s, i, IIf(condition, j, TheValue)) ' What could be TheValue?
Since length is of Variant type, I tried Empty. It didn't work. Neither did -1 and Nothing.
I didn't want to duplicate to Mid call in an If-Then-Else clause or somehow else. Is this possible?
Here is a working sample with OP's s = Mid(s, i, IIf(condition, j, TheValue)) line
Option Explicit
Property Get TheValue(Optional RetVal As Variant)
TheValue = RetVal
End Property
Private Sub Form_Load()
Dim s As String
Dim i As Long
Dim j As Long
Dim condition As Boolean
s = "test test test"
i = 6: j = 3
condition = False
s = Mid(s, i, IIf(condition, j, TheValue)) '<--- this works!
Debug.Print s
End Sub
Notice how TheValue returns a "missing" Variant i.e. one which tests positive for IsMissing and can be used in place of optional parameters instead of not passing actual argument.
No such value exists. When you omit the length parameter, the compiler chooses a different path through the VBRT -- it produces different code. If you want to emulate that, you need to do the same thing, using an If-Else or similar construct to handle the two cases, like #ÉtienneLaneville suggests
As an alternative to #Étienne's solution, VB provides the IsMissing method:
Public Function Mid(p_sString As String, p_iStart As Integer, Optional p_iLength As Integer) As String
If IsMissing(p_iLength) Then
Mid = VBA.Mid(p_sString, p_iStart)
Else
Mid = VBA.Mid(p_sString, p_iStart, p_iLength)
End If
End Function
And as this wrapper method returns a string, I suggest using the String verions of Mid, which is Mid$. The later is slightly faster than the Variant version (Mid)
This was nicely explained at this site, but at the time of this posting, the request times out. Not sure if gone forever or just a temporary problem.
You could define your own Mid function:
Public Function Mid(p_sString As String, p_iStart As Integer, Optional p_iLength As Integer = -1) As String
If p_iLength < 0 Then
Mid = VBA.Mid(p_sString, p_iStart)
Else
Mid = VBA.Mid(p_sString, p_iStart, p_iLength)
End If
End Function
This should work with the code from your question, using -1 (or any negative integer) as TheValue.
In c++, std::string these optional arguments are represented by either 0 when the default effect is zero position or length or std::string::npos when it is "infinite" length. You can explicitly supply that value and get the same behaviour.
I don't know what the equivalent constant is in m/s strings [In fact it is a different function definition, so there isn't one]. The alternative would be to pass in the string length, as that is the longest length currently possible.
The ?: ternary operator is an easy way to present 2 values with a condition to choose between them.
I have hunted about quite a bit but can't find a way to get at the Hexadecimal or Binary representation of the content of a Double variable in VB6. (Are Double variables held in IEEE754 format?)
The provided Hex(x) function is no good because it integerizes its input first.
So if I want to see the exact bit pattern produced by Atn(1), Hex(Atn(1)) does NOT produce it.
I'm trying to build a mathematical function containing If clauses. I want to be able to see that the values returned on either side of these boundaries are, as closely as possible, in line.
Any suggestions?
Yes, VB6 uses standard IEEE format for Double. One way to get what you want without resorting to memcpy() tricks is to use two UDTs. The first would contain one Double, the second a static array of 8 Byte. LSet the one containing the Double into the one containing the Byte array. Then you can examine each Byte from the Double one by one.
If you need to see code let us know.
[edit]
At the module level:
Private byte_result() As Byte
Private Type double_t
dbl As Double
End Type
Private Type bytes_t
byts(1 To 8) As Byte
End Type
Then:
Function DoubleToBytes (aDouble As Double) As Byte()
Dim d As double_t
Dim b As bytes_t
d.dbl = aDouble
LSet b = d
DoubleToBytes = b.byts
End Function
To use it:
Dim Indx As Long
byte_result = DoubleToBytes(12345.6789#)
For Indx = 1 To 8
Debug.Print Hex$(byte_result(Indx)),
Next
This is air code but it should give you the idea.
This is more of an "ethical" question than a technical question.
It's very obvious why Eval() and Execute() are dangerous if you allow user-defined data/variables to get passed through them. However, I've always gotten the vibe that the use of these functions is frowned upon no matter what and are only to be used as a last resort.
Anyway, I've used them here and there when it can make coding more efficient and dynamic... but I always make sure I know that what gets passed through the functions are controlled and not user-defined. Would you consider this bad coding? Is there a way a hacker could take advantage of those functions even if it's not reading anything defined by Request or Session variables or any other user-defined data?
If what you pass into the Eval() or Execute() is purely your own string, without any input the user can influence whatsoever, then it should be safe.
However, this also renders a lot of the possibilities of Eval() and Execute() useless.
For example, it is very tempting to use Eval() and Execute() for creating API-like functions, where a user calls a function in a querystring, and you simpley Eval() it instead of using a big select...case for every possible call.
I have also seen it used in CSV parsing, where column names are mapped to recordset-columns using eval(), again, very useful, but extremely dangerous, but you have already demonstrated in your question you are aware of that.
If you are absolutely sure the parsed code is under your complete control, it's very poweerful.
If it's any help, I use this function to replace Eval to a certain degree. It allows you to specify which functions are valid in Eval. To use it simply call Calculate(expression).
'Calculation limitations for use with Calculate function...
Const C_VALID_CALC_CHARS = "0123456789.+-*/()^\=,"
'NOTE: Deliberately broken this const so that it is readable in StackOverflow...
Const C_VALID_CALC_FUNCTIONS = " Abs Asc Atn CBool CByte CCur CDate
CDbl Chr CInt CLng Cos CSng CStr Date DateAdd DateDiff DatePart
DateSerial DateValue Day Escape Exp FormatCurrency FormatDateTime
FormatNumber FormatPercent GetLocale Hex Hour InStr InStrRev Int Fix
IsDate IsEmpty IsNull IsNumeric LCase Left Len Log LTrim RTrim Trim
Maths Mid Minute Month MonthName Now Oct Replace Right Rnd Round Second
Sgn Sin Space Split Sqr StrComp String StrReverse Tan Time Timer
TimeSerial TimeValue UCase Unescape Weekday WeekdayName Year "
'Calculate
' Calculates the expression string and returns a value.
'Usage:
' value = Calculate("Sin(43) * Cos(75)")
'Parameters:
' expression (string) - A string value containing the expression to be evaluated.
'Notes:
' This function provides a controlled method for evaluating specific
' functions but has been severly limited to minimise negative effects
' from hacking attempts. A complete list of available functions and
' symbols can be found in the two variables C_VALID_CALC_CHARS and
' C_VALID_CALC_FUNCTIONS.
Function Calculate(expression)
Dim rV
rV = ""
If expression & "" <> "" Then
Dim t, c, v
'Validate first...
t = expression
'Strip out all standard characters...
For c = 1 to Len(C_VALID_CALC_CHARS)
t = Replace(t, Mid(C_VALID_CALC_CHARS, c, 1), " ")
Next 'c
'Strip out multiple spaces...
Do While Instr(t, " ") > 0
t = Replace(t, " ", " ")
Loop
t = Trim(t)
'Check what we're left with...
v = t = ""
If Not v Then
Dim f
f = Split(t, " ")
v = True
For c = 0 To UBound(f, 1)
v = Instr(C_VALID_CALC_FUNCTIONS, f(c)) > 0
Next 'f
End If
'Define the return value...
If v Then
rV = Eval(expression)
Else
rV = "Invalid Expression!"
End If
End If
Calculate = rV
End Function
It may not be the fastest way to do it, especially if you're using it frequently, but you could use it as a way of validating an equation before launching into it.
I did test it a little while ago, but let me know if you have any problems.
I am running into the Type Mismatch error when I attempt to call a function I created.
Example:
Function DoThis(paramA, paramB, paramC)
If paramA = "Something" Then
DoThis = DoSomething
ElseIf paramA = "This" Then
DoThis = DoSomethingDifferent
Else
DoThis = DoThisOtherThing
End If
End Function
Dim result: result = DoThis(valueA, ValueB, ValueC)
Can anyone see what my mistake could be? Other functions are working correctly. I have double checked the spelling by actually copying and pasting the function name where I call it. I have verified that the function name is not used anywhere else, i.e., as a constant or something else.
Note that when debugging this the ValType for all arguments is vbString. Also I am never able to enter the function, so it is not like I am debugging the function, enter it and then get the type mismatch.
ty.
VBScript has only one data type called a Variant. A Variant is a special kind of data type that can contain different kinds of information, depending on how it is used. Because Variant is the only data type in VBScript, it is also the data type returned by all functions in VBScript.
There are some subtypes of data that a Variant can contain (e.g. Empty, Null, string, integer, object, array etc.) You can use some conversion functions to convert data from one subtype to another, if that conversion is not implicit in VBScript. Now, pay your attention to real, factual data subtype of True and vbTrue.
The True keyword (boolean literal) has a value (inner representation) equal to -1.
On the other hand, vbTrue is one of few built-in constants and, in despite of it's name, has a subtype of Integer! It's one of so-called Tristate Constants:
Constant Value Description
vbUseDefault -2 Use default from computer's regional settings.
vbTrue -1 True
vbFalse 0 False
I hope next code could make clear all above statements:
Wscript.Echo _
vbTrue, CStr( vbTrue), VarType( vbTrue), TypeName( vbTrue) , _
vbNewLine, True, CStr( True), VarType( True), TypeName( True)
However, used with If _condition_ Then ..., there are some particularities; in brief:
The Then part of the If ... statement conditionally executes groups of statements only when a single test If condition is not False, i.e. any non-zero number esteems to be true, not only -1. Therefore you are able to use whatever variable or expression (numeric or string) you choose as long as the result is numeric...
Summarizing: If _expr_ Then ... is the same as
If CBool(_expr_) Then ...
The reason why retval is retuning mismatch error because it has a numeric value and an alpha value and wsh does not like that.
A sure way to get a type mismatch error for the published code is to define DoSomething etc. as Subs (which seems probable, given the names).
I cannot explain why this was a problem, but today I reduced the function down to a simple boolean return value and I still got the type mismatch error.
So I then created a new function with the same parameters and such. When I changed the call to the new function the error goes away.
My original function with the simple boolean return:(MISMATCH ERROR)
Function IsInstalledCheck(valueToCheck, expectedValue, checkType)
IsInstalledCheck = vbFalse
End Function
My new function with the a simple return:(Works)
Function IsItemInstalled(valueToCheck, expectedValue, checkType)
IsItemInstalled = vbFalse
End Function
EDIT
Note that I had tried this with the standard True / False values as well. The solution was to simply recreated the same function with a new name and for whatever magical reason that worked. The function signature was the same, the order of variables, variable names, the test conditions, everything in the body of the new function is the same.
I am a noob to VB and I need to know how its done.
Haven't done VB in 3 years cannot remember much of it.
The textbox has a value in it (5.43), and it needs to be decreased by 0.34.
But this is the code:
TextBox3.Text = Val(TextBox3.Text) -0.34
How do I do this?
THIS IS VB 6 by the way
TextBox3.Text = CDbl(TextBox3.Text) - 0.34
Because your initial value has parenthesis (5.34) you must convert it to a specific number before operating on in.
Val does not recognize values in parens being negative. The Val() function in your original example is converting it to 0 in the same way that val("abcd") will also return 0 because it assumes both are strings.
You can test these conditions in the immediate window to quickly see the results.
Haven't tried it, but could be:
TextBox3.Text = Cdbl(TextBox3.Text) -0.34
The following code will do it:
TextBox3.Text = Cstr(CDbl(TextBox3.Text) - 0.34)
But you should be aware what is going on.
The TextBox does not store a double type, it stores a string type. The above code attempts to convert the string to a double, subtract your constant value from it, and convert it back to a string.
You should ask yourself what should happen if the string in the text box is not a valid number. In the above code, Double.Parse() will throw an exception. Double.TryParse() will return whether the conversion was successful.
Or is it impossible to enter a non-number into the text box? In which case, the safety check is unnecessary, though advisable.
You need to ask these questions when doing type conversions, or your program will behave unpredictably when a value is not convertible to the type you expected.
A safer way to decrement it would be:
Const DECREMENT_VALUE As Double = 0.34
Dim isDouble As Boolean
isDouble = IsNumeric(TextBox3.Text)
If isDouble Then
Dim newValue As Double
newValue = CDbl(TextBox3.Text)
newValue = newValue - DECREMENT_VALUE
TextBox3.Text = CStr(newValue)
Else
MsgBox "The Value was not a Double! Could not Decrement!"
End If
Try this.. It might just work
Dim TxtValue as Integer
TxtValue = TextBox3.Text
Since TxtValue is Integer, the decimal will be automatically dropped.
Like this??
TextBox3.Text=Double.Parse(TextBox3.Text)-0.43
This will work in C#
double number = Convert.ToDouble(textBox1.Text);
number = number - .34;