1. Albert John
  2. PowerBuilder
  3. Monday, 17 May 2021 02:21 AM UTC

Hi Guys

    I have built a DLL for Powerbuilder and I tried to calling a function from it, inside of function DLL I have debuged, it just worked fine, but it has crashed after PB called it when PB was complished the program, it's not carshed during calling the function though, the function within VC++ was complex though, it's like 

 

typedef struct query_settle_datail_struct{
const char * setl_optins;
const char * stmt_begndate;
const char * stmt_enddate;
double medfee_sumamt;
double fund_pay_sumamt;
double cash_payamt;
int fixmedins_setl_cnt;

}query_settle_datail_struct;

typedef struct query_file_struct{
char * file_qury_no;
char * filename;
char * fixmedins_code;
char * dld_endtime;
}query_file_struct;


typedef struct upload_file_content_struct{

const char * setl_id;
const char * mdtrt_id;
const char * psn_no;
double medfee_sumamt;
double fund_pay_sumamt;
double acct_pay;
const char * refd_setl_flag;
}upload_file_content_struct;

typedef struct query_settle_datail_ret_struct{

char * psn_no;
char * mdtrt_id;
char * setl_id;
char * msgid;
char * stmt_rslt;
char * refd_setl_flag;
char * memo;
}query_settle_datail_ret_struct;



__declspec(dllexport) int _stdcall querytransettledetail(general_struct & gs,

query_settle_datail_struct & qsds,
int updfilerecordscount,
upload_file_content_struct * updfilecontents,
query_file_struct & updfilestruct,
query_file_struct & dlfilestruct,
int & qsdrrecrodscount,
query_settle_datail_ret_struct * qsdrs,
general_ret_struct & grs);

 

I tried to decalre it on external function within PB

 

function long querytransettledetail(general_struct gs, &
query_settle_datail_struct qsds,&
long updfilerecordscount,&
upload_file_content_struct updfilecontents[],&
ref query_file_struct updfilestruct,&
ref query_file_struct dlfilestruct,&
ref long qsdrrecrodscount,&
ref query_settle_datail_ret_struct qsdrs[],&
ref general_ret_struct grs) &
LIBRARY "dgnewsbsapi.dll" Alias for 'querytransettledetail;Ansi'

 

 

the code below was what I trying to call this function

 

query_settle_datail_struct qsds
qsds.setl_optins=dw_3.getitemstring(row,"setl_optins")
qsds.stmt_begndate=string(dw_3.getitemdatetime(row,"stmt_begndate"),"yyyy-mm-dd")
qsds.stmt_enddate=string(dw_3.getitemdatetime(row,"stmt_enddate"),"yyyy-mm-dd")
qsds.medfee_sumamt=dw_3.getitemnumber(row,"medfee_sumamt")
qsds.fund_pay_sumamt=dw_3.getitemnumber(row,"fund_pay_sumamt")
qsds.cash_payamt=dw_3.getitemnumber(row,"cash_payamt")
qsds.fixmedins_setl_cnt=dw_3.getitemnumber(row,"fixmedins_setl_cnt")

long updfilerecordscount

updfilerecordscount=dw_query_detail.rowcount()
upload_file_content_struct updfilecontents[]
for ll_row=1 to updfilerecordscount

updfilecontents[ll_row].setl_id=dw_query_detail.getitemstring(ll_row,"setl_id")
updfilecontents[ll_row].mdtrt_id=dw_query_detail.getitemstring(ll_row,"mdtrt_id")
updfilecontents[ll_row].psn_no=dw_query_detail.getitemstring(ll_row,"psn_no")
updfilecontents[ll_row].medfee_sumamt=dw_query_detail.getitemnumber(ll_row,"medfee_sumamt")
updfilecontents[ll_row].fund_pay_sumamt=dw_query_detail.getitemnumber(ll_row,"fund_pay_sumamt")
updfilecontents[ll_row].acct_pay=dw_query_detail.getitemnumber(ll_row,"acct_pay")
updfilecontents[ll_row].refd_setl_flag=dw_query_detail.getitemstring(ll_row,"refd_setl_flag")
if isnull( updfilecontents[ll_row].refd_setl_flag) or trim(updfilecontents[ll_row].refd_setl_flag)="" then updfilecontents[ll_row].refd_setl_flag="0"

next

query_file_struct updfilestruct
updfilestruct.file_qury_no=space(50)
updfilestruct.filename=space(200)
updfilestruct.fixmedins_code=space(50)
updfilestruct.dld_endtime=space(50)

query_file_struct dlfilestruct
dlfilestruct.file_qury_no=space(50)
dlfilestruct.filename=space(200)
dlfilestruct.fixmedins_code=space(50)
dlfilestruct.dld_endtime=space(50)

long qsdrrecrodscount
qsdrrecrodscount=updfilerecordscount+20
query_settle_datail_ret_struct qsdrs[]
for ll_row=1 to qsdrrecrodscount
qsdrs[ll_row].psn_no=space(30)
qsdrs[ll_row].mdtrt_id=space(30)
qsdrs[ll_row].setl_id=space(30)
qsdrs[ll_row].msgid=space(30)
qsdrs[ll_row].stmt_rslt=space(6)
qsdrs[ll_row].refd_setl_flag=space(3)
qsdrs[ll_row].memo=space(500)

next

ll_result=querytransettledetail( gs1, &
qsds,&
updfilerecordscount,&
updfilecontents,&
updfilestruct,&
dlfilestruct,&
qsdrrecrodscount,&
qsdrs,&
grs1)

if ll_result=0 then

messagebox("ret","calling successful")

else

messagebox("ret","calling failed")

end if 

 

it carshed after it executed the messagebox function,the messagebox pop-up normal but afterward the program carshed, any idea? my speculation was PB crashed when it release the memory

John Fauss Accepted Answer Pending Moderation
  1. Tuesday, 18 May 2021 02:09 AM UTC
  2. PowerBuilder
  3. # 1

Hi, Albert -

I have several observations, questions & suggestions, which I'll cover in no particular order.

1. Do you realize that by specifying ;ansi in the PB external function declaration (EFD), you're telling PB to produce an under-the-covers copy of every argument that contains character data PRIOR to calling the DLL entry point, then converting and copying the contents of any parameters passed by reference back to Unicode when the DLL entry point completes? Given the apparent quantity of data being passed, this is a significant amount of work.

2. Are the DLL and PB application running as 32-bit? Obviously, a PB app running from within the IDE is going to be 32-bit. I bring this up to point out that the memory layout of structure members can differ, depending on bitness and the datatypes of the members involved.

3. Have you verified that the information in each type of PB structure can be correctly received and interpreted by the DLL? As Chris has mentioned, there can be inconsistencies between how PB lays out a structure in memory and how C++ does same. Given the number of and complexity of the structures, I strongly recommend you create a test DLL containing an entry point that accepts ONE type of structure, passed by value. In the DLL, verify that it can access all structure member values. Once that works, change the DLL and calling PB code to pass the structure by reference. Re-verify the DLL can access all structure member values, then change the values in the DLL and verify PB can see the values that have been set in the DLL. This is particularly important if you must convert character data between Unicode and ANSI. Then, for argument parameters that are an array of structures, repeat same for an array of that structure with 2 or 3 elements in the array. Doing this may sound like an unnecessary amount of work, but memory alignment errors can be very difficult to troubleshoot when working with DLL's, so validating that you know the correct coding techniques in both the DLL and in PB can be very helpful to achieving your overall goal.

4. My C++ skills are admittedly rusty, so I'm confused by the use/purpose of using the "&" operator in the DLL function declaration. It seems like there are some inconsistencies in how the argument parameters are defined in the PB external function declaration based on the DLL function declaration, but again, I could be off base here.

5. Keep in mind that the REF keyword in a PB EFD not only tells PB to pass the address of the argument parameter, it also tells PB that any changes to the argument value made by the DLL will be allowed and accessible by the PB application.

You're attempting to pass a potentially large quantity of information to/from a DLL in a variety of structure types. There are lots of places where subtle, hard-to-isolate issues can arise. A step-by-step, incremental approach to getting this to work is a good way to develop and debug an external interface of this complexity.

Best wishes, John

 

Comment
  1. Albert John
  2. Tuesday, 18 May 2021 03:39 AM UTC
I really apperciated your helps, thank you so much sir
  1. Helpful
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Monday, 17 May 2021 17:57 PM UTC
  2. PowerBuilder
  3. # 2

Hi Albert;

  The problem might be related to memory alignment. In the IDE's "System Options" dialogue have you tried the following ...

Regards ... Chris

Comment
  1. Albert John
  2. Tuesday, 18 May 2021 03:39 AM UTC
Thanks for answered my question,really apperciated it
  1. Helpful
There are no comments made yet.
René Ullrich Accepted Answer Pending Moderation
  1. Monday, 17 May 2021 05:44 AM UTC
  2. PowerBuilder
  3. # 3

Hi Albert,

I think the problem is the return of Strings. Usually you have to allocate memory in PowerBuilder first.

 

Here is an example of using GetTempPathW that illustrates how it may work:

FUNCTION long GetTempPathW (long nBufferLength, ref string lpBuffer) Library "kernel32.dll"

String ls_path
Long ll_length = 255

ls_path = Space (ll_length)
GetTempPathW (ll_length, ls_path)

 

Comment
  1. Albert John
  2. Monday, 17 May 2021 06:16 AM UTC
Hi ,thanks for answered my question, I did allocated memory though
  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.