{"name":"callExtension","operator":null,"title":"callExtension","type":"command","url":"https://community.bistudio.com/wiki/callExtension","revid":378445,"updated":"2026-04-14T14:09:53Z","groups":["System"],"status":"ok","replaced_by":[],"games":[{"game":"arma2oa","name":"Arma 2: Operation Arrowhead","version":"1.60"},{"game":"tkoh","name":"Take On Helicopters","version":"1.00"},{"game":"arma3","name":"Arma 3","version":"0.50"}],"since":{"game":"arma2oa","name":"Arma 2: Operation Arrowhead","version":"1.60"},"arma3_since":"0.50","branch":null,"locality":{"argument":null,"effect":null,"server_exec":false},"exec":null,"description":"Calls custom .dll also known as Extension. The name of the extension is the name of the extension .dll without \".dll\" part (or without \"_x64.dll\" part on 64-bit Arma). For example if the file is 'myExtension.dll' the name of the extension will be \"myExtension\". For 64-bit extensions, the name of the extension doesn't need to change and is still \"myExtension\". The game will automatically look for 'myExtension_x64.dll' when you use 64-bit Arma exe.\n\nThis command is blocking, meaning that the game will wait for the extension to return before continuing. This may cause FPS drop if extension is not optimised. If extension takes too long, consider making asynchronous extension, where the result of the work of the extension is collected in a separate call.\n\nCurrently there is no limit how much data you can send to the extension. However there is a limit on how much data you can return from extension in one call. The limit is known to the extension and is passed in `int outputSize`. The limit may or may not change in the future and is currently 10240 bytes. It is up to extension designer to handle multipart results if returned data exceeds output limit.\n\nSince Arma 3 v1.68 it is possible to pass array of arguments to extensions. The array of arguments could be anything and all elements will be converted to strings, however you might want to only send simple types like Booleans, Strings, Numbers and Arrays of all of the above. There is currently a limit on how many arguments can be sent and it is 2048 (since Arma 3 v1.92; previous limit: 1024). However an argument could be an Array itself, in this case extension maker will have to provide additional methods for parsing such arguments.\n\nPossible error codes:\n- 101: SYNTAX_ERROR_WRONG_PARAMS_SIZE\n- 102: SYNTAX_ERROR_WRONG_PARAMS_TYPE\n- 201: PARAMS_ERROR_TOO_MANY_ARGS\n- 301: EXECUTION_WARNING_TAKES_TOO_LONG\n- Arma 3 v2.22 400: EXTENSION_LOAD_FAILED\n- Arma 3 v2.22 403: EXTENSION_BLOCKED_BY_BATTLEYE\n- Arma 3 v2.22 404: EXTENSION_NOT_FOUND\n- Arma 3 v2.22 412: EXTENSION_BLOCKED_BY_SCRIPT\n- Arma 3 v2.22 415: EXTENSION_WRONG_ARCHITECTURE\nEach error will have entry in .rpt file with more details.\n\nThe extension execution timeout, after which `301: EXECUTION_WARNING_TAKES_TOO_LONG` warning is issued, is hardcoded on clients and is 1000.0 milliseconds (1 second). On the server the default limit is also 1 second, however it is possible to set custom limit with `callExtReportLimit` param (see Server Options).\n\nIf an extension with the given name cannot be found (or it is found but doesn't implement the required interface properly / at all) the following error will be written into the RPT (In this example the given dll-name was \"MyExtension\"):\n`14:27:07 CallExtension 'MyExtension' could not be found`\n\nIf an extension is not whitelisted with BattlEye (see Extensions for more info) it will be blocked on clients running with enabled BattlEye protection. RPT message outputted however is a little obscure:\n`21:35:04 Call extension 'MyExtension' could not be loaded: Insufficient system resources exist to complete the requested service`\n\nSince Arma 3 v1.70, `RVExtensionVersion` interface (see source code example below) has been added, which is called by the engine on extension load and expects extension version. This interface is designed to work with both, Linux and Windows. The max buffer size is 32 bytes. The version information will then appear in .rpt file like so:\n`19:06:36 CallExtension loaded: test_extension (.\\test_extension.dll) [1.0.0.1]`\n\nFor more information see Extensions.\n\nLinux specific\n\nWhile on Windows the extension name is case-insensitive, on Linux the extension name is case-sensitive and should match the name of the .so file exactly (minus \".so\" part).\n\n> [!IMPORTANT]\n> If a user has **anti-virus software real time protection running**, this could cause brand new extension to stutter the game and return with `EXECUTION_WARNING_TAKES_TOO_LONG` when executed for the first time, because of the AV software scanning.\n> After the extension is whitelisted by AV this should go away until a new version of the extension is installed.\n> Perhaps a dummy call to the extension on init should be considered as a feature of implementation to account for that.\n\n**Extension Context**\n\nSince Arma 3 v2.12 the engine will call the `RVExtensionContext` method (if it exists, see #Example 4) and pass the following data:\n- `steamID` of the client calling extension getPlayerUID or \"0\"\n- `fileSource` from which the extension was executed or \"\" if done on the fly\n- `missionName` missionNameSource\n- `serverName` serverName","syntaxes":[{"syntax":"extension callExtension function","since":null,"effect":null,"exec":null,"params":[{"name":"extension","type":"String","optional":false,"default":null,"description":"extension name","types":["String"],"since":null,"text":"extension: String - extension name"},{"name":"function","type":"String","optional":false,"default":null,"description":"data sent to the extension","types":["String"],"since":null,"text":"function: String - data sent to the extension"}],"returns":{"type":"String","types":["String"],"description":"data sent back from extension; If the extensiion was not found an empty String will be returned","text":"String - data sent back from extension; If the extensiion was not found an empty String will be returned"},"form":"binary","operator":null,"left":{"text":"extension","types":["String"]},"right":{"text":"function","types":["String"]}},{"syntax":"extension callExtension [function, arguments]","since":"arma3 1.68","effect":null,"exec":null,"params":[{"name":"extension","type":"String","optional":false,"default":null,"description":"extension name","types":["String"],"since":null,"text":"extension: String - extension name"},{"name":"function","type":"String","optional":false,"default":null,"description":"extension function identifier","types":["String"],"since":null,"text":"function: String - extension function identifier"},{"name":"arguments","type":"Array of Anything","optional":false,"default":null,"description":"function arguments. Each element will be converted to String automatically. Current allowed max length of this array is 2048 (since Arma 3 v1.92; previous limit: 1024)","types":["Array","Anything"],"since":null,"text":"arguments: Array of Anything - function arguments. Each element will be converted to String automatically. Current allowed max length of this array is 2048 (since Arma 3 v1.92; previous limit: 1024)"}],"returns":{"type":"Array with [result, returnCode, errorCode]","types":["Array"],"description":"result: String - data sent back from extension. It is up to extension maker what it is. - returnCode: Number - integer return from extension method. It is up to extension maker to define it. - errorCode: Number - error code in case of command error (see description). 0 means no errors.","text":"Array with [result, returnCode, errorCode]\n- result: String - data sent back from extension. It is up to extension maker what it is.\n- returnCode: Number - integer return from extension method. It is up to extension maker to define it.\n- errorCode: Number - error code in case of command error (see description). 0 means no errors."},"form":"binary","operator":null,"left":{"text":"extension","types":["String"]},"right":{"text":"[function, arguments]","types":["Array"]}}],"examples":[{"text":"```sqf\n_return = \"myExtension\" callExtension \"stringToBeParsed\";\n```","code":["_return = \"myExtension\" callExtension \"stringToBeParsed\";"]},{"text":"```sqf\n_result = \"test_extension\" callExtension str weapons player;\n_result = \"test_extension\" callExtension [\"fnc1\", getUnitLoadout player];\n_result = \"test_extension\" callExtension [\"fnc2\", magazinesAmmoFull player];\n_result = \"test_extension\" callExtension [\"fnc1\", [weapons player, magazines player]];\n```","code":["_result = \"test_extension\" callExtension str weapons player;\n_result = \"test_extension\" callExtension [\"fnc1\", getUnitLoadout player];\n_result = \"test_extension\" callExtension [\"fnc2\", magazinesAmmoFull player];\n_result = \"test_extension\" callExtension [\"fnc1\", [weapons player, magazines player]];"]},{"text":"```sqf\n_result = \"test_extension\" callExtension [\"fnc1\", [1, \"two\", true, [4, \"five\", false]]];\nparseSimpleArray (_result select 0) params [\"_number\",\"_string\",\"_boolean\",\"_array\"];\nsystemChat str [_number,_string,_boolean,_array];\n```\n\nSource Code ()\n\nThis is an example of an extension compatible with both syntaxes. When using 1st syntax, the data is just copied from input to output. When using alt syntax, the arguments are parsed and then assembled back into string array in 2 ways: fnc1 and fnc2. fnc1 is a fraction faster.\n\n```cpp\n#include <string>\n#include <vector>\n#include <iterator>\n#include <sstream>\n\n#define CURRENT_VERSION \"1.0.0.1\"\n\nextern \"C\"\n{\n    //--- Engine called on extension load\n    __declspec (dllexport) void __stdcall RVExtensionVersion(char *output, int outputSize);\n    //--- STRING callExtension STRING\n    __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);\n    //--- STRING callExtension ARRAY\n    __declspec (dllexport) int __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **args, int argsCnt);\n}\n\n//--- Extension version information shown in .rpt file\nvoid __stdcall RVExtensionVersion(char *output, int outputSize)\n{\n    //--- max outputSize is 32 bytes\n    strncpy_s(output, outputSize, CURRENT_VERSION, _TRUNCATE);\n}\n\n//--- name callExtension function\nvoid __stdcall RVExtension(char *output, int outputSize, const char *function)\n{\n    std::string str = function;\n    strncpy_s(output, outputSize, (\"Input Was: \" + str).c_str(), _TRUNCATE);\n}\n\n//--- name callExtension [function, args]\nint __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **args, int argsCnt)\n{\n    if (strcmp(function, \"fnc1\") == 0)\n    {\n        //--- Manually assemble output array\n        int i = 0;\n        std::string str = \"[\";\n\n        //--- Each argument can be accessed via args[n]\n        if (argsCnt > 0)\n            str += args[i++];\n\n        while (i < argsCnt)\n        {\n            str += \",\";\n            str += args[i++];\n        }\n\n        str += \"]\";\n\n        //--- Extension result\n        strncpy_s(output, outputSize, str.c_str(), _TRUNCATE);\n\n        //--- Extension return code\n        return 100;\n    }\n\n    else if (strcmp(function, \"fnc2\") == 0)\n    {\n        //--- Parse args into vector\n        std::vector<std::string> vec(args, std::next(args, argsCnt));\n\n        std::ostringstream oss;\n        if (!vec.empty())\n        {\n            //--- Assemble output array\n            std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<std::string>(oss, \",\"));\n            oss << vec.back();\n        }\n\n        //--- Extension result\n        strncpy_s(output, outputSize, (\"[\" + oss.str() + \"]\").c_str(), _TRUNCATE);\n\n        //--- Extension return code\n        return 200;\n    }\n\n    else\n    {\n        strncpy_s(output, outputSize, \"Avaliable Functions: fnc1, fnc2\", outputSize - 1);\n        return -1;\n    }\n}\n```","code":["_result = \"test_extension\" callExtension [\"fnc1\", [1, \"two\", true, [4, \"five\", false]]];\nparseSimpleArray (_result select 0) params [\"_number\",\"_string\",\"_boolean\",\"_array\"];\nsystemChat str [_number,_string,_boolean,_array];"]},{"text":"Since Arma 3 v2.12: \n\n```sqf\nhint (\"myExtContext\" callExtension \"\");\n```\n\nHere is a minimal example:\n\n```cpp\n#include <string>\n#include <vector>\n#include <iterator>\n#include <sstream>\n#include <iomanip>\n\nBOOL APIENTRY DllMain(    HMODULE hModule,\n                        DWORD ul_reason_for_call,\n                        LPVOID lpReserved)\n{\n    switch (ul_reason_for_call)\n    {\n        case DLL_PROCESS_ATTACH:\n        case DLL_THREAD_ATTACH:\n        case DLL_THREAD_DETACH:\n        case DLL_PROCESS_DETACH:\n            break;\n    }\n    return TRUE;\n}\n\nstd::vector<std::string> contextInfo;\n\nextern \"C\"\n{\n    //--- User entry point\n    __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);\n    //--- Engine passed context\n    __declspec (dllexport) void __stdcall RVExtensionContext(const char **args, int argsCnt);\n}\n\n//--- name callExtension function\nvoid __stdcall RVExtension(char *output, int outputSize, const char *function)\n{\n    //--- Not used here\n    (void)function;\n\n    if (!contextInfo.empty())\n    {\n        std::ostringstream oss;\n        const char qt = '\"';\n\n        for (auto it = contextInfo.begin(); it != contextInfo.end() - 1; ++it)\n            oss << std::quoted(*it, qt, qt) << \",\";\n        oss << std::quoted(contextInfo.back(), qt, qt);\n\n        //--- Send context info back\n        strncpy_s(output, outputSize, (\"[\" + oss.str() + \"]\").c_str(), _TRUNCATE);\n    }\n}\n\n//--- Context is executed first, copy it\nvoid __stdcall RVExtensionContext(const char **args, int argsCnt)\n{\n    contextInfo.assign(args, std::next(args, argsCnt));\n}\n```","code":["hint (\"myExtContext\" callExtension \"\");"]}],"multiplayer":null,"problems":null,"aliases":[],"see_also":["freeExtension","call","compile","parseSimpleArray","Extensions"],"notes":[],"categories":["Arma 2: Operation Arrowhead: New Scripting Commands","Arma 2: Operation Arrowhead: Scripting Commands","Arma 3: Scripting Commands","Command Group: System","Introduced with Arma 2: Operation Arrowhead version 1.60","Scripting Commands","Take On Helicopters: Scripting Commands"]}