Call out to 3Gl: struct includes char*

Author: i2stiller@gmx.de (istiller)

Hi freaks Just programming the interface to ELSTER (german tax office application) All going well until it came to the point to exchange a struct Okay, create a dummy entity and add all members of the (C-)struct as fields. The last two members are defined as "char*" Now is the question: how to say UnifAce that this are "char*" and not "char[n]" with a fix number n If I define this as C40 or C*, UnifAce is going into the nirvana. Any clue how to define? BTW: This is a simple task UnifAce should handle! I don't want to implement a wrapper, as then there is a need for an extra environment, maintance overhead and man power. TIA Ingo PS:The structure in question: typedef struct{ uint32_t version; uint32_t vorschau; uint32_t ersteSeite; uint32_t duplexDruck; const char* pdfName; const char* fussText; } eric_druck_parameter_t;

20 Comments

  1. Have you tried to create a signature of the operation in Uniface, I think that we have done that also in the past for complex operations with multiple parameters. Now we have removed all the 3GL calls and section in the ASN.
     
    We do everything with a .Net library that is com reg free (changed the manifest file of Uniface.exe)

    Author: Stijn Courtheyn (stijn.courtheyn@xperthis.be)
  2. Hi Stijn Yes, I did create a signature for the DLL. And all all but this function with this parameter are callable This is the function: ERICAPI_DECL int STDCALL EricBearbeiteVorgang( const char* datenpuffer, const char* datenartVersion, uint32_t bearbeitungsFlags, const eric_druck_parameter_t* druckParameter, const eric_verschluesselungs_parameter_t* cryptoParameter, EricTransferHandle* transferHandle, EricRueckgabepufferHandle rueckgabeXmlPuffer, EricRueckgabepufferHandle serverantwortXmlPuffer); Problem is this parameter const eric_druck_parameter_t* druckParameter (and of cource the next one with also a struct* as type) And I dodn't want to start a new overhead (wrapper) for just this case. As UnifAce tell us everytime, UnifAce is the best language in world for "business crtical applications", a normal struct parameter should be no challenge for UnifAce Ingo


    Author: istiller (i2stiller@gmx.de)
  3. Hi, I don't know if I understand your problem correctly.... But if this is the main problem or ar least the first part of the problem "Now is the question: how to say UnifAce that this are “char*” and not “char[n]” with a fix number n" Define parameter: Basic String Interface char* (length 2 - 10240000) Length  10240000   Hmmm, having thought about it, I suppose your problem is not to define the parameter on the level described by me....   Regards RogerW.


    Author: rogerw (roger.wallin@abilita.fi)
  4. Uniface has a run time fit if you define more than one C*, or if you put a fixed length variable after the C*.  We have found that, for database purposes anyway, you can define them as SC* and the uniface runtime lockup goes away. 


    Author: Iain Sharp (i.sharp@pcisystems.co.uk)
  5. Nope SC* don't solve the problem If I defined the struc typedef struct{ uint32_t version; uint32_t vorschau; uint32_t ersteSeite; uint32_t duplexDruck; const char* pdfName; const char* fussText; } eric_druck_parameter_t; as UnifAce table  ERIC_DRUCK_PARA   VERSION          I4   VORSCHAU       I4   ERSTESEITE     I4   DUPLEXDRUCK I4   PDFNAME         I4   FUSSTEXT        I4 and fill the fields   VERSION.ERIC_DRUCK_PARA          =2   VORSCHAU.ERIC_DRUCK_PARA       =0   ERSTESEITE.ERIC_DRUCK_PARA     =0   DUPLEXDRUCK.ERIC_DRUCK_PARA =0   PDFNAME.ERIC_DRUCK_PARA         =0   FUSSTEXT.ERIC_DRUCK_PARA        =0 the active will work, but with NULL-pointers for the strings. This is the resilt expected, as the layout of the C-struct equals the UnifAce-Table. But this does not solve my problem. I need to transfer string (inside a struct) to the DLL. @UnifAce: How to solve this? I need an answer as soon as possible as this is the base of our implementation of ELSTER TIA Ingo


    Author: istiller (i2stiller@gmx.de)
  6. I looked into this problem and I hope I understand the problem correctly.  This is what I did in a DLL project VS2015: 1 - declared the structure as described typedef struct { unsigned int version; unsigned int vorschau; unsigned int ersteSeite; unsigned int duplexDruck; const char * pdfName; const char * fussText; } eric_druck_parameter_t;   2 - I created a dll with two functions extern "C" __declspec(dllexport) int unidoCall(unsigned int l_version, unsigned int l_vorschau, unsigned int l_ersteSeite, unsigned int l_duplexDruc, char *l_pdfName, char * l_fussText); extern "C" __declspec(dllexport) int unidoCallEnt(eric_druck_parameter_t *p_entity); The function are empty and only do an outputdebugstring. int unidoCall(unsigned int l_version, unsigned int l_vorschau, unsigned int l_ersteSeite, unsigned int l_duplexDruc, char *l_pdfName, char * l_fussText) { OutputDebugStringA("unidoCall "); return 0; } int unidoCallEnt(eric_druck_parameter_t *p_entity) { OutputDebugStringA("unidoCallEnt "); return 0; }   In UNIFACE a callouttest signature is created and an entity with the same fields as the C-structure. In the database entity I have 1 2 3 Test123 FussText Calling the unidoCall with all separate parameters works fine. Calling the unidoCallEnt fails since all data is in one contiguous block of memory. Hence refering to p_entity->fusstext causes a crash Looking into memory shows me: 0x0731A7B0  00000000000000000001....00000000000000000002....00000000 0x0731A7E8 30 30 30 30 30 30 30 30 30 30 30 33 00 00 00 00 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 34 54 65 73 74 31 32 33 20 20 20 20 20 20 20 20 20 20 20 20 20 000000000003....00000000000000000004Test123 0x0731A820 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 46 75 73 73 54 65 78 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 FussText All data as one block and the test params are filled out with spaces and zeros (0x30). Expected was a reference to the separate members of the entity. In the current situation I would create an interface with the fields as separate parameter. The documentation also shows the occurrence as a structure in 3GL with members in the struct with an equal size of the fields in the db-table. There are no references in the sample like the char *Fusstext member. Other option is to call a 3gL function without parameter and call back into uniface to get the data per field, for instance with

    short ufget (unsigned char* field, unsigned char* buffer, short max); void newData(){

            do here your calls }   Hope this helps Kind regards Jasper de Keijzer


    Author: Jasper (jasper.de.keijzer@compuware.com)
  7. Moin Jasper Thanks for answering. You did describe the problem well :-) The layout of the entity-"struct" UnifAce will use on calling the C-funcktion looks like typedef struct{ uint32_t version; uint32_t vorschau; uint32_t ersteSeite; uint32_t duplexDruck; char[40] pdfName;             // if defined in UnifAce as C40 char[40] fussText; } A_eric_druck_parameter_t; If I define the last two member as I4 I got typedef struct{ uint32_t version; uint32_t vorschau; uint32_t ersteSeite; uint32_t duplexDruck; uint32_t pdfName;             // if defined in UnifAce as I4 uint32_t fussText; } B_eric_druck_parameter_t; Everybody knows that "char*" do have the same size in bytes then "uint32_t" char* is an address (pointer) into memory, nothing else the an integer So, "B_eric_druck_parameter_t" is equal by layout to "eric_druck_parameter_t" and I can call the function in question. Okay, if I know the address in memory or provide a NULL-pointer == 0 This thoughts are already done, BUT ... But I need "eric_druck_parameter_t" with two pointers to a "string" of chars in memory The idea by modifing the C-function, nice but not pratical :-) We are not the owner of this software we have to call. ELSTER is a peace of software if the german tax office (https://www.elster.de/eportal/start) I don't believe, if a call Berlin "Hey guys, we are using UnifAce. Please change your function, elsewhere we could not send you the tax values" that Berlin we change anything. So - as UnifAce is a modern and flexible program language - UnifAce do have a solution @UnifAce: So what the solution for this problem? And don't came around with: You have to write a wrapper. This are elementary things, every modern language should handle Regards Ingo


    Author: istiller (i2stiller@gmx.de)
  8. BTW Just got an answer from Berlin: "There is no workaround for the  char*  member" So before I start to program the wrapper "Hello UnifAce: any workaround within UnifAce?"


    Author: istiller (i2stiller@gmx.de)
  9. Ingo The question is, how would you let UNIFACE know the layout of your C-structure? I do not see any sensible way in the current signature form to explain the 4GL the format of this C-struct. And what if these pointers become 64bit?  Can you call support for this? Success Jasper


    Author: Jasper (jasper.de.keijzer@compuware.com)
  10. Jasper said ... The question is, how would you let UNIFACE know the layout of your C-structure? ... Jasper  

    Hi Jasper, I understand your question but in the previous post on this same subject Mike Taylor answered "using a Uniface entity". Isn't an enriched application model the answer to your question? As Roger already, I am really interested to understand which will be the long term solution to this issue. Regards, Gianni


    Author: gianni (gianni.sandigliano@unifacesolutions.com)
  11. Jasper said Ingo The question is, how would you let UNIFACE know the layout of your C-structure? I do not see any sensible way in the current signature form to explain the 4GL the format of this C-struct. And what if these pointers become 64bit?   

    Hi Jasper Uniface already supports struct: You define the (C-)struct as an entity in UnifAce. On calling a C-procedure with this entity, UnifAce does some marshalling   All numeric members will be (according to there Interface) convert to a integer type in C   Strings with fix a fixed number n of character will convert to char[n] What about strings with interface "C*" ?  How will UnifAce convert them?   And this is my idea/wish:   Convert "C*" at runtime in a char*  struct struct_t { char* a_char_star;);  struct_t a_struct;   On input, this is very easy:     a_struct.a_char_star= C_parameter = UnifAce_string.c_str();     function(&a_struct);  If this parameter is an output one:    a_struct.a_char_star = 0;    function(&a_struct);    UnifAce_string.assign(a_struct.a_char_star);    free(    a_struct.a_char_star);  If this parameter is an in/output one:    a_struct.a_char_star = malloc(MAX_BUFFER_SIZE);   MAX_BUFFER_SIZE could be defined by UnifAce and/or in ASN.    function(&a_struct);    UnifAce_string.assign(a_struct.a_char_star);    free(    a_struct.a_char_star); So it would be easy to transfer a string as char* into a 3GL and back. BTW: a marshalling like this must already exists, as UnifAce can use "char*" as an parameter on a 3GL-call No witchcreaft needed :-) Ingo      


    Author: istiller (i2stiller@gmx.de)
  12. Hi, We have built quite extensive web-service API:s in Visual Studio as Middleware between Uniface and national program-services, ie. being able to by ourselves define the api for Uniface to use. I'm a bit hesitant about what to demand from Uniface. I see Uniface as a programming-module mainly unifying the UI and the database access.  Uniface has enough to do, helping us to build nice UI:s, where by the way, they haven't been enough progressive the last decade. Where is the product that cross compiles for both desktop and web (and mobile).    Regards RogerW. PS. Sorry Ingo for this :-(.  Just build a small C++ program that is able to handle your C++ struct and define the api to fit Uniface yourself. On the other hand I'm interested in hearing about a solution to your problem....


    Author: rogerw (roger.wallin@abilita.fi)
  13. rogerw said Hi, I'm a bit hesitant about what to demand from Uniface. I see Uniface as a programming-module mainly unifying the UI and the database access.  Uniface has enough to do, helping us to build nice UI:s, where by the way, they haven't been enough progressive the last decade. Where is the product that cross compiles for both desktop and web (and mobile).   Regards RogerW. PS. Sorry Ingo for this :-(.  Just build a small C++ program that is able to handle your C++ struct and define the api to fit Uniface yourself. On the other hand I'm interested in hearing about a solution to your problem....  

      Hi Roger I remember the first step we did with UnifAce: There were no loops at all: Reason (by UnifAce)  "loops a 3GL, we are a 4GL!" Luckily UnifAce changed there mind and we do have all this 3GL stuff :-) On the other hand, you have to provide many function with global registers and use $perform Also there where cryptic function, one have to search for in the net (e.g. filesystem operation) This was more then 3GL, this was sometime magic ... So as a moderen language, it should be possible in UnifAce to define a struct layout. And yes, UnifAce have a lot advantages over othe languages! If this ist not true, we would be already on another language. But there is also a real world outside of the UnifAce universe. And we have to connect to this real world! If I have to tell my boss on every new application we will connect to out application:"Sorry, I have to write a wrapper first", I got the answer:"Will it not be better to write all in C#. UnifAce is old-fashioned and out of date." BTW: Announcing staff shake-out will do the rest to look for alternatives :-( So if I could tell my coleagues "no problem for UnifAce", this will help surviving of UnifAce in our company. Else I have to invest a few days to implement a proper, stable and secure wrapper. And time is money :-( Just my two censt to this problem Ingo


    Author: istiller (i2stiller@gmx.de)
  14. Jasper said Ingo The question is, how would you let UNIFACE know the layout of your C-structure? I do not see any sensible way in the current signature form to explain the 4GL the format of this C-struct. And what if these pointers become 64bit?  Can you call support for this?

    Here is an explanation how VB will do the convert from 4GL to 3GL >https://activevb.de/rubriken/kolumne/kol_4/cpptovbtypen.html (okay in german but the tables and examples should be easy to read) Ingo


    Author: istiller (i2stiller@gmx.de)
  15. Hi Ingo, I respect your opinion in this case and I hope you get a solution. However, I have heard so many young programmers shout about how good and comprehensive C# and C++ is compared to Uniface. It's very hard to explain to them that Uniface is built with VS and it's not meant to be compared to 3gl languages. It wouldn't be practical for Uniface to support all kind of concepts supported by a 3gl, then I promise that Uniface will lose. I've seen young programmers doing real balls of thread with C#, ie. code that is very hard to maintain and code that could have been made much simpler. This code is usually done by mistake (the programmer hasn't known better), but I'm sure that sometimes it's done deliberately to get some undeserved advantages. Thats why we need Uniface, ie. unifying the programming process for the most used concepts (UI, database access etc.). And as I said, I'm not content with what Uniface has done during the last decade.  For sure Uniface has to find a golden mean, to concentrate on the right things. Regards RogerW.


    Author: rogerw (roger.wallin@abilita.fi)
  16. rogerw said Hi Ingo, I respect your opinion in this case and I hope you get a solution. However, I have heard so many young programmers shout about how good and comprehensive C# and C++ is compared to Uniface. It's very hard to explain to them that Uniface is built with VS and it's not meant to be compared to 3gl languages. It wouldn't be practical for Uniface to support all kind of concepts supported by a 3gl, then I promise that Uniface will lose. I've seen young programmers doing real balls of thread with C#, ie. code that is very hard to maintain and code that could have been made much simpler. This code is usually done by mistake (the programmer hasn't known better), but I'm sure that sometimes it's done deliberately to get some undeserved advantages. Thats why we need Uniface, ie. unifying the programming process for the most used concepts (UI, database access etc.). And as I said, I'm not content with what Uniface has done during the last decade.  For sure Uniface has to find a golden mean, to concentrate on the right things. Regards RogerW.  

    Hi Roger I'm also like UnifAce :-) It (UnifAce) is a 4GL that hides most of 3GL for us, but sometimes is necassary to call 3GL. I don't want to programm in C/C++/C# but a way to define C-like structurs and arrays for calling DLLs would be nice to have. BTW: I did start programming with "Origin" on a MAI, then there was Synon on AS400 and now UnifAce on Max/Windows. So we always prefer 4GL lagunages to do our job :-) Ingo


    Author: istiller (i2stiller@gmx.de)
  17. rogerw said ... Thats why we need Uniface, ie. unifying the programming process for the most used concepts (UI, database access etc.). ... Regards RogerW.  

    Roger, my gotfeel is: as of today integration with other (external) subsystems is very very important, at least on same evel as UI and database access. Gianni


    Author: gianni (gianni.sandigliano@unifacesolutions.com)
  18. Gianni, You are right, and using web-services Uniface has done a good job introducing the Uniface struct, with which you can call almost all eg. Rest APIs (kind of modern web-service without soap). But trying to support directly all kind of native concepts in different kind of languages, that's hard. That's why you usually need some kind of wrapper. Regards RogerW. 


    Author: rogerw (roger.wallin@abilita.fi)
  19. rogerw said Gianni, You are right, and using web-services Uniface has done a good job introducing the Uniface struct, with which you can call almost all eg. Rest APIs (kind of modern web-service without soap). But trying to support directly all kind of native concepts in different kind of languages, that's hard. That's why you usually need some kind of wrapper. Regards RogerW.   

    Roger, this same discussion on DBMS interface level was solved many years ago differentiating datatypes from storageFormats; AFAIK the problem here is probably of same type...one of the many possible examples: - C* = 32bit char pointer - SC* = 64bit char pointer (or default pointer size) Complex: YES... Too complex: probably NOT! If approached with 20/80 method, many cases could be directly supported leaving wrappers aside or eventually to be used for fewer cases. My 2 cents... Gianni


    Author: gianni (gianni.sandigliano@unifacesolutions.com)
  20. Hi Freaks For char* in a struct I got a solution, thanks to Arthur at the u.B.G at Hamburg/Germany ! Windows allready do have a "wrapper"-DLL, called shlwapi.dll In the DLL there many, many function. One of them is "StrDup" (StrDupA and StrDupW) PSTR StrDupA( PCSTR pszSrch ); Input is a (const) string, i.e a normal "basis string" in UnifAce signature the function will copy the string onto a static heap and return the address This address can the pass to any DLL, direct or in a struct. Don't forget to free the memory after the job is done: LocalFree( HLOCAL hMem ); Ingo


    Author: istiller (i2stiller@gmx.de)