// BDE - (C) Copyright 1994 by Borland International #include "query.h" #define FILEHANDLESNEEDED 40 static char szStandard[] = ""; static DBStructArray dbarray; // Global array of structures containing // database connections (hDb's) and names. static int iSelectedDbIndex; // Index to currently selected // database connection. void SetSelected(HWND hDlg); //================================================================= // Function: // 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: Exit code (wParam value of WM_QUIT message) // // Description: // This is the application entry point for the Query sample // application. It will set up the app, init the instance, // process all event driven messages, and clean up the // application 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); // Make this a single instance program if (hPrevInstance) { MessageBox(GetFocus(), "This application is already running!", "Windows Driver", MB_OK | MB_ICONHAND); return FALSE; } // Start the application, and set the main dialog to not show until // everything is setup. hInst = hInstance; if (InitApp(SW_SHOW) == FALSE) { return FALSE; } // Process all event driven messages. while (GetMessage(&msg, NULL, NULL, NULL)) { if ((hMainWnd == NULL) || (!IsDialogMessage(hMainWnd, &msg))) { TranslateMessage(&msg); DispatchMessage(&msg); } } // Unregister CTL3D. Ctl3dUnregister(hInstance); return msg.wParam; } //==================================================================== // Function: // InitApp(nCmdShow); // // Input: nCmdShow - Show the main window // // 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; UINT16 i; UINT16 uCount; // Path returned by the GetPrivateProfileString() function CHAR szRelativeTblDirectory[DBIMAXPATHLEN+1]; CHAR szMessage[(DBIMAXMSGLEN * 2)]; // Allocate enough space to // contain message // 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. Please set" " FILES=40 in your CONFIG.SYS.", "System Error", MB_OK | MB_ICONHAND); return FALSE; } // Get the directory which contains the tables. GetPrivateProfileString("QUERY", "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. GetPrivateProfileString("QUERY", "PrivateDir", ".", (LPSTR)szRelativeTblDirectory, sizeof(szRelativeTblDirectory), "bde.ini"); // Create a fully qualified pathname for the table directory. if (MakeFullPath(szPrivDirectory, szRelativeTblDirectory)) { sprintf(szMessage, "Private Directory does not exist: %s." "\r\nPlease check BDE.INI in your Windows directory.", szPrivDirectory); MessageBox(NULL, szMessage, "System Error", MB_OK | MB_ICONHAND); return FALSE; } // Initialize Database Engine. if (QueryDbiInit() != DBIERR_NONE) { MessageBox(NULL, "Application will terminate", "Error", MB_OK); return FALSE; } // Explicitly initialize global array. for (i = 0; i < MAX_DATABASE_HANDLES; i++) { dbarray[i].hdb = 0; dbarray[i].szDatabaseName[0] = '\0'; } // 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, IDC_QUERY_EDIT), EditSubClassProc); _wpOrigWndProc1 = SubClassWindow(GetDlgItem(hMainWnd, IDC_RESULT_EDIT), EditSubClassProc); ShowWindow(hMainWnd, nCmdShow); return TRUE; } // =============================================================== // Function: // MainWndProc(hWnd, msg, wParam, lParam); // // Description: // This routine will process all messages for the primary // application window. Included in this are all menu // commands. // =============================================================== LRESULT CALLBACK MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static FARPROC lpfnConnectDlgProc; static DLGPROC lpfnAboutDlgProc; static DBIQryLang eQryLang; static CBPROGRESSDesc CbBuf; char * szQuery = NULL; static hDBICur hCur = 0; DBIResult rslt; LONG lTextLength; static char szOutputErrorString[(DBIMAXMSGLEN * 6) + 80]; static char szSelectedDatabase[80]; static HFONT hFont; DWORD lMinMax; // Contains both offset of first and // last selected characters WORD iStart; // Offset of first selected character WORD iEnd; // Offset of last selected character HWND hwnd; HBRUSH hBrush; switch (msg) { case WM_CREATE: eQryLang = qrylangSQL; // Set up default database. dbarray[0].hdb = QueryGetStandardConnection(); iSelectedDbIndex = 0; strcpy(dbarray[iSelectedDbIndex].szDatabaseName, szStandard); if (dbarray[iSelectedDbIndex].hdb == 0) { MessageBox(NULL, "Unable to create STANDARD standard " "database.", "Application Error", MB_ICONHAND); } PostMessage(hWnd, WM_SETUP, 0, 0); return FALSE; case WM_SETUP: hwnd = GetWindow(hWnd, GW_CHILD); while (hwnd != NULL) { Ctl3dSubclassCtl(hwnd); hwnd = GetWindow(hwnd, GW_HWNDNEXT); } if (! SendDlgItemMessage(hWnd, IDC_RADIO_QBE, BM_GETCHECK, 0, 0)) { SendDlgItemMessage(hWnd, IDC_RADIO_SQL, BM_SETCHECK, 1, 0); } // Set the font of the edit controls to be a fixed pitch font. hFont = (HFONT) GetStockObject(ANSI_FIXED_FONT); SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_SETFONT, (WPARAM) hFont, FALSE); SendDlgItemMessage(hWnd, IDC_RESULT_EDIT, WM_SETFONT, (WPARAM) hFont, FALSE); 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: // Need to set the focus to the first element of the dialog box. SetFocus(GetDlgItem(hWnd, IDC_QUERY_EDIT)); // Set static control displaying currently selected database. if (dbarray[iSelectedDbIndex].hdb == NULL) { sprintf(szSelectedDatabase, "No connection established"); } else { sprintf(szSelectedDatabase, "Current connection: %s", dbarray[iSelectedDbIndex].szDatabaseName); } SendDlgItemMessage(hWnd, IDS_CURRENT_CONNECTION, WM_SETTEXT, 0, (LPARAM) szSelectedDatabase); return FALSE; case WM_CLOSE: // Done to get rid of the "Parameter Not used" warning. // Done in this way in order to work with both BC++ and VC++. lParam = lParam; DestroyWindow(hWnd); return FALSE; case WM_DESTROY: CleanUpAnswer(&hCur); QueryDbiExit(); PostQuitMessage(0); return FALSE; case WM_COMMAND: switch (wParam) { case IDC_EXIT: DestroyWindow(hWnd); return TRUE; case IDC_RUN: // Allow query to be run only if we have a // valid database handle. if (dbarray[0].hdb == 0) { MessageBox(NULL, "No database connection established", "Query SQL/QBE Example", MB_OK); } else { Cls(); DisplayProgress(""); // Get the length of the query from the Query edit // control. lTextLength = SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_GETTEXTLENGTH, 0, 0); // Allocate space to contain the query. if ((szQuery = (char*) malloc((int) lTextLength + 1)) == NULL) { MessageBox(NULL, "Out of Memory!", "Fatal Error", MB_ICONHAND); return TRUE; } HourGlassCursor(TRUE); // Setup the callback. RegisterCallBack(hCur, cbGENPROGRESS, (UINT32)"Query Data", sizeof(CBPROGRESSDesc), (pVOID)&CbBuf, GenProgCallBack); // Get the text of the query from the Query edit // control. SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_GETTEXT, (int) lTextLength + 1, (LPARAM) szQuery); // Close the cursor if it is open. CleanUpAnswer(&hCur); // Execute the query. rslt = QueryQExec(dbarray[iSelectedDbIndex].hdb, eQryLang, szQuery, szOutputErrorString, &hCur); // Remove Callback function. RegisterCallBack(hCur, cbGENPROGRESS, (UINT32)"Query Data", sizeof(CBPROGRESSDesc), (pVOID)&CbBuf, NULL); if (szQuery) { free(szQuery); } // Check if query failed. if (rslt != DBIERR_NONE) { Cls(); Screen(szOutputErrorString); HourGlassCursor(FALSE); return TRUE; } // Terminate if no cursor was returned. if (hCur == 0) { Cls(); Screen("No information returned from Query."); HourGlassCursor(FALSE); return TRUE; } Cls(); DisplayTable(hCur, 0); } HourGlassCursor(FALSE); return TRUE; case IDC_LOADQUERY: LoadQuery(eQryLang); return TRUE; case IDC_SAVEQUERY: SaveQuery(eQryLang); return TRUE; case IDC_SAVERESULT: if (!hCur || !dbarray[0].hdb) { MessageBox(NULL, "No result set to save.", "Error", MB_ICONHAND); } else { if (!SaveResultSet (hCur, dbarray[0].hdb)) { MessageBox(NULL, "Error saving result set", "Error", MB_ICONHAND); } } return TRUE; case IDC_CONNECT: lpfnConnectDlgProc = MakeProcInstance ((FARPROC)ConnectDlgProc, hInst); DialogBox(hInst, szConnectDialogName, hWnd, (DLGPROC)lpfnConnectDlgProc); FreeProcInstance(lpfnConnectDlgProc); return TRUE; case IDC_HELP: MessageBox(NULL, szMainHelpText, "Query SQL/QBE Example", MB_OK); return TRUE; case IDC_ABOUT: lpfnAboutDlgProc = (DLGPROC)MakeProcInstance((FARPROC) AboutDlg, hInst); DialogBox(hInst, "AboutDlg", hWnd, lpfnAboutDlgProc); FreeProcInstance((FARPROC)lpfnAboutDlgProc); return TRUE; case IDC_RADIO_QBE: eQryLang = qrylangQBE; return TRUE; case IDC_RADIO_SQL: eQryLang = qrylangSQL; return TRUE; case IDM_COPY: // Determine which characters are selected. lMinMax = SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, EM_GETSEL, 0, 0L); // Get the first and last selected character. iStart = LOWORD(lMinMax); iEnd = HIWORD(lMinMax); // If nothing is selected, select all. if (iStart == iEnd) { SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, EM_SETSEL, 0, 0xfffeL); } // Copy the selected text in the QUERY edit box. SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_COPY, 0, 0L); return TRUE; case IDM_PASTE: SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_PASTE, 0, 0L); return TRUE; case IDM_CLEAR: SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_SETTEXT, 0, (LPARAM)(LPCSTR)""); return TRUE; case IDM_CLEARRESULT: SendDlgItemMessage(hWnd, IDC_RESULT_EDIT, WM_SETTEXT, 0, (LPARAM)(LPCSTR)""); return TRUE; case IDM_DELETE: PostMessage(hWnd, WM_COMMAND, IDM_CLEAR, 0l); PostMessage(hWnd, WM_COMMAND, IDM_CLEARRESULT, 0l); return TRUE; case IDM_CUT: SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, WM_COPY, 0, 0L); SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, EM_REPLACESEL, 0, (LPARAM)(LPCSTR)""); return TRUE; case IDM_UNDO: SendDlgItemMessage(hWnd, IDC_QUERY_EDIT, EM_UNDO, 0, 0L); return TRUE; } } return DefWindowProc(hWnd, msg, wParam, lParam); } //====================================================================== // Function: // EditSubClassProc(hWnd, msg, wParam, lParam) // // Input: hWnd - Handle of the window // msg - Message // wParam - WPARAM // lParam - LPARAM // // Return: It returns the result of the procedure. It can return the // result of the original edit control if the WM_CHAR is not a // tab character. // // Description: // This routine will process all I/O for the Comments edit // control. It does this by first checking if the tab key was // hit inside of the comment edit control. If it was it moves // control to the next control item and then does NOT let the // original edit control process the message. However, if the // WM_CHAR is not a tab then it lets the original edit control // process the message. //====================================================================== long FAR _pascal _export EditSubClassProc (HWND hWnd, WORD msg, WORD wParam, LONG lParam) { LRESULT lResult = 0; BOOL fCallOrigWndProc = TRUE; INT16 iId; UINT32 lType; WNDPROC WndProc; iId = GetDlgCtrlID(hWnd); if (iId == IDC_QUERY_EDIT) { WndProc = (WNDPROC)_wpOrigWndProc; } else { WndProc = (WNDPROC)_wpOrigWndProc1; } switch (msg) { case WM_GETDLGCODE: return DLGC_WANTMESSAGE; case WM_CHAR: if (wParam == '\t') { if (GetKeyState(VK_SHIFT)<0) { if (iId == IDC_QUERY_EDIT) { iId = IDC_RESULT_EDIT; } else { iId = IDC_RUN; } } else { if (iId == IDC_QUERY_EDIT) { lType = SendDlgItemMessage(hMainWnd, IDC_RADIO_SQL, BM_GETCHECK, 0, 0L); if (lType == 1) { iId = IDC_RADIO_SQL; } else { iId = IDC_RADIO_QBE; } } else { iId = IDC_QUERY_EDIT; } } SetFocus(GetDlgItem(hMainWnd, iId)); fCallOrigWndProc = FALSE; lResult = TRUE; } if (wParam == VK_ESCAPE) { MessageBeep(1); } break; } if (fCallOrigWndProc) { lResult = CallWindowProc(WndProc, hWnd, msg, wParam, lParam); } return lResult; } //====================================================================== // Function: // AboutDlg(hWnd, msg, wParam, lParam) // // Input: hWnd, msg, wParam, lParam // // Return: TRUE - Dialog Created. // FALSE - Dialog Failed to create. // // Description: // This routine will process all I/O for the ABOUT dialog. //====================================================================== BOOL FAR _pascal _export AboutDlg (HWND hWnd, WORD msg, WORD wParam, LONG lParam) { BOOL ret = FALSE; // Done to clear the unused warning. lParam = lParam; switch (msg) { case WM_COMMAND: switch (wParam) { case IDOK: case IDCANCEL: ret = TRUE; EndDialog(hWnd, ret); break; } break; } return ret; } //====================================================================== // Function: // ConnectDlgProc(hDlg, message, wParam, lParam) // // Input: hDlg, message, wParam, lParam // // Return: TRUE if dialog procedure processes a message // FALSE otherwise. // // Description: // Dialog box procedure for the dialog box that establishes // and removes connections to databases based on ALIASES // defined in IDAPI.CFG. //====================================================================== BOOL CALLBACK _export ConnectDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { int i; char szAliasName[81]; WORD ListIndex; int nIndex; char szConnectionName[DBIMAXPATHLEN + 1]; static char szDirectory[DBIMAXPATHLEN+1]; char szTemp[DBIMAXPATHLEN + 1]; switch (message) { case WM_INITDIALOG: QueryResetConnectDialog(hDlg, dbarray, iSelectedDbIndex); if (dbarray[0].hdb != 0) { GetWorkingDirectory(dbarray[0].hdb, szDirectory); } ShowWindow(hDlg, SW_HIDE); PostMessage(hDlg, WM_MYSETUP, 0, 0); return TRUE; case WM_MYSETUP: SendDlgItemMessage(hDlg, IDS_SELECTED_CONNECTION, WM_GETTEXT, DBIMAXPATHLEN, (LPARAM)szConnectionName); // Check if this is the standard database. if (!strcmp(szConnectionName, szStandard)) { // Show the Directory controls. ShowWindow(GetDlgItem(hDlg, IDC_DIRECTORY), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DIRECTORY), SW_SHOW); } else { // Hide the Directory controls. ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DIRECTORY), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_DIRECTORY), SW_HIDE); } // Set the directory. SendDlgItemMessage(hDlg, IDC_EDIT_DIRECTORY, WM_SETTEXT, 0, (LPARAM)(LPCSTR)szDirectory); ShowWindow(hDlg, SW_SHOW); return TRUE; case WM_CLOSE: EndDialog(hDlg, 0); return TRUE; case WM_COMMAND: switch (wParam) { case IDC_LB_CONNECTIONS: if (HIWORD(lParam) == LBN_SELCHANGE) { SetSelected(hDlg); } return TRUE; case IDC_BTN_CONNECT: // First check to see if any alias is selected, // if not, beep. ListIndex = (WORD) SendDlgItemMessage(hDlg, IDC_LB_ALIASES, LB_GETCURSEL, 0, 0); if (ListIndex == (WORD) LB_ERR) { MessageBeep(MB_ICONEXCLAMATION); return TRUE; } // If an alias is selected, run through // the array of handles/descriptions to see if we // have any free one's left. for (i = 1; i < MAX_DATABASE_HANDLES; i++) { if (dbarray[i].hdb == 0) { break; } } // If we don't, provide an error message. if (i == MAX_DATABASE_HANDLES) { MessageBox(NULL, "Maximum database handles limit " "reached.", "Error", MB_OK); } else { // If we do have room left in our array, // try to establish connection. If successful, // add database name to connections list. HourGlassCursor(TRUE); if ((dbarray[i].hdb = QueryConnectToDatabase(hDlg)) != 0) { ListIndex = (WORD) SendDlgItemMessage(hDlg, IDC_LB_ALIASES, LB_GETCURSEL, 0, 0); SendDlgItemMessage(hDlg, IDC_LB_ALIASES, LB_GETTEXT, (WPARAM)ListIndex, (LPARAM)szAliasName); strcpy(dbarray[i].szDatabaseName, szAliasName); SendDlgItemMessage(hDlg, IDC_LB_CONNECTIONS, LB_ADDSTRING, 0, (LPARAM)szAliasName); SendDlgItemMessage(hDlg, IDC_LB_CONNECTIONS, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)szAliasName); SetSelected(hDlg); } HourGlassCursor(FALSE); } return TRUE; case IDC_BTN_REMOVE: // Disconnect from the selected connection. nIndex = (WORD) SendDlgItemMessage(hDlg, IDC_LB_CONNECTIONS, LB_GETCURSEL, 0, 0); RemoveConnection(hDlg, dbarray, nIndex); return TRUE; case IDC_BTN_HELP: // Display information on this application. MessageBox(NULL, szConnectHelpText, "Help", MB_OK); return TRUE; case IDOK: // find currently selected database based // on the string in the static control // displaying this information. // Get currently selected database. SendDlgItemMessage(hDlg, IDS_SELECTED_CONNECTION, WM_GETTEXT, 80, (LPARAM) szConnectionName); // Compare currently selected database // to the strings in the array and // set iSelectedDbIndex based on that. // iSelectedDbIndex is in turn used // as the database handle used to // execute queries. for (i = 0; i < MAX_DATABASE_HANDLES, dbarray[i].hdb != 0; i++) { if (strcmpi(dbarray[i].szDatabaseName, szConnectionName) == 0) { iSelectedDbIndex = i; break; } } if (i == MAX_DATABASE_HANDLES) { iSelectedDbIndex = 0; } // Check if this is the standard database. if (!strcmp(szConnectionName, szStandard)) { // Get currently selected directory. SendDlgItemMessage(hDlg, IDC_EDIT_DIRECTORY, WM_GETTEXT, DBIMAXPATHLEN, (LPARAM)szTemp); // Only set if changed. if (strcmp(szTemp, szDirectory)) { // Check if the directory exists. if (!access(szTemp, 00)) { if (SetWorkingDirectory( dbarray[iSelectedDbIndex].hdb, szTemp)) { SendDlgItemMessage(hDlg, IDC_STATIC_STATUS, WM_SETTEXT, 0, (LPARAM) "Invalid Directory"); return FALSE; } } else { // Display message if directory does not exist. SendDlgItemMessage(hDlg, IDC_STATIC_STATUS, WM_SETTEXT, 0, (LPARAM) "Invalid Directory"); return FALSE; } } } else { } EndDialog (hDlg, 0); return TRUE; case IDCANCEL: EndDialog (hDlg, 0); return TRUE; } } return FALSE; } //====================================================================== // Function: // SetSelected (hDlg) // // Input: hDlg - Handle of the Dialog // // Return: None // // Description: // This routine sets which connection the application uses // for processing the query. //====================================================================== void SetSelected (HWND hDlg) { WORD ListIndex; char szConnectionName[DBIMAXPATHLEN + 1]; // Determine which connection is selected. ListIndex = (WORD)SendDlgItemMessage(hDlg, IDC_LB_CONNECTIONS, LB_GETCURSEL, 0, 0); // Get the selected connection. SendDlgItemMessage(hDlg, IDC_LB_CONNECTIONS, LB_GETTEXT, (WPARAM)ListIndex, (LPARAM)szConnectionName); // Set the Static control with the selected connection. SendDlgItemMessage(hDlg, IDS_SELECTED_CONNECTION, WM_SETTEXT, 0, (LPARAM) szConnectionName); // Check if this is the standard database. if (!strcmp(szConnectionName, szStandard)) { // Show the Directory controls. ShowWindow(GetDlgItem(hDlg, IDC_DIRECTORY), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DIRECTORY), SW_SHOW); } else { // Hide the directory controls. ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DIRECTORY), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_DIRECTORY), SW_HIDE); } } //====================================================================== // Function: // HourGlassCursor(turnOn) // // Input: turnOn - Turn on or off the Hourglass cursor // // Return: TRUE // // Description: // Turns the hourglass cursor on or off according to value // specified in turnOn. //====================================================================== BOOL CALLBACK HourGlassCursor (BOOL turnOn) { if (turnOn) { if (SetCursor(LoadCursor(NULL, IDC_WAIT))) { ShowCursor(TRUE); } } else { if (SetCursor(LoadCursor(NULL, IDC_ARROW))) { ShowCursor(TRUE); } } return TRUE; } //====================================================================== // Function: // LoadQuery(QryType) // // Input: Query Type (DBIQryLang). // // Return: 1 if succesful, // 0 if error // // Description: // Using a Windows 3.1 Common Dialog, opens a file open // dialog box to read a .QBE or .SQL query file into the // query edit window. //====================================================================== UINT16 LoadQuery (DBIQryLang QryType) { // File types for file open dialog box. char* SQLFilter = "SQL Script(*.SQL)\0*.SQL\0" "QBE Script(*.QBE)\0*.QBE\0"; char* QBEFilter = "QBE Script(*.QBE)\0*.QBE\0" "SQL Script(*.SQL)\0*.SQL\0"; HFILE hFile; // Handle to the returned file static char pBuf[256]; // filename LONG flength; // length of file char ch[1]; // input character OPENFILENAME ofn; // structure used by File Open // common dialog char* szInputBuffer; // pointer to input buffer char* start; // pointer used as a marker // Init the structure used by File Open dialog. ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hMainWnd; ofn.hInstance = hInst; if (QryType == qrylangQBE) { ofn.lpstrFilter = QBEFilter; } else { ofn.lpstrFilter = SQLFilter; } ofn.lpstrCustomFilter = NULL; ofn.nFilterIndex = 1L; ofn.lpstrFile = pBuf; ofn.nMaxFile = 256; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.lpstrDefExt = NULL; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; // Use the FileOpen common dialog box to get the file name. if (GetOpenFileName(&ofn)) { // Open the selected file hFile = _lopen(ofn.lpstrFile, READ); if (hFile == HFILE_ERROR) { MessageBox(NULL, "Could Not Open File", "File Open", MB_ICONHAND); return 0; } // Compute length of string needed for file text. flength = 0; while (_lread(hFile, ch, 1) != 0) { if (ch[0] == '\n') { flength += 2; // Need two for newline so // we can format for edit control. } else { flength++; // Otherwise length equals one per char. } } // Add one for null. flength += 1; // Return to beginning of file. _llseek(hFile, 0, 0); // Allocate memory, pointer "start" will remember our place. start = szInputBuffer = (char *) malloc((int) flength + 1); memset(szInputBuffer, 0, (int) flength + 1); if (!szInputBuffer) { MessageBox(NULL, "Unable to allocate memory", "Error", MB_ICONHAND); return FALSE; } while ( _lread(hFile, ch, 1) != 0) { if (ch[0] == '\n') { *szInputBuffer = '\r'; szInputBuffer++; *szInputBuffer = '\n'; szInputBuffer++; } else // Otherwise just read in characters. { *szInputBuffer = ch[0]; szInputBuffer++; } } // Reset to beginning of string. szInputBuffer = start; // Put the string into the edit control. SendDlgItemMessage(hMainWnd, IDC_QUERY_EDIT, WM_SETTEXT, 0, (LPARAM) szInputBuffer); // Cleanup. free(szInputBuffer); _lclose(hFile); return TRUE; } return FALSE; } //====================================================================== // Function: // SaveQuery(QryType) // // Input: Query Type (DBIQryLang). // // Return: 1 if succesful, // 0 if error // // Description: // Using a Windows 3.1 Common Dialog, opens a file save // dialog box to save the contents of the query edit // window to a .QBE or .SQL query file //====================================================================== UINT16 SaveQuery (DBIQryLang QryType) { // File types for File Save dialog box. char* SQLFilter = "SQL Script(*.SQL)\0*.SQL\0" "QBE Script(*.QBE)\0*.QBE\0"; char* QBEFilter = "QBE Script(*.QBE)\0*.QBE\0" "SQL Script(*.SQL)\0*.SQL\0"; static char pBuf[256]; // filename HFILE hFile; // Handle to the file OFSTRUCT ofStruct; // OpenFile structure OPENFILENAME ofn; // structure used by File Open common dialog char* szQuery; // pointer to text buffer char* szSeek; // equals szQuery at first LONG lTextLength; // length of text // Init the structure used by File Open dialog. ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hMainWnd; ofn.hInstance = hInst; if (QryType == qrylangQBE) { ofn.lpstrFilter = QBEFilter; } else { ofn.lpstrFilter = SQLFilter; } ofn.lpstrCustomFilter = NULL; ofn.nFilterIndex = 1L; ofn.lpstrFile = pBuf; ofn.nMaxFile = 256; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.lpstrDefExt = NULL; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT; if (GetSaveFileName(&ofn)) { // Determine the length of the text. lTextLength = SendDlgItemMessage(hMainWnd, IDC_QUERY_EDIT, WM_GETTEXTLENGTH, 0, 0); // Allocate memory to contain the query. if ((szQuery = szSeek = (char*) malloc((int)lTextLength + 1)) == NULL) { MessageBox(NULL, "Out of Memory!", "Fatal Error", MB_ICONHAND); return FALSE; } // Get the query from the edit control. SendDlgItemMessage(hMainWnd, IDC_QUERY_EDIT, WM_GETTEXT, (int)lTextLength + 1, (LPARAM)szQuery); // Open the selected file. hFile = OpenFile(ofn.lpstrFile, &ofStruct, OF_CREATE); // Check for errors. if (hFile == HFILE_ERROR) { MessageBox(NULL, "Could Not Open File", "File Open", MB_ICONHAND); return FALSE; } // Format the query and write to file. while (*szQuery) { if (*szQuery == '\r') { szQuery++; // Ignore extra newline. } else { _lwrite(hFile, (void huge *)(szQuery++), 1); } } // Close the file. _lclose(hFile); // Free memory. free(szSeek); } return TRUE; } //====================================================================== // Function: // SaveResultSet(hCur, hDb) // // Input: hCur - Handle to the cursor of the in-memory table representing // the result set of the last query. // hDb - Handle to a STANDARD database. // // Return: 1 on success // 0 on failure // // Description: // Using a Windows 3.1 Common Dialog, opens a file save // dialog box to save the contents of the query edit // window to a .QBE or .SQL query file //====================================================================== UINT16 SaveResultSet (hDBICur hCur, hDBIDb hDb) { static char pBuf[256]; // filename char pString[300]; // Message String OPENFILENAME ofn; // structure used by File Open common dialog char* ScriptFilter = "Paradox Database(*.DB)|*.DB|"; CHAR chWildChar = '|'; // This is the wildcard separator UINT16 uCtr = 0; while (ScriptFilter[uCtr]) { if (ScriptFilter[uCtr]==chWildChar) { ScriptFilter[uCtr]=0; } uCtr++; } // Init the structure used by File Open dialog. ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hMainWnd; ofn.hInstance = hInst; ofn.lpstrFilter = ScriptFilter; ofn.lpstrCustomFilter = NULL; ofn.nFilterIndex = 1L; ofn.lpstrFile = pBuf; ofn.nMaxFile = 256; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.lpstrDefExt = "DB"; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT; if (GetSaveFileName(&ofn)) { if (!QuerySaveResultSet(hCur, hDb, pBuf)) { return FALSE; } else { wsprintf(pString, "%s was successfully created.", pBuf); MessageBox(hMainWnd, pString, "Query SQL/QBE Example", MB_OK); } } return TRUE; } //====================================================================== // Function: // RemoveConnection(hDlg, array, nIndex) // // Input: hDlg - Handle to the connection dialog box. // array - A DBStructArray, i.e., an array of structures // containing valid database names and handles // nIndex - Index into the connection dialog box of // the database connection to be removed. // // Return: 1 on success // // Description: // Removes a database connection from the connection listbox // inside the connection dialog box. Also removes the // corrseponding structure from the array of structures passed // via the array parameter and resets the currently selected // selection to the STANDARD database. //====================================================================== UINT16 RemoveConnection (HWND hDlg, DBStructArray array, int nIndex) { int i; int j; switch(nIndex) { case 0: MessageBeep(MB_ICONEXCLAMATION); MessageBox(NULL, "Cannot delete STANDARD database", "Error", MB_ICONEXCLAMATION); break; case LB_ERR: MessageBeep(MB_ICONEXCLAMATION); break; default: // Reset the static control showing currently selected dialog // box back to the default. SendDlgItemMessage(hDlg, IDS_SELECTED_CONNECTION, WM_SETTEXT, 0, (LPARAM) szStandard); // Remove item from list box. SendDlgItemMessage(hDlg, IDC_LB_CONNECTIONS, LB_DELETESTRING, nIndex, 0); // Close database handle. QueryDbiCloseDatabase(&array[nIndex].hdb); // Pack array. for (i = nIndex, j = nIndex + 1; j < MAX_DATABASE_HANDLES; i++, j++) { array[i].hdb = array[j].hdb; strcpy(array[i].szDatabaseName, array[j].szDatabaseName); } // Last member is now blank. array[j].hdb = 0; strcpy(array[j].szDatabaseName, ""); } return TRUE; } //====================================================================== // Function: // GenProgCallBack(ecbType, iClientData, pCbInfo) // // Input: ecbType - Callback type (CBType) // iClientData - Pointer to client information that is passed into // the callback function (UINT32) // pCbInfo - The callback structure that holds the information // about the current state of affairs with // IDAPI(pVOID) // // Return: The action that should be taken (CBRType) // // Description: // This function is called when IDAPI is running an internal // process and the application setup the callback. The callback // is sent the current CallBack type (ecbType) so that it can // react appropriatly. It is sent the pointer to data that was // passed into the DbiRegisterCallBack function. This data can // be a Window handle, pointer to a structure etc. In this case // it is simply a string. It is also sent information about the // state of this callback in the structure that was passed into // the DbiRegisterCallBack() function. In our example the // callback is a progress callback - therefore, we passed a // progress structure into DbiRegisterCallBack(). We always // return cbrUSEDEF as we do not want to worry about the callback. // However, if this was another callback return type you may want // to return a different callback return type. //====================================================================== CBRType DBIFN GenProgCallBack (CBType ecbType, UINT32 iClientData, pVOID pCbInfo) { CBPROGRESSDesc *eCBPROGRESSDesc; CHAR szMessage[DBIMAXMSGLEN + 1 + 30]; // Reserve space for max // Message plus client // data memset(szMessage, 0, DBIMAXMSGLEN + 1); // Set to stop a Unused variable warning. iClientData=iClientData; switch (ecbType) { // In case this is a General Progress callback display the progress // information. case cbGENPROGRESS: // First cast the pVOID structure as a General Progress structure. eCBPROGRESSDesc = (CBPROGRESSDesc far *)pCbInfo; // Next if the percent done is -1 then the only relevent data is in // the message string (szMsg). if (eCBPROGRESSDesc->iPercentDone < 0) { wsprintf(szMessage, "%s", eCBPROGRESSDesc->szMsg); DisplayProgress(szMessage); } else { // Otherwise you can use the percent done. Here we simply // display the percent complete. But you can use this number // to display a moving bar to graphically display the amount // complete. wsprintf(szMessage, "%s:%i", eCBPROGRESSDesc->szMsg, eCBPROGRESSDesc->iPercentDone); DisplayProgress(szMessage); } break; default: DisplayProgress(" ### In the Callback function"); } return cbrUSEDEF; } //===================================================================== // Function: // MakeFullPath (pszDirectory, pszRelativeDirectory) // // Input: pszDirectory - String to contain the path to the tables // directory // pszRelativeDirectory - String which contains the relative offset // from the current directory // // Return: int - If the directory exists // // Description: // This function is used to get the fully qualified path to // the directory which will contain the tables. This function // will only work when pszRelativeDirectory contains either "." // an absolute path, or <..\\..\\>TABLES. //===================================================================== int MakeFullPath (pCHAR pszDirectory, pCHAR pszRelativeDirectory) { int iExists; // Does the directory exist? int iLen; // Length of the path int iLoop; // Loop counter int iDepth = 0; // How many ..\\ in the directory // Assume absolute path if second character is a ':'. if (pszRelativeDirectory[1] == ':') { strcpy(pszDirectory, pszRelativeDirectory); } else if (!strcmp(pszRelativeDirectory, ".")) { // Get the current working directory. getcwd(pszDirectory, DBIMAXPATHLEN); } else { // Get the current working directory. getcwd(pszDirectory, DBIMAXPATHLEN); iLen = strlen(pszDirectory); // Remove relative parts of the path. iDepth = 0; while (!strncmp(&pszRelativeDirectory[iDepth * 3], "..\\", 3)) { for (iLoop = iLen; iLoop > -1; iLoop = iLoop - 1) { if (pszDirectory[iLoop] == '\\') { break; } } iLen = iLoop - 1; iDepth++; } // Copy the 'TABLES' directory to form the full path to the tables. // Need to move szDirectory past the '\\' and szTblDirectory // past the '..\\'. strcpy(&pszDirectory[iLoop+1], &pszRelativeDirectory[(3 * iDepth)]); } // Check if the directory exists iExists = access(pszDirectory, 00); return iExists; }