QB64 Phoenix Edition
SUB & FUNCTION when declaring dynamic library - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://qb64phoenix.com/forum/forumdisplay.php?fid=3)
+---- Forum: Help Me! (https://qb64phoenix.com/forum/forumdisplay.php?fid=10)
+---- Thread: SUB & FUNCTION when declaring dynamic library (/showthread.php?tid=2790)



SUB & FUNCTION when declaring dynamic library - TerryRitchie - 06-09-2024

I just ran across something that is confusing me.

The User32 function SetCursorPos as outlined here in the Microsoft docs:

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursorpos

is a function. However, it's being declared as a SUB in the Wiki example code here:

https://qb64phoenix.com/qb64wiki/index.php/Windows_Libraries#Mouse_Area

At first I though this was a typo but the code works. Is this a typo that somehow works? Or is it possible to declare FUNCTIONs as SUBs in certain circumstances?


RE: SUB & FUNCTION when declaring dynamic library - Jack - 06-09-2024

Terry, the return value is simply discarded, but SetCursorPos  should be declared as a function
Code: (Select All)

DECLARE DYNAMIC LIBRARY "User32"
  FUNCTION SetCursorPos~& (BYVAL x AS LONG, BYVAL y AS LONG) 'move cursor position
END DECLARE

btw Terry, you probably won't be able to see my post as I seem to be on your ignore list Sad


RE: SUB & FUNCTION when declaring dynamic library - SMcNeill - 06-09-2024

In c, there really is no SUB or FUNCTION.   The main difference is that what basic considers to be a SUB would basically be a Function with a return; with no value attached to it.

For example, let's look at the simple sub_preset:
Code: (Select All)
void sub_preset(float x, float y, uint32 col, int32 passed) {
    if (is_error_pending())
        return;
    if (!(passed & 2)) {
        col = write_page->background_color;
        passed |= 2;
    }
    sub_pset(x, y, col, passed);
    return;
}

See the return there, with no value attached.  That's basically what we'd call a SUB.

And compare that to the FUNCTION Console:
Code: (Select All)
int32 func__console() {
    if (is_error_pending())
        return -1;
    return console_image;
}

See where we return the screen handle for the console there?

That's basically the difference in what we consider to be SUB vs FUNCTION, on the c-side of things.



So, the person who wrote the example for us basically decided that they didn't need the error return value, and they'd rather call it as a SUB than as an errorcode = FUNCTION type routine.

Unless you need the return value, for most c-style routines (like the windows API), you can use SUB instead of FUNCTION. 

Now, if you want that return value, then you're definitely going to want to use FUNCTION when you reference it.  Wink


RE: SUB & FUNCTION when declaring dynamic library - DSMan195276 - 06-09-2024

The short answer is that there are cases where the declaration does not have to be exact and it will still work. You're much better off writing accurate declarations though, declaring it as a `FUNCTION` is correct.

The long answer involves discussion of x86 calling conventions, which are the underlying rules involved in calling functions. In this case it works out because (assuming 64-bit) the RAX register will be used to store the return value, and RAX is also a caller-saved register. This means that when calling the `GetCursorPos()` function the caller has to assume the function may mess with the value of RAX and back it up beforehand if it needs to be kept (regardless of whether the function actually returns anything useful in it). The `GetCursorPos()` will then place the return value in `RAX`, and the calling code will simply ignore whatever value is left in there.

Note that this does not always work, you can see in the Windows section that if a structure is too large to fit into RAX then a different convention of the caller allocating space for the result and passing it to the function is used. In this case, if you did not list the correct return value then things would go very wrong (but then, you can't actually declare such a function in QB64, so it doesn't matter that much).

The different kinds of `DECLARE LIBRARY` are also different levels of forgiving in this regard, because while `Dynamic` will force the function to be the declared type, others like regular `Declare Library` simply insert a call to the specified function and rely in the definition already being provided in the C++ code (via a header or elsewhere).


RE: SUB & FUNCTION when declaring dynamic library - SMcNeill - 06-09-2024

In other words: DECLARE LIBRARY is messy.    Big Grin


RE: SUB & FUNCTION when declaring dynamic library - CharlieJV - 06-09-2024

(06-09-2024, 05:33 PM)TerryRitchie Wrote: I just ran across something that is confusing me.

The User32 function SetCursorPos as outlined here in the Microsoft docs:

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursorpos

is a function. However, it's being declared as a SUB in the Wiki example code here:

https://qb64phoenix.com/qb64wiki/index.php/Windows_Libraries#Mouse_Area

At first I though this was a typo but the code works. Is this a typo that somehow works? Or is it possible to declare FUNCTIONs as SUBs in certain circumstances?

In the world o' BASIC, we have functions and subroutines.  Functions for when we want a value returned, subroutine when we don't want a value returned (I.e. we just want to call the subroutine.)

In the Windows API, we have functions but we do not have subroutines.

When you don't care about the return value for any Windows API function, go ahead and declare it (and use it) as a SUB.  (If the return value is a boolean, as in for SUCCESS or FAILURE, you decide whether or not you want to check that for error handling;  if so, then declare as a function;  if not, then SUB is fine.)

When you do care about the return value for any Windows API function, go ahead and declare it (and use it) as a FUNCTION.

Aside: I'm a Gupta Team Developer programmer by trade.  It has functions but does not have subroutines.  Every function can be used in an expression when we expect a value returned from it.  Every function can also be directly called (like a BASIC subroutine), and the return value is ignored.  (Functions can be defined as either returning a value or not returning any value.)


RE: SUB & FUNCTION when declaring dynamic library - TerryRitchie - 06-09-2024

(06-09-2024, 06:02 PM)Jack Wrote: btw Terry, you probably won't be able to see my post as I seem to be on your ignore list Sad

Huh, you are not on my ignore list? The only one I've ever ignored on a QB64 forum was Clippy. Smile

Thanks for the clarification everyone. I'll stick with declaring them as a function.


RE: SUB & FUNCTION when declaring dynamic library - Jack - 06-09-2024

I miss Clippy Big Grin , yes my political  views were opposite his but I enjoyed Pete's interaction with him.
besides, I have learned not to take politics too seriously.


RE: SUB & FUNCTION when declaring dynamic library - DSMan195276 - 06-09-2024

I think there's something worth clarifying here in regards to `Declare Library` that is non-obvious. In C++ there's a big difference between the two lines in the `mycode` function here:

Code: (Select All)
int externalfunc(int);

int mycode() {
    externalfunc(2); // The return value of externalfunc(2) is ignored

    ((void(*)(int))externalfunc) (2); // externalfunc is treated as a function with no return value, and then called.
}

The first line of `mycode()` is perfectly valid C++ where the return value of a function is ignored. The second line is invalid (but still compiles and runs) where the external function is treated as having no return value at all. C++ makes no guarantees that the second one works, and indeed there are cases where the function will be called incorrectly.

For `Declare Library`, this becomes relevant. If you use regular `Declare Library` to call a function that's already accessible, then the call turns into a line like the first line in `mycode()`. Declaring it as a `SUB` does not matter because the declaration is still correct and the return value simply gets ignored.

If you use `Declare Dynamic Library` or `Declare CustomType Library` then your code is actually turned into something similar to the second line, where the `DECLARE` line is used to generate the function signature. This is where you can get into trouble if you introduce a mismatch.


RE: SUB & FUNCTION when declaring dynamic library - SpriggsySpriggs - 06-11-2024

I often declare external functions as both SUBs and FUNCTIONs (QB64 does not care if you have a SUB and a FUNCTION with the same name), depending on whether or not I'll need to keep the return value. Rather than just make a throwaway temp variable for the function, I'll use it as a SUB and get the same functionality. It boils down to preference on some stuff.