PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 1/49 TITLE : Using the Database Framework as/in a DLL. WELCOME TO BORLAND PARADOX ENGINE 3.0 & DATABASE FRAMEWORK ---------------------------------------------------------- Update 1 (1/6/92) ----------------- This file contains important, late-breaking information about Paradox Engine 3.0 & Database Framework. This update changes two things. The source to the Database Framework has been modified so that it will compile into a DLL (dynamic link library). Also, the makefile has been modified to give different library names for different options. TABLE OF CONTENTS ----------------- 1. Contacting Borland 2. List of files in this update 3. Updating the Database Frameworks 4. Generating the DLL version of the Database Frameworks 5. Libraries produced by makefile.bc 1. CONTACTING BORLAND --------------------- If you have any problems, please read this file, the HELPME.TXT file, and the Paradox Engine 3.0 & Database Framework manuals first. If you still need assistance, see the Paradox Engine 3.0 "User's Guide" manual for a complete description of the different services Borland offers. For your convenience, the contact information is summarized below. TechFax ------- U.S. and Canada 800-822-4269 (voice) File Download BBS ----------------- U.S. and Canada 408-439-9096 PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 2/49 TITLE : Using the Database Framework as/in a DLL. Online information services --------------------------- CompuServe GO BORLAND BIX JOIN BORLAND GEnie BORLAND Technical Support ----------------- U.S. and Canada (6 a.m. to 5 p.m. Pacific time): C/C++ 408-461-9133 Pascal 408-461-9177 Technical Advisor ----------------- U.S. and Canada (6 a.m. to 5 p.m. Pacific time): C/C++ 900-555-1002 Pascal 900-786-6080 Customer Service ---------------- U.S. and Canada (6 a.m. to 5 p.m. Pacific time): 408-438-5300 (voice) 2. LIST OF FILES IN THIS UPDATE ------------------------------- brecord.cpp (modified) dbfmain.cpp (new) dbfdll.def (new) envdef.h (modified) makefile.bc (modified) 3. UPDATING THE DATABASE FRAMEWORKS ----------------------------------- This patch contains files which need to be put into the proper directories. Copy envdef.h to the \PXENG30\C\INCLUDE directory. Copy brecord.cpp, dbfmain.cpp, dbfdll.def, and makefile.bc to the \PXENG30\C\SOURCE directory. Microsoft C/C++ Users, please note that only the makefile for Borland PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 3/49 TITLE : Using the Database Framework as/in a DLL. C++ was modified. The Database Frameworks as a DLL was tested only with Borland C++. It will not work with the Microsoft C/C++ compiler. 4. GENERATING THE DLL VERSION OF THE DATABASE FRAMEWORKS -------------------------------------------------------- A new parameter to the makefile is -DDLL. This will create the Database Framework as a .DLL. This will assume you are creating for Windows (-DWINDOWS) and that you are using the dynamic version of the run-time library (-DDYNAMIC). 5. LIBRARIES PRODUCED BY MAKEFILE.BC ------------------------------------ The makefile.bc now produces different libraries names depending on which options you have set. By default, the following libraries are created and which options were set: dbfbc.lib DOS, large dbfbcv.lib DOS, large with debug info dbfwm.lib WINDOWS, medium dbfwmv.lib WINDOWS, medium with debug info dbfwmd.lib WINDOWS, DYNAMIC, medium dbfwmvd.lib WINDOWS, DYNAMIC, medium with debug info dbfwl.lib WINDOWS, large dbfwlv.lib WINDOWS, large with debug info dbfwld.lib WINDOWS, DYNAMIC, large dbfwlvd.lib WINDOWS, DYNAMIC, large with debug info When creating the DLL version of the Database Framework, be aware that regardless of whether -DDBG is on or not, the files DBFDLL.DLL and the import library, DBFDLL.LIB, are created. /* ------------ *\ | DBFDLL.DEF | \* ------------ */ LIBRARY DBFDLL DESCRIPTION 'Database Framework DLL' EXETYPE WINDOWS PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 4/49 TITLE : Using the Database Framework as/in a DLL. CODE PRELOAD DISCARDABLE MOVEABLE DATA PRELOAD SINGLE MOVEABLE HEAPSIZE 4096 /* ---------- *\ | ENVDEF.H | \* ---------- */ /*********************************************************************** ** ENVDEF.H ** This file contains structure, type and error definitions used ** throughout the object layer. ** ***********************************************************************/ #if !defined( ENVDEF_H ) #define ENVDEF_H #include // Global defines. #define MAXNAMELEN 31 // Name limit for tables, fields, etc.) #define MAXPATHLEN 81 // Length of DOS path. #ifndef BOOL typedef int BOOL; #endif #ifndef INT16 typedef int INT16; #endif #ifndef INT32 typedef long INT32; #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 5/49 TITLE : Using the Database Framework as/in a DLL. // Engine type for Paradox -- Local, Network or Windows. enum BEngineType {pxLocal=1, pxNet=2, pxWin=3}; // File Share mode for the DOS Paradox Engine (local or network). // NetShare to share only network files; LocalShare to share lock local // and network files; with NoShare, neither local or network files // will be shared. enum PXDosShare {pxLocalShare=0, pxNetShare, pxNoShare}; // Lock mode for the Windows Paradox Engine; With SingleClient, // no locking. enum PXWinShare {pxShared=0, pxSingleClient=1, pxExclusive=2}; // Sort order for the Paradox Engine; enum PXSortOrder {pxAscii=1,pxIntl,pxNorDan,pxNorDan4,pxSwedFin}; enum PXTabCrtMode {px35Fmt=1,px40Fmt=2}; // Table lock mode for the Paradox Engine. enum PXTblLckMode {px40Lck=0,px35Lck=1}; // Modes for creating a new index on a table. enum PXKeyCrtMode {pxPrimary=0, pxSecondary, pxIncSecondary}; // Modes for Paradox locks. enum PXLockMode {pxFL=1, pxWL, pxPWL, pxPFL}; // Modes for Paradox searches. enum PXSearchMode {pxSearchFirst=0, pxSearchNext=1, pxClosestRecord=2}; // Modes for BLOB open. enum PXBlobOpenMode {pxBlobRead = 0, pxBlobWrite}; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 6/49 TITLE : Using the Database Framework as/in a DLL. // Values for a cursor's status. enum PXCursorStatus {atRecord = 0, atBegin, atEnd, atCrack}; // Environment structure for specifying engine's parameters. class _CLASSTYPE BEnv { public: BEngineType engineType; int bufSize; int maxTables; int maxRecBufs; int maxLocks; int maxFiles; PXSortOrder sortOrder; PXTabCrtMode tabCrtMode; // Fields relevant for Engine operation in network mode. PXDosShare dosShare; char netNamePath[MAXPATHLEN+1]; char userName[MAXNAMELEN+1]; PXTblLckMode tabLckMode; // Fields relevant for the Windows Paradox Engine. PXWinShare winShare; char clientName[MAXNAMELEN+1]; char reserved[32]; // Reserved for future use. BEnv() { memset(this,0,sizeof(BEnv)); } // initialize to zeros }; // Error code returned by most functions. typedef int Retcode; typedef unsigned FIELDNUMBER; // Field number; 1 .. N typedef unsigned TABLEHANDLE; // Table handle typedef int LOCKHANDLE; // Lock handle PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 7/49 TITLE : Using the Database Framework as/in a DLL. typedef long RECORDNUMBER; // Record number; 1 .. N typedef unsigned RECORDHANDLE; // Record handle typedef int BLOBHANDLE; // BLOB handle // Field Description Structure. enum PXFieldType { fldChar=9, fldShort=5, fldDouble=7, fldDate=2, fldBlob=3, fldLong=6}; enum PXFieldSubtype {fldstNone = 0, fldstMoney=21, fldstMemo=22, fldstBinary=23, fldstFmtMemo=24, fldstOleObj=25, fldstGraphic=26}; typedef struct { FIELDNUMBER fldNum; // Field number (1..n). char fldName[MAXNAMELEN+1]; // Null-terminated field name. PXFieldType fldType; // Field type. PXFieldSubtype fldSubtype; // Field Subtype. int fldLen; // Field Length; for BLOBs; // the header length. char reserved[20]; // For future use. } FieldDesc; // A custom record's field and map definition structure. Used in custom // record subclasses of BRecord. typedef struct { int useCnt; // Number of instances using this descriptor. int fieldCnt; // Count of fields in the custom record. FieldDesc far *desc; // Descriptor array for custom record's fields FIELDNUMBER *tblFldNbr; // Array maps custom record field numbers // to table's fields. Elements that don't // have a corresponding table field must // be set to 0. } CRFldMapdef; // Default Date structure. typedef struct { int year; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 8/49 TITLE : Using the Database Framework as/in a DLL. char month; char day; } BDate; class _CLASSTYPE BDbObject; class _CLASSTYPE BEngine; class _CLASSTYPE BDatabase; class _CLASSTYPE BCursor; class _CLASSTYPE BRecord; // The following error definitions are copied from PXENGINE.H. They // are included here so that the Database Framework programmer does // not have to include PXENGINE.H. #ifndef PXSUCCESS #define PXSUCCESS 0 // initialization errors #define PXERR_NOTINITERR 78 // Engine not initialized #define PXERR_ALREADYINIT 82 // Engine already initialized #define PXERR_NOTLOGGEDIN 98 // Could not login on network (to PARADOX.NET) #define PXERR_NONETINIT 107 // Engine not initialized with PXNetInit #define PXERR_NETMULTIPLE 15 // multiple PARADOX.NET files #define PXERR_CANTSHAREPDOXNET 134 // can't lock PARADOX.NET -- is SHARE.EXE loaded? #define PXERR_WINDOWSREALMODE 135 // can't run Engine in Windows real mode // hardware related errors #define PXERR_DRIVENOTREADY 1 // Drive not ready #define PXERR_DISKWRITEPRO 124 // Disk is write protected #define PXERR_GENERALFAILURE 126 // General hardware error // directory reg error codes #define PXERR_DIRNOTFOUND 2 // Directory not found #define PXERR_DIRBUSY 10 // Sharing violation PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 9/49 TITLE : Using the Database Framework as/in a DLL. #define PXERR_DIRLOCKED 11 // Sharing violation #define PXERR_DIRNOACCESS 12 // No access to directory #define PXERR_DIRNOTPRIVATE 14 // Single user, but directory is shared // file oriented errors #define PXERR_FILEBUSY 3 // File is busy #define PXERR_FILELOCKED 4 // File is locked #define PXERR_FILENOTFOUND 5 // Could not find file // table oriented errors #define PXERR_TABLEBUSY 118 // Table is busy #define PXERR_TABLELOCKED 119 // Table is locked #define PXERR_TABLENOTFOUND 120 // Table was not found #define PXERR_TABLEOPEN 83 // Unable to perform operation on open table #define PXERR_TABLEINDEXED 94 // Table is indexed #define PXERR_TABLENOTINDEXED 95 // Table is not indexed #define PXERR_TABLEEMPTY 105 // Operation on empty table #define PXERR_TABLEWRITEPRO 22 // Table is write protected #define PXERR_TABLEPRE40 93 // Feature not available for pre Paradox 4.0 tables #define PXERR_TABLECORRUPTED 6 // Table is corrupted #define PXERR_TABLEFULL 128 // Table is full #define PXERR_TABLESQL 130 // Table is SQL replica #define PXERR_INSUFRIGHTS 21 // Insufficient password rights #define PXERR_CANTUPGRADE 92 // Table too old to upgrade, or // existing table header too small. #define PXERR_LOCKTIMEOUT 137 // Timed out trying to achieve a lock. // index oriented errors #define PXERR_XCORRUPTED 7 // Primary index is corrupted #define PXERR_XOUTOFDATE 8 // Primary index is out of date #define PXERR_XSORTVERSION 13 // Sort for index different from table PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 10/49 TITLE : Using the Database Framework as/in a DLL. #define PXERR_SXCORRUPTED 122 // Secondary index is corrupted #define PXERR_SXOUTOFDATE 96 // Secondary index is out of date #define PXERR_SXNOTFOUND 121 // Secondary index was not found #define PXERR_SXOPEN 123 // Not used-here for backwards compatability #define PXERR_SXCANTUPDATE 136 // Can't update table open on non- maintained secondary #define PXERR_RECTOOBIG 125 // Record too big for index // record oriented errors #define PXERR_RECDELETED 50 // Another user deleted record #define PXERR_RECLOCKED 9 // Record is locked #define PXERR_RECNOTFOUND 89 // Record was not found #define PXERR_KEYVIOL 97 // Key violation #define PXERR_ENDOFTABLE 101 // End of table #define PXERR_STARTOFTABLE 102 // Start of table // errors specific for Windows Engine DLL #define PXERR_TOOMANYCLIENTS 131 #define PXERR_EXCEEDSCONFIGLIMITS 132 #define PXERR_CANTREMAPFILEHANDLE 133 // resource errors #define PXERR_OUTOFMEM 40 // Not enough memory to complete operation #define PXERR_OUTOFDISK 41 // Not enough disk space to complete operation #define PXERR_OUTOFSTACK 127 // Not enough stack space to complete operation #define PXERR_OUTOFSWAPBUF 129 // Not enough swap buffer space to complete operation #define PXERR_OUTOFFILEHANDLES 70 // No more file handles available #define PXERR_OUTOFTABLEHANDLES 72 // No more table handles available #define PXERR_OUTOFRECHANDLES 103 // No more record handles available PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 11/49 TITLE : Using the Database Framework as/in a DLL. #define PXERR_OUTOFLOCKHANDLES 111 // Too many locks on table #define PXERR_NOMORETMPNAMES 86 // No more temporary names available #define PXERR_TOOMANYPASSW 115 // Too many passwords specified // invalid parameters to functions #define PXERR_TYPEMISMATCH 30 // Data type mismatch #define PXERR_OUTOFRANGE 31 // Argument out of range #define PXERR_INVPARAMETER 33 // Invalid argument #define PXERR_INVDATE 73 // Invalid date given #define PXERR_INVFIELDHANDLE 75 // Invalid field handle #define PXERR_INVRECHANDLE 104 // Invalid record handle #define PXERR_INVTABLEHANDLE 76 // Invalid table handle #define PXERR_INVLOCKHANDLE 110 // Invalid lock handle #define PXERR_INVDIRNAME 114 // Invalid directory name #define PXERR_INVFILENAME 108 // Invalid file name #define PXERR_INVTABLENAME 99 // Invalid table name #define PXERR_INVFIELDNAME 74 // Invalid field name #define PXERR_INVLOCKCODE 106 // Invalid lock code #define PXERR_INVUNLOCK 109 // Invalid unlock #define PXERR_INVSORTORDER 112 // Invalid sort order table #define PXERR_INVPASSW 116 // Invalid password #define PXERR_INVNETTYPE 113 // Invalid net type (PXNetInit) #define PXERR_BUFTOOSMALL 117 // Buffer too small for result #define PXERR_STRUCTDIFFER 81 // Table structures are different #define PXERR_INVENGINESTATE 79 // Previous fatal error; cannot proceed // Blob error codes #define PXERR_BLOBMODE 51 // Operation not applicable for Blob's // open mode. #define PXERR_BLOBOPEN 52 // Blob already open. #define PXERR_BLOBINVOFFSET 53 // Invalid offset into Blob. #define PXERR_BLOBINVSIZE 54 // Invalid size for Blob. PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 12/49 TITLE : Using the Database Framework as/in a DLL. #define PXERR_BLOBMODIFIED 55 // Another user modified Blob. #define PXERR_BLOBCORRUPT 56 // Blob file corrupted. #define PXERR_BLOBNOINDEX 57 // Cannot index on a Blob. #define PXERR_BLOBINVHANDLE 59 // Invalid Blob handle. #define PXERR_BLOBNOSEARCH 60 // Can't search on a Blob field. // Locking related error codes #define PXERR_INUSEBYPDOX35 16 // Directory is in use by Paradox 3.5 // or Paradox Engine 2.0 #endif // Database Framework function that returns the error message // corresponding to an error number. char far *pascal far PXOopErrMsg(int errCode); // Database Framework errors. #define PXERR_INVENGINETYPE 400 #define PXERR_ENGINEOPEN 401 #define PXERR_ENGINENOTOPEN 402 #define PXERR_DBALREADYOPEN 403 #define PXERR_DBNOTOPEN 404 #define PXERR_CURSORALREADYOPEN 405 #define PXERR_CURSORNOTOPEN 406 #define PXERR_RECALREADYATT 407 #define PXERR_RECNOTATT 408 #define PXERR_INVFIELDTYPE 409 #define PXERR_INVCURRRECORD 410 #define PXERR_TABLESDIFFER 411 #define PXERR_INVKEYCOUNT 412 #define PXERR_NOKEYMAP 413 #define PXERR_NOCLEARNULL 414 #define PXERR_DATACONV 415 #define PXERR_BLOBNOTOPEN 416 // GENERATE Utility Errors #define PXERR_INCOMPLETESPEC 501 PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 13/49 TITLE : Using the Database Framework as/in a DLL. #define PXERR_NOSPECFILE 502 #define PXERR_INVOPTION 503 #define PXERR_CANTCREATEFILE 504 #define PXERR_NOLEFTPAREN 505 #define PXERR_NOCOMMAORRP 506 #define PXERR_INVCHARLEN 507 #define PXERR_INVTYPEWARN 508 #endif /* ------------- *\ | BRECORD.CPP | \* ------------- */ /******************************************************************* ** ** BRECORD.CPP ** ** This file contains the member functions of the BRecord class. ** *********************************************************************/ #include "envdef.h" #include "bcursor.h" #include "brecord.h" #include "pxengine.h" #include "intstrct.h" #include #include #include #include #include // Prototypes for locally-used functions. Retcode addRecord(curdef *, BRecord *); void deleteRecord(curdef *, BRecord *); Retcode addBlob(recdef *, blbdef *); Retcode convertFld(void *, PXFieldType, int, // Source value void *, PXFieldType, int); // destination. Retcode strToDate(const char *str, BDate *dt); PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 14/49 TITLE : Using the Database Framework as/in a DLL. Retcode dateToStr(const BDate *dt, char *str); // Constructor for making a generic record object for an open cursor. BRecord::BRecord(BCursor *cursor) { recdef *ro = new recdef; // See the INTSTRCT.H file. if (! ro) { lastError = PXERR_OUTOFMEM; recH = 0; curH = 0; return; } lastError = PXSUCCESS; ro->handleCnt = 0; recH = 0; recobj = (void *)ro; curH = cursor; if (! cursor) // Null cursor -> unattached record. return; if (! cursor->isOpen) lastError = PXERR_CURSORNOTOPEN; else if ((lastError = PXRecBufOpen(cursor->tabH,&recH)) == PXSUCCESS) addRecord((curdef *)cursor->curobj, this); } // Destructor for BRecord objects. BRecord::~BRecord() { detach(); recdef *ro = (recdef *)recobj; if (ro) { if (ro->handleCnt) delete [] ro->recblb; delete ro; } } // Delete the record's association with the cursor. PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 15/49 TITLE : Using the Database Framework as/in a DLL. Retcode BRecord::detach() { curdef *co = (curdef *)curH->curobj; recdef *ro = (recdef *) recobj; if (! recH) return(lastError = PXERR_RECNOTATT); // Mark BLOB status as closed. The resources allocated for all // BLOBs will be freed by the Paradox Engine with a RecBufClose call. for (int i=0;i < ro->handleCnt; i++) if (ro->recblb[i].blbRecH == recH) ro->recblb[i].state = blbClosed; deleteRecord(co, this); if ((lastError = PXRecBufClose(recH)) != PXSUCCESS) return(lastError); recH = 0; return(lastError); } // Attach the record object to an open cursor. Retcode BRecord::attach(BCursor *cur) { if (recH) return(lastError = PXERR_RECALREADYATT); if (! cur->isOpen) return(lastError = PXERR_CURSORNOTOPEN); curH = cur; if ((lastError = PXRecBufOpen(cur->tabH,&recH)) != PXSUCCESS) return(lastError); addRecord((curdef *)cur->curobj, this); return(lastError = PXSUCCESS); } // Clear the record buffer and set fields to "empty" values. // RecBufEmpty will fail if a BLOB is open. This function // doesn't perform operations on BLOBs. Retcode BRecord::clear() { if (! recH) return(lastError = PXERR_INVRECHANDLE); PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 16/49 TITLE : Using the Database Framework as/in a DLL. return(lastError = PXRecBufEmpty(recH)); } // For the descriptor in use, return the field handle for a // given name. For generic records, the table descriptor and // record descriptor are the same. FIELDNUMBER BRecord::getFieldNumber(const char *fldName) { curdef *co = (curdef *)curH->curobj; if (! recH) { lastError = PXERR_INVRECHANDLE; return(0); } lastError = PXSUCCESS; for (int i=0; i < co->fieldCnt; i++) if ( ! _fstrcmp(co->desc[i].fldName, (char far *) fldName)) { lastError = PXSUCCESS; return(i+1); } lastError = PXERR_INVFIELDNAME; return(0); } // Get the table field number for the record. For generic // records, there is no difference between record and // table field numbers. FIELDNUMBER BRecord::getTblFieldNumber(FIELDNUMBER fldnbr) { lastError = PXSUCCESS; return(fldnbr); } // For the generic table (and record) descriptor in use, // return its field count. int BRecord::getFieldCount() { curdef *co = (curdef *)curH->curobj; if (! recH) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 17/49 TITLE : Using the Database Framework as/in a DLL. { lastError = PXERR_INVRECHANDLE; return(0); } lastError = PXSUCCESS; return(co->fieldCnt); } // Given a field handle, return a field descriptor describing // the field's name, type, length, and so on. For generic // records, use the field descriptor in the cursor. (Table and // record descriptors are the same). Retcode BRecord::getFieldDesc(FIELDNUMBER fldnbr, FieldDesc& desc) { curdef *co = (curdef *)curH->curobj; if (! recH) { lastError = PXERR_INVRECHANDLE; return(lastError); } if (fldnbr > co->fieldCnt || fldnbr < 1) { lastError = PXERR_INVFIELDHANDLE; return(lastError); } desc = co->desc[fldnbr-1]; return(lastError = PXSUCCESS); } // This function performs the same operation as the previous // function except this signature returns the field type, // subtype, and length. Retcode BRecord::getFieldDesc(FIELDNUMBER fldnbr, PXFieldType &fldType, PXFieldSubtype &fldSubtype, int &fldLen) { curdef *co = (curdef *)curH->curobj; if (! recH) { lastError = PXERR_INVRECHANDLE; return(lastError); } PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 18/49 TITLE : Using the Database Framework as/in a DLL. if (fldnbr > co->fieldCnt || fldnbr < 1) { lastError = PXERR_INVFIELDHANDLE; return(lastError); } fldType = co->desc[fldnbr-1].fldType; fldSubtype = co->desc[fldnbr-1].fldSubtype; fldLen = co->desc[fldnbr-1].fldLen; return(lastError = PXSUCCESS); } // Copy the contents of a record, one field at a time, to // compatible fields of another record. Retcode BRecord::copyTo(BRecord *destRec) { BOOL custom = strcmp(nameOf(),"BRecord") || strcmp(destRec->nameOf(),"BRecord"); if ((lastError = PXRecBufCopy(recH, destRec->recH)) != PXSUCCESS) if (! custom) // See the BRECORD.H file. return(lastError); // Register the fact that the BLOBs in the destRec are now closed. recdef *ro = (recdef *) destRec->recobj; for (int i=0;i < ro->handleCnt; i++) if (ro->recblb[i].blbRecH == destRec->recH) ro->recblb[i].state = blbClosed; // If either the source or the destination record is a custom record, // transfer values to or from custom record fields, one field at a time. if (custom) { char *buf = new char[256]; if (! buf) return(lastError = PXERR_OUTOFMEM); Retcode ret; PXFieldType fldType1, fldType2; PXFieldSubtype fldSubtype; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 19/49 TITLE : Using the Database Framework as/in a DLL. int fldLen1, fldLen2; BOOL fNull; int cnt = destRec->getFieldCount(); for (int i=1; i <= cnt; i++) { if (isNull(i)) { destRec->setNull(i); continue; } destRec->clearNull(i); getFieldDesc(i,fldType1,fldSubtype,fldLen1); destRec->getFieldDesc(i,fldType2,fldSubtype,fldLen2); if (fldType2 == fldBlob) continue; // BLOB handling is separate. if ((ret = getField(i, (void *) buf, 255, fNull)) == PXSUCCESS) { if (fldType1 != fldType2) ret = convertFld((void *)buf,fldType1, fldLen1, (void *)buf,fldType2, fldLen2); if (! ret) ret = destRec->putField(i, (void *) buf); } if (ret) { delete buf; return(lastError = ret); } } delete buf; } return(lastError = PXSUCCESS); } // Copy the contents of srcRec, one field at a time, to compatible // fields in this record. Retcode BRecord::copyFrom(BRecord *srcRec) { if (! recH || !srcRec->recH) lastError = PXERR_INVRECHANDLE; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 20/49 TITLE : Using the Database Framework as/in a DLL. return(lastError = srcRec->copyTo(this)); } // Obtain values for fields of a generic record; store the // field as a character string regardless of its base type. Retcode BRecord::getField(FIELDNUMBER fldnbr,char *buf, int bufLen, BOOL& fNull) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; if ((lastError = getField(fldnbr, (void *) buf, bufLen, fNull)) != PXSUCCESS) return(lastError); if (fNull) return(lastError = PXSUCCESS); getFieldDesc(fldnbr,fldType,fldSubtype,fldLen); return(lastError = convertFld((void *)buf, fldType, fldLen, (void *) buf, fldChar, bufLen)); } // Get the field's value in its native format and return a pointer to // the value as a void pointer. Retcode BRecord::getField(FIELDNUMBER fldnbr,void *buf, int bufLen,BOOL& fNull) { BDate *dt = (BDate *) buf; int m,d,y; curdef *co = (curdef *)curH->curobj; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (fldnbr > co->fieldCnt || fldnbr < 1) return(lastError = PXERR_INVFIELDHANDLE); FieldDesc far &desc = co->desc[fldnbr-1]; fNull = FALSE; switch (desc.fldType) { case fldChar: lastError = PXGetAlpha(recH, fldnbr, bufLen, (char far *) buf); if (ISBLANKALPHA((char *) buf)) fNull = TRUE; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 21/49 TITLE : Using the Database Framework as/in a DLL. return(lastError); case fldShort: if (bufLen < sizeof(short)) return(lastError = PXERR_BUFTOOSMALL); lastError = PXGetShort(recH, fldnbr, (short far *)buf); if (ISBLANKSHORT(*((short *) buf))) fNull = TRUE; return(lastError); case fldDouble: if (bufLen < sizeof(double)) return(lastError = PXERR_BUFTOOSMALL); lastError = PXGetDoub(recH, fldnbr, (double far *)buf); if (ISBLANKDOUBLE(*((double *)buf))) fNull = TRUE; return(lastError); case fldDate: lastError = PXGetDate(recH, fldnbr, (long far *)buf); if (ISBLANKDATE(*((long *) buf))) fNull = TRUE; else if (lastError == PXSUCCESS) { PXDateDecode(*((long far *)buf), &m,&d,&y); dt->month = m; dt->day = d; dt->year = y; } return(lastError); default: return(lastError = PXERR_TYPEMISMATCH); } } Retcode BRecord::getField(FIELDNUMBER fldnbr, double& val, BOOL& fNull) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if ((lastError = getField(fldnbr, (void *) buf, 30, fNull)) != PXSUCCESS) return(lastError); if (fNull) return(lastError = PXSUCCESS); PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 22/49 TITLE : Using the Database Framework as/in a DLL. getFieldDesc(fldnbr,fldType,fldSubtype,fldLen); return(lastError = convertFld((void *)buf, fldType, 30, (void *) &val, fldDouble, sizeof(double))); } Retcode BRecord::getField(FIELDNUMBER fldnbr, INT16& val, BOOL& fNull) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if ((lastError = getField(fldnbr, (void *) buf, 30,fNull)) != PXSUCCESS) return(lastError); if (fNull) return(lastError = PXSUCCESS); getFieldDesc(fldnbr,fldType,fldSubtype,fldLen); return(lastError = convertFld((void *)buf, fldType, 30, (void *) &val, fldShort, sizeof(short))); } Retcode BRecord::getField(FIELDNUMBER fldnbr, INT32& val, BOOL& fNull) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if ((lastError = getField(fldnbr, (void *) buf, 30, fNull)) != PXSUCCESS) return(lastError); if (fNull) return(lastError = PXSUCCESS); getFieldDesc(fldnbr,fldType,fldSubtype,fldLen); return(lastError = convertFld((void *)buf, fldType, 30, (void *) &val, fldLong, sizeof(long))); } Retcode BRecord::getField(FIELDNUMBER fldnbr, BDate& val, BOOL& fNull) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 23/49 TITLE : Using the Database Framework as/in a DLL. if ((lastError = getField(fldnbr, (void *) buf, 30, fNull)) != PXSUCCESS) return(lastError); if (fNull) return(lastError = PXSUCCESS); getFieldDesc(fldnbr,fldType,fldSubtype,fldLen); return(lastError = convertFld((void *)buf, fldType, 30, (void *) &val, fldDate, sizeof(BDate))); } Retcode BRecord::getField(char *fldName, char *buf, int bufLen, BOOL& fNull) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(getField(fld, buf, bufLen,fNull)); } Retcode BRecord::getField(char *fldName, void *buf, int bufLen, BOOL& fNull) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(getField(fld, buf, bufLen, fNull)); } Retcode BRecord::getField(char *fldName, double& val, BOOL& fNull) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(getField(fld, val, fNull)); } Retcode BRecord::getField(char *fldName, INT16& val, BOOL& fNull) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(getField(fld, val, fNull)); } Retcode BRecord::getField(char *fldName, INT32& val, BOOL& fNull) { PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 24/49 TITLE : Using the Database Framework as/in a DLL. FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(getField(fld, val, fNull)); } Retcode BRecord::getField(char *fldName, BDate& val, BOOL& fNull) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(getField(fld, val, fNull)); } // The following putField functions provide counterpart // operations to getField functions. Retcode BRecord::putField(FIELDNUMBER fldnbr, const char *buf) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char tempBuf[31]; int len = strlen(buf); if (! recH) return(lastError = PXERR_INVRECHANDLE); if (getFieldDesc(fldnbr,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if (fldType != fldChar) { if ((lastError = convertFld((void *)buf, fldChar, len, (void *)tempBuf,fldType, 30)) != PXSUCCESS) return(lastError); return(lastError = putField(fldnbr, (void *) tempBuf)); } else return(lastError = putField(fldnbr, (void *) buf)); } Retcode BRecord::putField(FIELDNUMBER fldnbr, const void *buf) { BDate *dt = (BDate *) buf; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 25/49 TITLE : Using the Database Framework as/in a DLL. curdef *co = (curdef *)curH->curobj; long ld; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (fldnbr > co->fieldCnt || fldnbr < 1) return(lastError = PXERR_INVFIELDHANDLE); FieldDesc far &desc = co->desc[fldnbr-1]; switch (desc.fldType) { case fldChar: return(lastError = PXPutAlpha(recH, fldnbr, (char far *) buf)); case fldShort: return(lastError = PXPutShort(recH, fldnbr, *((short *)buf))); case fldDouble: return(lastError = PXPutDoub(recH, fldnbr, *((double *)buf))); case fldDate: if ((lastError = PXDateEncode((int)dt->month, (int)dt->day, (int)dt->year, &ld)) == PXSUCCESS) lastError = PXPutDate(recH, fldnbr, ld); return(lastError); default: return(lastError = PXERR_TYPEMISMATCH); } } Retcode BRecord::putField(FIELDNUMBER fldnbr, double val) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (getFieldDesc(fldnbr,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if ((lastError = convertFld((void *)&val, fldDouble, sizeof(double), (void *)buf,fldType, 30)) != PXSUCCESS) return(lastError); return(lastError = putField(fldnbr, (void *) buf)); } Retcode BRecord::putField(FIELDNUMBER fldnbr, INT16 val) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 26/49 TITLE : Using the Database Framework as/in a DLL. { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (getFieldDesc(fldnbr,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if ((lastError = convertFld((void *)&val, fldShort, sizeof(short), (void *)buf,fldType, 30)) != PXSUCCESS) return(lastError); return(lastError = putField(fldnbr, (void *) buf)); } Retcode BRecord::putField(FIELDNUMBER fldnbr, INT32 val) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (getFieldDesc(fldnbr,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if ((lastError = convertFld((void *)&val, fldLong, sizeof(long), (void *)buf,fldType, 30)) != PXSUCCESS) return(lastError); return(lastError = putField(fldnbr, (void *) buf)); } Retcode BRecord::putField(FIELDNUMBER fldnbr, const BDate& val) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; char buf[31]; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (getFieldDesc(fldnbr,fldType,fldSubtype,fldLen)) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 27/49 TITLE : Using the Database Framework as/in a DLL. return(lastError = PXERR_INVFIELDHANDLE); if ((lastError = convertFld((void *)&val, fldDate, sizeof(BDate), (void *)buf,fldType, 30)) != PXSUCCESS) return(lastError); return(lastError = putField(fldnbr, (void *) buf)); } Retcode BRecord::putField(char *fldName, const char *buf) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(putField(fld, buf)); } Retcode BRecord::putField(char *fldName, const void *buf) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(putField(fld, buf)); } Retcode BRecord::putField(char *fldName, double val) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(putField(fld, val)); } Retcode BRecord::putField(char *fldName, INT16 val) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(putField(fld, val)); } Retcode BRecord::putField(char *fldName, INT32 val) { FIELDNUMBER fld; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 28/49 TITLE : Using the Database Framework as/in a DLL. if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(putField(fld, val)); } Retcode BRecord::putField(char *fldName, const BDate& val) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(putField(fld, val)); } // Test if a field is null. BOOL BRecord::isNull(FIELDNUMBER fldnbr) { BOOL blank; if ((lastError = PXFldBlank(recH,fldnbr,&blank)) != PXSUCCESS) return(FALSE); return(blank); } BOOL BRecord::isNull(const char *fldname) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldname)) == 0) return(FALSE); return(isNull(fld)); } // Set a field to blank. Retcode BRecord::setNull(FIELDNUMBER fldnbr) { return(lastError = PXPutBlank(recH,fldnbr)); } Retcode BRecord::setNull(const char *fldName) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 29/49 TITLE : Using the Database Framework as/in a DLL. return(lastError); return(setNull(fld)); } Retcode BRecord::clearNull(FIELDNUMBER fldnbr) { curdef *co = (curdef *)curH->curobj; if (! recH) return(lastError = PXERR_INVRECHANDLE); if (fldnbr > co->fieldCnt || fldnbr < 1) return(lastError = PXERR_INVFIELDHANDLE); return(PXERR_NOCLEARNULL); } Retcode BRecord::clearNull(const char *fldName) { FIELDNUMBER fld; if ((fld = getFieldNumber(fldName)) == 0) return(lastError); return(clearNull(fld)); } // Open a BLOB for subsequent read or write operations based on mode. Retcode BRecord::openBlobRead(FIELDNUMBER fldnbr, BOOL usePrivateCopy) { blbdef blb; // Use the field number of the BLOB in the table, not the // custom record. That way, this function does not need // to be duplicated in custom record classes. FIELDNUMBER tblfld = getTblFieldNumber(fldnbr); if (usePrivateCopy) if ((lastError = PXBlobClone(recH, tblfld)) != PXSUCCESS) return(lastError); if ((lastError = PXBlobOpenRead(recH,tblfld,&blb.blbH)) != PXSUCCESS) return(lastError); blb.fldnbr = fldnbr; blb.privateBlb = usePrivateCopy; blb.state = blbOpenRead; blb.blbRecH = recH; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 30/49 TITLE : Using the Database Framework as/in a DLL. return(lastError = addBlob((recdef *)recobj, &blb)); } Retcode BRecord::openBlobWrite(FIELDNUMBER fldnbr, long size, BOOL copyOld) { blbdef blb; FIELDNUMBER tblfld = getTblFieldNumber(fldnbr); lastError = PXBlobOpenWrite(recH,tblfld,&blb.blbH,size,(int)copyOld); if (!lastError) { blb.fldnbr = fldnbr; blb.privateBlb = TRUE; blb.state = blbOpenWrite; blb.blbRecH = recH; lastError = addBlob((recdef *)recobj, &blb); } return(lastError); } // Get a BLOB Header. Retcode BRecord::getBlobHeader(FIELDNUMBER fldnbr, int size, void *buffer, int& bytesRead) { fldnbr = getTblFieldNumber(fldnbr); return(lastError = PXBlobQuickGet(recH,fldnbr,size,buffer,&bytesRead)); } // Get the size of an open BLOB. long BRecord::getBlobSize(FIELDNUMBER fld) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; if (getFieldDesc(fld,fldType,fldSubtype,fldLen)) { lastError = PXERR_INVFIELDHANDLE; return(0); } if (fldType != fldBlob) { PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 31/49 TITLE : Using the Database Framework as/in a DLL. lastError = PXERR_TYPEMISMATCH; return(0); } recdef *ro = (recdef *) recobj; unsigned long size; for (int i=0;i < ro->handleCnt; i++) if (ro->recblb[i].fldnbr == fld && (BOOL) ro->recblb[i].state) break; if (i == ro->handleCnt) { lastError = PXERR_BLOBNOTOPEN; return(0); } if ((lastError = PXBlobGetSize(ro->recblb[i].blbH, &size)) != PXSUCCESS) return(0); return(size); } // Read a segment of an open BLOB. Retcode BRecord::getBlob(FIELDNUMBER fld, unsigned int size, long offset, void far *buffer) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; if (getFieldDesc(fld,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if (fldType != fldBlob) return(lastError = PXERR_TYPEMISMATCH); recdef *ro = (recdef *) recobj; for (int i=0;i < ro->handleCnt; i++) if (ro->recblb[i].fldnbr == fld && (int) ro->recblb[i].state) break; if (i == ro->handleCnt) return(lastError = PXERR_BLOBNOTOPEN); return(lastError = PXBlobGet(ro->recblb[i].blbH,size,offset,buffer)); } // Close an open BLOB handle; closes both private and public BLOBs. // For a field, at most, one BLOB can be open at any time. PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 32/49 TITLE : Using the Database Framework as/in a DLL. Retcode BRecord::closeBlob(FIELDNUMBER fld, BOOL accept) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; if (getFieldDesc(fld,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if (fldType != fldBlob) return(lastError = PXERR_TYPEMISMATCH); recdef *ro = (recdef *) recobj; for (int i=0; i < ro->handleCnt; i++) if (ro->recblb[i].fldnbr == fld && (int) ro->recblb[i].state) break; if (i == ro->handleCnt) return(lastError = PXERR_BLOBNOTOPEN); lastError = PXBlobClose(ro->recblb[i].blbH, accept); ro->recblb[i].state = blbClosed; ro->recblb[i].privateBlb = FALSE; return(lastError); } // Write a segment of an open BLOB. Retcode BRecord::putBlob(FIELDNUMBER fld, unsigned int size, long offset, void far *buffer) { PXFieldType fldType; PXFieldSubtype fldSubtype; int fldLen; if (getFieldDesc(fld,fldType,fldSubtype,fldLen)) return(lastError = PXERR_INVFIELDHANDLE); if (fldType != fldBlob) return(lastError = PXERR_TYPEMISMATCH); recdef *ro = (recdef *) recobj; for (int i=0;i < ro->handleCnt; i++) if (ro->recblb[i].fldnbr == fld && (int) ro->recblb[i].state) break; if (i == ro->handleCnt) return(lastError = PXERR_BLOBNOTOPEN); if ((lastError = PXBlobPut(ro->recblb[i].blbH, size, offset, buffer)) != PXSUCCESS) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 33/49 TITLE : Using the Database Framework as/in a DLL. return(lastError); clearNull(fld); // Clear the null bit in Custom records. return(lastError = PXSUCCESS); // Ignore clearNull error for generic // records. } // Drop a BLOB field from a record. Retcode BRecord::dropBlob(FIELDNUMBER fldnbr) { return(lastError = PXBlobDrop(recH, fldnbr)); } // This function provides a place holder for preprocessing // routines. Retcode BRecord::preprocess() { return(lastError = PXSUCCESS); } // This function provides a place holder for postprocessing // routines. Retcode BRecord::postprocess() { return(lastError = PXSUCCESS); } // Redefine pure virtuals from the BDbObject class. char * BRecord::nameOf() const { return("BRecord"); } void BRecord::printOn( ostream& os) { FieldDesc desc; char *buf = new char[256]; BOOL fNull; if (! buf) { PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 34/49 TITLE : Using the Database Framework as/in a DLL. lastError = PXERR_OUTOFMEM; return; } int cnt = getFieldCount(); os << nameOf() << " { \n"; for (int i=1; i <= cnt; i++) { getFieldDesc(i, desc); getField(i, buf, 256, fNull); os << " " << desc.fldName << " = "; if (desc.fldType == fldBlob) os << "Blob Field"; else if (fNull) os << "Null" ; else os << buf ; os << "\n"; } os << "}\n"; delete buf; } // The following two routines are used to maintain a list of records // for a cursor. The Database Framework does not assume the presence // of any Class library (not even Borland's container library Classlib). // Consequently, no List class is used. Retcode addRecord(curdef *cur, BRecord *rec) { // Add this record object to the record vector in the cursor. int i; BRecord **newvec; for (i = 0; i < cur->handleCnt; i++) if (! cur->recList[i]) // empty slot ? { cur->recList[i] = rec; return(PXSUCCESS); } if (! (newvec = new BRecord *[cur->handleCnt+4]) ) // Four more handles. return(PXERR_OUTOFMEM); for (i = 0; i < cur->handleCnt; i++) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 35/49 TITLE : Using the Database Framework as/in a DLL. newvec[i] = cur->recList[i]; newvec[i++] = rec; newvec[i] = newvec[i+1] = newvec[i+2] = 0; if (cur->handleCnt) delete [] cur->recList; cur->handleCnt += 4; cur->recList = newvec; return(PXSUCCESS); } // Delete the record from the Open Record list of its cursor. void deleteRecord(curdef *cur, BRecord *rec) { for (int i = 0; i < cur->handleCnt; i++) if (cur->recList[i] == rec) { cur->recList[i] = 0; return; } } // Add the BLOB to the Open BLOB list of its record. Retcode addBlob(recdef *rec, blbdef *blb) { // Add this BLOB definition to the Record object. int i; blbdef *newvec; for (i = 0; i < rec->handleCnt; i++) if (rec->recblb[i].fldnbr == blb->fldnbr) // BLOB field already has { // a slot. rec->recblb[i] = *blb; return(PXSUCCESS); } if (! (newvec = new blbdef[rec->handleCnt+1]) ) // One more handle. return(PXERR_OUTOFMEM); for (i = 0; i < rec->handleCnt; i++) newvec[i] = rec->recblb[i]; newvec[i] = *blb; if (rec->handleCnt) delete [] rec->recblb; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 36/49 TITLE : Using the Database Framework as/in a DLL. rec->handleCnt += 1; rec->recblb = newvec; return(PXSUCCESS); } // Convert value in source pointed to by srcPtr and leave // the result in destPtr; Retcode convertFld(void *srcPtr, PXFieldType srcType, int srcLen, void *destPtr, PXFieldType destType, int destLen) { char buf[31]; BDate dt; long ld; double db; Retcode ret = 0; switch(destType) { case fldChar: switch(srcType) { case fldChar: if (srcPtr == destPtr) // Nothing to copy. return(ret); break; case fldShort: srcLen = sprintf(buf,"%d",*((short *) srcPtr)); srcPtr = buf; break; case fldLong: srcLen = sprintf(buf,"%ld",*((long *) srcPtr)); srcPtr = buf; break; case fldDouble: srcLen = sprintf(buf,"%G",*((double *) srcPtr)); srcPtr = buf; break; case fldDate: dateToStr((BDate *) srcPtr, buf); srcPtr = buf; break; default: return(PXERR_INVFIELDTYPE); PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 37/49 TITLE : Using the Database Framework as/in a DLL. } if (srcLen > destLen && strlen((char *) srcPtr) > destLen) { ret = PXERR_BUFTOOSMALL; strncpy((char *) destPtr, (char *) srcPtr, destLen); } else strcpy((char *) destPtr, (char *) srcPtr); break; case fldShort: switch(srcType) { case fldChar: if (sscanf((char *) srcPtr,"%lf",&db) < 1) ret = PXERR_DATACONV; if (db < SHRT_MIN || db > SHRT_MAX) ret = PXERR_OUTOFRANGE; *((short *) destPtr) = (short) db; break; case fldShort: *((short *) destPtr) = *((short *) srcPtr); break; case fldLong: ld = *((long *) srcPtr); if (ld < SHRT_MIN || ld > SHRT_MAX) ret = PXERR_OUTOFRANGE; *((short *) destPtr) = (short) ld; break; case fldDouble: db = *((double *) srcPtr); if (ISBLANKDOUBLE(db)) ret = PXERR_DATACONV; else if (db < SHRT_MIN || db > SHRT_MAX) ret = PXERR_OUTOFRANGE; else *((short *) destPtr) = (short) db; break; case fldDate: ret = PXERR_TYPEMISMATCH; break; default: ret = PXERR_INVFIELDTYPE; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 38/49 TITLE : Using the Database Framework as/in a DLL. break; } break; case fldDouble: switch(srcType) { case fldChar: if (sscanf((char *) srcPtr,"%lf",&db) < 1) ret = PXERR_DATACONV; *((double *) destPtr) = db; break; case fldShort: *((double *) destPtr) = *((short *) srcPtr); break; case fldLong: *((double *) destPtr) = *((long *) srcPtr); break; case fldDouble: *((double *) destPtr) = *((double *) srcPtr); break; case fldDate: ret = PXERR_TYPEMISMATCH; break; default: ret = PXERR_INVFIELDTYPE; break; } break; case fldLong: switch(srcType) { case fldChar: if (sscanf((char *) srcPtr,"%lf",&db) < 1) ret = PXERR_DATACONV; if (db < LONG_MIN || db > LONG_MAX) ret = PXERR_OUTOFRANGE; *((long *) destPtr) = (long) db; break; case fldShort: *((long *) destPtr) = *((short *) srcPtr); break; PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 39/49 TITLE : Using the Database Framework as/in a DLL. case fldLong: *((long *) destPtr) = *((long *) srcPtr); break; case fldDouble: db = *((double *) srcPtr); if (ISBLANKDOUBLE(db)) ret = PXERR_DATACONV; else if (db < LONG_MIN || db > LONG_MAX) ret = PXERR_OUTOFRANGE; else *((long *) destPtr) = (long) db; break; case fldDate: ret = PXERR_TYPEMISMATCH; break; default: ret = PXERR_INVFIELDTYPE; break; } break; case fldDate: switch(srcType) { case fldChar: ret = strToDate((char *) srcPtr, &dt); *((BDate *) destPtr) = dt; break; case fldShort: case fldLong: case fldDouble: ret = PXERR_TYPEMISMATCH; break; case fldDate: *((BDate *) destPtr) = *((BDate *) srcPtr); break; default: ret = PXERR_INVFIELDTYPE; break; } break; default: PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 40/49 TITLE : Using the Database Framework as/in a DLL. ret = PXERR_INVFIELDTYPE; break; } return(ret); } // Convert String to Date. The string must be in the format // MM/DD/YYYY. You may rewrite this function to handle a // variety of different Date formats. Retcode strToDate(const char *str, BDate *dt) { int i; long ld; if (! isdigit(*str)) return(PXERR_INVDATE); dt->month = *str++ - '0'; if (isdigit(*str)) dt->month = dt->month * 10 + (*str++ - '0'); // 2-digit month. if (*str++ != '/') return(PXERR_INVDATE); if (! isdigit(*str)) return(PXERR_INVDATE); dt->day = *str++ - '0'; if (isdigit(*str)) dt->day = dt->day * 10 + (*str++ - '0'); // 2-digit day. if (*str++ != '/') return(PXERR_INVDATE); if (! isdigit(*str)) return(PXERR_INVDATE); i = *str++ - '0'; if (! isdigit(*str)) return(PXERR_INVDATE); i = i * 10 + (*str++ - '0'); if (! *str) // 2-digit year. i += 1900; else { if (! isdigit(*str)) return(PXERR_INVDATE); i = i * 10 + *str++ - '0'; if (! isdigit(*str)) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 41/49 TITLE : Using the Database Framework as/in a DLL. return(PXERR_INVDATE); i = i * 10 + (*str++ - '0'); // 4-digit year. if (*str) return(PXERR_INVDATE); } dt->year = i; return(PXDateEncode(dt->month,dt->day,dt->year,&ld)); } // Convert Date to String. The string will be output in the format // MM/DD/YYYY. You may rewrite this function to handle a variety of // different Date formats. Retcode dateToStr(const BDate *dt, char *str) { sprintf(str,"%02d/%02d/%04d",(int) dt->month,(int) dt->day, (int) dt->year); return(PXSUCCESS); } /* ------------ *\ | DBFMAIN.CPP | \* ------------ */ // // DLLMAIN.CPP // // This file contains LibMain and WEP for creating // the Database Framework DLL. // #include #pragma argsused int FAR PASCAL LibMain(HINSTANCE hInstance, WORD /*wDataSeg*/, WORD /* cbHeapSize */, LPSTR lpCmdLine) { return 1; } PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 42/49 TITLE : Using the Database Framework as/in a DLL. #pragma argsused int FAR PASCAL WEP ( int /*bSystemExit*/ ) { return 1; } /* ------------- *\ | MAKEFILE.BC | \* ------------- */ #--------------------------------------------------------------------------# # # # MAKEFILE for the Paradox Engine Database Framework # # # # Copyright (c) Borland International 1992 # # All Rights Reserved # # # # This makefile supports Borland C++ 3.1 using MAKE 3.6. # # # #--------------------------------------------------------------------------# # # # Usage: # # # # make # # builds library for DOS only. # # # # make -DWINDOWS # # builds library for Windows only. # # # # make -DDLL # # builds library as Windows DLL. # # NOTE: When creating a DLL, it overwrites any existing DLL # # with the same name. # # # # options: # # # # -DDBG specifies to include debugging information. # # # # -DMDL=... specifies the memory model used in building # # the Database Framework library. The letter 'm' # # is used to specify medium model and 'l' is used # PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 43/49 TITLE : Using the Database Framework as/in a DLL. # for large model. When building the library for DOS, # # only large model is supported; for Windows, both # # medium and large models are acceptable. # # # # -DDYNAMIC specifes to build the library to support # # dynamic linking of the Borland C++ RTL or # # ObjectWindows. Applicable only when building # # the Database Framework library for Windows. # # # # -DINCLUDE=... specifies the directories for include files. # # Only needed if the Database Framework was not installed # # in the default location. # # # # -DLIB=... specifies the directory where the compiler libraries # # are located. Only needed if the Database Framework was # # not installed in the default location. # # # # Note that if you are using a compiler that utilizes environment # # variables for LIB or INCLUDE paths, that these variables can interfere # # with proper operation of this make file. To use the make file properly, # # you can remove an INCLUDE or LIB environment variable by typing # # 'set LIB=' or 'set INCLUDE=' from DOS. # # # # Make puts created object modules in the OBJ subdirectory of # # the SOURCE directory. # # # #--------------------------------------------------------------------------# # turn on automatic dependency checking .AUTODEPEND # # Translator Definitions # # if you are using Turbo C++, change bcc to tcc CC = bcc TLIB = tlib IMPLIB = implib TLINK = tlink PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 44/49 TITLE : Using the Database Framework as/in a DLL. #-------------------------------------------------------------------------# # # # COMPILER Include and Library paths # # # #-------------------------------------------------------------------------# # adjust to reflect your compiler installation CCINCLUDE = d:\bc\include #-------------------------------------------------------------------------# # # # PARADOX ENGINE Include and Library paths # # # #-------------------------------------------------------------------------# # adjust to reflect your Paradox Engine installation ENGINCLUDE = ..\INCLUDE ENGLIB = ..\LIB ENGWINLIB = ..\..\WINDOWS #-------------------------------------------------------------------------# # # # COMPILER Options # # # #-------------------------------------------------------------------------# # # Memory Model Defaults to Large # !if !$d(MDL) MDL=l !endif # # DLL supports only Windows and Dynamic versions of run-time library # !if $d(DLL) DLLNAME = DBFDLL WINDOWS = DUMMY1 # make sure Windows is defined PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 45/49 TITLE : Using the Database Framework as/in a DLL. DYNAMIC = DUMMY2 # make sure dynamic is also defined !if $d(DBG) TLINKFLAG = /c/C/v/TWD !else TLINKFLAG = /c/C/TWD !endif !endif # # Stop if using DOS and memory model isn't large # !if !$d(WINDOWS) && $(MDL) != l !error Only large model supported for DOS !endif # # Only medium and large memory models for Windows # !if $d(WINDOWS) && ( $(MDL) != m && $(MDL) != l) !error Only Medium and Large model for Windows !endif # # -DDYNAMIC option supported for Windows only # !if $d(DYNAMIC) && !$d(WINDOWS) !error Dynamic linking is for Windows only. !endif # # Debug Information On/Off # !if $d(DBG) DBGFLAG = -v !else DBGFLAG = -v- !endif # PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 46/49 TITLE : Using the Database Framework as/in a DLL. # Which Library To Build, DOS or Windows # # If you want a different library name for your Windows framework, # change the first BUILDLIB entry to another name, such as dbfengw.lib. # !if $d(DBG) DEBUGFLAG=v !endif !if $d(DYNAMIC) DYNAMICFLAG=d !endif !if $d(WINDOWS) BUILDLIB = $(ENGLIB)\dbfw$(MDL)$(DEBUGFLAG)$(DYNAMICFLAG).lib !if $d(DLL) BUILDDIR = $(ENGLIB) BUILDLIB = $(ENGLIB)\dbfdll.lib !endif !else BUILDLIB = $(ENGLIB)\dbfbc$(DEBUGFLAG).lib !endif # # Where to put object modules for DOS or Windows # !if $d(WINDOWS) OBJDIR = WOBJ !else OBJDIR = DOBJ !endif # # Overall compilation options # ALLFLAGS = -c -m$(MDL) $(DBGFLAG) -vi- -w -I$(CCINCLUDE) -I$(ENGINCLUDE) !if $d(WINDOWS) CFLAGS = $(ALLFLAGS) -DWINDOWS -W -n$(OBJDIR) !if $d(DYNAMIC) PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 47/49 TITLE : Using the Database Framework as/in a DLL. CFLAGS = $(ALLFLAGS) -DWINDOWS -D_CLASSDLL -W -n$(OBJDIR) !if $d(DLL) CFLAGS = $(ALLFLAGS) -DWINDOWS -DDLL -D_CLASSDLL -D_RTLDLL -WDE -n$(OBJDIR) !endif !endif !else CFLAGS = $(ALLFLAGS) -n$(OBJDIR) !endif # # Implicit Rules # .c.obj: $(CC) -c {$< } .cpp.obj: $(CC) -c {$< } # # List Macros # LIB_dependencies = \ $(OBJDIR)\bcursor.obj \ $(OBJDIR)\bdatabas.obj \ $(OBJDIR)\bengine.obj \ $(OBJDIR)\brecord.obj \ $(OBJDIR)\pxmsg.obj # # Explicit Rules # !if !$d(DLL) $(BUILDLIB) : $D $(LIB_dependencies) - del $(BUILDLIB) $(TLIB) $< @&&| +$(OBJDIR)\bcursor.obj & +$(OBJDIR)\bdatabas.obj & +$(OBJDIR)\bengine.obj & +$(OBJDIR)\brecord.obj & +$(OBJDIR)\pxmsg.obj PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 48/49 TITLE : Using the Database Framework as/in a DLL. | !else $(BUILDLIB) : $D $(LIB_dependencies) $(OBJDIR)\dbfmain.obj - del $(BUILDLIB) $(TLINK) $(TLINKFLAG) @&&| c0d$(MDL).obj $(LIB_dependencies) $(OBJDIR)\dbfmain.obj $(BUILDDIR)\$(DLLNAME).DLL $(DLLNAME).MAP $(ENGWINLIB)\pxengwin.lib crtldll.lib import.lib cw$(MDL).lib $(DLLNAME).DEF | implib $(BUILDLIB) $(ENGLIB)\$(DLLNAME).DLL !endif $D: -@ if not exist $(OBJDIR)\nul mkdir $(OBJDIR) # comment out the below line if you don't want Make to do # an automatic 'cleanup' of the object module directory. -@ if exist $(OBJDIR)\*.obj del $(OBJDIR)\*.obj # # Individual File Dependencies # $(OBJDIR)\bcursor.obj: bcursor.cpp $(CC) $(CFLAGS) bcursor.cpp $(OBJDIR)\bdatabas.obj: bdatabas.cpp $(CC) $(CFLAGS) bdatabas.cpp $(OBJDIR)\bengine.obj: bengine.cpp $(CC) $(CFLAGS) bengine.cpp $(OBJDIR)\brecord.obj: brecord.cpp $(CC) $(CFLAGS) brecord.cpp $(OBJDIR)\pxmsg.obj: pxmsg.cpp $(CC) $(CFLAGS) pxmsg.cpp $(OBJDIR)\dbfmain.obj: dbfmain.cpp $(CC) $(CFLAGS) dbfmain.cpp PRODUCT : Paradox Engine NUMBER : 1169 VERSION : 3.0 OS : WIN DATE : October 22, 1993 PAGE : 49/49 TITLE : Using the Database Framework as/in a DLL. DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.