// BDE - (C) Copyright 1994 by Borland International #include "address.h" static bReset = FALSE; //================================================================= // Name: WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) // // Input: hInstance - The handle that represents the applications // unique instance ID. // hPrevInstance - Indicates if this is the first instance // of the app. // lpCmdLine - Command line parameters (up to the app to parse). // nCmdShow - TRUE = Show as non-icon application // // Return: ??? // // Description: This is the application entry point for the // Windows driver. It will set up the app, init // the Windows instance, process all event driven // messages, and clean up the suite prior to // returning to Windows. //================================================================= int _pascal WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; lpCmdLine = lpCmdLine; nCmdShow = nCmdShow; // Register CTL3D Ctl3dRegister(hInstance); Ctl3dAutoSubclass(hInstance); Ctl3dColorChange(); // Make this a single instance program if (hPrevInstance) { MessageBox(GetFocus(), "This application is already running!", "AddressBook Manager", MB_OK | MB_ICONHAND); return(FALSE); } // Start the application, and set the main dialog to no show until // everything is setup. hInst = hInstance; if (InitApp(SW_HIDE) == FALSE) { return(FALSE); } // Process all event driven messages... while (GetMessage(&msg, NULL, NULL, NULL)) { if (! IsDialogMessage(hMainWnd, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // Unregister CTL3D Ctl3dUnregister(hInstance); return msg.wParam; } //==================================================================== // Name: InitApp(); // // Input: None. // // Return: TRUE - Init worked // FALSE - Init failed // // Description: Create the application window & init any default // of the main window. //==================================================================== BOOL InitApp (int nCmdShow) { WNDCLASS wc; unsigned uCount; // Make certain to allocate enough space for the message. char szMessage[(DBIMAXMSGLEN * 2) + 1]; char szRelativeTblDirectory[DBIMAXPATHLEN+1]; // Init the application & create the needed windows wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA; wc.hInstance = hInst; wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(9999)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); wc.lpszMenuName = NULL; wc.lpszClassName = "MainWindowClass"; // Register the class if(!RegisterClass(&wc)) { MessageBox(NULL, "RegisterClass failed!", "System Error", MB_OK | MB_ICONHAND); return(FALSE); } // Increase the number of file handles that are available to the // system. uCount = SetHandleCount(FILEHANDLESNEEDED); if (uCount < FILEHANDLESNEEDED) { MessageBox(NULL, "Not enough file handles available. 'Set files=40'" " in CONFIG.SYS.", "System Error", MB_OK | MB_ICONHAND); return FALSE; } // Get the directory which contains the tables. GetPrivateProfileString("ADDRESS", "TblDir", "..\\..\\TABLES", (LPSTR)szRelativeTblDirectory, sizeof(szRelativeTblDirectory), "bde.ini"); // Create a fully qualified pathname for the table directory if (MakeFullPath(szTblDirectory, szRelativeTblDirectory)) { sprintf(szMessage,"Table Directory does not exist: %s", szTblDirectory); MessageBox(NULL, szMessage, "System Error", MB_OK | MB_ICONHAND); return FALSE; } // Get the private directory. Needed in case example is run off a // CD-ROM. GetPrivateProfileString("ADDRESS", "PrivateDir", ".", (LPSTR)szRelativeTblDirectory, sizeof(szRelativeTblDirectory), "bde.ini"); // Create a fully qualified path for the table private. if (MakeFullPath(szPrivDirectory, szRelativeTblDirectory)) { sprintf(szMessage,"Private Directory does not exist: %s", szPrivDirectory); MessageBox(NULL, szMessage, "System Error", MB_OK | MB_ICONHAND); return FALSE; } // Create the dialog that serves as the main window hMainWnd = CreateDialog(hInst, "MainDlg", 0, NULL); if (hMainWnd == NULL) { MessageBox(NULL, "CreateDialog failed!", "System Error", MB_OK | MB_ICONHAND); return(FALSE); } _wpOrigWndProc = SubClassWindow(GetDlgItem(hMainWnd, IDE_COMMENTS), EditSubClassProc); ShowWindow(hMainWnd, nCmdShow); return(TRUE); } // =============================================================== // Name: MainWndProc(hWnd, msg, wParam, lParam); // // Desc: This routine will process all messaged for the primary // application window. Included in this are all menu // commands. // =============================================================== LRESULT CALLBACK MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { UINT32 lRet = FALSE; pCHAR pszTableInfo = NULL; UINT16 iSize; CHAR szInitIndex[]="FullName"; CHAR szMdxName[DBIMAXPATHLEN]; UINT16 iRangeVal = 0; UINT16 i; CHAR szABType[DBIMAXNAMELEN]; CHAR szTable[DBIMAXNAMELEN]; CHAR szMsg[150]; UINT16 iType; BOOL bFlag; ABHANDLES AbHandle; pCS pCreate = NULL; DLGPROC lpProc; HWND hwnd; HBRUSH hBrush; // The following variables are static so that the original state that // is passed into the window proc is kept after we fall through it. static hDBIDb hDb; static hDBICur hCur; static hDBIDb hTempDb; static hDBICur hTempCur; static CHAR szTempName[DBIMAXNAMELEN]; static CHAR szTempDir[DBIMAXPATHLEN]; // These variables are used for the FileOpen/FileSave dialogs LPFOCHUNK lpFOChunk; hErrorWnd = hWnd; switch (msg) { case WM_CREATE: if((lpfnFileHook = (FARHOOK)MakeProcInstance( (FARPROC)FileHook, hInst))==NULL) { WinMsg("Could not create Common Dialog Hook", MB_ICONHAND, MB_OK); } PostMessage(hWnd, WM_DBIINIT, 0, 0); break; case WM_DBIINIT: hwnd = GetWindow(hWnd, GW_CHILD); while (hwnd != NULL) { Ctl3dSubclassCtl(hwnd); hwnd = GetWindow(hwnd, GW_HWNDNEXT); } // Check to see if the engine could not initialize. if(DbInit()!=DBIERR_NONE) { // There was an error so shut down. PostQuitMessage(0); break; } // Get the length of the table name plus the path plus 10 bytes. iSize = strlen(szTblDirectory) + strlen(szTblName) + 10; // Create the two tables - the Paradox Business table and the // dBASE personal table. for(i=0; i<2; i++) { // Get memory to hold the full table name with path. if((pszTableInfo = (pCHAR)malloc(iSize * sizeof(CHAR))) ==NULL) { WinMsg("You have run out of memory!", MB_ICONHAND, MB_OK); SendMessage(hWnd, WM_DESTROY, 0, 0L); } if(i==1) { strcpy((pCHAR)szTblName, szPERSONAL); strcpy((pCHAR)szTblType, szDBASE); strcpy(szABType, szPERSONAL); } else { strcpy((pCHAR)szTblName, szBUSINESS); strcpy((pCHAR)szTblType, szPARADOX); strcpy(szABType, szBUSINESS); } // Check if the table exists or empty. if(!TableExist(pszTableInfo)) { OpenDB(&hDb, NULL, NULL, NULL); if(CreateTable(hDb, &hCur, szABType)==DBIERR_NONE) { // Fill it with the data that is inside the resource // file. if(FillTable(hCur, szABType)) { CloseTable(&hCur); } } CloseDb(&hDb); } free(pszTableInfo); } OpenDB(&hDb, NULL, NULL, NULL); if(!GetTable(hDb, &hCur)) { // Get the Production index's name. GetMdxName(hCur, szMdxName); // Switch to the an index. This is done because we are // using a dBASE table which defaults to no index upon being // opened. You can choose any index by changing the // szInitIndex variable. SetIndex(&hCur, szInitIndex); // Goto the top of the table and move forward one record. GoTop(hCur, TRUE); } else { wsprintf(szMsg, "The following table: %s is corrupt - please" " delete it and rerun the program.", szTblName); WinMsg(szMsg, MB_ICONHAND, MB_OK); PostMessage(hWnd, WM_DESTROY, 0, 0L); return FALSE; } if(hCur==NULL) { WinMsg("Error opening tables!", MB_ICONHAND, MB_OK); PostMessage(hWnd, WM_DESTROY, 0, 0L); } else { ShowWindow(hWnd, SW_SHOW); // Display the field names for this table in the main // window. SetFieldNames(hCur); // Get the message number for the common dialog hook. iMSGFileOK = RegisterWindowMessage(FILEOKSTRING); // Display the first record. PostMessage(hWnd, WM_DISPLAY, 0, 0L); } break; case WM_CTLCOLOR: hBrush = Ctl3dCtlColorEx(msg, wParam, lParam); if (hBrush != (HBRUSH)0) { return (long)(WORD)hBrush; } else { return DefWindowProc(hWnd, msg, wParam, lParam); } case WM_SYSCOLORCHANGE: Ctl3dColorChange(); return TRUE; case WM_NCPAINT: case WM_NCACTIVATE: case WM_SETTEXT: return Ctl3dDlgFramePaint(hWnd, msg, wParam, lParam); case WM_SETFOCUS: SetFNameFocus(); break; case WM_DISPLAY: // Check the navigational buttons. CheckButtons(hCur); // Display the current record. DisplayTable(hCur); // Setup the edit controls so that the user can only // enter the correct amount of information. SetupEdits(); break; case WM_ABFILECREATE: iType = wParam; if(iType == 1) { strcpy((pCHAR)szABType, szBUSINESS); } else { strcpy((pCHAR)szABType, szPERSONAL); } if(bIsServer) { strcpy((pCHAR)szTable, (pCHAR)lParam); // Strip out any periods. StripChar((pCHAR)szTblName, szTable, 46); } if(CreateTable(hTempDb, &hTempCur, szABType)==DBIERR_NONE) { if(FillTable(hTempCur, szABType)) { if(CloseTable(&hTempCur)==DBIERR_NONE) { SendMessage(hWnd, WM_ABFILEOPEN, 0, lParam); } } } else { strcpy((pCHAR)szTblName, szTempName); strcpy((pCHAR)szTblDirectory, szTempDir); if(hTempDb) { CloseDb(&hTempDb); } hTempCur = 0; hTempDb = 0; if(hCur) { GetTblType(hCur, (pCHAR)szTblType); } } break; case WM_ABFILEOPEN: if(!CanContinue("Do you wish to save your changes" " before opening the new table", ID_UNDO_REC)) { SaveRec(hCur, FALSE); } if(bIsServer) { strcpy((pCHAR)szTable, (pCHAR)lParam); } else { strcpy((pCHAR)szTblName, (pCHAR)lParam); } if(GetTable(hTempDb, &hTempCur) == DBIERR_NONE) { CheckTable(hTempCur, &bFlag); if(bFlag) { EnableMenuItem(GetMenu(hMainWnd),ID_CLEAR_RANGE, MF_GRAYED); if(hDb) { CloseDb(&hDb); } hDb = hTempDb; hCur = hTempCur; hTempCur = 0; hTempDb = 0; if(AtBOF(hCur) && AtEOF(hCur)) { WinMsg("Filling the empty table with the default " "data.", MB_ICONHAND, MB_OK); FillTable(hCur, szBUSINESS); } GoTop(hCur, TRUE); InitIndex1(&hCur); SetAll(TRUE); // Display the field names for this table in the // main window. SetFieldNames(hCur); // Display the current record. PostMessage(hWnd, WM_DISPLAY, 0, 0L); } else { wsprintf(szMsg, "The Table named: %s is not a valid " "AddressBook table. Please try again", szTblName); WinMsg(szMsg, MB_ICONHAND, MB_OK); strcpy((pCHAR)szTblName, szTempName); strcpy((pCHAR)szTblDirectory, szTempDir); if(hTempDb) { CloseDb(&hTempDb); } hTempCur = 0; hTempDb = 0; if(hCur!=NULL) { GetTblType(hCur, (pCHAR)szTblType); } } } else { strcpy((pCHAR)szTblName, szTempName); strcpy((pCHAR)szTblDirectory, szTempDir); if(hTempDb) { CloseDb(&hTempDb); } if(hCur) { GetTblType(hCur, (pCHAR)szTblType); } hTempDb = 0; } break; case WM_COMMAND: switch(wParam) { // These messages are two buttons that are not visible // until the user sends an ID_ADD_REC message by pressing // the add button or choosing the add menu option. Once // that is done the OK button will stay dimmed until the // user has input valid data. Which consists of some first // and last name and a valid date. case IDOK: // Insert the record. HourGlassCursor(TRUE); SaveRec(hCur, TRUE); HourGlassCursor(FALSE); // Reset the controls back to normal. EndNewRec(hCur); SetFNameFocus(); break; case IDCANCEL: // Confirm if the data will be lost. if(CanContinue("Data not saved cancel anyway?", IDOK)) { // Reset the controls and cancel any data. EndNewRec(hCur); } break; // Check all the edits at once for any changes. Then // check if the data is valid. case IDE_FIRST_NAME: case IDE_LAST_NAME: case IDE_LAST_DATE: case IDE_ADDRESS1: case IDE_ADDRESS2: case IDE_CITY: case IDE_STATE: case IDE_ZIP: case IDE_PHONE1: case IDE_PHONE2: case IDE_COMMENTS: if (HIWORD(lParam) == EN_UPDATE && !bReset) { if(Varified()) { // If in add mode enable the OK button. if(NewRecMode) { EnableWindow(GetDlgItem(hMainWnd, IDOK), TRUE); } else { SetControl(ID_MOD_REC, TRUE); SetControl(ID_UNDO_REC, TRUE); } } else { if(NewRecMode) { // Disable the OK button, so that the // user cannot save the invalid data. EnableWindow(GetDlgItem(hMainWnd, IDOK), FALSE); } else { // Disable the save button but do not // disable the Undo button. SetControl(ID_MOD_REC, FALSE); SetControl(ID_UNDO_REC, TRUE); } } } break; case ID_DELETETABLE: if(WinMsg("Delete This table?", MB_ICONHAND, MB_YESNO)==IDYES) { HourGlassCursor(TRUE); if((DeleteTable(&hCur, hDb, (pCHAR)szTblName, (pCHAR)szTblType)) == DBIERR_NONE) { ClearDlg(); SetAll(FALSE); } HourGlassCursor(FALSE); } break; case ID_NEW: if((lpFOChunk = (LPFOCHUNK) malloc(sizeof(FOCHUNK))) == NULL) { return 0; } if((pCreate = (pCS) malloc(sizeof(ABCREATESTRUCT))) == NULL) { return 0; } pCreate->phDb = &hTempDb; pCreate->uType = 1; // Clear the variable before re-using the variable. memset(szTempName, '\0', DBIMAXNAMELEN); memset(szTempDir, '\0', DBIMAXPATHLEN); memset(szTable, '\0', DBIMAXNAMELEN); OpenDB(&hTempDb, NULL, NULL, NULL); InitializeStruct((LPSTR)lpFOChunk, pCreate); strcpy((pCHAR)szTable, szTblName); if ( GetSaveFileName( &(lpFOChunk->ofn) ) ) { strcpy(szTempDir, szTblDirectory); memset((pCHAR)szTblDirectory, '\0', DBIMAXPATHLEN); if(bIsServer) { strcpy((pCHAR)szTempName, szTable); strcpy((pCHAR)szTblType, ""); } else { strcpy((pCHAR)szTempName, szTblName); memset((pCHAR)szTblName, '\0', DBIMAXNAMELEN); GetFileTitle(lpFOChunk->ofn.lpstrFile, (pCHAR)szTblName, DBIMAXTBLNAMELEN - 1); strncpy((pCHAR)szTblDirectory, lpFOChunk->ofn.lpstrFile, (lpFOChunk->ofn.nFileOffset)-1); strlwr((pCHAR)szTblName); if(strstr(szTblName, ".dbf")==NULL) { strcpy((pCHAR)szTblType, szPARADOX); } else { strcpy((pCHAR)szTblType, szDBASE); } } iType = pCreate->uType; SendMessage(hWnd, WM_ABFILECREATE, iType, (LPARAM)szTblName); } else { ProcessCDError(CommDlgExtendedError()); // The user pressed cancel so we must close the // temporary database handle. if(hTempDb) { CloseDb(&hTempDb); } strcpy((pCHAR)szTblName, szTable); } free(lpFOChunk); free(pCreate); break; case ID_OPEN: if((lpFOChunk = (LPFOCHUNK) malloc(sizeof(FOCHUNK))) == NULL) { return 0; } if((pCreate = (pCS) malloc(sizeof(ABCREATESTRUCT))) == NULL) { return 0; } pCreate->phDb = &hTempDb; pCreate->uType = 0; // Clear the variable before re-using the variable. memset(szTempName, '\0', DBIMAXNAMELEN); memset(szTempDir, '\0', DBIMAXPATHLEN); memset(szTable, '\0', DBIMAXNAMELEN); OpenDB(&hTempDb, NULL, NULL, NULL); InitializeStruct((LPSTR)lpFOChunk, pCreate); strcpy((pCHAR)szTable, szTblName); if((lpfnFileHook = (FARHOOK)MakeProcInstance( (FARPROC)FileHook, hInst))==NULL) { WinMsg("Could not create Common Dialog Hook", MB_ICONHAND, MB_OK); } if ( GetOpenFileName( &(lpFOChunk->ofn) ) ) { strcpy(szTempDir, szTblDirectory); memset((pCHAR)szTblDirectory, '\0', DBIMAXPATHLEN); if(bIsServer) { strcpy((pCHAR)szTempName, szTable); } else { strcpy((pCHAR)szTempName, szTblName); memset((pCHAR)szTblName, '\0', DBIMAXNAMELEN); GetFileTitle(lpFOChunk->ofn.lpstrFile, (pCHAR)szTblName, DBIMAXTBLNAMELEN - 1); strncpy((pCHAR)szTblDirectory, lpFOChunk->ofn.lpstrFile, (lpFOChunk->ofn.nFileOffset)-1); } SendMessage(hWnd, WM_ABFILEOPEN, 0, (LPARAM)szTblName); } else { // The user pressed cancel so we must close the // temporary database handle. if(hTempDb != NULL) { CloseDb(&hTempDb); } strcpy((pCHAR)szTblName, szTable); } free(lpFOChunk); free(pCreate); break; // Display the About dialog box. case ID_ABOUT: lpProc = (DLGPROC)MakeProcInstance((FARPROC) AboutDlg, hInst); DialogBox(hInst, "AboutDlg", hMainWnd, lpProc); FreeProcInstance((FARPROC) lpProc); SetFNameFocus(); break; // Display the Order dialog box. case ID_ORDER: lpProc = (DLGPROC)MakeProcInstance((FARPROC) OrderDlg, hInst); AbHandle.phCur = &hCur; AbHandle.hDb = hDb; // Pass the pointer to the ABHandle structure so it // can be modified inside the dialogbox. if(DialogBoxParam(hInst, "OrderDlg", hMainWnd, lpProc, (LONG)(void far*)&AbHandle)==IDOK) { // Display the current record. DisplayTable(hCur); CheckButtons(hCur); } FreeProcInstance((FARPROC) lpProc); SetFNameFocus(); break; // Display the Range dialog box. case ID_RANGE: lpProc = (DLGPROC)MakeProcInstance((FARPROC)RangeDlg, hInst); AbHandle.phCur = &hCur; AbHandle.hDb = hDb; // Pass the pointer to the ABHandle structure so it // can be modified inside the dialogbox. iRangeVal = DialogBoxParam(hInst, "RangeDlg", hMainWnd, lpProc, (LONG)(void far*)&AbHandle); if(iRangeVal == IDOK) { // Set the global variable RangeSet to TRUE as // we did set a range for the present cursor. RangeSet = TRUE; // Display the current record. DisplayTable(hCur); CheckButtons(hCur); // Enable the Clear Range menu option. EnableMenuItem(GetMenu(hMainWnd), ID_CLEAR_RANGE, MF_ENABLED); } else { SetFNameFocus(); } FreeProcInstance((FARPROC) lpProc); break; // This menu option is enabled ONLY after a range has // been set. case ID_CLEAR_RANGE: ResetRange(hCur); // Go to the first record in the table. GoTop(hCur, TRUE); // Disable the Reset Range menu option. EnableMenuItem(GetMenu(hMainWnd), ID_CLEAR_RANGE, MF_GRAYED); // Set the global variable to FALSE. RangeSet = FALSE; // Display the current record. DisplayTable(hCur); CheckButtons(hCur); break; // Display the Search dialog box. case ID_SEARCH: lpProc = (DLGPROC)MakeProcInstance((FARPROC) SearchDlg, hInst); AbHandle.phCur = &hCur; AbHandle.hDb = hDb; // Pass the pointer to the ABHandle structure so it // can be modified inside the dialogbox. if(DialogBoxParam(hInst, "SearchDlg", hMainWnd, lpProc, (LONG)(void far*)&AbHandle)==IDOK) { // Move one record past the crack that the Search // function leaves you at. CHKERR(GetNextRec(hCur)); } FreeProcInstance((FARPROC) lpProc); // Display the current record. DisplayTable(hCur); CheckButtons(hCur); break; case ID_ADD_REC: // Change the "mode" of the main window so as to allow // for a new name to be entered. This "mode" will not // be deactivated until the IDOK and IDCANCEL messages // are processed in this message switch! ChangeEntryMode(hCur); // Clear the edit controls to allow the user to input // the new data easily. ClearDlg(); // Enable the Cancel button. EnableWindow(GetDlgItem(hMainWnd, IDCANCEL), TRUE); // Disable the OK button until valid data has been // input. EnableWindow(GetDlgItem(hMainWnd, IDOK), FALSE); // Put the current date into the Date Edit control. SetDefaultDate(); SetFNameFocus(); break; case ID_NEXT_REC: // Move one record forward. MoveRec(hCur, NEXT_REC); break; case ID_PREV_REC: // Move back one record. MoveRec(hCur, PREV_REC); break; case ID_FIRST_REC: // Move to the first record in the table. MoveRec(hCur, TOP); break; case ID_LAST_REC: // Move to the last record in the table. MoveRec(hCur, BOTTOM); break; case ID_MOD_REC: if(CanContinue("Do you want to modify this record?", ID_UNDO_REC)) { // Modify record. SaveRec(hCur, FALSE); // Set the navigational controls. CheckButtons(hCur); SetControl(ID_MOD_REC, FALSE); SetControl(ID_UNDO_REC, FALSE); } break; case ID_DEL_REC: if(WinMsg("Do you want to delete this record?", MB_ICONHAND, MB_YESNO)== IDYES) { // Delete the record. DeleteRecord(hCur); CheckButtons(hCur); } break; case ID_UNDO_REC: if(CanContinue("All changes will be lost - Undo " "anyway?", ID_UNDO_REC)) { // Redisplay the original data from the table. PostMessage(hWnd, WM_DISPLAY, 0, 0L); } break; case ID_EXIT: PostMessage(hWnd, WM_CLOSE, 0, 0L); break; default: lRet = DefWindowProc(hWnd, msg, wParam, lParam); break; } break; case WM_CLOSE: if(CanContinue("Data not saved quit anyway?", IDOK)) { DestroyWindow(hWnd); } else { SetFNameFocus(); } break; case WM_DESTROY: if(hCur) { CloseTable(&hCur); } if(hDb) { CloseDb(&hDb); } DbExit(); // Quit the application. PostQuitMessage(0); break; default: // Otherwise default to the DefWindowProc. lRet = DefWindowProc(hWnd, msg, wParam, lParam); break; } return(lRet); } //====================================================================== // Name: FillStruct() // // Input: Record structure pointer (RecordType *), Starting Resource ID // (UINT16), AddressBook type (pCHAR). // // Return: TRUE - The structure is filled. // // Desc: This routine will fill the structure with the strings that start // at Offset and are found in the resource file. //====================================================================== BOOL FillStruct (RecordType *pRec, UINT16 iOffSet, pCHAR pszABType) { // Used to keep count of the resource ID. We add one to the uNumFields // to take into account the extra #define for the Bussiness/Spouse pair. UINT16 j=IDS_FIRST_NAME_1 + (iOffSet*(uNumFields + 1)); memset(pRec, 0, sizeof(RecordType)); // Get the string into the structure LoadString(hInst, j++, (pCHAR)pRec->FName, sizeof(pRec->FName)); LoadString(hInst, j++, (pCHAR)pRec->LName, sizeof(pRec->LName)); // Check if this is a personal addressbook. if(strcmpi(pszABType, szPERSONAL) == 0) { LoadString(hInst, j++, (pCHAR)pRec->Spouse, sizeof(pRec->Spouse)); // Increment j to get past the Business data. j++; } else { j++; LoadString(hInst, j++, (pCHAR)pRec->Spouse, sizeof(pRec->Spouse)); } LoadString(hInst, j++, (pCHAR)pRec->Addrs1, sizeof(pRec->Addrs1)); LoadString(hInst, j++, (pCHAR)pRec->Addrs2, sizeof(pRec->Addrs2)); LoadString(hInst, j++, (pCHAR)pRec->City, sizeof(pRec->City)); LoadString(hInst, j++, (pCHAR)pRec->State, sizeof(pRec->State)); LoadString(hInst, j++, (pCHAR)pRec->Zip, sizeof(pRec->Zip)); LoadString(hInst, j++, (pCHAR)pRec->Phone1, sizeof(pRec->Phone1)); LoadString(hInst, j++, (pCHAR)pRec->Phone2, sizeof(pRec->Phone2)); LoadString(hInst, j++, (pCHAR)pRec->Date1, sizeof(pRec->Date1)); LoadString(hInst, j++, (pCHAR)pRec->Comment, sizeof(pRec->Comment)); return TRUE; } //====================================================================== // Name: DisplayTable() // // Input: Cursor handle (hDBICur). // // Return: TRUE - The record is displayed. // FALSE - The record Structure allocation failed. // // Desc: This routine will fill a structure with the record pointed // to by the cursor and then display the record in the main Window. //====================================================================== BOOL DisplayTable (hDBICur hCur) { RecordType *pRecord = NULL; // Allocate a temporary buffer to read information that is pointed // to by the cursor. if((pRecord = (RecordType *) malloc(1 * sizeof(RecordType))) == NULL) { WinMsg("You have run out of memory!", MB_ICONHAND, MB_OK); return FALSE; } memset(pRecord, 0, sizeof(RecordType)); // Set the Reset Variable to TRUE. bReset = TRUE; // Fill the structure with the record. GetData(hCur, pRecord); // Display the record. DispRec(pRecord); // Set the Reset Variable to FALSE. bReset = FALSE; SetControl(ID_MOD_REC, FALSE); SetControl(ID_UNDO_REC, FALSE); SetFNameFocus(); free(pRecord); return TRUE; } //====================================================================== // Name: TableExist() // // Input: Char string that holds the table's FULL name and path (pCHAR). // // Return: TRUE - The table exists and IS NOT empty. // FALSE - The table is empty or does not exist. // // Desc: This routine takes in a table name and checks if the table // exists. If it exists it checks if the table is empty. //====================================================================== BOOL TableExist (pCHAR pszTableInfo) { BOOL bRetVal; INT16 iExist = 0; hDBIDb hDb; hDBICur hCur; // Create the full path string of the table. strcpy(pszTableInfo, szTblDirectory); strcat(pszTableInfo, "\\"); strcat(pszTableInfo, szTblName); if(strcmpi(szTblType, szDBASE)==0) { strcat(pszTableInfo, ".dbf"); strcat((pCHAR)szTblName, ".dbf"); } else { strcat(pszTableInfo, ".db"); strcat((pCHAR)szTblName, ".db"); } iExist = access(pszTableInfo, 00); // Check if the table exists if(iExist == -1) { bRetVal = FALSE; } else { OpenDB(&hDb, NULL, NULL, NULL); GetTable(hDb, &hCur); // Go to the top of the table and stay at the BOF crack. GoTop(hCur, FALSE); // If we are at the EOF as well we have an empty table. if(AtEOF(hCur)) { bRetVal = FALSE; } else { bRetVal = TRUE; } // Close up and return the bool RetVal. CloseDb(&hDb); } return bRetVal; } //====================================================================== // Name: FillTable() // // Input: Cursor handle (hDBICur), and AddressBook Type (pCHAR). // // Return: TRUE - The record was added to the table. // FALSE - The record Structure allocation failed. // // Desc: This function fills the table with all the strings that are // in the resource file. //====================================================================== BOOL FillTable (hDBICur hCur, pCHAR pszABType) { RecordType *pRecord = NULL; UINT16 i; BOOL bRet = FALSE; // Allocate a temporary buffer to read information sitting in // the resource file. if((pRecord = (RecordType *) malloc(1 * sizeof(RecordType))) == NULL) { WinMsg("You have run out of memory!", MB_ICONHAND, MB_OK); return FALSE; } for(i=0; iFName); SetDlgItemText(hMainWnd, IDE_LAST_NAME, pRecord->LName); SetDlgItemText(hMainWnd, IDE_SP_COMP, pRecord->Spouse); SetDlgItemText(hMainWnd, IDE_ADDRESS1, pRecord->Addrs1); SetDlgItemText(hMainWnd, IDE_ADDRESS2, pRecord->Addrs2); SetDlgItemText(hMainWnd, IDE_CITY, pRecord->City); SetDlgItemText(hMainWnd, IDE_STATE, pRecord->State); SetDlgItemText(hMainWnd, IDE_ZIP, pRecord->Zip); SetDlgItemText(hMainWnd, IDE_PHONE1, pRecord->Phone1); SetDlgItemText(hMainWnd, IDE_PHONE2, pRecord->Phone2); SetDlgItemText(hMainWnd, IDE_LAST_DATE, pRecord->Date1); SetDlgItemText(hMainWnd, IDE_COMMENTS, pRecord->Comment); return TRUE; } //====================================================================== // Name: MoveRec() // // Input: Cursor handle (hDBICur) and Movement (INT16). // // Return: None. // // Desc: This function moves the cursor to the bottom or the top // of the table. Or it moves it a record forward or backwards. //====================================================================== DBIResult MoveRec (hDBICur hCur, INT16 iMovement) { // Check if data has been changed by looking at the status of the Undo // button. Then ask if the user wishes to lose the data by moving. if(CanContinue("Data not saved move to next record anyway?", ID_UNDO_REC)) { HourGlassCursor(TRUE); switch(iMovement) { // These macros are defined in the header file. case TOP: GoTop(hCur, TRUE); break; case BOTTOM: GoBottom(hCur, TRUE); break; case NEXT_REC: if(!AtEOF(hCur)) { CHKERR(GetNextRec(hCur)); } break; case PREV_REC: if(!AtBOF(hCur)) { GetPrevRec(hCur); } break; default: return DBIERR_NOTSUPPORTED; } // Check the navigational controls and display the current record. CheckButtons(hCur); DisplayTable(hCur); } else { SetFNameFocus(); } HourGlassCursor(FALSE); return DBIERR_NONE; } //====================================================================== // Name: CheckButtons() // // Input: Cursor handle (hDBICur). // // Return: None. // // Desc: This function checks the position of the cursor and then // enables or disables the naviagtional buttons AND menu options. //====================================================================== void CheckButtons (hDBICur hCur) { if(AtEOF(hCur)) { // If at EOF disable the Next and Last record buttons and // menu options. SetControl(ID_NEXT_REC, FALSE); SetControl(ID_LAST_REC, FALSE); } else { // Else enable them. SetControl(ID_NEXT_REC, TRUE); SetControl(ID_LAST_REC, TRUE); } if(AtBOF(hCur)) { // If at BOF disable the Prev and First record buttons // and menu options. SetControl(ID_PREV_REC, FALSE); SetControl(ID_FIRST_REC, FALSE); } else { // Else enable them. SetControl(ID_PREV_REC, TRUE); SetControl(ID_FIRST_REC, TRUE); } // If the table is empty. if(AtBOF(hCur) && AtEOF(hCur)) { if(GetPrevRec(hCur)==DBIERR_BOF && GetNextRec(hCur)==DBIERR_EOF) { SetControl(ID_DEL_REC, FALSE); SetControl(ID_ORDER, FALSE); SetControl(ID_RANGE, FALSE); SetControl(ID_SEARCH, FALSE); } else { SetControl(ID_DEL_REC, TRUE); SetControl(ID_ORDER, TRUE); SetControl(ID_RANGE, TRUE); SetControl(ID_SEARCH, TRUE); } } else { SetControl(ID_DEL_REC, TRUE); SetControl(ID_ORDER, TRUE); SetControl(ID_RANGE, TRUE); SetControl(ID_SEARCH, TRUE); } SetFNameFocus(); } //====================================================================== // Name: SetupEdits() // // Input: None. // // Return: None. // // Desc: This function sets the text input limit of each of the edit // controls that are in the main window. //====================================================================== void SetupEdits (void) { // Use the constants -1 to allow room for the NULL terminator. SendDlgItemMessage(hMainWnd, IDE_FIRST_NAME, EM_LIMITTEXT, (WPARAM)NAMELEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_LAST_NAME, EM_LIMITTEXT, (WPARAM)NAMELEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_SP_COMP, EM_LIMITTEXT, (WPARAM)ADDRESSLEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_COMMENTS, EM_LIMITTEXT, (WPARAM)COMMENTLEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_ADDRESS1, EM_LIMITTEXT, (WPARAM)ADDRESSLEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_ADDRESS2, EM_LIMITTEXT, (WPARAM)ADDRESSLEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_CITY, EM_LIMITTEXT, (WPARAM)CITYLEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_STATE, EM_LIMITTEXT, (WPARAM)STATELEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_ZIP, EM_LIMITTEXT, (WPARAM)ZIPLEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_PHONE1, EM_LIMITTEXT, (WPARAM)PHONELEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_PHONE2, EM_LIMITTEXT, (WPARAM)PHONELEN-1, 0L); SendDlgItemMessage(hMainWnd, IDE_LAST_DATE, EM_LIMITTEXT, (WPARAM)DATELEN-1, 0L); // Disable the Cancel and OK buttons that are hidden. EnableWindow(GetDlgItem(hMainWnd, IDCANCEL), FALSE); EnableWindow(GetDlgItem(hMainWnd, IDOK), FALSE); } //====================================================================== // Name: SaveRec() // // Input: Cursor handle (hDBICur), Add or Overwrite bool (BOOL). // // Return: TRUE: If the memory is allocated. // FALSE: If the memory allocation fails. // // Desc: This function takes the data from off the main window and // puts it in a record structure. Then based upon the bAdd Bool // it inserts the record or overwrites the old record. //====================================================================== BOOL SaveRec (hDBICur hCur, BOOL bAdd) { RecordType *pRecord=NULL; // Allocate a temporary buffer to store data that is inside the // main Window. if((pRecord = (RecordType *) malloc(1 * sizeof(RecordType))) == NULL) { WinMsg("You have run out of memory!", MB_ICONHAND, MB_OK); return FALSE; } // Clear the record structure. memset(pRecord, 0, sizeof(RecordType)); // Get the data from the main Window and put it into the record // structure. GetRec(pRecord); // Add the record or insert the record based upon the bAdd value. AddRecord(hCur, pRecord, bAdd); free(pRecord); CheckButtons(hCur); return TRUE; } //====================================================================== // Name: GetRec() // // Input: Record structure pointer (RecordType *). // // Return: TRUE. // // Desc: This function fills the record structure with the data that // is in the main Window. //====================================================================== BOOL GetRec (RecordType *pRecord) { GetDlgItemText(hMainWnd, IDE_FIRST_NAME, pRecord->FName, NAMELEN); GetDlgItemText(hMainWnd, IDE_LAST_NAME, pRecord->LName, NAMELEN); GetDlgItemText(hMainWnd, IDE_SP_COMP, pRecord->Spouse, ADDRESSLEN); GetDlgItemText(hMainWnd, IDE_ADDRESS1, pRecord->Addrs1, ADDRESSLEN); GetDlgItemText(hMainWnd, IDE_ADDRESS2, pRecord->Addrs2, ADDRESSLEN); GetDlgItemText(hMainWnd, IDE_CITY, pRecord->City, CITYLEN); GetDlgItemText(hMainWnd, IDE_STATE, pRecord->State, STATELEN); GetDlgItemText(hMainWnd, IDE_ZIP, pRecord->Zip, ZIPLEN); GetDlgItemText(hMainWnd, IDE_PHONE1, pRecord->Phone1, PHONELEN); GetDlgItemText(hMainWnd, IDE_PHONE2, pRecord->Phone2, PHONELEN); GetDlgItemText(hMainWnd, IDE_LAST_DATE, pRecord->Date1, DATELEN); GetDlgItemText(hMainWnd, IDE_COMMENTS, pRecord->Comment, COMMENTLEN); return TRUE; } //====================================================================== // Name: FillDropList() // // Input: Window Handle (HWND), Cursor handle(hDBICur), Database Handle // (hDBIDb), Resource ID (UINT16), and Active Index name (pCHAR). // // Return: The name of presently active index on the AddressBook table. // // Desc: This function fills the combobox represented by Id with the all // names that are open on the table. It also returns the name // of the currently active index inside of the pszActiveIndex // string. //====================================================================== UINT16 FillDropList (HWND hWnd, UINT16 iId, UINT16 iNumIdxs, pABIDXDESC pABIdxDesc, pCHAR pszIndex) { UINT16 i; // used for loop counter UINT32 lOff; UINT32 lIndex; // Fill the combobox with all the index names that are listed in the // pABIdxDesc structure. for(i=0; i 0) && (iLName >0)) { bRetVal = TRUE; } else { bRetVal = FALSE; } GetDlgItemText(hMainWnd, IDE_LAST_DATE, pDate, DATELEN); // Need to convert the string to a Date structure pVal = strtok(pDate, pFmtDate->szDateSeparator); if(pVal && bRetVal) { d.month = atoi(pVal); pVal = strtok(NULL, pFmtDate->szDateSeparator); if(pVal && bRetVal) { d.day = atoi(pVal); pVal = strtok(NULL, pFmtDate->szDateSeparator); if(pVal && bRetVal) { d.year = atoi(pVal); } else { bRetVal = FALSE; } } else { bRetVal = FALSE; } } else { bRetVal = FALSE; } if(bRetVal) { // Check if the date is legal. rslt = DateEncode(d.month, d.day, d.year, &TempDate); if(rslt == DBIERR_NONE) { bRetVal = TRUE; } else { bRetVal = FALSE; } } free(pszFName); free(pszLName); free(pDate); free(pFmtDate); return bRetVal; } //====================================================================== // Name: SetDefaultDate() // // Input: None. // // Return: None. // // Desc: This function puts the current date into the Last Date edit // control so that we have a valid date to start. //====================================================================== DBIResult SetDefaultDate (void) { struct dosdate_t d; pFMTDate pFmtDate; CHAR szDateString[DATELEN]; if((pFmtDate = (pFMTDate) malloc(sizeof(FMTDate))) == NULL) { WinMsg("You have run out of memory!", MB_ICONHAND, MB_OK); return DBIERR_NOMEMORY; } CHKERR(GetDateFormat(pFmtDate)); _dos_getdate(&d); if(pFmtDate->iDateMode==0) { wsprintf(szDateString, "%02d%s%02d%s%02d", d.month, pFmtDate->szDateSeparator, d.day, pFmtDate->szDateSeparator, d.year); } if(pFmtDate->iDateMode==1) { wsprintf(szDateString, "%02d%s%02d%s%02d", d.day, pFmtDate->szDateSeparator, d.month, pFmtDate->szDateSeparator, d.year); } if(pFmtDate->iDateMode==2) { wsprintf(szDateString, "%02d%s%02d%s%02d", d.year, pFmtDate->szDateSeparator, d.month, pFmtDate->szDateSeparator, d.day); } SetDlgItemText(hMainWnd, IDE_LAST_DATE, szDateString); free(pFmtDate); return DBIERR_NONE; } //====================================================================== // Name: EndNewRec() // // Input: Cursor handle (hDBICur). // // Return: None. // // Desc: This function is called during the end of the Add new person // function. It changes the current state of the NewRecMode // global variable. Then it checks the navigational controls // and sets focus unto the First Name edit control. //====================================================================== void EndNewRec (hDBICur hCur) { ChangeEntryMode(hCur); DisplayTable(hCur); CheckButtons(hCur); SetFNameFocus(); } //====================================================================== // Name: PutField() // // Input: Record structure pointer (RecordType *), pointer to the input // text (pCHAR), and Array element number (UINT16). // // Return: None. // // Desc: This function puts input text into the correct field of the // record structure pointer based upon MemberNum. //====================================================================== void PutField (RecordType *pRec, pCHAR pszText, UINT16 iMemberNum) { switch(iMemberNum) { case 0: strcpy(pRec->FName, pszText); break; case 1: strcpy(pRec->LName, pszText); break; case 2: strcpy(pRec->Spouse, pszText); break; case 3: strcpy(pRec->Addrs1, pszText); break; case 4: strcpy(pRec->Addrs2, pszText); break; case 5: strcpy(pRec->City, pszText); break; case 6: strcpy(pRec->State, pszText); break; case 7: strcpy(pRec->Zip, pszText); break; case 8: strcpy(pRec->Phone1, pszText); break; case 9: strcpy(pRec->Phone2, pszText); break; case 10: strcpy(pRec->Date1, pszText); break; } } //====================================================================== // Name: GetField() // // Input: Record structure pointer (RecordType *), pointer to the input // text (pCHAR), and Array element number (UINT16). // // Return: None. // // Desc: This function gets data from the field in the record structure, // based upon the input variable - MemberNum. //====================================================================== void GetField (RecordType *pRec, pCHAR pszText, UINT16 iMemberNum) { switch(iMemberNum) { case 0: strcpy(pszText, pRec->FName); break; case 1: strcpy(pszText, pRec->LName); break; case 2: strcpy(pszText, pRec->Spouse); break; case 3: strcpy(pszText, pRec->Addrs1); break; case 4: strcpy(pszText, pRec->Addrs2); break; case 5: strcpy(pszText, pRec->City); break; case 6: strcpy(pszText, pRec->State); break; case 7: strcpy(pszText, pRec->Zip); break; case 8: strcpy(pszText, pRec->Phone1); break; case 9: strcpy(pszText, pRec->Phone2); break; case 10: strcpy(pszText, pRec->Date1); break; } } //====================================================================== // Name: GetCond() // // Input: Handle to the window that has the check boxes. // // Return: Which check box is checked. // // Desc: This function simply returns a number based upon which check // box is checked. //====================================================================== DBISearchCond GetCond (HWND hWnd) { DBISearchCond eRet; UINT32 iCond=0; UINT16 i=IDC_GREATEREQ; while(iCond!=1) { iCond = SendDlgItemMessage(hWnd, i, BM_GETCHECK, 0, 0L); i++; } // Subtract 1 to counteract the last i++ i--; switch(i) { case IDC_EQUAL: eRet = keySEARCHEQ; break; case IDC_GREATER: eRet = keySEARCHGT; break; case IDC_GREATEREQ: eRet = keySEARCHGEQ; break; } return eRet; } //====================================================================== // Name: CanContinue() // // Input: Pointer to the string that is to be displayed (pCHAR), and // a resource ID (UINT16). // // Return: If the resource is enabled, then it returns the user's response. // Otherwise, it returns a TRUE. // // Desc: This function checks if the Id is enabled. If it is then it // prompts the user with the pString and returns the response. // Otherwise it returns a TRUE. //====================================================================== BOOL CanContinue (pCHAR pszString, UINT16 iId) { BOOL bRetVal = TRUE; // Check to see if the button is enabled. if(IsWindowEnabled(GetDlgItem(hMainWnd, iId))) { if(WinMsg(pszString, MB_ICONHAND, MB_YESNO) == IDNO) { bRetVal = FALSE; } } return bRetVal; } //========================================================================= // Function: FillAliasCBBox() // // Input: Pointer to the Alias Structures(pDBDesc), Number of aliases // (UINT32), and the Combo Box's ID to fill (UINT16) // // Returns: None // // Desc: This function is used to fill the CB whose ID is CBId. The // CB is filled with the Aliases that are available to the // client. //========================================================================= void FillAliasCBBox (pDBDesc pAliases, UINT32 lNumAliases, UINT16 iCBId, HWND hWnd) { UINT16 i; UINT32 lSel; CHAR szString[]="NULL - Std Tables"; // First put all the aliases into the CB. for(i=0; i<(UINT16)lNumAliases; i++) { SendMessage(GetDlgItem(hWnd, iCBId), CB_ADDSTRING, 0, (LPARAM)pAliases[i].szName); } // Now add the NULL alias which is the local tables. SendMessage(GetDlgItem(hWnd, iCBId), CB_ADDSTRING, 0, (LPARAM)szString); // Now get the Paradox item number and display Paradox in the Alias CB. lSel = SendMessage(GetDlgItem(hWnd, iCBId), CB_FINDSTRING, (WPARAM)-1, (LPARAM)szString); SendMessage(GetDlgItem(hWnd, iCBId), CB_SETCURSEL, (UINT16)lSel, 0L); } //========================================================================= // Function: FillFileList() // // Input: Window handle(HWND), Number of tables to display (UINT32), // Handle of the database (hDBIDb). // // Returns: TRUE if the names of the table are uppercase on the server. // FALSE if the names of the table are lowercase on the server. // // Desc: This function is used to fill the listbox whose ID is LBId // with all the table names who are available to the database // (hDb). We use this to fill the list box in the common // dialogbox with all the table names in the remote database. //========================================================================= BOOL FillFileList (HWND hWnd, UINT16 iLBId, hDBIDb hDb) { hDBICur hTblCur; BOOL bRet = TRUE; TBLBaseDesc baseDesc; HourGlassCursor(TRUE); GetTableList(hDb, &hTblCur); // Go to the top of the table. GoTop(hTblCur, FALSE); // Put all the Tablenames into the Filelist. while((GetNextTblRec(hTblCur, &baseDesc))!=DBIERR_EOF) { SendMessage(GetDlgItem(hWnd, iLBId), LB_ADDSTRING, 0, (LPARAM)baseDesc.szName); } if(islower(baseDesc.szName[0])) { bRet = FALSE; } CloseTable(&hTblCur); HourGlassCursor(FALSE); return bRet; } //========================================================================= // Function: SetFieldNames() // // Input: Cursor handle (hDBICur). // // Returns: None // // Desc: This function is used to set the field names into the dialog // box. It gets the field names and displays them in proper // format with a trailing :. //========================================================================= void SetFieldNames (hDBICur hCur) { UINT16 i; pFIELDName pFieldNames; CHAR szName[DBIMAXTBLNAMELEN]; if((pFieldNames = (pFIELDName) malloc(sizeof(FIELDNAME) * uNumFields)) == NULL) { WinMsg("You have run out of memory!", MB_ICONHAND, MB_OK); return; } // Get the field names and the amount of fields. GetFldNames(hCur, pFieldNames); for(i=0; i