I'll break down a C API binding string from that other thread:
private __safe foreign handler _ReadBackAnalogOut (out rBuffer as CInt) returns nothing binds to "c:K8055D>ReadBackAnalogOut!stdcall"
private -- means this handler will be invisible outside of the context of the current Extension module.
__safe -- there is safe and unsafe context, I'm a bit sketchy on this. The docs say: Foreign handlers are always considered unsafe, and thus may only be called from unsafe context - i.e. from within an unsafe handler, or unsafe statement block. The _safe keyword seems to be undocumented, I've only seen it used with C APIs, but the bottom line is foreign handlers that have this keyword can be called outside of a safe/unsafe block.
foreign handler -- as opposed to a regular handler, this let's us know we are binding to some external code
_ReadBackAnalogOut -- the name we'll be using to call this foreign handler, naming conventions here are up to your own discretion
(out rBuffer as CInt) -- inside the parens are declaring what the the foreign handler is expecting to receive (in) or send back (
out) or both (inout) when this external code is being called. In this case it's declaring that the foreign code will return a parameter that should be a C signed integer (
as CInt) but you might also be able to use LCB's type 'as Number' or any other variable type that's compatible with a C signed int. When I say compatible what I mean is the data can fit, byte size wise, into the type you're declaring. So make sure you're using the correct type. A unsigned C integer (as CUint) can fight a signed int, but will give you the wrong number range. rBuffer is an arbitrarily named variable but the lead 'r' is a commonly used convention for indicating it's a variable that's being return.
returns nothing -- the foreign code will return nothing (null) at least not in the normal way, in the case of this handler the variable you pass for 'rBuffer' is will be filled (out) with the result of the foreign code. With many APIs the return value here will simply be 'returns CBool (or Boolean) that indicates success or failure of the call.
binds to -- Always needed, just indicates the next quoted string is the actual binding string for the foreign handler, that gives libFFI some clues about the code being called.
"c:K8055D>ReadBackAnalogOut!stdcall" --
The binding string starts with "
c:" which says the library or API we want is C based. It can be one of c: java: or objc: (and maybe others? js:? And I see mention of Pascal in the docs).
Followed by
K8055D>, so K8055D is the library or API name to look for, followed by '>'. The actual foreign code library can be included in platform_cpu specifically named folders in your extension project folder, or the foreign code library may be an API (or .Framework for MacOS) part of the OS or in user installed common shared library folder in the OS. I'm not sure of the exact order that memory or directories are searched for libraries / function symbols. Like if there were two copies of the same library available, I'm not sure if it would load the included copy first or another one in the system one first.
ReadBackAnalogOut -- ReadBackAnalogOut is the name of the actual function we want to use from the foreign code library.
!stdcall is the calling convention, with C on windows this is one of default, stdcall, thiscall, fastcall, cdecl, pascal, register All but default are Win32-only. I've only had to change this once so far, most of the time you probably don't need to worry about it. On Java / Android this can be one of instance, static, or nonvirtual. I haven't done much with Android in some time so I don't know anything about those calling conventions.
Now in some regular handler you then call like _ReadBackAnalogOut( tMyCint ), tMyInt would be an integer variable you've already declared in the calling handler with 'variable tMyInt as CInt' or variable tMyInt as Integer'.
A lot of times the the returned data or object may need further processing to get the data into a format that's useful for our scripting language. For example ObjC's NSColor Red Blue Green components might be floating point numbers between 0.00000 and 1.00000, so we would multiply them by 255 to get to be 8 bit RGB values we can use with our scripts language.
The binding strings look a bit different depending on if you're binding to c:, java:, or objc: foreign code. You can, and in the case of Apple probably need to, mix c: and objc: APIs together in the same module (C based CoreAudio AND Objective C based AVAudio APIs for example)
The foreign code is only resolved when it's called so you won't know if you got the foreign binding strings correct until you actually try to use that foreign handler.
Besides knowing how to bind to the foreign code, you will probably need to learn about the API you're trying to use first. And of course there's bound to be some 'gotchas' along the way too. Like for examples dealing with returned data that's in a different byte order, or maybe you get back a Pointer to data or an Object that exists elsewhere and need to parse the block of data a pointer points to (variable foreign type declarations is a whole other thing to know) or need to query an object for its relevant properties.
Once you start to get the feel of it, it does get a little easier. I've used ChatGPT to type out a lot of binding strings for me nowadays, and most of the time it even makes valid binding strings.
https://github.com/OpenXTalk-org/OpenXT ... -naming.md
https://github.com/OpenXTalk-org/OpenXT ... form-id.md
https://github.com/OpenXTalk-org/OpenXT ... cedence.md
https://github.com/OpenXTalk-org/OpenXT ... ference.md
https://github.com/OpenXTalk-org/OpenXT ... 20Guide.md
https://github.com/OpenXTalk-org/OpenXT ... g%20OXT.md
https://github.com/OpenXTalk-org/OpenXT ... ference.md