'In PowerBASIC (versions lower than 7.x) it is not possible to directly call a C
'function in a DLL if that function uses the _cdecl calling convention. This is
'because PowerBASIC uses the _stdcall calling convention for calling functions.
'This is a problem because if _cdecl is used, the calling function is responsible
'for cleaning up; the stack. However, if _stdcall is used, the called function is
'responsible for cleaning up the stack.
'The solution is to use wrapper DLL which wraps __cdecl calls into __stdcall calls.
'Such a wrapper interface is provided in DLL file "NIST_library_stdcall.dll".
'However beginning from PowerBASIC Version 7.x
'Sub/Function can be declared as CDECL or SDECL/STDCALL or BDECL.
'In this sample project __stdcall wrapper interface is used for backwards compability.

$DllName = "NIST_library_stdcall.dll"


DECLARE FUNCTION RegisterNIST () AS LONG
'DECLARE FUNCTION RegisterNIST LIB "NIST_library_stdcall.dll" ALIAS "RegisterNIST_stdcall" () AS LONG
DECLARE FUNCTION CreateNewNISTFile () AS LONG
DECLARE FUNCTION WriteNISTToFile (BYVAL filename AS STRING) AS LONG
DECLARE FUNCTION ReadNISTFromFile(BYVAL filename AS STRING) AS LONG
DECLARE FUNCTION ReadNISTFromMemory(BYREF byte_array AS BYTE, BYVAL size_of_byte_array AS LONG) AS LONG
DECLARE FUNCTION CheckIfRecordTypeExists(BYVAL recordtypenumber AS LONG) AS LONG
DECLARE FUNCTION ReadNumberOfRecords(BYVAL recordtypenumber AS LONG) AS LONG
DECLARE FUNCTION ReadIDCofRecord(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG
DECLARE FUNCTION ReadRecordTxtField(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG, BYVAL recordfieldnumber AS LONG, BYVAL recordfieldname AS STRING) AS LONG
DECLARE FUNCTION ReadSizeOfRecordTxtField(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG, BYVAL recordfieldnumber AS LONG, BYVAL recordfieldname AS STRING) AS LONG
DECLARE FUNCTION ReadRecordTxtFieldName(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG, BYVAL recordfieldnumber AS LONG) AS LONG
DECLARE FUNCTION ReadSizeOfRecordTxtFieldName(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG, BYVAL recordfieldnumber AS LONG) AS LONG
DECLARE FUNCTION ReadRecordTxtFieldDescription(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG, BYVAL recordfieldnumber AS LONG, BYVAL recordfieldname AS STRING) AS LONG
DECLARE FUNCTION ReadSizeOfRecordTxtFieldDescription(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG, BYVAL recordfieldnumber AS LONG, BYVAL recordfieldname AS STRING) AS LONG
DECLARE FUNCTION ReadRecordExportedTxtFields(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG
DECLARE FUNCTION ReadSizeOfRecordExportedTxtFields(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG
DECLARE FUNCTION ReadRecordBinaryField(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG
DECLARE FUNCTION ReadSizeOfRecordBinaryField(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG
DECLARE FUNCTION CreateHBITMAPfromRecordBinaryField(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG
DECLARE FUNCTION InsertRecordBinaryFieldFromFile(BYVAL record_type_number AS LONG, BYVAL idc AS LONG, BYVAL filename AS STRING) AS LONG
DECLARE FUNCTION InsertRecordBinaryFieldFromMemory(BYVAL record_type_number AS LONG, BYVAL idc AS LONG, BYREF input_byte_array AS BYTE, BYVAL size_of_input_byte_array AS LONG, BYVAL CGA AS STRING, _
        BYVAL CGA_int AS LONG, BYVAL HLL AS LONG, BYVAL VLL AS LONG)  AS LONG
DECLARE FUNCTION InsertRecordTxtField(BYVAL record_type_number AS LONG, BYVAL idc AS LONG, BYVAL record_field_number AS LONG, BYVAL record_field_name AS STRING, BYVAL input_data AS STRING) AS LONG
DECLARE FUNCTION DeleteRecord(BYVAL recordtypenumber AS LONG, BYVAL idc AS LONG) AS LONG





TYPE NISTLibrary_Proc

    pRegisterNIST                             AS DWORD
    pCreateNewNISTFile                        AS DWORD
    pWriteNISTToFile                          AS DWORD
    pReadNISTFromFile                         AS DWORD
    pReadNISTFromMemory                       AS DWORD
    pCheckIfRecordTypeExists                  AS DWORD
    pReadNumberOfRecords                      AS DWORD
    pReadIDCofRecord                          AS DWORD
    pReadRecordTxtField                       AS DWORD
    pReadSizeOfRecordTxtField                 AS DWORD
    pReadRecordTxtFieldName                   AS DWORD
    pReadSizeOfRecordTxtFieldName             AS DWORD
    pReadRecordTxtFieldDescription            AS DWORD
    pReadSizeOfRecordTxtFieldDescription      AS DWORD
    pReadRecordExportedTxtFields              AS DWORD
    pReadSizeOfRecordExportedTxtFields        AS DWORD
    pReadRecordBinaryField                    AS DWORD
    pReadSizeOfRecordBinaryField              AS DWORD
    pCreateHBITMApfromRecordBinaryField       AS DWORD
    pInsertRecordBinaryFieldFromFile          AS DWORD
    pInsertRecordBinaryFieldFromMemory        AS DWORD
    pInsertRecordTxtField                     AS DWORD
    pDeleteRecord                             AS DWORD







END TYPE

TYPE NISTLibrary_Params

    hLib    AS LONG
    DProcs  AS NISTLibrary_Proc

END TYPE


GLOBAL NISTLibrary_Param AS NISTLibrary_Params



' This call loads the NISTLibrary library, an optional library name may be set.
' All other procedures will call this procedure anyway.
' The lib is loaded only once.
FUNCTION NISTLibrary_LoadLibrary() AS LONG

    DIM dp AS NISTLibrary_Params
    LOCAL sOptLibName AS STRING

    IF NISTLibrary_Param.hLib THEN
        FUNCTION = 1
        EXIT FUNCTION
    END IF

    sOptLibName = $DllName
    NISTLibrary_Param.hLib = LoadLibrary( BYVAL STRPTR( sOptLibName ) )

    SELECT CASE NISTLibrary_Param.hLib
       CASE 0 TO 32
          NISTLibrary_Param.hLib = 0
          EXIT FUNCTION
    END SELECT



    NISTLibrary_Param.DProcs.pRegisterNIST                              = GetProcAddress( NISTLibrary_Param.hLib, "RegisterNIST_stdcall" )
    NISTLibrary_Param.DProcs.pCreateNewNISTFile                         = GetProcAddress( NISTLibrary_Param.hLib, "CreateNewNISTFile_stdcall" )
    NISTLibrary_Param.DProcs.pWriteNISTToFile                           = GetProcAddress( NISTLibrary_Param.hLib, "WriteNISTToFile_stdcall" )
    NISTLibrary_Param.DProcs.pReadNISTFromFile                          = GetProcAddress( NISTLibrary_Param.hLib, "ReadNISTFromFile_stdcall" )
    NISTLibrary_Param.DProcs.pReadNISTFromMemory                        = GetProcAddress( NISTLibrary_Param.hLib, "ReadNISTFromMemory_stdcall" )
    NISTLibrary_Param.DProcs.pCheckIfRecordTypeExists                   = GetProcAddress( NISTLibrary_Param.hLib, "CheckIfRecordTypeExists_stdcall" )
    NISTLibrary_Param.DProcs.pReadNumberOfRecords                       = GetProcAddress( NISTLibrary_Param.hLib, "ReadNumberOfRecords_stdcall" )
    NISTLibrary_Param.DProcs.pReadIDCofRecord                           = GetProcAddress( NISTLibrary_Param.hLib, "ReadIDCofRecord_stdcall" )
    NISTLibrary_Param.DProcs.pReadRecordTxtField                        = GetProcAddress( NISTLibrary_Param.hLib, "ReadRecordTxtField_stdcall" )
    NISTLibrary_Param.DProcs.pReadSizeOfRecordTxtField                  = GetProcAddress( NISTLibrary_Param.hLib, "ReadSizeOfRecordTxtField_stdcall" )
    NISTLibrary_Param.DProcs.pReadRecordTxtFieldName                    = GetProcAddress( NISTLibrary_Param.hLib, "ReadRecordTxtFieldName_stdcall" )
    NISTLibrary_Param.DProcs.pReadSizeOfRecordTxtFieldName              = GetProcAddress( NISTLibrary_Param.hLib, "ReadSizeOfRecordTxtFieldName_stdcall" )
    NISTLibrary_Param.DProcs.pReadRecordTxtFieldDescription             = GetProcAddress( NISTLibrary_Param.hLib, "ReadRecordTxtFieldDescription_stdcall" )
    NISTLibrary_Param.DProcs.pReadSizeOfRecordTxtFieldDescription       = GetProcAddress( NISTLibrary_Param.hLib, "ReadSizeOfRecordTxtFieldDescription_stdcall" )
    NISTLibrary_Param.DProcs.pReadRecordExportedTxtFields               = GetProcAddress( NISTLibrary_Param.hLib, "ReadRecordExportedTxtFields_stdcall" )
    NISTLibrary_Param.DProcs.pReadSizeOfRecordExportedTxtFields         = GetProcAddress( NISTLibrary_Param.hLib, "ReadSizeOfRecordExportedTxtFields_stdcall" )
    NISTLibrary_Param.DProcs.pReadRecordBinaryField                     = GetProcAddress( NISTLibrary_Param.hLib, "ReadRecordBinaryField_stdcall" )
    NISTLibrary_Param.DProcs.pReadSizeOfRecordBinaryField               = GetProcAddress( NISTLibrary_Param.hLib, "ReadSizeOfRecordBinaryField_stdcall" )
    NISTLibrary_Param.DProcs.pCreateHBITMAPfromRecordBinaryField        = GetProcAddress( NISTLibrary_Param.hLib, "CreateHBITMAPfromRecordBinaryField_stdcall" )
    NISTLibrary_Param.DProcs.pInsertRecordBinaryFieldFromFile           = GetProcAddress( NISTLibrary_Param.hLib, "InsertRecordBinaryFieldFromFile_stdcall" )
    NISTLibrary_Param.DProcs.pInsertRecordBinaryFieldFromMemory         = GetProcAddress( NISTLibrary_Param.hLib, "InsertRecordBinaryFieldFromMemory_stdcall" )
    NISTLibrary_Param.DProcs.pInsertRecordTxtField                      = GetProcAddress( NISTLibrary_Param.hLib, "InsertRecordTxtField_stdcall" )
    NISTLibrary_Param.DProcs.pDeleteRecord                              = GetProcAddress( NISTLibrary_Param.hLib, "DeleteRecord_stdcall" )




    ' Are all calls available IN the DLL?
    IF INSTR( PEEK$( VARPTR( NISTLibrary_Param.DProcs ), LEN( NISTLibrary_Proc ) ), MKL$( 0 ) ) THEN

        FreeLibrary NISTLibrary_Param.hLib
        NISTLibrary_Param = dp

    END IF

    FUNCTION = ISTRUE( NISTLibrary_Param.hLib )

END FUNCTION



' You should free the library on application exit.
FUNCTION NISTLibrary_FreeLibrary() AS LONG

    DIM dp AS NISTLibrary_Params

    IF NISTLibrary_Param.hLib = 0 THEN EXIT FUNCTION

    FreeLibrary NISTLibrary_Param.hLib

    NISTLibrary_Param = dp

    FUNCTION = 1

END FUNCTION
