mrider Posted April 16, 2015 Posted April 16, 2015 Here's my situation: I've dinked around with trying to create a C++ object in AutoIt by matching the object declaration as a struct, and failed miserably. No doubt it's because while I understand in principal what "BEGIN_INTERFACE" and "END_INTERFACE" do, I don't really know what they do in actual fact, and consequently I can't replicate that when designing an AutoIt struct. So - I figured I'd write a C DLL that fronts and/or wrappers my C++ objects that will allow me to basically steer them from AutoIt. To validate that I know WTF I'm doing, I figured I'd write a dead simple C++ object and wrapper functions that allow me to communicate back and forth. I can get it all to work if I declare my wrappers as __cdecl, but I can't get it to work if they're declared __stdcall. I'm compiling from mingw. Keep in mind that the code below is only intended to validate my thoughts. So I took some fairly obvious and glaring shortcuts with safety and etcetera because I'm simply validating that I can instantiate a C++ object, and then have it call back to my AutoIt code. We're not necessarily interested in style. What I'm interested in is why AutoIt can't see the functions if they're declared __stdcall. I must be blind, or too close to the problem, because I just can't see why it doesn't work. If I alter everything to use __cdecl it all works swimmingly. With it as is, I get the error printout below. >"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "C:Scriptstest.au3" /UserParams +>12:38:15 Starting AutoIt3Wrapper v.14.801.2025.0 SciTE v.3.4.4.0 Keyboard:00000409 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64 Environment(Language:0409) +> SciTEDir => C:Program Files (x86)AutoIt3SciTE UserDir => C:Program Files (x86)AutoIt3SciTEAutoIt3Wrapper >Running AU3Check (3.3.12.0) from:C:Program Files (x86)AutoIt3 input:C:Scriptstest.au3 +>12:38:15 AU3Check ended.rc:0 >Running:(3.3.12.0):C:Program Files (x86)AutoIt3autoit3.exe "C:Scriptstest.au3" --> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop 'init' not found in the DLL file 'add_callback' not found in the DLL file 'add_callback' not found in the DLL file 'add_callback' not found in the DLL file 'add_callback' not found in the DLL file 'uninit' not found in the DLL file +>12:38:15 AutoIt3.exe ended.rc:0 +>12:38:15 AutoIt3Wrapper Finished. >Exit code: 0 Time: 0.533 All my code: // File: test.h #ifndef _TEST_H_ #define _TEST_H_ #ifdef BUILDING_TEST_DLL #define TEST_DLL __declspec(dllexport) #else #define TEST_DLL __declspec(dllimport) #endif #ifdef __cplusplus extern "C" { #endif void __stdcall TEST_DLL init(void); void __stdcall TEST_DLL uninit(void); void __stdcall TEST_DLL add_callback(const void * callback); void __stdcall TEST_DLL do_callback(void); #ifdef __cplusplus } #endif #endif // _TEST_H_ expandcollapse popup// File: test.cpp #include <stdlib.h> #include <vector> #include "test.h" #define test_callback size_t class TestObject { public: void __stdcall AddCallback(const void * pCallback); void __stdcall DoCallback(void); TestObject(); ~TestObject(); private: std::vector<const void *> m_pCallbacks; size_t m_uiLastIndex; }; TestObject::TestObject() { m_pCallbacks.reserve(10); m_uiLastIndex = 0; } TestObject::~TestObject() { // No action needed since vector cleans up } void __stdcall TestObject::AddCallback(const void * pCallback) { if(pCallback) m_pCallbacks.push_back(pCallback); } void __stdcall TestObject::DoCallback(void) { size_t (*callback) (size_t); callback = (size_t(*)(size_t)) m_pCallbacks[m_uiLastIndex]; callback(m_uiLastIndex); m_uiLastIndex++; if(m_uiLastIndex > (m_pCallbacks.size() -1)) { m_uiLastIndex = 0; } } // C Wrapper functions TestObject * test_object; void __stdcall init() { test_object = new TestObject(); } void __stdcall TEST_DLL uninit(void) { delete test_object; } void __stdcall TEST_DLL add_callback(const void * callback) { test_object->AddCallback(callback); } void __stdcall TEST_DLL do_callback(void) { test_object->DoCallback(); } expandcollapse popupOnAutoItExitRegister("TestDone") Local $func_template = "CallBack%d" Local $handles[4] Local $pointers[4] Local $dll = DllOpen("test.dll") DllCall($dll, "NONE", "init") If @error Then TranslateDllCallError(@error, "init") EndIf For $i = 0 To UBound($handles) - 1 Local $name = StringFormat($func_template, ($i + 1)) $handles[$i] = DllCallbackRegister($name, "ULONG_PTR", "ULONG_PTR") $pointers[$i] = DllCallbackGetPtr($handles[$i]) DllCall($dll, "NONE", "add_callback", "PTR", $pointers[$i]) If @error Then TranslateDllCallError(@error, "add_callback") Else ConsoleWrite("Added pointer " & $i & @LF) EndIf Next For $i = 1 To 10 DllCall($dll, "NONE", "do_callback") Next Func TranslateDllCallError($err, $func) Switch $err Case 1 ConsoleWriteError("Unable to use DLL file" & @LF) Case 2 ConsoleWriteError("Unknown 'return type'" & @LF) Case 3 ConsoleWriteError("'" & $func & "' not found in the DLL file" & @LF) Case 4 ConsoleWriteError("Bad number of parameters" & @LF) Case 5 ConsoleWriteError("Bad parameter" & @LF) Case Else ConsoleWriteError("Unknown error value" & @LF) EndSwitch EndFunc Func CallBack1($param) ConsoleWrite("CallBack1(" & $param & ")" & @LF) Return $param EndFunc Func CallBack2($param) ConsoleWrite("CallBack2(" & $param & ")" & @LF) Return $param EndFunc Func CallBack3($param) ConsoleWrite("CallBack3(" & $param & ")" & @LF) Return $param EndFunc Func CallBack4($param) ConsoleWrite("CallBack4(" & $param & ")" & @LF) Return $param EndFunc Func TestDone() For $i = 0 To UBound($handles) - 1 DllCallbackFree($handles[$i]) Next DllCall($dll, "NONE", "uninit") If @error Then TranslateDllCallError(@error, "uninit") EndIf DllClose($dll) EndFunc :: build.bat @echo off IF EXIST *.dll DEL *.dll IF EXIST *.o DEL *.o IF EXIST *.a DEL *.a g++ -Wall -c -DBUILDING_TEST_DLL test.cpp g++ -shared -o test.dll -static-libgcc -static-libstdc++ test.o -Wl,--out-implib,libtest_dll.a How's my riding? Dial 1-800-Wait-There Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.
FaridAgl Posted April 17, 2015 Posted April 17, 2015 I never successed to do this too, using VC++, however I'm sure I did it all OK. Keeping forward to oit. http://faridaghili.ir
bernd670 Posted May 2, 2015 Posted May 2, 2015 (edited) Hello,I do it always follows!/* * test.h * */ #ifndef TEST_H_ #define TEST_H_ #ifdef BUILD_DLL #ifdef __cplusplus #define DLL_EXPORT extern "C" __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllexport) #endif #else #define DLL_EXPORT #endif DLL_EXPORT void __stdcall init(void); DLL_EXPORT void __stdcall uninit(void); DLL_EXPORT void __stdcall add_callback(const void * callback); DLL_EXPORT void __stdcall do_callback(void); #endif /* TEST_H_ */ expandcollapse popup/* * test.cpp * */ #include "test.h" #include <_mingw.h> #include <minwindef.h> #include <crtdefs.h> #include <vector> BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: // attach to process // return FALSE to fail DLL load break; case DLL_PROCESS_DETACH: // detach from process break; case DLL_THREAD_ATTACH: // attach to thread break; case DLL_THREAD_DETACH: // detach from thread break; } return TRUE; // succesful } #define test_callback size_t class TestObject { public: void __stdcall AddCallback(const void * pCallback); void __stdcall DoCallback(void); TestObject(); ~TestObject(); private: std::vector<const void *> m_pCallbacks; size_t m_uiLastIndex; }; TestObject::TestObject() { m_pCallbacks.reserve(10); m_uiLastIndex = 0; } TestObject::~TestObject() { // No action needed since vector cleans up } void __stdcall TestObject::AddCallback(const void * pCallback) { if(pCallback) m_pCallbacks.push_back(pCallback); } void __stdcall TestObject::DoCallback(void) { size_t (*callback) (size_t); callback = (size_t(*)(size_t)) m_pCallbacks[m_uiLastIndex]; callback(m_uiLastIndex); m_uiLastIndex++; if(m_uiLastIndex > (m_pCallbacks.size() -1)) { m_uiLastIndex = 0; } } // C Wrapper functions TestObject * test_object; DLL_EXPORT void __stdcall init() { test_object = new TestObject(); } DLL_EXPORT void __stdcall uninit(void) { delete test_object; } DLL_EXPORT void __stdcall add_callback(const void * callback) { test_object->AddCallback(callback); } DLL_EXPORT void __stdcall do_callback(void) { test_object->DoCallback(); }with the following compiler optionsfor Debug Version:g++ -DBUILD_DLL -O0 -g3 -Wall -c -fmessage-length=0 -o test.o "..\\test.cpp" g++ -s -mwindows -Wl,--add-stdcall-alias -Wl,--kill-at -static-libgcc -static-libstdc++ -shared -Wl,--out-implib=TestDLL.lib -Wl,--output-def=TestDLL.def -o TestDLL.dll test.oand for Release Version:g++ -DBUILD_DLL -O3 -Wall -c -fmessage-length=0 -o test.o "..\\test.cpp" g++ -s -mwindows -Wl,--add-stdcall-alias -Wl,--kill-at -static-libgcc -static-libstdc++ -shared -Wl,--out-implib=TestDLL.lib -Wl,--output-def=TestDLL.def -o TestDLL.dll test.o Edited May 3, 2015 by bernd670 greetingsbernd I hacked 127.0.0.1 ->
mrider Posted May 5, 2015 Author Posted May 5, 2015 (edited) First off, sorry it took a few days to respond - I didn't notice the new post until now. It looks like you are using 64 bit MinGW, where I'm using 32 bit. I had to change the includes a bit in test.cpp in order to get it to compile, since "minwindef.h" and "crtdefs.h" is not included with my version. I'm not sure if that's why this doesn't work for me or what, but now AutoIt crashes when the function returns. The good news is that AutoIt can find the function though - so I'm a bit closer. So thanks for that, I'll investigate further when I have some free time...Not that this is that big of a deal, it's just annoying that I can only use cdecl. Edited May 5, 2015 by mrider How's my riding? Dial 1-800-Wait-There Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.
bernd670 Posted May 5, 2015 Posted May 5, 2015 (edited) Hello, for me it also works with the 32 bit version of mingw. I only #include <minwindef.h> #include <crtdefs.h>replaced by#include <windef.h>and then with the same compiler options compiled as mentioned above.Important as well as the option is#AutoIt3Wrapper_UseX64=nin AutoIt.With this scriptexpandcollapse popup#AutoIt3Wrapper_UseX64=n OnAutoItExitRegister("TestDone") Local $func_template = "CallBack%d" Local $handles[4] Local $pointers[4] Local $dll = DllOpen("TestDLL.dll") DllCall($dll, "NONE", "init") If @error Then TranslateDllCallError(@error, "init") EndIf For $i = 0 To UBound($handles) - 1 Local $name = StringFormat($func_template, ($i + 1)) $handles[$i] = DllCallbackRegister($name, "ULONG_PTR", "ULONG_PTR") $pointers[$i] = DllCallbackGetPtr($handles[$i]) DllCall($dll, "NONE", "add_callback", "PTR", $pointers[$i]) If @error Then TranslateDllCallError(@error, "add_callback") Else ConsoleWrite("Added pointer " & $i & @LF) EndIf Next For $i = 1 To 10 DllCall($dll, "NONE", "do_callback") Next Func TranslateDllCallError($err, $func) Switch $err Case 1 ConsoleWriteError("Unable to use DLL file" & @LF) Case 2 ConsoleWriteError("Unknown 'return type'" & @LF) Case 3 ConsoleWriteError("'" & $func & "' not found in the DLL file" & @LF) Case 4 ConsoleWriteError("Bad number of parameters" & @LF) Case 5 ConsoleWriteError("Bad parameter" & @LF) Case Else ConsoleWriteError("Unknown error value" & @LF) EndSwitch EndFunc Func CallBack1($param) ConsoleWrite("CallBack1(" & $param & ")" & @LF) Return $param EndFunc Func CallBack2($param) ConsoleWrite("CallBack2(" & $param & ")" & @LF) Return $param EndFunc Func CallBack3($param) ConsoleWrite("CallBack3(" & $param & ")" & @LF) Return $param EndFunc Func CallBack4($param) ConsoleWrite("CallBack4(" & $param & ")" & @LF) Return $param EndFunc Func TestDone() For $i = 0 To UBound($handles) - 1 DllCallbackFree($handles[$i]) Next DllCall($dll, "NONE", "uninit") If @error Then TranslateDllCallError(@error, "uninit") EndIf DllClose($dll) EndFuncI get the resultAdded pointer 0 Added pointer 1 Added pointer 2 Added pointer 3 CallBack1(0) CallBack2(1) CallBack3(2) CallBack4(3) CallBack1(0) CallBack2(1) CallBack3(2) CallBack4(3) CallBack1(0) CallBack2(1)I hope my English is somewhat understandable Edited May 15, 2015 by bernd670 greetingsbernd I hacked 127.0.0.1 ->
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now