API dll calls - c syntax conversion

MiKman

New Member
I am treading into new waters here, but I need to make some calls to procedures located in a .dll file. Following is the c syntax for the call:

int Process_record (
char *inputRec,
int *inputSize,
char *outputRec,
int *outputSize,
TSTError *STError )

the TSTError is defined as the following:

enum TTypeCode{erWindows,erInternal};
struct TSTError {
int STErrorCode,
TTypeCode STErrorType,
char STErrorMsg[255]
}PSTError;

So far I have the following:
PROCEDURE Process_record EXTERNAL "record.dll":
DEF RETURN PARAM vReturn AS INT.
DEF INPUT PARAM inputRec AS CHAR.
DEF INPUT PARAM inputSize AS INT.
DEF OUTPUT PARAM outputRec AS CHAR.
DEF OUTPUT PARAM outputSize AS INT.
DEF OUTPUT PARAM TSTError AS MEMPTR.
END PROCEDURE.

but this whole TTypeCode has me thrown for a loop. Any ideas where I need to go from here? Or does it look ok up to this point?

Thanks,
Mike
 
Hi Mike,

Not sure if you can define the return parameter first, all the examples I have seen define it as the last parameter. Also the C procedure expects pointers to in for in and out size (ie int *) so you need memptr types on these. If you intend to call process_record a number of times it's best to load the procedure persistent

Code:
PROCEDURE Process_record EXTERNAL "record.dll" persistent:
    DEF INPUT PARAM inputRec AS CHAR.
    DEF INPUT PARAM inputSize AS MEMPTR.
    DEF OUTPUT PARAM outputRec AS CHAR.
    DEF OUTPUT PARAM outputSize AS MEMPTR.
    DEF OUTPUT PARAM TSTError AS MEMPTR.
    DEF RETURN PARAM vReturn AS INT.
END PROCEDURE.

use RELEASE EXTERNAL PROCEDURE "record.dll". in window close trigger.

example of call is as follows:

Code:
def var lm_insize as memptr no-undo.
def var lm_outsize as memptr no-undo.
def var lm_STError as memptr no-undo.
def var lc_return as char no-undo.

def var STErrorCode as int no-undo.
def var STErrorType as int no-undo.
def var ErrorString as char no-undo.
def var inputRec as char no-undo.
def var outputRec as char no-undo.

set-size(lm_insize) = 2.
set-size(lm_outsize) = 2.
put-short(lm_insize) = length(inputRec).

run Process_record(
    input inputRec,
    input lm_insize,
    output outputRec,
    output lm_outsize,
    output lm_STError
    output lc_return).

assign
    STErrorCode = get-short(lm_STError, 1)
    STErrorType = get-short(lm_STError, 3)
    ErrorString = get-string(lm_STError, 5).

set-size(lm_insize) = 0.
set-size(lm_outsize) = 0.

Hope this gets you on the right path.

Simon
 

MiKman

New Member
still no go

This is how I have it now, thanks for the help, but it still seems to be not working properly I am getting no visible progress/windows errors however I do get a 0 (zero) back in the STErrorCode which, according to the dll documentation, indicates function failure. I also get a 0 (zero) in STErrorType, which, according to the dll documentation, indicates a windows error. And the vChar is blank so not much help. I think there must be something failing and I don't know what. is there anyway I can debug these calls to a dll? It's not our dll so I cannot look at the code... any ideas?


PROCEDURE Process_record EXTERNAL "STransDirect.DLL" CDECL:
DEF INPUT PARAM vinputRec AS MEMPTR.
DEF INPUT PARAM vinputSize AS MEMPTR.
DEF OUTPUT PARAM voutputRec AS MEMPTR.
DEF OUTPUT PARAM voutputSize AS MEMPTR.
DEF OUTPUT PARAM vTSTError AS MEMPTR.
DEF RETURN PARAM vReturn AS LONG.
END PROCEDURE.


called like so from:

DEF VARIABLE vErrorMsg AS MEMPTR NO-UNDO.
DEF VARIABLE vResultSize AS MEMPTR NO-UNDO.
DEF VARIABLE vResultPtr AS MEMPTR NO-UNDO.
DEF VARIABLE vInSize AS MEMPTR NO-UNDO.
DEF VARIABLE vInPtr AS MEMPTR NO-UNDO.
DEF VARIABLE vRawRec AS RAW NO-UNDO.
DEF VARIABLE STErrorType AS INT NO-UNDO.
DEF VARIABLE STErrorCode AS INT NO-UNDO.

SET-SIZE(vErrorMsg) = 260.
SET-SIZE(vInSize) = 2.
SET-SIZE(vResultSize) = 2.
SET-SIZE(vResultPtr) = 300.
SET-SIZE(vInPtr) = vLength.

PUT-BYTES(vInPtr,1) = GET-BYTES(vRawRec,1,vLength).
put-short(vInSize,1) = vLength + 3 NO-ERROR.

RUN Process_record (INPUT vInPtr,
INPUT vInLength,
OUTPUT vResultPtr,
OUTPUT vResultLength,
OUTPUT vErrorMsg,
OUTPUT vReturn).

ASSIGN
vInt = GET-SHORT(vOutputLength,1).
vChar = get-string(vErrorMsg, 5).
STErrorCode = get-short(vErrorMsg, 1).
STErrorType = get-short(vErrorMsg, 3).
vResultRec = GET-STRING(vResultPtr,1).
 

bendaluz2

Member
Your definition isnt quite right

It should be

<pre>
PROCEDURE Process_record EXTERNAL "STransDirect.DLL" CDECL:
DEF INPUT PARAM vinputRec AS CHAR.
DEF INPUT PARAM vinputSize AS MEMPTR.
DEF OUTPUT PARAM voutputRec AS CHAR.
DEF OUTPUT PARAM voutputSize AS MEMPTR.
DEF OUTPUT PARAM vTSTError AS MEMPTR.
DEF RETURN PARAM vReturn AS LONG.
END PROCEDURE.
</pre>

A character variable does not need to be passed through as a MEMPTR as it is already a pointer. All other data types, however, do.
 

MiKman

New Member
thanks guys But I have one more problem

I think it is functioning as intended, but I am still not getting the response I would like. I think the problem is that This dll I am calling has 2 procedures in it. One is the one we have been discussing and one is a much more simple call:

PROCEDURE Load_ini EXTERNAL "STransDirect.dll" CDECL:
DEF INPUT PARAM INIPath AS CHAR.
DEF RETURN PARAM vint AS LONG.
END PROCEDURE.

This one actually works I get a return value of 1 (which means successful) when I call it with the following:

RUN Load_ini (INPUT "C:\Windows\",
OUTPUT vReturn).

However, these two routines work in conjunction with each other the first points to and loads an initialization file for use with when I call the second routine to manipulate the data. I think this dll needs to be loaded persistently, but the problem is I cannot define both these procedures with the persistent option, as I get an error when I call the second procedure. same error if I only load one persistently. (Prowin32 - This program has performed an illegal operation PROWIN32 caused an invalid page fault in
module PROW32.DLL at 017f:1000a6e7.)

Is there anyway to load a dll persistently outside of the procedure declarations? Like load it once then define procedures, and when done release it?

Thanks for all the help guys I appreciate it.
Mike
 

MiKman

New Member
ok thats not the problem

I jumped the gun a bit on the previous post, I have set both external procedure definitions to PERSISTENT. ANd it appears to be working ok. The problem with the error I am getting seems to be something I have either setup incorrect with the struct or defined the memptr to the wrong size maybe... I think the problem is now with this:

enum TTypeCode{erWindows,erInternal};

struct TSTError {
int STErrorCode,
TTypeCode STErrorType,
char STErrorMsg[255]
}PSTError;

which I is just an OUTPUT param defined as a MEMPTR. But what should I initialize the size to? This is what I have it set to now.

SET-SIZE(vErrorMsg) = 260.

Can anyone see any flaws with this size?

Thanks,
Mike
 
Try defining the TSTError parameter as input-output.

Use some put-short and put-string statements to initialise it with data if this gets changed back to zero and blank at least you know the routine is updating your structure.
 

MiKman

New Member
Thanks simon, but unfortunately...

It's not updating the fields, great idea tho. I don't think I would have thought of it. There must be something wrong with my initial set-size for the memptr. If I knew how many bytes this structure required I think I would be away...


enum TTypeCode{erWindows,erInternal}; /* what does this really mean? */

struct TSTError {
int STErrorCode, /* 4 bytes right? */
TTypeCode STErrorType, /* I have no clue see above enum */
char STErrorMsg[255] /* 255 bytes obviously */
}PSTError;

I think it has to be exactly acurate otherwise I cannot get the correct values from memory I cannot just give it some arbitrarily large byte count it doesn't work...

Any more help anyone can give is much appreciated...

Thanks,
Mike
 
enum is 4 bytes giving 263 bytes for your total structure size.

It could also be the case that the DLL is expecting a pointer to the structure pointer in which case you will need to use the get-pointer-value fuction:

Code:
SET-SIZE(vErrorMsg) = 263.
SET-SIZE(vErrorMsgPtr) = 4.
PUT-LONG(vErrorMsgPtr, 1) = GET0-POINTER-VALUE(vErrorMsg).

RUN Process_record (
    INPUT vInPtr,
    INPUT vInLength,
    INPUT vResultPtr,
    INPUT vResultLength,
    INPUT vErrorMsg,
    OUTPUT vReturn).

Also notice how the memptrs you have created should be passed as input parameters. This is because you are passing a pointer to some memory you have allocated to the DLL to be updated with result data.

I have seen some others pass these pointers as input-output, but if you have created memory and intend to use set-size to free it later I can't see why you would allow the DLL to change your pointer value. The contents YES but the actual pointer NO.
 

MiKman

New Member
Thanks Simon!

I appreciate the tips on the INPUT/OUPTUT for pointers I never really thought thats what I was doing was passing the location not the value. thanks. Also I finally was able to get ahold of the developer of the dll and foudn out that the error structure is currently not used (not what the documentation said!) So this is the reason it's not being updated.

Thanks again.
 
Top