BASIC: What does an exclamation mark at the end of a function name mean? - basic

DECLARE FUNCTION AanUit! (Baan AS INTEGER, Aktie AS INTEGER)
DECLARE FUNCTION fVraagStatus! (Baan AS INTEGER)
DECLARE FUNCTION fMelding! (Tekst AS STRING, Warning AS INTEGER)
FUNCTION fVraagStatus (VraagBaan AS INTEGER)
´ retrieve status somewhere
fVraagStatus = False or True
END FUNCTION
FUNCTION fMelding (Tekst AS STRING, Warning AS INTEGER)
´ locate (move cursor), print stuff
END FUNCTION
My Question: What does an exclamation mark at the end of a function name mean?
I am rewritting an old program to .net and came across something weird and i want to understand why there is a '!' at the end of the function decleration. I don't really need to write my own code, it's Just for my peace of mind.

It means the function returns a SINGLE. Exclamation point is a shortcut for As Single.

Related

How do I insert a string into another string in Lua?

Is there a function in Lua that returns a string inserted into another one on given position?
For example string.insert(str1, str2, pos).
Using it: string.insert('Hello World!', 'My ', 6) becomesHello My World! and so on.
There is no such function in the standard Lua library. But it's easy to write one:
function string.insert(str1, str2, pos)
return str1:sub(1,pos)..str2..str1:sub(pos+1)
end
Note how it automatically handles negative positions (*), which count from the end of the string, as most other string functions do.
(*) it needs a small change to make pos=-1 work.

How does the Left() function work with the GetWindowsDirectory API when passed a fixed-length string?

I could not make my title both descriptive & concise. I am reading through a book called Power Programming with VBA, and one of the examples uses a Windows API called GetWindowsDirectoryA, which takes the string lpBuffer & long nSize parameters. Once it is declared, the author uses it in a subroutine to retrieve the Windows directory.
What confuses me is the way in which this happens. Here is the code:
#If VBA7 And Win64 Then
Declare PtrSafe Function GetWindowsDirectoryA Lib "kernel32" _
(ByVal lpBuffer As String, ByVal nSize As Long) As Long
#Else
Declare Function GetWindowsDirectoryA Lib "kernel32" _
(ByVal lpBuffer As String, ByVal nSize As Long) As Long
#End If
Sub ShowWindowsDir()
Dim WinPath As String * 255 'Why does this work even if I make it a regular variant string?
Dim WinDir As String
WinPath = Space(255) 'Also works fine if I change this number or comment it out, though if I comment it out, the symbols remain
WinDir = Left(WinPath, GetWindowsDirectoryA(WinPath, Len(WinPath)))
MsgBox WinDir, vbInformation, "Windows Directory"
End Sub
Nothing is wrong with how it works. When I watch it execute step-by-step in the editor, it seems to somehow perform an extra step that isn't obvious to me.
When WinPath is declared it is an empty string with a capacity of 255 characters. I am not sure why this is necessary, since removing the fixed-length nature of the string still works fine.
WinPath is filled with 255 spaces for unknown reasons. It works just as well without this.
Here is my paradox. We are passing WinPath as an argument to Left, but WinPath has only 255 spaces in it, & the second part of Left normally tells it to truncate the 1st parameter to X number of spaces. How does providing GetWindowsDirectoryA(WinPath, Len(WinPath)) circumvent this normal logic, and suddenly produce the result: "C:\Windows"?
I feel like if I understand how this works, it will help me understand how the other APIs do business as well. Btw, the comments in the code are mine, not the author's.
Before a function may be called, all its parameters need to be evaluated. Until that happens, the function is not called yet.
Left has two parameters, and we provide an expression for the second parameter. That expression, GetWindowsDirectoryA(WinPath, Len(WinPath)), has to be evaluated in full before Left is called.
The expression has a side effect of modifying the contents of WinPath, so after GetWindowsDirectoryA() returns, WinPath contains new value.
Only then execution enters Left, and it gets a chance to read the arguments that have been passed to it.
Note that it would not even matter in this case if WinPath was actually pushed on the stack before GetWindowsDirectoryA was executed. If that was the case, it's the variable that is pushed, not its contents. So when Left would have been called, it would have read the WinPath variable from the stack and it would have anyway pointed to the modified data.
As for your concerns about the initial contents of WinPath, the buffer has to be allocated before you call GetWindowsDirectoryA, so you do need to fill it with some throwaway characters such as spaces or vbNullChars. You can do that by having the * 255 modifier or by calling = Space(255), doing both is redundant. Note however that the buffer should be MAX_PATH characters long, which is 260.
When the function is executed, the parameter list needs to be in positive order when it pops up from the stack, so it needs to be in reverse order(from back to front) when loading, GetWindowsDirectoryA executes first, then WinPath gets a value, and then returns the value to the parameter list.
Here's a simple Win32 program.
#include <windows.h>
#include <iostream>
void f(int a, int b)
{
printf("a = %d\nb = %d\n", a, b);
}
int main()
{
int i = 1;
f(i, ++i);
getchar();
return 0;
}
result:
a = 2
b = 2
But not
a = 1
b = 2

Excel VBA Evaluate and non-integer arguments

I've written this function:
Function Resolveq(Equacao As String, Variavel As String, Valor As Double) As Double
Resolveq = Evaluate(Replace(Equacao, Variavel, Valor))
End Function
and tested it with:
the expression (passed to Equacao) 25*EXP(-x/100)
the variable (Variavel) x
the values 18 and 18.25
With the value 18 (or any other integer) the expression is calculated correctly; with 18.25 (or any other non-integer value) Excel returns a #Value! error.
But calculating the same expression with the expression written in a cell, it goes well, with integer and non-integer values.
Can someone, please, give me a light here?
The problem is the parameters of the Replace function are not being used correctly. They are:
Replace (string1, find, replacement, [start, [count, [compare]]] )
The replacement parameter is expecting a string and you are passing a Double.
Convert the Double to a string before you pass it to the function.
Function Resolveq(Equacao As String, Variavel As String, Valor As Double) As Double
Dim ValourStr as String
ValourStr = CStr(Valor)
Resolveq = Evaluate(Replace(Equacao, Variavel, ValourStr))
End Function
This works for me
Sub test()
Dim var As Variant
var = Resolveq("25*EXP(-x/100)", "x", 18.25)
End Sub
And this entered in a cell also works for me
=Resolveq("25*EXP(-x/100)", "x", 18.25)

Excel macro to change the field data type string to long

I have a function which returns value as string.
Function Trimcell(cellvalue As varnant) As String
Trimcell = Replace(CStr(cellvalue), " ", "")
End Function
I want to change the data type string to long . Any help.
Change your function to this:
Function Trimcell(cellvalue As varnant) As Long
Trimcell = Val(Replace(CStr(cellvalue), " ", ""))
End Function
You have a spelling error - varnant instead of Variant.
A better option than using Replace is to use Val which removes blanks, tabs, and linefeed characters from a string and returns a Double. It also stops reading the string at the first non-numeric character apart from period (.) which it recognises as the decimal separator.
As you have declared cellvalue As Variant you shouldn't need CStr either.
Function Trimcell2(cellvalue As Variant) As Long
Trimcell = Val(cellvalue)
End Function

How do you pass a VB string argument to a function written in C?

I have a problem here: I'm trying to pass a VB6 string to a function written in C, but I think it is different from LPSTR. When the function is called, my VB6 IDE crashes. How do I pass a VB string as an argument to a function in C? Below is my code. Thanks to all:
VB6
Private Declare Function WritestStr Lib “teststr.dll” (ByRef mystr As String) As Long
Private Sub command1_Click()
Dim mystr as string
Call WritestStr(mystr)
Msgbox mystr
End Sub
VC6
include “windows.h”
Int __stdcall WritestStr(LPSTR *mystr)
{
*mystr = “Venancio Guedes”;
return 0;
}
It's been eons since I wrote VB/Win32 function declarations, but I'm fairly sure I remember that by default all parameters to an external library function in VB6 are passed byref; however, the VB6 String type is already a pointer-based type, so a byref parameter that is already passed byref pushes the wrong value onto the stack. That causes the reference to crash inside the DLL. Try passing it ByVal, instead, because the "value" of the parameter is really the string pointer itself, which is what the DLL function expects.
As I said, its been a looong time since I wrote these kinds of declarations, so all standard caveats apply, but I'm pretty sure that's close.
Good luck!
EDIT The ByVal declaration for the DLL function is correct. The fix now should be for you to initialize/allocate the string before the call to the DLL function with spaces, eg:
Dim vbString as String
Dim result as Long
vbString = Space$(255) ' just make sure this number is large enough
result = WritestStr(vbString)
VB strings are called BSTR in the OLE documentation, and is almost compatible with LPWSTR. They are null terminated 2 byte per character Unicode (UTF-16) strings, but with a 32 bit length immediately before the memory the string pointer points to.
Your code uses LPSTR*, which is a pointer to a pointer to a 1 byte per character ANSI string. Obviously, you are doing this so as to return your string to the VB6 code.
Unfortunately, these two are incompatible.
The reason why the code crashes is that you are passing the VB6 variable <mystr> to your function, but by default it is set to vbNullString, which is like:
BSTR mystr = NULL;
But your main problem is that VB cannot possibly use your C function as written. There is no way of writing a Declare statement for LPSTR*. If you changed your C code to
include “windows.h”
Int __stdcall WritestStr(LPSTR mystr)
{
const LPSTR myconststr = “Venancio Guedes”;
if (mystr)
int destlen = strlen(mystr);
int srclen = strlen(myconststr);
if (destlen >= srclen)
{
strcpy(mystr, myconststr);
return 0;
}
return srclen;
}
... you could change the declare to:
Private Declare Function WritestStr Lib “teststr.dll” (ByVal mystr As String) As Long
... and ensure you declare a buffer to accept the string.
You could write a Declare statement for LPSTR, but you need to
Private Sub command1_Click()
Dim mystr As string
Dim nLen As Long
mystr = Space$(1024)
nLen = WritestStr(mystr)
Msgbox Left$(mystr, nLen)
End Sub
This is very reminiscent of how most Win32 API functions work.
Passing mystr as ByVal informs VB6 that it must copy <mystr> from BSTR to a temporary LPSTR, and pass a pointer to that buffer. When it has finished executing WriteStr() it then copies the LPSTR buffer back to the original BSTR.
Allocating a VB string buffer <mystr> to pass to your function gives you something to write back into.
Alternatively, you could rewrite your C program to accept a BSTR natively (the cleanest and more portable solution if you want to have mult-languages). In which case your original VB6 declaration would stand i.e. ByRef mystr As String. Unfortunately, you would still have to write into a buffer like you are doing here.
If you want to have LPWSTR*, LPSTR* or BSTR* you will have to declare your function in a type library - something I don't have the time here to talk about.

Resources