guides:machine_code

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
guides:machine_code [2024-01-02 15:14] – [3. Multiple Functions] Show the MCode4GCC strategy geekguides:machine_code [2024-01-02 16:18] (current) – Add section 6, Importing functions geek
Line 357: Line 357:
 Although there are many things you can do with MCode, sometimes it is helpful or even necessary to callback to AutoHotkey for some actions. For example, it can be extremely valuable to call back to AutoHotkey for OutputDebug, MsgBox, or other debugging-oriented logging tools. Although there are many things you can do with MCode, sometimes it is helpful or even necessary to callback to AutoHotkey for some actions. For example, it can be extremely valuable to call back to AutoHotkey for OutputDebug, MsgBox, or other debugging-oriented logging tools.
  
-AutoHotkey provides a tool to export its own functions to be consumed as a callback from C/C++ APIs, [[https://www.autohotkey.com/docs/v2/lib/CallbackCreate.htm|CallbackCreate]], which can be used very easily with your own MCode functions as well. The simplest way to do this is to create your callback, then pass it as a parameter to the function.+AutoHotkey provides a tool to export its own functions to be consumed as a callback from C/%%C++%% APIs, [[https://www.autohotkey.com/docs/v2/lib/CallbackCreate.htm|CallbackCreate]], which can be used very easily with your own MCode functions as well. The simplest way to do this is to create your callback, then pass it as a parameter to the function.
  
 <runner ahk2> <runner ahk2>
Line 412: Line 412:
  
 It may be tempting to try to use CallbackCreate in order to wrap mathematical functions like Sqrt, however this should be avoided normally because it will absolutely destroy any performance gains that you were aiming to achieve by using MCode in the first place. Instead, native machine code implementations of sqrt and other mathematical functions should be embedded or imported. It may be tempting to try to use CallbackCreate in order to wrap mathematical functions like Sqrt, however this should be avoided normally because it will absolutely destroy any performance gains that you were aiming to achieve by using MCode in the first place. Instead, native machine code implementations of sqrt and other mathematical functions should be embedded or imported.
 +
 +==== 6. Importing Functions ====
 +
 +Writing C or %%C++%% code in an MCode environment, without any access to the standard libraries, can be extremely limiting. These limits can be eased significantly by importing key functions from DLLs that ship with Windows, or from third-party DLLs that you have on hand.
 +
 +The basic strategy is this:
 +
 +  - Load the DLL using AutoHotkey
 +  - Fetch the function pointer using AutoHotkey
 +  - Pass that function pointer using the same strategy we did for CallbackCreate
 +  - Call that function from your MCode
 +
 +For example, we can import ''sqrt'' from ''msvcrt.dll'' in order to do some mathematical calculations:
 +
 +<runner ahk2>
 +#Requires AutoHotkey v2.0
 +
 +if !(hDll := DllCall("GetModuleHandle", "Str", "msvcrt", "Ptr"))
 + throw OSError(,, "Failed to find DLL msvcrt")
 +if !(pFunction := DllCall("GetProcAddress", "Ptr", hDll, "AStr", "sqrt", "Ptr"))
 + throw Error(,, "Failed to find function sprintf from DLL msvcrt")
 +
 +;double hypotenuse(double (*sqrt)(double), double a, double b) {
 +; return sqrt(a * a + b * b);
 +;}
 +lib := MCode("2,x86:8g8QRCQI8g8QTCQQi0QkBPIPWcDyD1nJ8g9YwfIPEUQkBP/g,x64:8g9ZyfIPWdJmDyjB8g9Ywkj/4Q==")
 +
 +MsgBox DllCall(lib, "Ptr", pFunction, "Double", 3.0, "Double", 4.0, "Cdecl Double")
 +
 +MCode(mcode) {
 +  static e := Map('1', 4, '2', 1), c := (A_PtrSize=8) ? "x64" : "x86"
 +  if (!regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", &m))
 +    return
 +  if (!DllCall("crypt32\CryptStringToBinary", "str", m.3, "uint", 0, "uint", e[m.1], "ptr", 0, "uint*", &s := 0, "ptr", 0, "ptr", 0))
 +    return
 +  p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")
 +  if (c="x64")
 +    DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", &op := 0)
 +  if (DllCall("crypt32\CryptStringToBinary", "str", m.3, "uint", 0, "uint", e[m.1], "ptr", p, "uint*", &s, "ptr", 0, "ptr", 0))
 +    return p
 +  DllCall("GlobalFree", "ptr", p)
 +}
 +</runner>
 +
 +When working with MCL, importing functions like this can be handled automatically by the ''MCL_IMPORT'' macro. Any standalone loader generated by MCL that has an import like this will automatically include any AHK-side import loading code that would otherwise have to be written manually. Imports done this way are automatically added to the global scope, so they do not have to be passed as a parameter to DllCall.
 +
 +<runner ahk2>
 +#Requires AutoHotkey v2.0
 +#include <MCL>
 +
 +lib := MCL.FromC("
 +(
 +#include <mcl.h>
 +MCL_IMPORT(double, msvcrt, sqrt, (double));
 +
 +double hypotenuse(double a, double b) {
 + return sqrt(a * a + b * b);
 +}
 +)")
 +
 +MsgBox DllCall(lib, "Double", 3.0, "Double", 4.0, "Cdecl Double")
 +</runner>
 +
 +MCL can also be used to import functions from third-party DLLs, such as lua54.dll. For more information about that, please refer to the [[libraries:machine_code:mcl|library page for MCL]].
 ===== Compatibility Notes ===== ===== Compatibility Notes =====