"Sputnik" help  
Sputnik Help
fixed(<keyValuePair>, ...)
{
statements
...
} fixed(<keyValuePair>, ...)~;

Description

The Fixed Statement in Sputnik is used to fix the memory location of a variable or array. By fixing the memory, you can directly access and modify the elements of the variable or array. This can be useful when working with external libraries or when you need precise control over memory management.

Parameters

<keyValuePair> A list of key value pairs in the "$key => $value" format where the "key" will be a variable created holding the pointer to the "value" data.

Remarks

Fixed statements may be nested.

The Fixed Statement in Sputnik provides a powerful mechanism for fixing the memory location of variables or arrays. By fixing the memory, you gain direct access to the elements of the variable or array, allowing for efficient manipulation and precise control over memory management.

When working with low-level operations or performance-critical scenarios, the Fixed Statement becomes particularly valuable. It enables you to optimize your code by eliminating unnecessary memory overhead and reducing the need for data copying.

However, it's crucial to exercise caution when using the Fixed Statement. Fixing a variable or array should only be done when necessary, as it introduces potential risks such as memory leaks or accessing invalid memory regions. Careful attention should be given to proper memory management and ensuring that the fixed statement is used judiciously and correctly.

Once a variable or array is fixed, you can access its elements using pointer arithmetic or direct indexing. This direct access can provide significant performance advantages in certain scenarios, but it also requires a thorough understanding of memory manipulation and the associated risks.

In summary, the Fixed Statement offers a powerful tool for memory control and optimization in Sputnik. It empowers you to fine-tune your code for performance while highlighting the need for responsible memory management practices.

Related

None.

Example

Fixing a Variable:

my $a = (Int32)777;
fixed(my $ptr => $a)
    PtrWrite($ptr, "i", 0, PtrRead($ptr, "i") + 1);
say $a;
// PRINTS
// 778

In the provided code snippet, a variable $a is declared and assigned the integer value 777. Subsequently, the fixed statement is used, which allows for the creation of a fixed pointer ($ptr) to the memory location of the variable $a. The fixed statement is often used in C# to pin a variable in memory, preventing it from being moved by the garbage collector, which can be useful when working with interop scenarios or low-level memory operations.

Within the fixed block, the PtrWrite function is employed to write a new value to the memory location pointed to by $ptr. Specifically, it increments the value at the memory location by 1. The PtrRead function is then used to retrieve the updated value from the memory location.

Finally, the result is printed using the say statement, displaying the incremented value of $a, which is now 778.

In summary, this code showcases the use of the fixed statement to pin a variable in memory, allowing direct manipulation of its memory location, and demonstrates how to increment the value stored in that memory location.

Fixing an Array:

// make we have the plugin to use dllcall
PluginLoad("++SputnikNative");

// make a function to get the cursor position using dllcall
Function GetCursorPos()
{
    // we will use an array with 2 integers to get the mouse position
    my $pos = array((Int32)0, (Int32)0);
    // lock the arrays elements to a fixed point in memory
    fixed(my $ptr => $pos)
    {
        // send that fixed address to the windows api to allow it to write to it
        DllCall(@CallCdecl, "user32.dll", "GetCursorPos", "i", "t", $ptr);
    }
    // return the mouse position
    return $pos;
}

// display it
printr GetCursorPos();

// PRINTS
// Array
// (
//     [0] => 1154
//     [1] => 547
// )

The code snippet provided demonstrates the usage of the Fixed Statement in Sputnik to retrieve the cursor position using a DllCall. The Fixed Statement is used to fix an array with two integer elements to a specific memory location. By doing so, we can pass the fixed memory address to the Windows API function "GetCursorPos" to populate the array with the current mouse position.

First, the necessary plugin "++SputnikNative" is loaded to enable the usage of DLL calls. Then, the function "GetCursorPos" is defined. Inside this function, we create an array named "$pos" with two elements of type Int32 to store the X and Y coordinates of the cursor. The "fixed" statement is used to fix the memory location of the array.

Within the "fixed" block, we declare a pointer variable "$ptr" and assign it the fixed memory address of the "$pos" array. This ensures that the memory location of the array remains unchanged throughout the execution of the block. We then call the "DllCall" function, passing the fixed memory address as an argument to the "GetCursorPos" function from the "user32.dll" library.

After the "fixed" block ends, the "$pos" array now contains the cursor position retrieved from the Windows API. Finally, the "printr" function is used to display the contents of the "$pos" array, which consists of the X and Y coordinates of the cursor.

Executing the code produces the following output:

// PRINTS
// Array
// (
//     [0] => 1154
//     [1] => 547
// )

The output demonstrates that the "GetCursorPos" function successfully retrieves and displays the current mouse position by utilizing the Fixed Statement to lock the array elements to a fixed memory location.

We can optimize the above function by importing the DllCall and thus we dont have to reconstruct it each time:

// make we have the plugin to use dllcall
PluginLoad("++SputnikNative");
// import the GetCursorPos from the Windowws API to Sputnik as the _GetCursorPos function
DllCallImport(@CallCdecl, "user32.dll", "GetCursorPos:_GetCursorPos", "i", "t");

// make a function to get the cursor position using dllcall
Function GetCursorPos()
{
    // we will use an array with 2 integers to get the mouse position
    my $pos = array((Int32)0, (Int32)0);
    // lock the arrays elements to a fixed point in memory
    fixed(my $ptr => $pos)
    {
        // send that fixed address to the windows api to allow it to write to it
        // using the _GetCursorPos function that we defined earlier
        _GetCursorPos($ptr);
    }
    // return the mouse position
    return $pos;
}

// display it
printr GetCursorPos();

// PRINTS
// Array
// (
//     [0] => 1154
//     [1] => 547
// )

The optimization introduced in the updated code snippet improves the efficiency of the GetCursorPos function by importing the DllCall directly. By importing the function as _GetCursorPos using DllCallImport, we eliminate the need to reconstruct the DllCall every time the function is called.

This optimization provides several benefits. First, it reduces the overhead of constructing the DllCall with each function invocation, resulting in improved performance. Second, it enhances code readability and maintainability by abstracting the DllCall implementation details behind a concise and reusable function. Third, it promotes code reuse and modularity, as the imported function can be easily utilized in other parts of the program without duplicating code.

Overall, this optimization improves the efficiency, readability, and maintainability of the code by importing the DllCall and utilizing the defined _GetCursorPos function directly in the GetCursorPos implementation.

It is also possible to use a TypeDef here like so:

PluginLoad("++SputnikNative");
TypeDef(q~ struct { int x; int y; } POINT; ~);
Function
GetCursorPos() { my $pos = (POINT)null; fixed(my $ptr => $pos) DllCall(@CallCdecl, "user32.dll", "GetCursorPos", "i", "t", $ptr); return (POINT)$pos; } printr GetCursorPos();

// PRINTS // Array // ( // [0] => 1154 // [1] => 547 // )

Using the deferred fixed meaning it becomes active until the function ends without needing { } blocks:

Function GetCursorPos()
{
    my $pos = array((Int32)0, (Int32)0);
    fixed(my $ptr => $pos)~;
    DllCall(@CallCdecl, "user32.dll", "GetCursorPos", "i", "t", $ptr);
    return &$pos;
}
printr *GetCursorPos();

// PRINTS
// Array
// (
//     [0] => 1154
//     [1] => 547
// )

In the above example the Fixed statement remains active until the end of the function and is not confined to a { } block however since functions only process their return before the defers and the Fixed statement in this form uses the defer system to process its clean up we would get an empty array. To fix that its sent back as a pointer then dereferenced at the caller to obtain the newly modified array.

We could also use the Rule Return Defer to achieve this like so:

"rd" Function GetCursorPos()
{
    defer $ret = $pos;
    my $pos = array((Int32)0, (Int32)0);
    fixed(my $ptr => $pos)~;
    DllCall(@CallCdecl, "user32.dll", "GetCursorPos", "i", "t", $ptr);
    return $ret;
}
printr GetCursorPos();

// PRINTS
// Array
// (
//     [0] => 1154
//     [1] => 547
// )

This time the rule was used causing the return value to be processed after the defer statement allowing the return value to be up to date after the Fixed statement finished cleaning up.


Contact
Cheryl (uberfox@hotmail.com)
Homepage
http://ubersoft.org