Dear all, I'm struggling with passing an ExternalAddress to a c function call with uFFI. Firstly, I get the ExternalAddress from this method: myFFI>>create: aString ^ self ffiCall: #(void * CreateObject (String aString) ) [in c: void* CreateObject(char* szProgId)] The method that uses the resulting ExternalAddress is defined as: myFFI>>ask: anExternalAddress ^ self ffiCall: #(void CallMethod (void * anExternalAddress) ) [in c: void CallMethod(void* myObj)] In playground I have | w | w := myFFI create: 'Word.Application'. myFFI ask: w . w gets a "nice", properly looking external address, however the last line crushes Pharo, its window gets closed. I went through the uFFI book, however I cannot find the answer. I'm on Windows 10 x64, Pharo 7.0.4 32-bit. Best wishes, Tomaz
Hi Thomas, Can you share more about the definition of your CallMethod function in C?
From the uFFI point of view the binding looks okâ¦
How are you opening Pharo? From the command line or the pharo launcher? Are you on cygwin/mingw? One other possibility (since youâre playing with C libraries) is to launch Pharo inside a gdb/lldb so you can check the reason behind the error when it crashes. Keep us posted, Guille
El 10 sept 2019, a las 19:53, Tomaž Turk <tomaz.turk@ef.uni-lj.si> escribió:
Dear all,
I'm struggling with passing an ExternalAddress to a c function call with uFFI. Firstly, I get the ExternalAddress from this method:
myFFI>>create: aString ^ self ffiCall: #(void * CreateObject (String aString) )
[in c: void* CreateObject(char* szProgId)]
The method that uses the resulting ExternalAddress is defined as:
myFFI>>ask: anExternalAddress ^ self ffiCall: #(void CallMethod (void * anExternalAddress) )
[in c: void CallMethod(void* myObj)]
In playground I have
| w | w := myFFI create: 'Word.Application'. myFFI ask: w .
w gets a "nice", properly looking external address, however the last line crushes Pharo, its window gets closed.
I went through the uFFI book, however I cannot find the answer.
I'm on Windows 10 x64, Pharo 7.0.4 32-bit.
Best wishes, Tomaz
Hi, thanks for your quick reply. I found the culprint while writing this email :-) Generally, what I'm trying to do is to make a very basic package to create and communicate with COM components on Windows, mostly as an exercise :-) I found this library: http://disphelper.sourceforge.net/ as a great start, so you don't have to fiddle with OLE/COM headaches. The problematic function in C is defined as: __declspec(dllexport) void CallMethod(void* myObj) { ... } It takes a pointer to a COM object, which was previously returned by __declspec(dllexport) void* CreateObject(char* szProgId) { ... IDispatch * myObj = NULL ... return &myObj; } So, CreateObject() creates COM object and returns a pointer to it, CallMethod() takes this pointer and tries to communicate with it. My error was in returning a pointer to a pointer ... since IDispatch * myObj = NULL was actually hidden in a macro and I missed its true definition, huh. I'm running Pharo from PharoLauncher directly on Win10, without cygwin/mingw. For DLL I use Visual Studio 2019. I was not sure whether the pointer survives from one FFI call to another, or how Pharo loads/unloads DLLs - but it works as expected. Thanks again and best wishes, Tomaz ------ Original Message ------ From: "Guillermo Polito" <guillermopolito@gmail.com> To: "Tomaž Turk" <tomaz.turk@ef.uni-lj.si>; "Any question about pharo is welcome" <pharo-users@lists.pharo.org> Sent: 11. 09. 2019 10:29:34 Subject: Re: [Pharo-users] uFFI ExternalAddress challenges
Hi Thomas,
Can you share more about the definition of your CallMethod function in C? From the uFFI point of view the binding looks okâ¦
How are you opening Pharo? From the command line or the pharo launcher? Are you on cygwin/mingw? One other possibility (since youâre playing with C libraries) is to launch Pharo inside a gdb/lldb so you can check the reason behind the error when it crashes.
Keep us posted, Guille
El 11 sept 2019, a las 11:07, Tomaž Turk <tomaz.turk@ef.uni-lj.si> escribió:
Hi, thanks for your quick reply.
no problem ;)
I found the culprint while writing this email :-)
Cool!
Generally, what I'm trying to do is to make a very basic package to create and communicate with COM components on Windows, mostly as an exercise :-) I found this library: http://disphelper.sourceforge.net/ <http://disphelper.sourceforge.net/> as a great start, so you don't have to fiddle with OLE/COM headaches.
The problematic function in C is defined as:
__declspec(dllexport) void CallMethod(void* myObj) { ... }
It takes a pointer to a COM object, which was previously returned by
__declspec(dllexport) void* CreateObject(char* szProgId) { ... IDispatch * myObj = NULL ... return &myObj; }
So, CreateObject() creates COM object and returns a pointer to it, CallMethod() takes this pointer and tries to communicate with it.
My error was in returning a pointer to a pointer ... since IDispatch * myObj = NULL was actually hidden in a macro and I missed its true definition, huh.
Yes, looking at the code above it seems strange returning the &myObj, being myObj a local variable. Because that means that you would be returning a pointer to the stack, from a frame that already returned...
I was not sure whether the pointer survives from one FFI call to another
Well, the pointer survives, the area of memory pointed by that pointer will be recycled with subsequent calls in general.
, or how Pharo loads/unloads DLLs - but it works as expected.
In general Pharo will load the library on usage, so you donât have to care about it. Iâm sure the library is not unloaded, unless it is done explicitly (you can check VirtualMachine >> unloadModule:)
Thanks again and best wishes, Tomaz
Cheers!
Well, the pointer survives, the area of memory pointed by that pointer will be recycled with subsequent calls in general.
I'll pay special attention to that, but it's probably a matter of properly creating and releasing COM objects. I have another question - in FFI call, how would one send a wide string, as in void CallMethod(void * COMObj, wchar_t * MethodName) I might have additional questions about UTF-8 and other code page nuances ... Best wishes, Tomaz
El 11 sept 2019, a las 11:43, Tomaž Turk <tomaz.turk@ef.uni-lj.si> escribió:
Well, the pointer survives, the area of memory pointed by that pointer will be recycled with subsequent calls in general.
I'll pay special attention to that, but it's probably a matter of properly creating and releasing COM objects.
I have another question - in FFI call, how would one send a wide string, as in
void CallMethod(void * COMObj, wchar_t * MethodName)
I might have additional questions about UTF-8 and other code page nuances â¦
:D Windows is particularly different than other platforms. In *nixes most APIs require a char* with the encoded bytes, which we can encode in Pharo doing something like âmy stringâ utf8Encoded => a byte array with the encoded string But for windows, I think the best is to use their encoding APIs. Youâll find the image already has some support for that, that we use to access environment variables and the working directory string. Check the class Win32WideString and its class comment ;)
Best wishes, Tomaz
participants (2)
-
Guillermo Polito -
Tomaž Turk