» Home

  » Developer Guide


Brass SSE Developer Guide - Tutorials

 

Tutorial 9- Bitwise Operators, Win32API Type Conversion and Extensions

In the last tutorial we saw how to import functions from the Win32API. All the Win32API functions use their own types (actually C/C++ types) for variables. This tutorial will explain what Shiny types are compatible with what C types, and how to perform bitwise operations.

 

Type Compatibility

This section is just a table of the most common types you'll find in the Win32API, and what Shiny types are compatible with them.

Shiny Type Win32API Type
string char* (usually byref)
const char* (byval)
LPTSTR (usually byref)
LPCTSTR (byval)
TCHAR (usually byref)
 
int int
UINT
DWORD (via type conversion)
 
double double
int
DWORD (via type conversion)
 
bool BOOL
bool
 
dword DWORD
int (via type conversion)
HWND
COLORREF
HANDLE

 

Bitwise Operations

Bitwise operators are used to manipulate individual bits of data in a dword value. In tutorial 5 you learned how logical operators affect the outcome of boolean tests, for example:

if(a == 1 and b == 2)
{
}

This if statement will only execute if both a is equal to 1 and b is equal to 2.

Bitwise operators work in the same manner on individual bits, rather than on boolean tests. There are 4 bitwise operators: AND, OR NOT and XOR. Shiny supports dual-syntax for them:

VB-like C-like Meaning
bitand & Bitwise AND
bitor | Bitwise OR
bitnot ~ Bitwise NOT
bitxor ^ Bitwise XOR (Exclusive OR)

Here are some sample uses:

// Perform bitwise AND on value of Dword2 and Dword2, store in Result
dword Result = Dword1 bitand Dword2;

// Perform same bitwise AND operation using C-like syntax
dword Result = Dword1 & Dword2;

// Perform bitwise OR with Dword1 and 0x00000001
dword Result = Dword1 bitor 0x00000001;

// Perform same bitwise OR using C-like syntax
dword Result = Dword1 | 0x00000001;

// Perform bitwise NOT with 2 DWORDs
dword Result = 0x00000001 ~ 0x00001000;

// Perform bitwise XOR with 2 DWORDs
dword Result = Dword1 ^ Dword 2;

Bitwise operations are generally used to track state flags in a dword: the win32api uses DWORDs for states a lot.

If you're not particularly familiar with bitwise operations please read this generic tutorial, which explains how bitwise operators work and how to use them. It refers to the C/C++ use of bitwise operators, which is compatible with the C-like syntax of Shiny.

 

Shiny Extensions

We've already seen how to use the import statement to gain access to all of the Win32API functions. There's another side to this import process though.

To allow access to the Win32API, the Shiny Virtual Machine (VM) must convert between Shiny types and C types "on the fly". It has to perform these conversions at the time the function is called. Not only that, the VM is allowing you to call an arbitrary function with an arbitrary return type and an arbitrary number of parameters, none of which is predefined in the VM.

C coders will immediately see the difficulty here! Calling an unknown function by name is easy enough, but passing the right parameters and handling the right return type at runtime when you don't know the function prototype at build time is very difficult.

To allow this the VM has to do some magic behind the scenes. And like everything in software, magic takes time! In the grand scheme of things calling a Win32API function from a plugin isn't particularly slow, but the actual action of the Brass VM setting up, making the call then cleaning up afterwards does take time.

To solve this, Shiny extensions were created. These are DLL's that know about the Shiny VM and the Brass system. Inside these DLL's are all sorts of useful functions that make access to the Win32API easier. Because they understand Shiny types they don't need to perform any conversion on variables before the Win32API calls are made, and that makes the extension DLLs much faster than standard imported Win32API calls.

Using the extensions is exactly like using the Win32API. In the last tutorial you learned that this is how you declare a Win32API import:

import mydll int GiveMeANumber();

 

Using an extension function is exactly the same, except you replace the import statement with an extension statement:

extension mydll int GiveMeANumber();

 

Everything else is exactly the same as importing Win32API functions, including how to declare parameters in the extension statement. Extension functions are also called in the same way.

You should always use extension functions in preference to Win32API functions where possible

Extensions are faster, less likely to cause problems and easier to use.

 

Where to get Extensions

The other great thing about extensions is that the Brass development team can keep releasing new ones all the time. To use an extension simply visit the Extensions main page.

Scroll down the list of extensions until you find one that does what you want, then visit its reference page. On the page will be a link to download the extension DLL - download it and save it to <Brass Install Folder>\Extensions. It will be available for use immediately, you don't have to do anything else.

The reference page for the extension DLL will list all the functions it provides and how to use them.

If you want to give your plugin to other people, remember to make them aware of what extensions they need.

 

Using the SSEdit Extension Wizard

Manually typing in extension declarations is pretty boring, so there's a handy way to speed things up. SSEdit comes with the Shiny Extension Wizard accessible from the View - "Extension Wizard" option or the icon on the toolbar. The Extension Wizard scans your <Brass Install Folder>\Extensions folder and gathers information on all the available extensions.

 

Simply scroll through the extension DLL list until you find the one you want, then select it. A list of all the extension functions in the extension DLL will be added to the bottom listbox. You can then click on a function to see a description, and click the "Add this extension function" button to have SSEdit automatically add the declaration to your code (declarations are inserted at the very top of your source).

You'll notice that SSEdit adds your declarations inside a set of { } braces. There is no technical reason for this, it just allows you to use the "Collapse code" feature (the + and - icons in the margin) to hide your extension declarations for visual purposes.

 

A Quick Recap

This tutorial was short and sweet, to cover some of the extra bits of information you'll need when importing functions from the Win32API.

In this tutorial you saw:

  • Which Shiny types are compatible with which C types
  • How to use bitwise operators
  • All about Shiny extensions
  • The Shiny Extension Wizard

Congratulations - you've finished the tutorial series for the Shiny language, SSEdit and Brass plugins! Now it's time to code your own plugins and share them with the Brass community. If you need any help with SSE development come join us on the forums.