Advanced Language Features
From Xojo Documentation
Contents
These language features are not commonly used on most projects and are for advanced users.
External Methods
An External Method adds a reference to an external method which can be a method on a DLL (on Windows), a dylib (on macOS) or a shared library (on Linux). You can also use the Declare command to create an external method.
External Methods are not supported on iOS. Use the Declare command instead.
External methods are added using Insert ↠ External Method for a class or module. In the Inspector for the External Method, you can provide the necessary information, including:
- Method Name
The name of the method. This is the name you will use to call the method. - Parameters
The parameters required by the method. - Return Type
The return type of if the method is a function. - Scope
The scope of the method matches the scoping rules for items in a module or class. - Lib
The library containing the method. - Alias
This is optional and refers to the actual method name in the library. You only need to provide it if you are using a different Method Name than what the method is called in the library. - Soft
Select Soft to only check if the method exists at run-time, rather than when the app launches. - Objective-C
Select Objective-C to add an external method to an Objective-C method. This changes the Alias field to say "Selector" where you can specify the selector to call the method.
For more information on creating External Methods, refer to the Declare command in the Language Reference.
Structures
A Structure is a compound value type. It consists of a series of fields that are grouped together as a single block. You control the size and order of the fields. A structure provides a convenient alternative to a MemoryBlock as they are also often used to group together information for external function calls.
The values of structures have specific sizes giving the structure its own specific size.
You typically only use structures when you have very specific memory or performance requirements or when you need to interface with an outside API that requires a structure. In most cases, you will want to use Classes with appropriate properties for your data management.
Structures are added to project items such as modules, classes and windows. To add a structure, select the Add button on the toolbar and select Structure from the menu (or use the Insert menu in the main menu bar). This displays the Structure Editor where you specify the fields in the structure and their sizes.
Use the “+” button to add a new field. Fields are added by entering their name followed by the type in this form:
So to enter an Integer you would do:
Note that when you enter a field, it shows the size. This is the amount of bytes that the field uses in the structure. Integers use 4 bytes (in 32-bit apps), for example.
You can prefix a name with an underscore (_) in order to hide it from auto-complete.
Array of Bytes
The preferred way to deal with strings of text in a Structure is to create an array of Bytes, which you can do like this:
Strings
Not supported on iOS. Use an Array of Bytes instead.
Strings are a special case because you have to specify the exact size of the string in bytes. Unlike normal strings, a string in a structure always takes up the specified size in the structure and you cannot exceed it. Also, strings in structures do not contain encoding information. The syntax is:
So to have a String with a size of 50:
When you are creating a structure to pass to an external method, be sure that your sizes precisely match the sizes specified by the API of the method.
Usage
When you are creating a structure to pass to an external method, be sure that your sizes precisely match the sizes specified by the API of the method.
You can reference structure members using dot notation:Structures are useful for organizing data, but they are not object-oriented and are limited in many ways (such as with string sizes). For your project’s internal data management, you should almost always use a class over a structure.
However, structures are small and memory efficient. In addition to being useful when used with external methods and Declares, they may also be useful in specific situations where memory must be managed carefully.
Blank and Comment Lines
When creating your structure, you can leave specific lines blank (nothing for the description) or you can enter a comment for the description. These lines are properly ignored.
Structure Alignment
Structure alignment refers to aligning the data at a memory offset equal to some multiple of the word size. Data alignment can increase the computer's performance.
Structures can be aligned using Attributes. You add the attribute "StructureAlignment" to a structure and use one of the legal values: 1, 2, 4, 8, 16, 32, 64, and 128 as the value.
To specify a structure alignment, add an attribute to the Attribute List in the Inspector. Specify "StructureAlignment" in the Name field and enter the desired alignment value.
64-bit Notes
The Integer data type varies in size for a 32-bit or 64-bit app. For a 32-bit app, an Integer is 4 bytes. For a 64-bit app, an Integer is 8 bytes. In the Structure Editor, 32-bit sizes are shown by default. If you want to see 64-bit sizes, turn the "Show 64 bit Sizes" property to ON in the advanced Inspector for the structure.
Delegates
A Delegate data type is an object representing a specific method. Delegates are an advanced feature that decouple interface from implementation in a similar way to events or interfaces. This decoupling allows you to treat a method implementation as a variable that is changeable based on run-time conditions. They represent methods that are callable without knowledge of the target object. You can change the function the delegate points to on the fly.
A Delegate can be declared in either a module or a class. You use the Insert→Delegate menu command or the Add button on the toolbar in the Code Editor to create a Delegate entry, which appears under the containing object. A delegate must have a name and can have optional parameters and a return type. To use a delegate, you have to point it to an address for a method. You can do this using the AddressOf or WeakAddressOf commands. Only methods that match the parameters and return type (the signature) of the delegate may be assigned to the delegate.
When the Delegate contains the address of a method, you can call the method using the Invoke method of the Delegate.
To try out a quick example, create a Delegate on a window and call it MethodCaller. Also on the window, create two methods: TestMethod and AnotherMethod. Each with this code:
Since these two methods have the same signature they can be assigned to a Delegate and called using the Invoke method. This code in the Action event handler of a Button calls a different method depending the state of a CheckBox:
If MethodCheck.Value Then
callMethod = AddressOf TestMethod
Else
callMethod = AddressOf AnotherMethod
End If
callMethod.Invoke
You can also create a delegate using an external function that returns a pointer. That code would look like this: