As promised a bit more in detail regarding the previous part. The official info about extensions is here, it also has examples for other languages. Let’s have a closer look at C++ function RVExtension, which is the entry and exit point of our .dll extension (extern “C” is of no concern to us, it is a compiler linkage directive):

void __stdcall RVExtension(char *output, int outputSize, const char *function) {}

When extension is called from ArmA the function param will contain whatever argument we supplied with callExtension command:

extension = "mydllname"; function = "whatever we send to RVExtension"; extension callExtension function;

After this command is executed ArmA will search for mydllname.dll file. If found, function param in RVExtension inside .dll will become ‘whatever we send to RVExtension’. Also the actual mydllname.dll file will now get associated with ArmA and you won’t be able to delete or overwrite it without closing ArmA first. But this is not all. outputSize will also receive a value. This value is assigned by the ArmA engine automatically and this value indicates the maximum size of output ArmA will expect to receive back. It can be less but it cannot be more.

The developer obviously wishes to stay flexible with this one as it probably somehow affects their freedom to modify the engine if it is fixed. This is why if you’re planning to send something back to ArmA from your extension you have to check if it fits inside the allowance. If your output is bigger you will have to make arrangements and send it in parts.

Since extensions were introduced the outputSize changed several times. It started with 4kB, then it was increased to 16kB. Last time I checked it was 10kB. You probably don’t have to worry about it if your output is quite small, but if your extension accesses a database for example, then you should definitely perform the size checks. Oh yes of course, the output param is obviously for your output. To send anything back to ArmA use strncpy_s as demonstrated in Part 1 (I assume you have sufficient C++ knowledge to use this command) .

Now let’s talk about callExtension. This command is as fast as call command and it is also blocking command, just like call. This means that it will wait for RVExtension function to finish in case there is an output to receive. This is why it is in your interest to exit RVExtension function as soon as possible. Any delay introduced here will affect the engine scheduling for the whole game.

If you need to access a database or you have heavy calculation going on or maybe you want to fetch info from the Internet (especially if those are repeated tasks) – you should not let the game wait. What you should do is access RVExtension, start worker thread from it and exit immediately, then come back later and check if you have your result ready to be collected.

I have  tried thread-less solution with my debug console #1 and threaded with debug console #2. I can tell you right now, threaded solutions are the way to go. I have also made very fast MySql driver using threaded solution, which I’m going to share as soon as I have documentation ready. But for the moment this should do, should get you started on your first extension.


Part 3, how to make extension in C#