1. Albert John
  2. PowerBuilder
  3. Friday, 23 April 2021 07:38 AM UTC

I'm a PB 12.5 classic user and I  was trying  to call a C++ dll,the parameter has array like 

 in C++

 

 

typedef struct clientinfo_insuinfo_ret_struct{
int insuinforecordscount;
double * balc;
char ** insutype;
char ** psn_type;
char ** psn_insu_stas;
char ** psn_insu_date;
char ** paus_insu_date;
char ** cvlserv_flag;
char ** insuplc_admdvs;
char ** emp_name;

}clientinfo_insuinfo_ret_struct;

typedef struct clientinfo_idetinfo_ret_struct{
int idetinforecordscount;
char ** psn_idet_type;
char ** psn_type_lv;
char ** memo;
char ** begntime;
char ** endtime;
}clientinfo_idetinfo_ret_struct;

 

int getclientinfo(general_struct & gs,
clientinfo_struct & cs,
clientinfo_baseinfo_ret_struct & cbrs,
clientinfo_insuinfo_ret_struct & cinsurs,
clientinfo_idetinfo_ret_struct & cidenrs,
general_ret_struct & grs)

 

in PB 

then I tried to build structure with array like 

$PBExportHeader$clientinfo_insuinfo_ret_struct.srs
global type clientinfo_insuinfo_ret_struct from structure
long insuinforecordscount
double balc[]
string insutype[]
string psn_type[]
string psn_insu_stas[]
string psn_insu_date[]
string paus_insu_date[]
string cvlserv_flag[]
string insuplc_admdvs[]
string emp_name[]
end type

 

$PBExportHeader$clientinfo_idetinfo_ret_struct.srs
global type clientinfo_idetinfo_ret_struct from structure
long idetinforecordscount
string psn_idet_type[]
string psn_type_lv[]
string memo[]
string begntime[]
string endtime[]
end type

 

and I tried to pass the sturcture like code below,it's not working 

 

 

 

I could see the arrays within structure h

long ll_row



cirs1.insuinforecordscount=0



for ll_row=1 to 50
cirs1.balc [ll_row]= 0.0;
cirs1.insutype [ll_row]= space(10);
cirs1.psn_type [ll_row]= space(10);
cirs1.psn_insu_stas[ll_row] = space(10);
cirs1.psn_insu_date[ll_row] = space(30);
cirs1.paus_insu_date[ll_row] = space(30);
cirs1.cvlserv_flag[ll_row] = space(10);
cirs1.insuplc_admdvs[ll_row] = space(10);
cirs1.emp_name[ll_row] = space(200);

next

string ls_psn_idet_type[50],ls_psn_type_lv[50]
string ls_memo[50],ls_begntime[50],ls_endtime[50]


for ll_row=1 to 50

ls_psn_idet_type[ll_row] =space(6);
ls_psn_type_lv[ll_row] = space(6);
ls_memo[ll_row] = space(500);
ls_begntime[ll_row] = space(30);
ls_endtime[ll_row] =space(30);

next

 

clientinfo_idetinfo_ret_struct cidrs1
cidrs1.idetinforecordscount = 0


for ll_row=1 to 50
cidrs1.psn_idet_type[ll_row] =space(6);
cidrs1.psn_type_lv[ll_row] = space(6);
cidrs1.memo[ll_row] = space(500);
cidrs1.begntime[ll_row] = space(30);
cidrs1.endtime[ll_row] =space(30);
next

 


ll_result = getclientinfo(gs1, cs1, cbrs1, cirs1, cidrs1, grs1)

as been initialized

please take a look at  structure1.png and structure2.png as well in the attchements

 

but when I tried to debug it on VC++ ,(I was using VC++ 2013 ), I saw the cirs1 and  cidrs1 as well was totally like uninitialized, please take a look at the "debug which PB calling.png" in the attachement 

I have compared the normal one which direct calling that function with C++,the memory was totally different ,please take a loook at "calling from C++.png"

any idea what wrong I have done? or I should tried something else way to complished this,I was trying to pass a bunch of values which from a web services,it has tooks me 2 months,hopefully I'm not gonna rewrite the code,that was painful though

updated:

 even I tried upgrade PB to 2019 and upgraded my project as well, but it doesn't work, it probably I have done something wrong but I have no idea

 

updated

I tried to use PB 2019 dw importjson functionality,it works for me, but the problem was the  the sequence of node  that means must be exactly like json string

update

I was facing the problem of lost prprecision of double variable which the string which export with PB, when I tried to import that string into json in C++, I didn't it would b a problem

 

update 

the problem I have been resolved I changed C++ like 

 

typedef struct clientinfo_insuinfo_ret_struct{

double  balc;
char * insutype;
char * psn_type;
char * psn_insu_stas;
char * psn_insu_date;
char * paus_insu_date;
char * cvlserv_flag;
char * insuplc_admdvs;
char * emp_name;

}clientinfo_insuinfo_ret_struct;

typedef struct clientinfo_idetinfo_ret_struct{

char * psn_idet_type;
char * psn_type_lv;
char * memo;
char * begntime;
char * endtime;
}clientinfo_idetinfo_ret_struct;

 

int getclientinfo(general_struct & gs,
clientinfo_struct & cs,

clientinfo_baseinfo_ret_struct & cbrs,

int & insuinforecordscount,
clientinfo_insuinfo_ret_struct * cinsurs,

int & idetinforecordscount,
clientinfo_idetinfo_ret_struct * cidenrs,
general_ret_struct & grs)

$PBExportHeader$clientinfo_insuinfo_ret_struct.srs
global type clientinfo_insuinfo_ret_struct from structure

double balc
string insutype
string psn_type
string psn_insu_stas
string psn_insu_date
string paus_insu_date
string cvlserv_flag
string insuplc_admdvs
string emp_name
end type

 

$PBExportHeader$clientinfo_idetinfo_ret_struct.srs
global type clientinfo_idetinfo_ret_struct from structure

string psn_idet_type
string psn_type_lv
string memo
string begntime
string endtime
end type

long ll_row

 

long insuinforecordscount

insuinforecordscount=0

 clientinfo_insuinfo_ret_struct cirs1[]

for ll_row=1 to 50
cirs1[ll_row].balc = 0.0;
cirs1[ll_row].insutype = space(10);
cirs1[ll_row].psn_type = space(10);
cirs1[ll_row].psn_insu_stas = space(10);
cirs1[ll_row].psn_insu_date = space(30);
cirs1[ll_row].paus_insu_date = space(30);
cirs1[ll_row].cvlserv_flag = space(10);
cirs1[ll_row].insuplc_admdvs = space(10);
cirs1[ll_row].emp_name = space(200);

next

 

clientinfo_idetinfo_ret_struct cidrs1[]
cidrs1.idetinforecordscount = 0


for ll_row=1 to 50
cidrs1[ll_row].psn_idet_type =space(6);
cidrs1[ll_row].psn_type_lv = space(6);
cidrs1[ll_row].memo = space(500);
cidrs1[ll_row].begntime = space(30);
cidrs1[ll_row].endtime =space(30);
next

 


ll_result = getclientinfo(gs1, cs1, cbrs1, cirs1, cidrs1, grs1)

it works for me, I'd like to thanks for all you guys,thanks for the helps, I apperciated it

Attachments (4)
John Fauss Accepted Answer Pending Moderation
  1. Friday, 23 April 2021 20:27 PM UTC
  2. PowerBuilder
  3. # 1

I've thought about this a little more and I think the issue is due to the differences between PB and C++ in how string arrays are represented in memory.

I believe string arrays in C++ are laid out as a continuous series of null-terminated characters, followed by a series-terminating null character, for example:

string-one/0string-two/0string-three/0/0

Another way to look at this information from PB's perspective is that this is simply an array of characters where a single null delimits adjacent strings and a double-null sequence marks the end of the last string.

This is not how PB manages a string array. In order for PB to "decode" or decompose the C++ array of strings, you have to scan the characters one-by-one and re-construct each string in PB. To pass an array of PB strings to C++ DLL, you do the opposite.

The "GetFileName" free code sample PB application on Roland Smith's TopWizProgramming web site shows how to decompose the **char character sequence into an array of PB strings. Look at the of_CharToString function in the n_getfilename object and also the of_GetFileName function. It can also perform the opposite translation (of_StringtoChar function).

HTH, John

Comment
  1. John Fauss
  2. Friday, 23 April 2021 21:37 PM UTC
To do this using a structure, I think you'll have to use either a blob or an initialized character array in place of each string array, then unpack/pack the blob/character array in PB.
  1. Helpful
  1. Albert John
  2. Saturday, 24 April 2021 00:50 AM UTC


I really appreciate your helps, I didn't expect it's way more compliacted, I just have an idea to deal with this issue, I was trying to parse json to the PB application, due to PB 12.5 has no such functionality, I have to parse the json in C++, due to the PB 2019 has functionalities which parse json, I gonna try this PB build-in function, https://docs.appeon.com/pb2019/application_techniques/ch18s02.html#d0e14108

TBH I used to use char ** as the parameters of function in PB, not in the structure as parameter , overall it worked fine for me ,I have no idea it might be an issue when I use it in structure, due to it has a bunch of variables(around 50 variable which is array) from the restful web service, I tried it in my way,anyway, thank you again
  1. Helpful
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Friday, 23 April 2021 14:59 PM UTC
  2. PowerBuilder
  3. # 2

Hi Albert;

  This could be due to the changes that Sybase made in PB version 12.6 that are now within Appeon PB as well. That would be the decision to align structures on double-word (8-byte) memory boundaries vs 1 byte alignment memory alignment in PB version 12.5.X and below.

  You can change the byte alignment in the PB IDE's "System Options" dialogue, as follows:

  If the above works, have a look at the "progma_pack" setting in the PB Help for more guidance.

FYI: http://www.appeon.com/developers/get-help/knowledgebase/use-1-byte-structure-member-alignment-external-function-64-bit-pb-applications.html

Regards ... Chris

Comment
  1. Albert John
  2. Saturday, 24 April 2021 00:45 AM UTC
OK cool ,thank you so much ,sir
  1. Helpful
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Friday, 23 April 2021 14:13 PM UTC
  2. PowerBuilder
  3. # 3

Hi, Albert - 

I suggest you attack this issue in small steps. Set aside your large, complex interface momentarily.

Create a DLL entry point that populates a single PB string variable passed by reference and get that working.

PB strings are Unicode (Unicode-16LE, to be specific, like Windows). Is your C++ DLL doing the same?

Next, populate a PB string array. How will the DLL know/determine the number of strings in the PB array? If the DLL is assuming the string array is terminated by a double-null character sequence, this may not be the case. PB may manage arrays differently. I know in many cases in the Windows API where an array of varying size is passed, an integer count of the number of elements contained in the array is also passed, either as a separate argument or as another structure member. Something to keep in mind.

Next, introduce using a structure. Start simple and add complexity step by step. Build up your knowledge and expertise gradually and don't try to solve the entire problem at once.

You are obviously aware that all of the strings to be returned to PB by the DLL have to first be populated and initialized in PB, as PB must manage the memory used by its variables/arrays.

I think what you are trying to accomplish can be done, but it may not turn out to be as straightforward to pull off as you may have first thought.

Good luck!

Comment
  1. Albert John
  2. Friday, 23 April 2021 14:30 PM UTC
PB strings are Unicode (Unicode-16LE, to be specific, like Windows). Is your C++ DLL doing the same?

A:yes, I did use Use Unicode Character Set

How will the DLL know/determine the number of strings in the PB array?

A: I used variable which insuinforecordscount and idetinforecordscount as well for couting the number of strings

on the other hand each string determined by \n though

  1. Helpful
  1. Albert John
  2. Friday, 23 April 2021 14:30 PM UTC
thanks for answered my question and the suggestions
  1. Helpful
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Friday, 23 April 2021 13:10 PM UTC
  2. PowerBuilder
  3. # 4

I'm a noob but ... could it be your DLL needs to be registered with regsvr32.exe ?

I see that's probably a stupid remark, as you seem to be able to debug this in C++, meaning that your DLL is being called.

Why not convert this DLL to C# DLL. It'll make your life much easier and you can use the DLL importer tool to import the functions.

(probably also stupid, maybe your C++ project is huge!)

Hope anyone else can help you out.

(Can you post the DLL ? )

Comment
  1. Albert John
  2. Friday, 23 April 2021 14:26 PM UTC
thanks for answered my question,nope, it's a regular dll which is NOT ole
  1. Helpful
  1. Albert John
  2. Friday, 23 April 2021 14:31 PM UTC
it's unnecessary to be registered with regsvr32.exe
  1. Helpful
There are no comments made yet.
Andreas Mykonios Accepted Answer Pending Moderation
  1. Friday, 23 April 2021 10:26 AM UTC
  2. PowerBuilder
  3. # 5

Hi.

As far as I remember, ** means it is a pointer to an array (pointer to a pointer, probably because it's inside a structure). If I'm right then you are not calling you function correctly. You may need to use the ref keyword, but let see if someone with more experience with c can give a better hint.

Andreas.

Comment
  1. Albert John
  2. Friday, 23 April 2021 12:19 PM UTC
thanks for answered my question,I forgot to metion that I did use ref

in Global external function I decleared

function long getclientinfo(general_struct gs,&

clientinfo_struct cs,&

ref clientinfo_baseinfo_ret_struct cbrs,&

ref clientinfo_insuinfo_ret_struct cinsurs,&

ref clientinfo_idetinfo_ret_struct cidenrs,&

ref general_ret_struct grs) &

LIBRARY "dgnewsbsapi.dll" Alias for 'getclientinfo;Ansi'

but it's not working
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.