xbelanch 11 Posted July 28, 2016 Hi everyone, After reading the BIS documentation of how to create extensions (https://community.bistudio.com/wiki/Extensions) and see examples from KK's blog I tried to make the same sample but on Cygwin (MSYS-2) but It's doesn't work. I do appreciate some help from anyone with more experience than me. I share the code and the compilation command lines: Source code (my1st.cpp): // Windows Header Files: #include <Windows.h> #define DLLEXPORT __declspec(dllexport) extern "C" { DLLEXPORT void __stdcall RVExtension(char *output, int outputSize, const char *function); } void __stdcall RVExtension(char *output, int outputSize, const char *function) { strncpy_s(output, outputSize, "IT WORKS!", _TRUNCATE); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Command line compilation: g++ -c -o my1st.o my1st.cpp g++ -o my1st.dll my1st.o -s -shared -Wl,--subsystem,windows Share this post Link to post Share on other sites
Arkensor 96 Posted July 28, 2016 Hey there, under windows either install the VS2013 compiler kit for VS2015 or just install the enitre VS2013. Then make a new dll, without any predefined code. You won't need anything that VS thinks you would need there. Use code from Killzonekids blog, or maybe have a look at my extension (see signature), to have a basic structure. then compile for x86, make sure to use vs2013 compiler, as arma players have that Redistributable Package installed, and do your testing. To compile under linux, I would suggest looking into my mentioned project, as a how to compile and the commands are included as well as the src for that. Regards Arkensor Share this post Link to post Share on other sites
xbelanch 11 Posted July 28, 2016 Thanks for your answer @Arkensor. I have installed VS2010 and it works perfectly to build the "Hello world" sample from KK's blog. I'm used to work with cygwin for developing my own projects and that was the reason I'm finding a way to build arma 3 extensions properly with that environment. Also I took a look on your notes of how to compile on Linux. I found it very helpful but at the moment my focus is on see if I can find a workaround before I give it up ;) and move finally to VS. Share this post Link to post Share on other sites
Foxyy 16 Posted July 30, 2016 First i would find out if your DLL exports the interface function. One way to do this is using DUMPBIN. To do this you must open the Visual Studio developer command prompt, and execute DUMPBIN like so. dumpbin /EXPORTS "my/path/myextension.dll" If all goes well you should see output similar to this. Dump of file myextension.dll File Type: DLL Section contains the following exports for myextension.dll 00000000 characteristics 578F8D42 time date stamp Wed Jul 20 17:40:02 2016 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00014F5F _RVExtension@12 = @ILT+3930(_RVExtension@12) Summary 1000 .00cfg 1000 .data 1000 .gfids 2000 .idata 7000 .rdata 2000 .reloc 1000 .rsrc 2B000 .text 13000 .textbss 1000 .tls Note the export _RVExtension@12. This is what Arma looks for when you use callExtension. Share this post Link to post Share on other sites
xbelanch 11 Posted July 31, 2016 Hi Foxyy. Yep. It does, but it doesn't work. Here's the output after compiling with next g++ parameters: g++ -shared -fPIC -m32 -std=c++11 test.cpp -o test.dll -Wl,--subsystem -Wl,windows -Wl,--out-implib=libtest.dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import If I test the result with file test.dll it results: test.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows and here's the result after execute dumpbin /exports test.dll Dump of file test.dll File Type: DLL Section contains the following exports for test.dll 00000000 characteristics 579E0DA9 time date stamp Sun Jul 31 16:39:37 2016 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00001570 RVExtension@12 Summary 1000 .CRT 1000 .bss 1000 .data 2000 .debug_abbrev 1000 .debug_aranges 7000 .debug_info 2000 .debug_line 1000 .debug_loc 1000 .debug_ranges 1000 .debug_str 1000 .edata 1000 .eh_frame 1000 .idata 1000 .rdata 1000 .reloc 2000 .text 1000 .tls I don't have a big experience with .dlls but it seems that .dlls built with mingw doesn't like to Arma 3 ;) It'd be great if it works... hope you have more luck and skills than me! PS: the same file compiled by cl /LD test.cpp /link /out:test.dll File Type: DLL Section contains the following exports for testMSVC.dll 00000000 characteristics 579E0EA6 time date stamp Sun Jul 31 16:43:50 2016 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00001000 _RVExtension@12 Summary 2000 .data 2000 .rdata 1000 .reloc 5000 .text Share this post Link to post Share on other sites
Foxyy 16 Posted July 31, 2016 1 0 00001570 RVExtension@12 You've exported the function incorrectly. The name should be _RVExtension@12 . Note the underscore at the beginning. Share this post Link to post Share on other sites
xbelanch 11 Posted July 31, 2016 (edited) Ouch! alright... but that's the compiler do :-/ it seems to be closed to this thread: http://stackoverflow.com/questions/35701657/how-to-implement-the-rvextension-function-for-an-arma-3-dll-in-rust UPDATE: This http://stackoverflow.com/questions/2804893/c-dll-export-decorated-mangled-names, this http://stackoverflow.com/questions/2810118/how-to-tell-the-mingw-linker-not-to-export-all-symbols and this http://www.transmissionzero.co.uk/computing/advanced-mingw-dll-topics/ helped me a lot to understand much better the challenge. After spending several hours dealing with it I achieved the same symbol name that exports Visual Studio but still doesn't work uu Edited August 1, 2016 by xbelanch Share this post Link to post Share on other sites
Foxyy 16 Posted August 1, 2016 Alright, if the function is exported correctly now, next you might try rigging up a little test case to call the function yourself. #include <iostream> #include <Windows.h> int main() { HMODULE module = LoadLibrary("myextension.dll"); if (!module) { std::cout << "!module" << std::endl; return; } FARPROC farproc = GetProcAddress(module, "_RVExtension@12"); if (!farproc) { std::cout << "!farproc" << std::endl; return; } auto* function = reinterpret_cast<void (__stdcall*)(char*, size_t, const char*)>(farproc); char buffer[10240]; buffer[0] = 0; function(buffer, sizeof(buffer), "my extension arguments"); std::cout << "result:" << buffer << std::endl; return 0; } Something like this ought to do. Then you can fire up your favourite debugger and get debugging. Share this post Link to post Share on other sites
xbelanch 11 Posted August 1, 2016 test.cpp source code: #include <Windows.h> #include <string.h> extern "C" __declspec(dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function) { outputSize -= 1; if (!strcmp(function,"version")) { strncpy(output,"1.0",outputSize); } else if (strcmp(function, "function") == 0) { strncpy(output, "return of a function", outputSize); } else { strncpy(output,function,outputSize); } } // Normal Windows DLL junk... BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } compilation command lines: gcc -W -c -o test.o test.cpp && dllwrap -s -o test.dll --def test.def test.o -Wl,--subsystem -Wl,windows -Wl,--enable-stdcall-fixup where test.def is: EXPORTS _RVExtension@12 = RVExtension if I execute your helpful testing code it works: $ ./foxyy.exe result:1.0 same source code compiled with VS CL I obtain the same result: cl /LD test.cpp /link /out:test2.dll Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.dll /dll /implib:test.lib /out:test2.dll test.obj Creating library test.lib and object test.exp Dumpbin /exports of the binary generated with g++: File Type: DLL Section contains the following exports for test.dll 00000000 characteristics 579F5C22 time date stamp Mon Aug 01 16:26:42 2016 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00001570 _RVExtension@12 Summary 1000 .CRT 1000 .bss 1000 .data 1000 .edata 1000 .eh_fram 1000 .idata 1000 .rdata 1000 .reloc 1000 .rsrc 2000 .text 1000 .tls Share this post Link to post Share on other sites
Foxyy 16 Posted August 1, 2016 Clearly your library works. Does Arma load it? To find out you should first call it using callExtension. Next there are a variety of ways to find out which modules are loaded by a process. You could do it programmatically, for example using the .NET Process class and its Modules property. You could also attach a debugger such as the one integrated in Visual Studio. Personally i tend to use the more lightweight Cheat Engine for such simple tasks. Or you could use the Windows Resource Monitor (Vista and later), which lists the modules loaded by a process in the CPU tab under associated modules. Of course in all cases you should disable BattlEye, as the rootkit it installs makes peering this information a bit trickier. If your module is indeed loaded, but still you get the wrong results in game, i suggest you attach a debugger to the game process and breakpoint your code to step through it and see what is going on. Share this post Link to post Share on other sites
xbelanch 11 Posted August 2, 2016 No... Arma doesn't load it. I checked it with Process Explorer. Arma loads the dlls (as you said) dinamically every time you use callExtension (and that works if I check it with a dll built with VS). Maybe I must open a ticket at https://feedback.bistudio.com/? Share this post Link to post Share on other sites
Arkensor 96 Posted August 2, 2016 Arma loads the dll on first call, and keeps it until the arma procrss ends. Its a static library, it wont be loaded every time sou call it. To find out if the dll is loaded, do a output back to arma and log it into rpt or try to move the dll. If arma made love with it, you wont be able to move the dll, as it is in use. Share this post Link to post Share on other sites
xbelanch 11 Posted August 2, 2016 Yep, alright... "dinamically" wasn't correct. I understand (and sorry in advance if I'm wrong) when you say "loads the dll on first" it refers at the time that any sqf calls the function callExtension. Before that Arma doesn't load any third-party dlls (and this makes sense for safety reasons I guess) and following that logic you can put a new dll while Arma is running and load it (always at your own risk xD) Share this post Link to post Share on other sites
killzone_kid 1330 Posted August 2, 2016 Are you running Arma with BattlEye? Because unless it is whitelisted with BE it will not load. Share this post Link to post Share on other sites
Foxyy 16 Posted August 2, 2016 Are you running Arma with BattlEye? Because unless it is whitelisted with BE it will not load. I believe OP mentioned that when building with MSVC, everything worked as expected so i assume this is not the problem. Also last time i tried it BattlEye did not block loading extensions in singleplayer in Arma 3, like it does in Arma 2, though this could since have changed. Share this post Link to post Share on other sites
killzone_kid 1330 Posted August 2, 2016 I believe OP mentioned that when building with MSVC, everything worked as expected so i assume this is not the problem. Also last time i tried it BattlEye did not block loading extensions in singleplayer in Arma 3, like it does in Arma 2, though this could since have changed. I had many comments on the blog about extensions not working only to find out it was due to BE blocking them. I never asked how and when people were using them. Share this post Link to post Share on other sites
xbelanch 11 Posted August 2, 2016 Are you running Arma with BattlEye? Because unless it is whitelisted with BE it will not load. Yep. MSVC built is fully working without no problem with BE... I started to think that the problem with Mingw dll is related to .CRT (http://stackoverflow.com/questions/15822048/using-mingw-to-build-a-windows-dll-that-depends-on-visual-studio-crt-msvcr110-d) Share this post Link to post Share on other sites
Foxyy 16 Posted August 3, 2016 If you're sure your library is not getting loaded by the game, next i would breakpoint LoadLibraryExA and GetProcAddress in kernelbase.dll and check the last error after each call to figure out why one of them is failing. Share this post Link to post Share on other sites
gossamersolid 155 Posted August 3, 2016 How about you run arma 3 without BE to prove that's not the cause. It has definitely blocked my client side dll before. Share this post Link to post Share on other sites
xbelanch 11 Posted August 3, 2016 Color me embarassed. Well... what can I say? Good news? It works. Bad news? It was because BE :( My apologies... I've lost the general picture shrinking my mind on the dll compilation output. Anyway... very thanks for helping me. :) Now we can say that Mingw can build extensions for Arma 3 Share this post Link to post Share on other sites
Foxyy 16 Posted August 3, 2016 Of course it can, like any other C++ compiler. You said before that the library built with MSVC worked. Did you also use BE then, and did that not get blocked, while the library built with MinGW did? It seems very odd to me that BE would act differently depending on the compiler used to build the library. Share this post Link to post Share on other sites
xbelanch 11 Posted August 3, 2016 My bad. I was launching Arma the whole time directly from the exe not from the launcher... lesson learned and sorry for wasting your time :( Share this post Link to post Share on other sites