On 23 May 2014, at 2:52 , Henrik Johansen <[email protected]> wrote:
> > On 23 May 2014, at 2:36 , Torsten Bergmann <[email protected]> wrote: > >> Hi, >> >> as there was no responded so far I tried to track the problem deeper and did >> a short test >> client in C/C++ to verify if I can call WKHTMLTOPDF there and generate a PDF >> and to >> compare to the Pharo/NativeBoost client. >> >> Attached is the according CPP file which works and results in a PDF with the >> google >> homepage. >> >> I also additionally implemented the callback functions in the Pharo wrapper >> and >> using the error handling I noticed that the component returns "Failed >> loading page http:// ..." >> >> >> With that info I compared the C/C++ calls to the Pharo/NativeBoost calls >> more deeply and >> found out that in C/C++ the following call for an object setting works (by >> returning 1): >> >> >> // this returns 1 in C/C++ which is OK >> int a = wkhtmltopdf_set_object_setting(os, "page", >> "http://www.google.de"); >> printf("object set %i",a); >> >> >> while in Pharo the same call fails (by returning 0): >> >> "The following call failed and returns 0 instead of 1" >> self setObjectSetting: 'page' to: 'http://www.google.de' in: os. > > With argument type char * , NB does not 0-terminate your strings, but passes > in the argument you provided raw. > ByteStrings have an internal representation size a multiplum of 4, thus > ‘page’ will have no accidentally terminating 0, while ‘out’ does, and the > call fails since whatever garbage bytes are in the image after the string > instance (‘page’) leads to the it not being recognized as a valid property > name. > > Change the call definitions to use String as argument type instead, and NB > will convert the args to zero-terminated strings for you: > > NBFFICallout stdcall: #(int > wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, String > aName, String value)) module: 'wkhtmltox.dll' > > Alternatively, you need to provide null-terminated strings yourself: > > x := self setObjectSetting: ('page' , (Character value: 0) asString) to: > 'http://www.google.de', (Character value: 0) asString) in: os. > > Which also returns makes it return 1. > > Cheers, > Henry To test it then *actually* worked, I implemented: getObjectSetting: aName in: settings into: value ofSize: vs <primitive: #primitiveNativeCall module: #NativeBoostPlugin> ^NBFFICallout stdcall: #(int wkhtmltopdf_get_object_setting(wkhtmltopdf_object_settings* settings, String aName, char* value, int vs)) module: 'wkhtmltox.dll' Note, you *cannot* use String for a parameter being written to, while NB in that case would pass along a zero-terminated copy for you, it does *not* copy the contents back into the actual string instance @ end of call. It’s also easy to spot garbage characters added when value was // 4 = 0 (using char * definition): x := self setObjectSetting: (‘page' , Character null asString) to: 'http://www.google.de' in: os. "http://www.google.de size = 20" Transcript show: x. buffer := String new: 40. x := self getObjectSetting: ('page' , Character null asString) in: os into: buffer ofSize: buffer size. (buffer indexOf:Character null) > 21 "Probably true..." Cheers, Henry PS: That’s a glorious getter API… It returns 1 even if your buffer is shorter than the actual parameter, so your only way to be sure you’ve fetched all of it, is to test that the result give contains a null character, and if not, retry with a larger buffer… (The sane thing to do would be allowing you to query the parameter length, either through a * int parameter, or a separate function).
signature.asc
Description: Message signed with OpenPGP using GPGMail
