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).


Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to