guides:machine_code

This is an old revision of the document!


Machine Code

With great appreciation of the original MCode Tutorial by nnnik

Machine code is the lowest level of binary code that your computer can run on. Programming languages like C, C++, Rust, and Go all compile to machine code in order for your computer to understand them. Machine code can run several hundred times faster than equivalent AutoHotkey code, which does not compile to machine code.

In the AutoHotkey community the term "MCode" refers to tools and methods used for putting machine code into scripts. These MCode tools normally take code written in a language like C, use a compiler to turn that code into machine code, then turns that machine code either directly into AutoHotkey code or into text that can be loaded using a custom AutoHotkey library and then called by DllCall.

MCode is important for optimization when writing scripts that need to process a relatively large amount of data quickly. Here are some common situations where MCode can be helpful:

  • Encoding or decoding data more than a few kilobytes in size, in formats like Json
  • Hashing files or large amounts of text
  • Manipulating images like GDI+ bitmaps (especially for custom ImageSearch algorithms)
  • Performing real-time calculations, such as for a physics engine

MCode is not the only way to achieve these performance goals. It is possible, and sometimes more flexible, to use the normal tooling of those compiled languages to produce a standard machine code DLL that can be used from AutoHotkey. However, a script that comes with a custom DLL is harder to share because it takes multiple files, it can take up more disk space than a normal script, and is more likely to be blocked by antivirus and corporate application filters.

Before you can get started with MCode, you will need:

  • Some understanding of how to read and write C or C++ code
  • A basic understanding of how to use DllCall to interact with C APIs (like the Windows API)
  • An MCode library which can create and load MCode
  • A compiler compatible with your chosen MCode library

If you are not very familiar with programming in C or C++, a great place to start is on Codecademy which offers a variety of free interactive programming courses.

There are not very many MCode libraries, but the most comprehensive is MCL [v1][v2]. Other options are listed on the Libraries page.

If using MCL, the easiest compiler to install is likely TDM-GCC if you do not already have a compiler installed. MCL will support most GCC compatible compilers.

Once you have MCL in your Lib folder and a compatible compiler installed, you are ready to begin creating MCode functions.

The simplest function you can create will be one that returns a number, like this:

int MyFunction()
{
  return 42;
}

With the MCL library, MCode functions must be exported to AutoHotkey. You can export a C function using MCL by including the MCL header and calling the MCL_EXPORT(Name, [Type1, Arg1, Type2, Arg2, ReturnType]) macro. Any number of Type/Arg pairs can be included, where Type is the AutoHotkey type that would be given to DllCall and Arg is the parameter name that would be written in AutoHotkey. The ReturnType should be specified for any function that returns a type other than void, and should also match an AutoHotkey DllCall type.

#include <mcl.h>
MCL_EXPORT(MyFunction, Int)
int MyFunction()
{
  return 42;
}

Once you have your appropriate C code, you may give it to MCL.StandaloneAHKFromC(c) in order to be compiled.

This will output a function that you can put into your script that, when called, gives you an object that has your exported functions as methods.

The functions you export can be more complicated than just returning a number. They can do actual work, too.

When testing complicated functions with MCL, it is not always necessary to first generate an includable function and then test your code. Instead, you can use MCL.FromC(c) to go straight from C code to the library object.

Here, we are writing a C function to find the null character at the end of a string, thereby calculating the length of a string:

Once you are done developing your C library, you may use MCL.StandaloneAHKFromC(c) to create the version that cannot be modified but also does not require a compiler to be installed.

In MCode tools other than MCL, recursive functions would not always work correctly. In MCL, they work perfectly normally.

In MCode tools other than MCL, having multiple functions would not work properly without complicated workarounds. You can read more about those workarounds in the original MCode tutorial. In MCL, they work perfectly normally.

MCode libraries generally support generating both 32 and 64 bit machine code, but they may not generate both at once. In MCL, for example, the default is to generate machine code that is the same as the edition of AutoHotkey being used. Running MCL with AutoHotkey U32 will generate 32 bit machine code, and AutoHotkey U64 will generate 64 bit machine code.

Although it is generally recommended to use AutoHotkey U64, when 32 bit is required there are some things to keep in mind. C functions in 32 bit machine code default to the "CDecl" calling convention, which will cause memory leaks if not accounted for. To account for that, you must either adjust any DllCall lines to specify "CDecl" (which you can read more about on the DllCall documentation page) or you can adjust your C function declaration to use the standard calling convention by adding _stdcall to its signature:

int _stdcall SomeFunc(int arg1, int arg2) {}

Because MCL writes the DllCall lines for you, it is recommended to add _stdcall to the signature of any functions being exported for use by 32-bit AHK.