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. I checked how I wrapped this API call again and again - it is fine from my side: setObjectSetting: aName to: value in: settings <primitive: #primitiveNativeCall module: #NativeBoostPlugin> ^NBFFICallout stdcall: #(int wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, char* aName, char* value)) module: 'wkhtmltox.dll' and I still have no idea why it fails. Especially because "wkhtmltopdf_set_object_setting" function is not different from "wkhtmltopdf_set_global_setting" which is exactly the same way wrapped, works and returns 1 in exactly the same example. I would really appreciate if someone could have a second look... To reproduce on Windows: 1. Download the 32 bit version of WKHTML from http://wkhtmltopdf.org and install it 2. Copy the "wkhtmltox.dll" to either the folder of the VM executable or the Windows directory so it can be found 3. Load the package WKHTML2PDF-Core-TorstenBergmann.7 from http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF into Pharo 3.0#30848 4. Check the Transcript while evaluating: WKPDFLibrary example One can see that within this code #setObjectSetting:to:in: fails while #setGlobalSetting:to:in: works. Maybe I just do not see the obvious. Help is appreciated. Thanks in advance! bye T.
I think this is because it is a C++ lib. NativeBoost cannot be used with C++ lib. It is a problem of call convention that is not the same from C to C++. As I discuss with some people it seems be a complexe problem, each C++ compiler seems have it own convention. But Igor can maybe be more accurate about that. A C wrapper to call C++, which should work. On 23 May 2014, at 02:36, Torsten Bergmann <astares@gmx.de> 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.
I checked how I wrapped this API call again and again - it is fine from my side:
setObjectSetting: aName to: value in: settings
<primitive: #primitiveNativeCall module: #NativeBoostPlugin>
^NBFFICallout stdcall: #(int wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, char* aName, char* value)) module: 'wkhtmltox.dll'
and I still have no idea why it fails.
Especially because "wkhtmltopdf_set_object_setting" function is not different from "wkhtmltopdf_set_global_setting" which is exactly the same way wrapped, works and returns 1 in exactly the same example.
I would really appreciate if someone could have a second look...
To reproduce on Windows:
1. Download the 32 bit version of WKHTML from http://wkhtmltopdf.org and install it 2. Copy the "wkhtmltox.dll" to either the folder of the VM executable or the Windows directory so it can be found 3. Load the package WKHTML2PDF-Core-TorstenBergmann.7 from http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF into Pharo 3.0#30848 4. Check the Transcript while evaluating:
WKPDFLibrary example
One can see that within this code #setObjectSetting:to:in: fails while #setGlobalSetting:to:in: works.
Maybe I just do not see the obvious. Help is appreciated. Thanks in advance!
bye T.
<main.cpp>
Best Regards Jean Baptiste Arnaud jbaptiste.arnaud@gmail.com
On 23 May 2014, at 11:31, Jean Baptiste Arnaud <jbaptiste.arnaud@gmail.com> wrote:
I think this is because it is a C++ lib. NativeBoost cannot be used with C++ lib. It is a problem of call convention that is not the same from C to C++. As I discuss with some people it seems be a complexe problem, each C++ compiler seems have it own convention. But Igor can maybe be more accurate about that. A C wrapper to call C++, which should work.
Ronieâs SWIG for NativeBoost has some C++ support: http://forum.world.st/SWIG-for-Native-Boost-FFI-td4738511.html
On 23 May 2014, at 02:36, Torsten Bergmann <astares@gmx.de> 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.
I checked how I wrapped this API call again and again - it is fine from my side:
setObjectSetting: aName to: value in: settings
<primitive: #primitiveNativeCall module: #NativeBoostPlugin>
^NBFFICallout stdcall: #(int wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, char* aName, char* value)) module: 'wkhtmltox.dll'
and I still have no idea why it fails.
Especially because "wkhtmltopdf_set_object_setting" function is not different from "wkhtmltopdf_set_global_setting" which is exactly the same way wrapped, works and returns 1 in exactly the same example.
I would really appreciate if someone could have a second look...
To reproduce on Windows:
1. Download the 32 bit version of WKHTML from http://wkhtmltopdf.org and install it 2. Copy the "wkhtmltox.dll" to either the folder of the VM executable or the Windows directory so it can be found 3. Load the package WKHTML2PDF-Core-TorstenBergmann.7 from http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF into Pharo 3.0#30848 4. Check the Transcript while evaluating:
WKPDFLibrary example
One can see that within this code #setObjectSetting:to:in: fails while #setGlobalSetting:to:in: works.
Maybe I just do not see the obvious. Help is appreciated. Thanks in advance!
bye T.
<main.cpp>
Best Regards Jean Baptiste Arnaud jbaptiste.arnaud@gmail.com
Hi Jean, thanks for answering. I dont think that the convention is an issue here: internally it is written in C++, but it exposes the API as simple C functions. The calls with NB work (even the callbacks). What confuses me most is that the call to "wkhtmltopdf_set_global_setting" works while the "wkhtmltopdf_set_object_setting"  does not. They have exactly the same signature and are called one after the other. First one returns proper int 1 (success) as in the non-Smalltalk example, the other one 0 which means it failed. There is no magic in the Pharo code, just simple calls. Also the non-Smalltalk example proves that the component is working. Maybe a side effect of NativeBoost itself? Looks like so far I'm lost without the help of Igor here... Thx T.  Gesendet: Freitag, 23. Mai 2014 um 11:31 Uhr Von: "Jean Baptiste Arnaud" <jbaptiste.arnaud@gmail.com> An: "Pharo Development List" <pharo-dev@lists.pharo.org> Betreff: Re: [Pharo-dev] NativeBoost and WKHTML I think this is because it is a C++ lib. NativeBoost cannot be used with C++ lib. It is a problem of call convention that is not the same from C to C++. As I discuss with some people it seems be a complexe problem, each C++ compiler seems have it own convention. But Igor can maybe be more accurate about that. A C wrapper to call C++, which should work.  On 23 May 2014, at 02:36, Torsten Bergmann <astares@gmx.de> 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[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'[http://www.google.de'] in: os. I checked how I wrapped this API call again and again - it is fine from my side:    setObjectSetting: aName to: value in: settings <primitive: #primitiveNativeCall module: #NativeBoostPlugin> ^NBFFICallout stdcall: #(int wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, char* aName, char* value)) module: 'wkhtmltox.dll' and I still have no idea why it fails. Especially because "wkhtmltopdf_set_object_setting" function is not different from "wkhtmltopdf_set_global_setting" which is exactly the same way wrapped, works and returns 1 in exactly the same example. I would really appreciate if someone could have a second look... To reproduce on Windows: 1. Download the 32 bit version of WKHTML from http://wkhtmltopdf.org[http://wkhtmltopdf.org] and install it 2. Copy the "wkhtmltox.dll" to either the folder of the VM executable    or the Windows directory so it can be found 3. Load the package WKHTML2PDF-Core-TorstenBergmann.7    from http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF[http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF] into Pharo 3.0#30848 4. Check the Transcript while evaluating:        WKPDFLibrary example    One can see that within this code #setObjectSetting:to:in: fails while #setGlobalSetting:to:in:    works. Maybe I just do not see the obvious. Help is appreciated. Thanks in advance! bye T. <main.cpp> Best Regards Jean Baptiste Arnaud jbaptiste.arnaud@gmail.com[jbaptiste.arnaud@gmail.com]  Â
Hi, If I were to debug this, I would: 1 ) make sure there's no C++ interfering, try to compile using C compiler (not C++, I guess you run Windows and MSVC, I think there's command line option to process file as C). If not possible, wrap all methods you want to call form St in extern "C" {} block. Does it work? If not, then C++ compiler is doing it's magic which NB doesn't. 2 ) If it does, run whole thing under debugger, set breakpoint to the faulty function and check that arguments are correct and what's return value. If args are incorrect, then the problem is in either yours or NB's code. If return value is correct, then the problem is also in either yours or NB's code. If the return value is incorrect, well then the problem could be either in the library or some sort of GC thing as GC moves stuff around, which most of C/C++ libraries don't like much. In that case, I learned, the only way us to read library's code and single-step through it to see that the code actually does with data you pass down. HTH, Jan On 23/05/14 10:51, Torsten Bergmann wrote:
Hi Jean,
thanks for answering. I dont think that the convention is an issue here: internally it is written in C++, but it exposes the API as simple C functions. The calls with NB work (even the callbacks).
What confuses me most is that the call to "wkhtmltopdf_set_global_setting" works while the "wkhtmltopdf_set_object_setting" does not. They have exactly the same signature and are called one after the other. First one returns proper int 1 (success) as in the non-Smalltalk example, the other one 0 which means it failed.
There is no magic in the Pharo code, just simple calls. Also the non-Smalltalk example proves that the component is working. Maybe a side effect of NativeBoost itself?
Looks like so far I'm lost without the help of Igor here...
Thx T.
Gesendet: Freitag, 23. Mai 2014 um 11:31 Uhr Von: "Jean Baptiste Arnaud" <jbaptiste.arnaud@gmail.com> An: "Pharo Development List" <pharo-dev@lists.pharo.org> Betreff: Re: [Pharo-dev] NativeBoost and WKHTML
I think this is because it is a C++ lib. NativeBoost cannot be used with C++ lib. It is a problem of call convention that is not the same from C to C++. As I discuss with some people it seems be a complexe problem, each C++ compiler seems have it own convention. But Igor can maybe be more accurate about that. A C wrapper to call C++, which should work.
On 23 May 2014, at 02:36, Torsten Bergmann <astares@gmx.de> 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[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'[http://www.google.de'] in: os.
I checked how I wrapped this API call again and again - it is fine from my side:
setObjectSetting: aName to: value in: settings
<primitive: #primitiveNativeCall module: #NativeBoostPlugin>
^NBFFICallout stdcall: #(int wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, char* aName, char* value)) module: 'wkhtmltox.dll'
and I still have no idea why it fails.
Especially because "wkhtmltopdf_set_object_setting" function is not different from "wkhtmltopdf_set_global_setting" which is exactly the same way wrapped, works and returns 1 in exactly the same example.
I would really appreciate if someone could have a second look...
To reproduce on Windows:
1. Download the 32 bit version of WKHTML from http://wkhtmltopdf.org[http://wkhtmltopdf.org] and install it 2. Copy the "wkhtmltox.dll" to either the folder of the VM executable or the Windows directory so it can be found 3. Load the package WKHTML2PDF-Core-TorstenBergmann.7 from http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF[http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF] into Pharo 3.0#30848 4. Check the Transcript while evaluating:
WKPDFLibrary example
One can see that within this code #setObjectSetting:to:in: fails while #setGlobalSetting:to:in: works.
Maybe I just do not see the obvious. Help is appreciated. Thanks in advance!
bye T.
<main.cpp>
Best Regards Jean Baptiste Arnaud jbaptiste.arnaud@gmail.com[jbaptiste.arnaud@gmail.com]
Hi Jan, I did not compile the WKHTML component, just used the predefined DLL from the website. I know that there is no C++ interfering as the DLL has a normal C interface. So no C++ calling convention stuff/name mangling etc. is involved, no SWIG required or additional C wrapper. One can download and use the DLL as a usual C DLL like many others. So C/C++ was only involved because after the mentioned single Pharo/NB call failed and I could not see the reason in my code I wanted a Pharo independent non-smalltalk calling example to prove that the DLL is working. Could have used any other language (Java, VB, ...) to call the WKHTML DLL. So I use the DLL as a black box, similar like any other API where you do not have the source code. Debugging the DLL or modifying its source code by adding debug outputs would mean to go through all the hazzle of compiling WKHTML myself. According to the website this would also additionally require many tools (Perly, Python, Windows SDK, VisualStudio, ...) which I do not have installed. Way too much effort as I only thought it would be a nice idea if we could provide a Pharo binding to print something easily from Pharo using HTML -> PDF. As you see on the calling example WKHTML is simple and straightforward with an init, put some settings (file/URL) and calling the conversion. I also think that the route to debugging the DLL would be questionable - my simple non-Smalltalk calling example proves that the DLL is properly working as the website states. So according to this the problem must be on the Pharo wrapper or NativeBoost side who calls the component. Therefore I looked at my wrapper code again and again - nothing suspicious. Thats why I asked: either I'm blind to "not see the forest because of the all the trees" or there is still some bug left in NB. Maybe there is also an easy way to check/compare the calls. Thanks T.
Gesendet: Freitag, 23. Mai 2014 um 12:11 Uhr Von: "Jan Vrany" <jan.vrany@fit.cvut.cz> An: "Pharo Development List" <pharo-dev@lists.pharo.org> Betreff: Re: [Pharo-dev] NativeBoost and WKHTML
Hi,
If I were to debug this, I would:
1 ) make sure there's no C++ interfering, try to compile using C compiler (not C++, I guess you run Windows and MSVC, I think there's command line option to process file as C). If not possible, wrap all methods you want to call form St in extern "C" {} block. Does it work? If not, then C++ compiler is doing it's magic which NB doesn't.
2 ) If it does, run whole thing under debugger, set breakpoint to the faulty function and check that arguments are correct and what's return value. If args are incorrect, then the problem is in either yours or NB's code. If return value is correct, then the problem is also in either yours or NB's code. If the return value is incorrect, well then the problem could be either in the library or some sort of GC thing as GC moves stuff around, which most of C/C++ libraries don't like much.
In that case, I learned, the only way us to read library's code and single-step through it to see that the code actually does with data you pass down.
HTH, Jan
On 23/05/14 10:51, Torsten Bergmann wrote:
Hi Jean,
thanks for answering. I dont think that the convention is an issue here: internally it is written in C++, but it exposes the API as simple C functions. The calls with NB work (even the callbacks).
What confuses me most is that the call to "wkhtmltopdf_set_global_setting" works while the "wkhtmltopdf_set_object_setting" does not. They have exactly the same signature and are called one after the other. First one returns proper int 1 (success) as in the non-Smalltalk example, the other one 0 which means it failed.
There is no magic in the Pharo code, just simple calls. Also the non-Smalltalk example proves that the component is working. Maybe a side effect of NativeBoost itself?
Looks like so far I'm lost without the help of Igor here...
Thx T.
Gesendet: Freitag, 23. Mai 2014 um 11:31 Uhr Von: "Jean Baptiste Arnaud" <jbaptiste.arnaud@gmail.com> An: "Pharo Development List" <pharo-dev@lists.pharo.org> Betreff: Re: [Pharo-dev] NativeBoost and WKHTML
I think this is because it is a C++ lib. NativeBoost cannot be used with C++ lib. It is a problem of call convention that is not the same from C to C++. As I discuss with some people it seems be a complexe problem, each C++ compiler seems have it own convention. But Igor can maybe be more accurate about that. A C wrapper to call C++, which should work.
On 23 May 2014, at 02:36, Torsten Bergmann <astares@gmx.de> 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[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'[http://www.google.de'] in: os.
I checked how I wrapped this API call again and again - it is fine from my side:
setObjectSetting: aName to: value in: settings
<primitive: #primitiveNativeCall module: #NativeBoostPlugin>
^NBFFICallout stdcall: #(int wkhtmltopdf_set_object_setting(wkhtmltopdf_object_settings* settings, char* aName, char* value)) module: 'wkhtmltox.dll'
and I still have no idea why it fails.
Especially because "wkhtmltopdf_set_object_setting" function is not different from "wkhtmltopdf_set_global_setting" which is exactly the same way wrapped, works and returns 1 in exactly the same example.
I would really appreciate if someone could have a second look...
To reproduce on Windows:
1. Download the 32 bit version of WKHTML from http://wkhtmltopdf.org[http://wkhtmltopdf.org] and install it 2. Copy the "wkhtmltox.dll" to either the folder of the VM executable or the Windows directory so it can be found 3. Load the package WKHTML2PDF-Core-TorstenBergmann.7 from http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF[http://smalltalkhub.com/#!/~TorstenBergmann/WKHTML2PDF] into Pharo 3.0#30848 4. Check the Transcript while evaluating:
WKPDFLibrary example
One can see that within this code #setObjectSetting:to:in: fails while #setGlobalSetting:to:in: works.
Maybe I just do not see the obvious. Help is appreciated. Thanks in advance!
bye T.
<main.cpp>
Best Regards Jean Baptiste Arnaud jbaptiste.arnaud@gmail.com[jbaptiste.arnaud@gmail.com]
On 23.05.2014 02:36, Torsten Bergmann wrote:
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):
while in Pharo the same call fails (by returning 0):
I tried to use another DLL which required me to change "stackAlignment" on Windows to answer 16 instead of 1; running on Win7 64 Bit. Could your problem be caused by something like that? (Just a shot in the dark). Best regards, Markus
On 23 May 2014, at 2:36 , Torsten Bergmann <astares@gmx.de> 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
On 23 May 2014, at 2:52 , Henrik Johansen <henrik.s.johansen@veloxit.no> wrote:
On 23 May 2014, at 2:36 , Torsten Bergmann <astares@gmx.de> 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).
YES, COOL - it now works as the attached PDF proves. 1000 timesRepeat: [ Transcript show: 'Henrik thanks!!!' ;cr ] Henrik - you have saved me to have to return to the darker sides of computing and digg deeper into low level again ;) I knew that it must have been something in the calling wrapper and was too blind to see it. A little bit misleading that one can not use the original C signature in the NB description with char* and autoconversion through NB. Maybe I was too used to NB's predecessor FFI where one wrote char* and just passed the Smalltalk string. Stupid me, I should have RTFM of NativeBoost instead of assuming its close to FFI in this regard! So again the problem was in front of the computer. Hey: that now means one can easily generate a PDF from websites or HTML generated by Pharo or Seaside, ... which I think is way cool! In return: will clean up the code as soon as possible, also a config, documention and an entry in the config browser. We can now proudly say: even when you want to print fancy stuff there is no excuse not to use Pharo for that ;) Bye T.
Gesendet: Freitag, 23. Mai 2014 um 14:52 Uhr Von: "Henrik Johansen" <henrik.s.johansen@veloxit.no> An: "Pharo Development List" <pharo-dev@lists.pharo.org> Betreff: Re: [Pharo-dev] NativeBoost and WKHTML
On 23 May 2014, at 2:36 , Torsten Bergmann <astares@gmx.de> 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
On 23 May 2014, at 3:46 , Torsten Bergmann <astares@gmx.de> wrote:
YES, COOL - it now works as the attached PDF proves.
1000 timesRepeat: [ Transcript show: 'Henrik thanks!!!' ;cr ]
Henrik - you have saved me to have to return to the darker sides of computing and digg deeper into low level again ;)
I knew that it must have been something in the calling wrapper and was too blind to see it.
A little bit misleading that one can not use the original C signature in the NB description with char* and autoconversion through NB.
Maybe I was too used to NB's predecessor FFI where one wrote char* and just passed the Smalltalk string.
Stupid me, I should have RTFM of NativeBoost instead of assuming its close to FFI in this regard! So again the problem was in front of the computer.
Really, blame char *, itâs too ambiguous. Is it raw byte(s)? Is it a string? How is its length conveyed? Whatâs the encoding supposed to be? You canât really determine the answer to those questions up front in the FFI, though the right answer is usually clear on a case-by-case basis from the context. * So the NB rationale is (I think) not to do extra overhead which would still, sometimes, leave the user stumped at some strange error when the automatic handling mismatches reality. You only get bitten by it once (or maybe twice?), though the path to enlightenment could be less bumpy :) Cheers, Henry * No corresponding length parameter? Either single element or null-terminated string, as per context. String or bytes? Should be clear from context. Encoding? Well⦠usually utf8, but could also be some environment-defined code page, gotta check the library docs to be sure. Say what you want about Windows, but at least they their APIs use explicit string types with well defined encoding.
participants (6)
-
Henrik Johansen -
Jan Vrany -
Jean Baptiste Arnaud -
Marcus Denker -
Markus Fritsche -
Torsten Bergmann