/* * SCLIENT.C * * This module contains functions associated with the client dialog box * in SAMPLE.EXE. * * Copyright (C) 1991 by Daytris. All rights reserved. */ #include #include #include #include #include #ifndef ZORTECH #include #endif #include "dbmgr.h" #include "sampledb.h" #include "sample.h" /************************************************ * Local data ************************************************/ static CLIENT client; static enum { MODE_ADD, MODE_UPDATE, MODE_DELETE } eMode; static BOOL bAddressChange; static HANDLE hAddresses; /************************************************ * Function Declarations ************************************************/ BOOL AddClientDlg( HWND hWnd); BOOL UpdateClientDlg( HWND hWnd); BOOL DeleteClientDlg( HWND hWnd); static BOOL GetSelectedClient( HWND hWnd, CLIENT *pClient, short *pIndexSel); static BOOL AddClientAddresses( HWND hWnd); static BOOL DeleteClientAddresses( HWND hWnd); static BOOL FreeClientAddresses( HWND hWnd); BOOL FAR PASCAL ClientProc( HWND hDlg, unsigned iMessage, WORD wParam, LONG lParam); static void SetClientFields( HWND hDlg); static BOOL GetClientFields( HWND hDlg); static BOOL StoreAddressHandles( HWND hDlg); /*************************************************************************** * Function : AddClientDlg * * Purpose : This function drives the add client dialog box. * * Returns : TRUE - client added * FALSE - add aborted or error in add ***************************************************************************/ BOOL AddClientDlg( HANDLE hWnd) { short nStatus; DWORD dwStatus; FARPROC lpfnClientProc; /* Set static variables */ eMode = MODE_ADD; bAddressChange = FALSE; /* Initialize the client structure */ memset( &client, 0, sizeof( CLIENT)); client.lClientNbr = setup.lNextClientNbr; /* Create an instance and open the Client window */ lpfnClientProc = MakeProcInstance( ClientProc, hInst); nStatus = DialogBox( hInst, "client", hWnd, lpfnClientProc); FreeProcInstance( lpfnClientProc); /* User selected OK */ if( nStatus == IDOK) { /* Add the client */ if( dwStatus = XDbRecordAdd( hDb, "client", &client, sizeof( CLIENT)) ) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* Add the member addresses */ if( bAddressChange) { if( ! AddClientAddresses( hWnd)) return FALSE; } /* Increment the client number counter and update the setup record */ setup.lNextClientNbr++; if( dwStatus = XDbRecordUpdate( hDb, "setup", &setup, sizeof( SETUP))) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* Flush the database */ DbFlush( hDb); /* Add the client to the list box */ AddToClientListBox( hWnd, &client); } else /* IDCANCEL */ { /* Free all address handles for this client */ if( ! FreeClientAddresses( hWnd)) return FALSE; } return TRUE; } /*************************************************************************** * Function : UpdateClientDlg * * Purpose : This function drives the add client dialog box. * * Returns : TRUE - client added * FALSE - update aborted or error in update ***************************************************************************/ BOOL UpdateClientDlg( HANDLE hWnd) { short nStatus, nIndex; DWORD dwStatus; FARPROC lpfnClientProc; /* Set the mode */ eMode = MODE_UPDATE; /* Initialize the client structure */ if( ! GetSelectedClient( hWnd, &client, &nIndex)) { MessageBeep( 0); return FALSE; } /* Create an instance and open the Client window */ lpfnClientProc = MakeProcInstance( ClientProc, hInst); nStatus = DialogBox( hInst, "client", hWnd, lpfnClientProc); FreeProcInstance( lpfnClientProc); /* User selected OK */ if( nStatus == IDOK) { /* Update the client */ if( dwStatus = XDbRecordUpdate( hDb, "client", &client, sizeof( CLIENT)) ) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* If any address has changed, delete all member addresses and add addresses in handle table. */ if( bAddressChange) { if( ! DeleteClientAddresses( hWnd)) return FALSE; if( ! AddClientAddresses( hWnd)) return FALSE; } /* Flush the database */ DbFlush( hDb); /* Update the listbox */ DeleteFromClientListBox( hWnd, nIndex); AddToClientListBox( hWnd, &client); } else /* IDCANCEL */ { /* Free all address handles for this client */ if( ! FreeClientAddresses( hWnd)) return FALSE; } return TRUE; } /*************************************************************************** * Function : DeleteClientDlg * * Purpose : This function drives the client record deletion process. * * Returns : TRUE - client deleted * FALSE - delete aborted or error in delete ***************************************************************************/ BOOL DeleteClientDlg( HWND hWnd) { short nStatus, nIndex; DWORD dwStatus; /* Initialize the client structure */ if( ! GetSelectedClient( hWnd, &client, &nIndex)) { MessageBeep( 0); return FALSE; } /* Ask user if they're sure */ nStatus = MessageBox( hWnd, "Are you sure?", "Delete Client", MB_ICONQUESTION | MB_YESNO); /* User selected YES */ if( nStatus == IDYES) { /* Delete all member addresses */ if( ! DeleteClientAddresses( hWnd)) return FALSE; /* Delete the client */ if( dwStatus = DbRecordDelete( hDb, "client")) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* Flush the database */ DbFlush( hDb); /* Remove client from listbox */ if( ! DeleteFromClientListBox( hWnd, nIndex)) return FALSE; } return TRUE; } /*************************************************************************** * Function : GetSelectedClient * * Purpose : This function retrieves the selected client record from * the database. It uses the client number in the string * of the listbox as a key value to retrieve upon. The * listbox index is also returned. * * Returns : TRUE - client retrieved * FALSE - error ***************************************************************************/ static BOOL GetSelectedClient( HWND hWnd, CLIENT *pClient, short *pIndex) { LONG lKey; DWORD dwStatus; char szBuffer[64], *pTemp; /* Get the listbox selection */ if( (*pIndex = (short)SendMessage( hWndClientLB, LB_GETCURSEL, 0, 0L)) == LB_ERR) { return FALSE; } if( SendMessage( hWndClientLB, LB_GETTEXT, *pIndex, (LONG)(LPSTR)szBuffer) == LB_ERR) { MessageBox( hWnd, "SendMessage / LB_GETTEXT", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } /* Find the client number in the selected string */ if( bSortByNumber) pTemp = strtok( szBuffer, " "); else { pTemp = strchr( szBuffer, 0); for( pTemp-- ; *pTemp != ' ' ; pTemp--) ; pTemp++; } lKey = atol( pTemp); /* Retrieve the record */ if( dwStatus = XDbRecordGetByKey( hDb, "client", "lClientNbr", pClient, sizeof( CLIENT), &lKey, sizeof( LONG))) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } return TRUE; } /*************************************************************************** * Function : AddClientAddresses * * Purpose : This function adds the addresses associated with the client * record. A base handle, 'hAddresses', contains a null * terminated array of address handles (records) to be added. * * Returns : TRUE - add ok * FALSE - error in add ***************************************************************************/ static BOOL AddClientAddresses( HWND hWnd) { HANDLE FAR *lpAddressHandle; DWORD dwStatus; /* If no addresses, return */ if( ! hAddresses) return TRUE; /* Get a pointer to the array of address handles */ if( ! (lpAddressHandle = (HANDLE FAR *)GlobalLock( hAddresses))) { MessageBox( hWnd, "Memory: GlobalLock", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } for( ; *lpAddressHandle ; lpAddressHandle++) { /* Add the address record */ if( dwStatus = DbRecordAdd( hDb, "address", *lpAddressHandle)) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* Make a set connection between the client and address. The address record will be a member of the client. */ if( dwStatus = DbSetAdd( hDb, "client", "address")) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* Free the address handle */ if( GlobalFree( *lpAddressHandle)) { MessageBox( hWnd, "Memory: GlobalFree", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } } /* Unlock and free the array of address handles */ GlobalUnlock( hAddresses); if( GlobalFree( hAddresses)) { MessageBox( hWnd, "Memory: GlobalFree", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE; } /*************************************************************************** * Function : DeleteClientAddresses * * Purpose : This function deletes all address records that are members * of the selected client. * * Returns : TRUE - delete ok * FALSE - error in delete ***************************************************************************/ static BOOL DeleteClientAddresses( HWND hWnd) { DWORD dwStatus; while( 1) { /* Set currency to first member record in the set */ dwStatus = DbSetFindFirst( hDb, "client", "address"); /* Check for errors */ if( dwStatus == E_NOTFOUND) break; if( dwStatus) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* IMPORTANT: All set connections must be deleted before the member record of a set is deleted */ /* Delete the set connection between client (owner) and address (member) */ if( dwStatus = DbSetDelete( hDb, "client", "address")) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } /* Delete the address record */ if( dwStatus = DbRecordDelete( hDb, "address")) { DbError( hWnd, dwStatus, __FILE__, __LINE__); return FALSE; } } return TRUE; } /*************************************************************************** * Function : FreeClientAddresses * * Purpose : This function frees all addresses associated with the * selected client. 'hAddresses' contains a handle to * a null terminated array of address handles in the listbox. * * Returns : TRUE - free ok * FALSE - error in free ***************************************************************************/ static BOOL FreeClientAddresses( HWND hWnd) { HANDLE FAR *lpAddressHandle; /* If no addresses, return */ if( ! hAddresses) return TRUE; /* Get a pointer to the array of address handles */ if( ! (lpAddressHandle = (HANDLE FAR *)GlobalLock( hAddresses))) { MessageBox( hWnd, "Memory: GlobalLock", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } for( ; *lpAddressHandle ; lpAddressHandle++) { /* Free the address handle */ if( GlobalFree( *lpAddressHandle)) { MessageBox( hWnd, "Memory: GlobalFree", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } } /* Unlock and free the array of address handles */ GlobalUnlock( hAddresses); if( GlobalFree( hAddresses)) { MessageBox( hWnd, "Memory: GlobalFree", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE; } /*************************************************************************** * Function : ClientProc * * Purpose : This function is the window procedure for 'add' and 'update' * client. * * Returns : TRUE - message processed * FALSE - message not processed ***************************************************************************/ BOOL FAR PASCAL ClientProc( HWND hDlg, unsigned iMessage, WORD wParam, LONG lParam) { switch( iMessage) { case WM_INITDIALOG: { short nTab; if( eMode == MODE_ADD) SetWindowText( hDlg, "Add Client"); else SetWindowText( hDlg, "Update Client"); /* Set a tab stop in the listbox out of sight. The handle to the ADDRESS structure will be stored here (in ASCII) */ nTab = (LOWORD( GetDialogBaseUnits()) * 100) / 4; SendDlgItemMessage( hDlg, IDC_ADDR_LISTBOX, LB_SETTABSTOPS, 1, (LONG)(LPSTR)&nTab); SetClientFields( hDlg); /* If update mode, load the address listbox */ if( eMode == MODE_UPDATE) LoadAddressListBox( hDlg); /* Set focus to Name field */ SetFocus( GetDlgItem( hDlg, IDC_EDIT_NAME)); return TRUE; } case WM_COMMAND: switch( wParam) { case IDOK: if( ! GetClientFields( hDlg)) break; StoreAddressHandles( hDlg); EndDialog( hDlg, IDOK); break; case IDCANCEL: StoreAddressHandles( hDlg); EndDialog( hDlg, IDCANCEL); break; case IDC_ADD_ADDR: if( AddAddressDlg( hDlg)) bAddressChange = TRUE; break; case IDC_UPDATE_ADDR: if( UpdateAddressDlg( hDlg)) bAddressChange = TRUE; break; case IDC_DELETE_ADDR: if( DeleteAddressDlg( hDlg)) bAddressChange = TRUE; break; } return TRUE; } return FALSE; } /*************************************************************************** * Function : SetClientFields * * Purpose : This function initializes the client dialog fields. It * uses the static 'client' structure. * * Returns : n/a ***************************************************************************/ static void SetClientFields( HWND hDlg) { char szBuffer[36]; /* Set client number */ ltoa( client.lClientNbr, szBuffer, 10); SetDlgItemText( hDlg, IDC_EDIT_NUMBER , szBuffer); /* Set client name */ SendDlgItemMessage( hDlg, IDC_EDIT_NUMBER, EM_LIMITTEXT, sizeof( client.szName) - 1, 0L); SetDlgItemText( hDlg, IDC_EDIT_NAME, client.szName); /* Set client description */ SendDlgItemMessage( hDlg, IDC_EDIT_DESC, EM_LIMITTEXT, sizeof( client.szDescription) - 1, 0L); SetDlgItemText( hDlg, IDC_EDIT_DESC, client.szDescription); /* Set client balance */ sprintf( szBuffer, "%.2f", client.dBalance); SendDlgItemMessage( hDlg, IDC_EDIT_BALANCE, EM_LIMITTEXT, 10, 0L); SetDlgItemText( hDlg, IDC_EDIT_BALANCE, szBuffer); } /*************************************************************************** * Function : GetClientFields * * Purpose : This function retrieves the client dialog fields. It * also performs minor field error checking. Client fields * are stored in the static 'client' structure. * * Returns : TRUE - fields ok * FALSE - error in field (focus is set) ***************************************************************************/ static BOOL GetClientFields( HWND hDlg) { char szBuffer[36]; GetDlgItemText( hDlg, IDC_EDIT_NAME, client.szName, sizeof( client.szName)); GetDlgItemText( hDlg, IDC_EDIT_DESC, client.szDescription, sizeof( client.szDescription)); GetDlgItemText( hDlg, IDC_EDIT_BALANCE, szBuffer, sizeof( szBuffer)); client.dBalance = atof( szBuffer); /* Name field required */ if( ! *client.szName) { MessageBox( hDlg, "Name required", "Invalid Input", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK); /* Set focus to Name field */ SetFocus( GetDlgItem( hDlg, IDC_EDIT_NAME)); return FALSE; } return TRUE; } /*************************************************************************** * Function : StoreAddressFields * * Purpose : This function stores all the address handles associated * with a client in a null-terminated array. 'hAddresses' * contains a handle to the array. * * Returns : TRUE - address handles stored * FALSE - error ***************************************************************************/ static BOOL StoreAddressHandles( HWND hDlg) { short nCount, i; HANDLE FAR *lpAddressHandle; /* Set handle to address handle array to NULL */ hAddresses = NULL; /* Get the number of addresses in listbox */ nCount = (short)SendMessage( GetDlgItem( hDlg, IDC_ADDR_LISTBOX), LB_GETCOUNT, 0, 0L); if( ! nCount) return TRUE; /* Allocate space to store address handles. Leave last entry NULL to trigger end of addresses. */ if( ! (hAddresses = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)(sizeof( HANDLE) * (nCount + 1)))) ) { MessageBox( hDlg, "Out of memory", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } /* Lock handle */ if( ! (lpAddressHandle = (HANDLE FAR *)GlobalLock( hAddresses)) ) { MessageBox( hDlg, "Memory: GlobalLock", "Fatal Error", MB_ICONEXCLAMATION | MB_OK); return FALSE; } /* Get each address handle and store it */ for( i=0 ; i