Home Forums HTBasic Forum Bug List Reply To: Bug List

#448
guynoir
Participant

    In order to amplify on item #4 in my previous post, I would like to summarize the issues I have run into when passing strings from/to HT Basic and a DLL. One is documented the other is not.

    1. A string variable must dimensioned one character longer than the maximum number of characters it needs to hold in order to leave room for the null terminator. If not, an error 1108 will be generated when passing the string variable to a DLL. This issue is documented.

    2. Passing a string literal of one character or less to a DLL does not work as expected. This issue is not documented. Normally, when passing a string by either value (i.e. a literal) or by reference, a pointer to a null terminated string is passed to the DLL. Passing a one character string does not pass a pointer to the DLL as expected but instead passes a single character (byte) value. Passing a null literal doesn’t pass an address either. In fact I’m not sure if it passes anything at all.

    The Outcome of all this is that passing strings to a DLL can produce unexpected results. Take for example the following code

    DLL LOAD “DLL_file”
    DLL GET “VOID DLL_file:Dll_sub”
    CALL Sub1(“String”)

    SUB Sub1(S$)
    CALL Dll_sub(S$)
    SUBEND

    The above code will always generate ERROR 1108 when calling Dll_sub. This is because Sub1 will create S$ of the minimum required length (i.e. 6), just long enough to hold “String”. This when passed to Dll_sub it will generate an error because the DLL will not have the room to add the null terminator to the string. The same error will happen in the following case where the string is passed by value instead of passing a literal.

    DLL LOAD “DLL_file”
    DLL GET “VOID DLL_file:Dll_sub”
    DIM S$[8]
    S$=”String”
    CALL Sub1((S$))

    SUB Sub1(S$)
    CALL Dll_sub(S$)
    SUBEND

    As a work around the following code should work in many cases:

    DLL LOAD “DLL_file”
    DLL GET “VOID DLL_file:Dll_sub”
    DIM S$[8]
    S$=”String”
    CALL Sub1(S$)

    SUB Sub1(S$)
    CALL Dll_sub((S$))
    SUBEND

    Obviously, the above code won’t work correctly if Dll_sub returns a value through S$. It also won’t work if S$ is defined as a single or zero length string (i.e. S$=””). In this situation Dll_sub would not be passed a pointer to a string but a character literal or possibly nothing at all. HT Basic will probably crash when the DLL attempts to treat the passed information as the pointer it expects.

    The following is the only way that I have found that will reliably handle all passed strings:

    DLL LOAD “DLL_file”
    DLL GET “VOID DLL_file:Dll_sub”
    DIM S$[8]
    S$=”String”
    CALL Sub1(S$)

    SUB Sub1(S$)
    ALLOCATE T$[MIN(MAXLEN(T$)+1,32767)]
    T$=S$ ! required if S$ is used for input
    CALL Dll_sub(T$)
    S$=T$ ! required if S$ is used for output
    SUBEND

    Sub1 insures that the string is at least one character longer than maximum length supported by the passed string variable S$. It also passes the string value by reference thus avoiding a problem is S$ is passed as single length or null string literal.

    Now you might maintain that the best solution is to call Dll_sub directly. That way you would have direct control on what was input to the DLL and thereby avoid some of these problems. While possible in this example, in many cases it simply is not. Even when it is, I strongly recommend accessing DLL SUB’s only through HT Basic wrapping functions or SUB’s. This is especially true in libraries that may be used by third parties. HT Basic does not detect parameter mis-matches on call’s to DLL SUBs, even at run-time. Also, the way the variable is passed (by reference or by type) is critical. Get either of these wrong when calling a DLL SUB and you will likely crash HT Basic and no have no record of what happened or where. A wrapper SUB or function can insure that the DLL SUB is accessed correctly and minimize the chance of a crash.

    Scroll to Top
    HTB icon

    Please Sign In