home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------------
- Child.C --- Cursors child window procedure
-
- Description:
- This sample is spread across four files, each named for the role
- the contained functions play. Each file header contains a brief
- description of its purpose and the routines it contains.
-
- CHILD.C contains those routines which maintain a child window.
- These include most interfaces with ODBC including all data
- retrieval and display. These functions are:
-
- AllocChild - Allocate and prepare child window memory
- AllocClipRgn - Allocate clip region for painting
- Cancel - Cancel SQL request
- CancelSQL - Cancel asynchronous SQL request
- ChildProc - Process child window messages
- CvtSqlToCType - Return the default ODBC C type for a SQL type
- DeleteRow - Build and issue a positioned delete
- DoChildMenu - Process a menu request
- DoSQL - Issue SQL statement and prepare all required
- variables necessary for displaying the data
- Fetch - Retrieve one row set
- FreeStmt - Issue ODBC SQLFreeStmt (and adjust child memory)
- GetCurrentValue - Retrieve (in character format) column value
- from current row (used by DIALOGS.C)
- GetData - Issue a SQLGetData request
- GetTableName - Extract table name from SQL
- IsUpdateable - Check whether a column can be updated
- OnDataRow - Determine if point is over displayed row of data
- PaintChild - Paint child window
- ParamValid - Validate the max column width of lpChild
- SetCurrentValue - Set a column value in the current row
- (used by DIALOGS.C)
- SetPos - Set current position in row set
- SetScroll - Set scroll bar states and ranges
- SizeScroll - Size and position scroll bars
- UpdateRow - Build and issue a positioned update request
-
- This code is furnished on an as-is basis as part of the ODBC SDK and is
- intended for example purposes only.
-
- --------------------------------------------------------------------------*/
-
- /* Includes --------------------------------------------------------------*/
- #include "headers.h"
-
- #pragma warning(disable:4001)
- #include "resource.h"
- #include "crsrdemo.h"
-
-
- // Constants ---------------------------------------------------------------
- #define fDISABLED (MF_BYCOMMAND | MF_DISABLED | MF_GRAYED)
- #define fENABLED (MF_BYCOMMAND | MF_ENABLED)
- #define NULLIFEMPTY(x) (*x?x:NULL)
-
- const char szDELETE[] = "DELETE FROM ";
- const char szFROM[] = "FROM";
- const char szUPDATE[] = "UPDATE ";
- const char szWHERE[] = " WHERE CURRENT OF ";
- const char szNoDataTitle[] = "No data to display";
- const char szNoData[] = "The query didn't return any data";
- const char szSET[] = " SET ";
- const char szDataAffected[] = "%ld rows were affected";
- const char szRowAffected[] = "%ld row was affected";
-
- const int cMAXCOLS = 15;
-
- #define Async(x) lpChild->fCanceled = FALSE; \
- while ((rc = (x)) == SQL_STILL_EXECUTING) \
- CancelSQL(lpChild);
-
- #define STMTError(x) ODBCError(lpChild->hwnd, SQL_HANDLE_STMT, lpChild->hstmt, (x))
-
-
- // Prototypes --------------------------------------------------------------
- LPCHILD INTFUNC AllocChild(HWND);
- void INTFUNC AllocClipRgn(LPCHILD);
- void INTFUNC Cancel(LPCHILD);
- void INTFUNC CancelSQL(LPCHILD);
- SWORD INTFUNC CvtSqlToCType(SWORD);
- void INTFUNC DeleteRow(LPCHILD);
- BOOL INTFUNC DoChildMenu(LPCHILD, WPARAM, LPARAM);
- void INTFUNC DoSQL(LPCHILD);
- void INTFUNC Fetch(LPCHILD);
- void INTFUNC FreeStmt(UWORD, LPCHILD);
- void INTFUNC GetData(LPCHILD);
- void INTFUNC GetTableName(LPSTR, LPCSTR);
- int INTFUNC OnDataRow(LPCHILD, LPARAM);
- void INTFUNC PaintChild(LPCHILD, HDC, BOOL, BOOL, BOOL);
- BOOL INTFUNC ParamValid(LPCHILD);
- void INTFUNC SetPos(LPCHILD, UWORD);
- void INTFUNC SetScroll(LPCHILD);
- void INTFUNC SizeScroll(LPCHILD);
- void INTFUNC UpdateRow(LPCHILD);
- #ifdef THREAD
- void INTFUNC DeleteRowThread(LPCHILD);
- void INTFUNC DoSQLThread(LPCHILD);
- void INTFUNC FetchThread(LPCHILD);
- void INTFUNC GetDataThread(LPCHILD);
- void INTFUNC UpdateRowThread(LPCHILD);
- #endif
-
- /* AllocChild --------------------------------------------------------------
- Description: Allocate and initialize child variables
- --------------------------------------------------------------------------*/
- LPCHILD INTFUNC AllocChild(HWND hwnd)
- {
- SQLHSTMT hstmt;
- LPCHILD lpChild;
- char sz[cbSTRLEN];
-
- // Allocate ODBC SQLHSTMT and set cursor name
- if (DBCError(hwnd, SQLAllocHandle(SQL_HANDLE_STMT,g_hdbc, &hstmt)))
- return NULL;
-
- #ifdef THREAD
- wsprintf(sz, szTITLEFMT, (LPSTR)g_szDSN, g_cCursor, GetCurrentThreadId());
- #else
- wsprintf(sz, szTITLEFMT, (LPSTR)g_szDSN, g_cCursor);
- #endif
-
- SetWindowText(hwnd, sz);
-
- wsprintf(sz, szCURSORNAME, g_cCursor);
- if (ODBCError(hwnd, SQL_HANDLE_STMT, hstmt,
- SQLSetCursorName(hstmt, (UCHAR FAR *)sz, SQL_NTS)))
- return NULL;
-
- // Allocate child window structure and initialize
- lpChild = (LPCHILD)AllocPtr(sizeof(CHILD));
-
- lpChild->hwnd = hwnd;
- lpChild->fInSetScroll = FALSE;
- lpChild->fIsMinimized = FALSE;
- lpChild->fHaveMouse = FALSE;
- lpChild->iMouseRow = -1;
- lpChild->fNoConcurrency = FALSE;
- lpChild->fNoCursorType = FALSE;
-
- lpChild->ccols = 0;
- lpChild->crowwin = 0;
- lpChild->ccolwin = 0;
- lpChild->fVScroll =
- lpChild->fHScroll = FALSE;
- lpChild->lpsz = AllocPtr(cbBUFSIZE);
-
- lpChild->hrgn = NULL;
-
- lpChild->hstmt = hstmt;
- lpChild->hstmtTmp = SQL_NULL_HSTMT;
-
- lpChild->fBindByRow = IDC_RADIO_BINDROW;
- lpChild->fConcurrency = SQL_CONCUR_VALUES;
- lpChild->crowKeyset = SQL_CURSOR_STATIC;
- lpChild->crowRowset = 10;
- lpChild->fAsync = FALSE;
- lpChild->irowPos = 0;
- lpChild->irow = 0;
- lpChild->cBind = 0;
- lpChild->fBindAll = TRUE;
- lpChild->ccolRetrieved = 0;
-
- lpChild->arow = 1;
- lpChild->rrow = 10;
- lpChild->ccol = 0;
- lpChild->lpnTabs = NULL;
- lpChild->lpcol = NULL;
- lpChild->lpfStatus = NULL;
- lpChild->fResultSetExists = FALSE;
- lpChild->fDataFetched = FALSE;
- lpChild->rglpv = NULL;
- lpChild->crowMaxBind = DEF_MAXBIND;
-
- lpChild->lpb = NULL;
- lpChild->sql = AllocPtr(cbMAXSQL);
- lpChild->cbrow = 0;
- lpChild->dwGuiFlags = GUIF_ALWAYSFETCH;
- #ifdef THREAD
- InitializeCriticalSection (&lpChild->ThreadCreation);
- #endif
-
- // Create scroll bars
- lpChild->hwndVScroll = CreateWindow(szSCROLLCLASS, NULL,
- WS_CHILD | SBS_VERT,
- 0, 0, 0, 0,
- hwnd, (HMENU)1, g_hinst, NULL);
-
- lpChild->hwndHScroll = CreateWindow(szSCROLLCLASS, NULL,
- WS_CHILD | SBS_HORZ,
- 0, 0, 0, 0,
- hwnd, (HMENU)2, g_hinst, NULL);
-
- // Load default SQL string
- LoadString(g_hinst, IDS_SQL, sz, cbSTRLEN);
- wsprintf(lpChild->sql, sz, g_szTable);
-
- return lpChild;
- }
-
-
- /* AllocClipRgn ------------------------------------------------------------
- Description: Allocate child window clip region
- --------------------------------------------------------------------------*/
- void INTFUNC AllocClipRgn(LPCHILD lpChild)
- {
- RECT rc;
-
- // Determine client window size less space for scroll bars
- GetClientRect(lpChild->hwnd, &rc);
-
- if (lpChild->hrgn) DeleteObject(lpChild->hrgn);
-
- if (lpChild->fVScroll)
- rc.right -= g_cxVScroll - 1;
- rc.bottom -= g_cyHScroll - 1;
-
- // Allocate clip region
- lpChild->hrgn = CreateRectRgn(rc.left,
- rc.top,
- rc.right,
- rc.bottom);
- return;
- }
-
-
- /* CancelSQL ---------------------------------------------------------------
- Description: Display message while an async request is executing and
- give the user a chance to cancel the request (if it has
- not already been canceled)
- --------------------------------------------------------------------------*/
- void INTFUNC CancelSQL(LPCHILD lpChild)
- {
- char sz[cbSTRLEN];
- int rc;
-
- // Display message
- LoadString(g_hinst, IDS_STILLEXEC, sz, sizeof(sz));
- rc = MessageBox(lpChild->hwnd,
- sz, g_szTITLE,
- MB_ICONINFORMATION |
- (lpChild->fCanceled
- ? MB_OK
- : MB_OKCANCEL | MB_DEFBUTTON1));
-
- // If the user requested, cancel the current request
- if (rc == IDCANCEL)
- lpChild->fCanceled = SUCCESS(SQLCancel(lpChild->hstmt));
-
- return;
- }
-
-
- /* ChildProc ---------------------------------------------------------------
- Description: Child window procedure
- --------------------------------------------------------------------------*/
- LRESULT EXPFUNC ChildProc(HWND hwnd,
- UINT msg,
- WPARAM wparam,
- LPARAM lparam)
- {
- LPCHILD lpChild;
-
- // Get access to child variables and set current window handle
- lpChild = (LPCHILD)GetWindowLong(hwnd, 0);
-
- switch (msg) {
-
- // Allocate child variables and save pointer
- case WM_CREATE:
- lpChild = AllocChild(hwnd);
-
- SetWindowLong(hwnd, 0, (LONG)lpChild);
-
- if (!lpChild)
- return -1;
- break;
-
- // Paint child window (active or inactive)
- case WM_PAINT: {
- PAINTSTRUCT ps;
- BOOL fActive;
-
- fActive = (hwnd ==
- FORWARD_WM_MDIGETACTIVE(g_hwndClient, SendMessage));
-
- BeginPaint(hwnd, &ps);
- PaintChild(lpChild, ps.hdc, TRUE, FALSE, fActive);
- EndPaint(hwnd, &ps);
- break;
- }
-
- // Trap mouse if over a rowset row
- case WM_LBUTTONDOWN:
- lpChild->iMouseRow = OnDataRow(lpChild, lparam);
- if (lpChild->iMouseRow >= 0) {
- lpChild->fHaveMouse = TRUE;
- SetCapture(hwnd);
- }
- break;
-
- // Make row current row (if mouse is still on the row)
- case WM_LBUTTONUP:
- if (!lpChild->fHaveMouse)
- break;
-
- ReleaseCapture();
- lpChild->fHaveMouse = FALSE;
-
- if (lpChild->fDataFetched &&
- lpChild->fConcurrency != SQL_CONCUR_READ_ONLY &&
- lpChild->crowKeyset != SQL_CURSOR_FORWARD_ONLY &&
- lpChild->iMouseRow == OnDataRow(lpChild, lparam)) {
- RECT rc;
- int y;
-
- GetClientRect(hwnd, &rc);
-
- y = (int)HIWORD(lparam) - rc.top - g_cy;
-
- SetPos(lpChild,
- (UWORD)(GetScrollPos(lpChild->hwndVScroll, SB_CTL) + (y / g_cy) + 1));
- }
- break;
-
- // Convert keyboard requests to scroll and change window requests
- case WM_KEYDOWN:
- if (wparam == VK_TAB) {
- FORWARD_WM_MDINEXT(g_hwndClient, hwnd,
- (GetKeyState(VK_BACK) & 0x1000 ? TRUE :FALSE),
- SendMessage);
- break;
- }
-
- else if (wparam == VK_DOWN || wparam == VK_UP) {
-
- msg = WM_VSCROLL;
- GET_WM_VSCROLL_CODE(wparam, lparam) =
- (wparam == VK_DOWN
- ? SB_LINEDOWN
- : SB_LINEUP);
- }
- else if (wparam == VK_LEFT || wparam == VK_RIGHT) {
- if (!lpChild->fHScroll)
- break;
-
- msg = WM_HSCROLL;
- GET_WM_HSCROLL_CODE(wparam, lparam) =
- (wparam == VK_RIGHT
- ? SB_LINEDOWN
- : SB_LINEUP);
- }
- else
- break;
-
- // Scroll window
- case WM_HSCROLL:
- case WM_VSCROLL: {
- HWND hwndCtl;
- int cInc;
- int iPos;
- int cPage;
- int nPos;
- int iOrig;
- int nMin, nMax;
-
- if (!lpChild->fDataFetched)
- break;
-
- // Determine scroll direction and distance
- hwndCtl = (msg == WM_HSCROLL
- ? lpChild->hwndHScroll
- : lpChild->hwndVScroll);
- cInc = (msg == WM_HSCROLL ? 1 : 1);
- cPage = (msg == WM_HSCROLL
- ? lpChild->ccolwin
- : lpChild->crowwin - 1);
- nPos = GET_WM_HSCROLL_POS(wparam, lparam);
- iPos =
- iOrig = GetScrollPos(hwndCtl, SB_CTL);
-
- GetScrollRange(hwndCtl, SB_CTL, &nMin, &nMax);
- switch (GET_WM_HSCROLL_CODE(wparam, lparam)) {
- case SB_BOTTOM: iPos = nMax; break;
- case SB_LINEDOWN: iPos+= cInc; break;
- case SB_LINEUP: iPos-= cInc; break;
- case SB_PAGEDOWN: iPos+= cPage; break;
- case SB_PAGEUP: iPos-= cPage; break;
- case SB_TOP: iPos = nMin; break;
- case SB_THUMBPOSITION: iPos = nPos; break;
- }
-
- // For updateable cursors, vertical scroll requests move the
- // current row scroll the window only as needed to keep the
- // current row visible
- if (msg == WM_VSCROLL &&
- lpChild->crowKeyset != SQL_CURSOR_FORWARD_ONLY &&
- lpChild->fConcurrency != SQL_CONCUR_READ_ONLY) {
- int delta;
-
- if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_LINEDOWN)
- delta = cInc;
- else if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_LINEUP)
- delta = -cInc;
- else if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_PAGEDOWN) {
- if (iPos <= nMax)
- delta = cPage;
- else
- delta = lpChild->crowRowset - lpChild->irowPos;
- }
- else if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_PAGEUP) {
- if (iPos >= nMin)
- delta = -cPage;
- else
- delta = 1 - lpChild->irowPos;
- }
- else if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_BOTTOM)
- delta = lpChild->crowRowset - lpChild->irowPos;
- else if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_TOP)
- delta = 1 - lpChild->irowPos;
- else if (GET_WM_HSCROLL_CODE(wparam, lparam) == SB_THUMBPOSITION) {
- if (lpChild->irowPos > (UWORD)iPos &&
- lpChild->irowPos < (UWORD)(iPos+lpChild->crowwin))
- delta = 0;
- else if (iPos == nMin)
- delta = 1 - lpChild->irowPos;
- else if (iPos == nMax)
- delta = lpChild->crowRowset - lpChild->irowPos;
- else if (iPos <= iOrig)
- delta = iPos + lpChild->crowwin - 1 - lpChild->irowPos;
- else
- delta = iPos - lpChild->irowPos + 1;
- }
- else
- break;
-
- SetPos(lpChild, (UWORD)(lpChild->irowPos + delta));
-
- if ((GET_WM_HSCROLL_CODE(wparam, lparam) == SB_LINEDOWN ||
- GET_WM_HSCROLL_CODE(wparam, lparam) == SB_LINEUP) &&
- lpChild->irowPos > (UWORD)iOrig &&
- lpChild->irowPos < (UWORD)(iOrig+lpChild->crowwin))
- break;
- }
-
- // Pin scroll requests within scroll boundaries
- if (iPos < nMin)
- iPos = nMin;
- else if (iPos > nMax)
- iPos = nMax;
-
- // Scroll the window if movement has occurred
- if (iPos != iOrig) {
- HDC hdc;
- BOOL fTitle;
-
- hdc = GetDC(hwnd);
-
- SetScrollPos(hwndCtl, SB_CTL, iPos, TRUE);
-
- fTitle = (msg == WM_HSCROLL);
-
- PaintChild(lpChild, hdc, fTitle, FALSE, TRUE);
-
- ReleaseDC(hwnd, hdc);
- }
- break;
- }
-
- // Activate the child window
- case WM_MDIACTIVATE: {
- HDC hdc;
-
- AdjustMenus();
-
- hdc = GetDC(hwnd);
-
- PaintChild(lpChild, hdc, TRUE, TRUE,
- GET_WM_MDIACTIVATE_FACTIVATE(lpChild->hwnd, wparam, lparam));
-
- ReleaseDC(lpChild->hwnd, hdc);
- break;
- }
-
- // Free all child memory
- case WM_DESTROY:
- if (lpChild) {
- FreeStmt(SQL_DROP, lpChild);
-
- FreePtr(lpChild->lpsz);
- FreePtr(lpChild->sql);
- #ifdef THREAD
- DeleteCriticalSection (&lpChild->ThreadCreation);
- #endif
- FreePtr(lpChild);
-
- SetWindowLong(hwnd, 0, 0L);
- }
- break;
-
- // Close the window
- case WM_CLOSE:
- g_cChild--;
-
- if( !g_cChild )
- #ifdef WIN32
- SendMessage(g_hwndClient, WM_MDISETMENU,
- (WPARAM)g_hmenuFrame,
- (LPARAM)g_hmenuFrameWindow);
- #else
- FORWARD_WM_MDISETMENU(g_hwndClient, 0, g_hmenuFrame,
- g_hmenuFrameWindow, SendMessage);
- #endif
-
- // Destroy child window
- FORWARD_WM_MDIDESTROY(g_hwndClient, hwnd, SendMessage);
- AdjustMenus();
- break;
-
- // Pass all other messages (eventually) to the MDI window procedure
- default:
-
- // Reset scroll bars (if needed) when the window is resized
- if (msg == WM_SIZE) {
-
- if (wparam == SIZE_MINIMIZED)
- lpChild->fIsMinimized = TRUE;
-
- else {
- if (lpChild->fIsMinimized)
- lpChild->fIsMinimized = FALSE;
-
- SizeScroll(lpChild);
-
- if (lpChild->fDataFetched) {
- int row;
-
- SetScroll(lpChild);
-
- row = GetScrollPos(lpChild->hwndVScroll, SB_CTL);
-
- if (lpChild->fConcurrency != SQL_CONCUR_READ_ONLY &&
- lpChild->irowPos >= (UWORD)(row+lpChild->crowwin))
- if (lpChild->crowwin > 1)
- SetScrollPos(lpChild->hwndVScroll,
- SB_CTL,
- lpChild->irowPos-lpChild->crowwin+1,
- TRUE);
- else
- SetScrollPos(lpChild->hwndVScroll,
- SB_CTL,
- lpChild->irowPos-lpChild->crowwin,
- TRUE);
- }
-
- AllocClipRgn(lpChild);
- }
-
- InvalidateRect(hwnd, NULL, TRUE);
- }
-
- // Handle child window menu requests
- else if (msg == WM_COMMAND)
- DoChildMenu(lpChild, wparam, lparam);
-
- // Pass message on to the MDI window procedure
- return DefMDIChildProc(hwnd, msg, wparam, lparam);
- }
-
- return (LRESULT)NULL;
- }
-
-
- /* CvtSqlToCType -----------------------------------------------------------
- Description: Determine the default ODBC C type for a given SQL type
- --------------------------------------------------------------------------*/
- SWORD INTFUNC CvtSqlToCType(SWORD fSqlType)
- {
- switch (fSqlType) {
- case SQL_CHAR:
- case SQL_VARCHAR:
- case SQL_LONGVARCHAR:
- case SQL_DECIMAL:
- case SQL_NUMERIC:
- case SQL_BIGINT: return SQL_C_CHAR;
-
- case SQL_BIT: return SQL_C_BIT;
- case SQL_TINYINT:
- case SQL_SMALLINT: return SQL_C_SHORT;
- case SQL_INTEGER: return SQL_C_LONG;
- case SQL_REAL: return SQL_C_FLOAT;
-
- case SQL_FLOAT:
- case SQL_DOUBLE: return SQL_C_DOUBLE;
-
- case SQL_BINARY:
- case SQL_VARBINARY:
- case SQL_LONGVARBINARY: return SQL_C_BINARY;
-
- case SQL_TYPE_DATE: return SQL_C_TYPE_DATE;
- case SQL_TYPE_TIME: return SQL_C_TYPE_TIME;
- case SQL_TYPE_TIMESTAMP: return SQL_C_TYPE_TIMESTAMP;
-
- case SQL_DATE: return SQL_C_DATE;
- case SQL_TIME: return SQL_C_TIME;
- case SQL_TIMESTAMP: return SQL_C_TIMESTAMP;
- }
-
- return SQL_C_CHAR;
- }
-
-
- /* DeleteRow ---------------------------------------------------------------
- Description: Delete the current (positioned) row
- --------------------------------------------------------------------------*/
- void INTFUNC DeleteRow(LPCHILD lpChild)
- {
- HCURSOR hcur;
- LPSTR lpsz;
- LPSTR lpszT;
- SWORD cb;
-
- // Ensure the delete request is valid
- if (!lpChild->fDataFetched) {
- DoMessage(lpChild->hwnd, IDS_NODATAFETCHED);
- return;
- }
-
- if (*(lpChild->lpfStatus + lpChild->irowPos - 1) == SQL_ROW_NOROW) {
- DoMessage(lpChild->hwnd, IDS_NOROWDELETE);
- return;
- }
-
- if (*(lpChild->lpfStatus + lpChild->irowPos - 1) == SQL_ROW_ERROR) {
- DoMessage(lpChild->hwnd, IDS_ERRORROWDELETE);
- return;
- }
-
- if (*(lpChild->lpfStatus + lpChild->irowPos - 1) == SQL_ROW_DELETED) {
- DoMessage(lpChild->hwnd, IDS_DELROWDELETE);
- return;
- }
-
- if (lpChild->fConcurrency == SQL_CONCUR_READ_ONLY) {
- DoMessage(lpChild->hwnd, IDS_NOUPDATE);
- return;
- }
-
- lpsz = AllocPtr(2 * cbMAXSQL);
- lpszT = lpsz + cbMAXSQL;
-
- // Verify the request and allocate a new (temporary) SQLHSTMT for the delete
- LoadString(g_hinst, IDS_DELETEROW, lpsz, cbMAXSQL);
- if (IDYES == MessageBox(lpChild->hwnd, lpsz,
- g_szTITLE, MB_ICONQUESTION | MB_YESNO) &&
- !DBCError(lpChild->hwnd, SQLAllocHandle(SQL_HANDLE_STMT,g_hdbc, &lpChild->hstmtTmp))) {
-
- // Build DELETE <table> WHERE CURRENT OF <cursor> statement
- lstrcpy(lpsz, szDELETE);
-
- GetTableName(lpszT, lpChild->sql);
- lstrcat(lpsz, lpszT);
-
- lstrcat(lpsz, szWHERE);
-
- lpszT = lpsz + lstrlen(lpsz);
-
- hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
-
- if (!STMTError(SQLGetCursorName(lpChild->hstmt, (UCHAR FAR *)lpszT,
- cbMAXSQL, &cb))) {
-
- // Issue the request via SQLPrepare/SQLExecute
- if (!ODBCError(lpChild->hwnd, SQL_HANDLE_STMT, lpChild->hstmtTmp,
- SQLPrepare(lpChild->hstmtTmp, (UCHAR FAR *)lpsz, SQL_NTS)) &&
- !ODBCError(lpChild->hwnd, SQL_HANDLE_STMT, lpChild->hstmtTmp,
- SQLExecute(lpChild->hstmtTmp)) ) {
- UWORD irowPos;
-
- irowPos = lpChild->irowPos;
-
- // Completely refresh local rowset buffer
- lpChild->rrow = 0;
- lpChild->FetchOP = SQL_FETCH_RELATIVE;
- Fetch(lpChild);
-
- // Reset current position (fetching sets it to the first row)
- SetPos(lpChild, irowPos);
-
- // Repaint window
- InvalidateRect(lpChild->hwnd, NULL, FALSE);
- }
- }
-
- DBCError(lpChild->hwnd, SQLFreeHandle(SQL_HANDLE_STMT,lpChild->hstmtTmp));
- lpChild->hstmtTmp = SQL_NULL_HSTMT;
-
- SetCursor(hcur);
-
- }
-
- FreePtr(lpsz);
-
- return;
- }
-
-
- /* DoChildMenu -------------------------------------------------------------
- Description: Respond to a request from the child window menu
- --------------------------------------------------------------------------*/
- BOOL INTFUNC DoChildMenu(LPCHILD lpChild, WPARAM wParam, LPARAM lParam)
- {
- UNREF_PARAM (lParam);
- switch (GET_WM_COMMAND_ID(wParam, lparam)) {
-
- case IDM_STMT_SEND:
- if (IDOK == DoDialog(lpChild->hwnd, IDD_STATEMENT, StmtDlgProc))
- #ifdef THREAD
- DoSQLThread(lpChild);
- #else
- DoSQL(lpChild);
- #endif
- break;
-
- case IDM_STMT_TABLE:
- if (IDOK == DoDialog(lpChild->hwnd, IDD_TABLE_INFO, SQLTablesDlgProc))
- #ifdef THREAD
- DoSQLThread(lpChild);
- #else
- DoSQL(lpChild);
- #endif
- break;
-
- case IDM_STMT_TYPE:
- lpChild->dwOperation = OPER_TYPES;
- #ifdef THREAD
- DoSQLThread(lpChild);
- #else
- DoSQL(lpChild);
- #endif
- break;
-
-
-
- case IDM_STMT_OPTIONS: // general
- {
- CHILD ChildOld;
-
- // save old values (only works because no pointers
- // get modified in options)
-
- memcpy(&ChildOld, lpChild, sizeof(ChildOld));
- // no modification on those option values yet
- lpChild->fBind =
- lpChild->fMaxBind =
- lpChild->fRowset = FALSE;
-
- if (IDOK == DoDialog(lpChild->hwnd, IDD_OPTION_DIALOG,
- OptionsDlgProc) && ParamValid(lpChild)) {
- if (lpChild->fDataFetched) {
- FreeStmt(SQL_CLOSE, lpChild);
- FreeStmt(SQL_UNBIND, lpChild);
- }
- }
- else {
- // restore previous state
- memcpy(lpChild, &ChildOld, sizeof(ChildOld));
- }
- break;
- }
-
- case IDM_STMT_CANCEL: // general
- Cancel(lpChild);
- break;
-
- case IDM_FETCH_FIRST:
- lpChild->FetchOP = SQL_FETCH_FIRST;
- #ifdef THREAD
- FetchThread(lpChild);
- #else
- Fetch(lpChild);
- #endif
- break;
-
- case IDM_FETCH_PRIOR:
- lpChild->FetchOP = SQL_FETCH_PRIOR;
- #ifdef THREAD
- FetchThread(lpChild);
- #else
- Fetch(lpChild);
- #endif
- break;
-
- case IDM_FETCH_NEXT:
- lpChild->FetchOP = SQL_FETCH_NEXT;
- #ifdef THREAD
- FetchThread(lpChild);
- #else
- Fetch(lpChild);
- #endif
- break;
-
- case IDM_FETCH_LAST:
- lpChild->FetchOP = SQL_FETCH_LAST;
- #ifdef THREAD
- FetchThread(lpChild);
- #else
- Fetch(lpChild);
- #endif
- break;
-
- case IDM_FETCH_ABSOLUTE:
- if (IDOK == DoDialog(lpChild->hwnd, IDD_ABSOLUTE, AbsDlgProc)) {
- lpChild->FetchOP = SQL_FETCH_ABSOLUTE;
- #ifdef THREAD
- FetchThread(lpChild);
- #else
- Fetch(lpChild);
- #endif
- }
- break;
-
- case IDM_FETCH_RELATIVE:
- if (IDOK == DoDialog(lpChild->hwnd, IDD_RELATIVE, RelDlgProc)) {
- lpChild->FetchOP = SQL_FETCH_RELATIVE;
- #ifdef THREAD
- FetchThread(lpChild);
- #else
- Fetch(lpChild);
- #endif
- }
- break;
-
- case IDM_FETCH_GET:
- #ifdef THREAD
- GetDataThread(lpChild);
- #else
- GetData(lpChild);
- #endif
- break;
-
- case IDM_FETCH_DELETEROW:
- #ifdef THREAD
- DeleteRowThread(lpChild);
- #else
- DeleteRow(lpChild);
- #endif
- break;
-
- case IDM_FETCH_UPDATEROW:
- #ifdef THREAD
- UpdateRowThread(lpChild);
- #else
- UpdateRow(lpChild);
- #endif
- break;
- default:
- return FALSE;
- }
-
- AdjustMenus();
- return TRUE;
- }
-
- #ifdef THREAD
- void INTFUNC DoSQLThread(LPCHILD lpChild)
- {
- DWORD dwThreadId;
-
- EnterCriticalSection (&lpChild->ThreadCreation);
- lpChild->hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)DoSQL,
- (LPVOID)lpChild, 0, &dwThreadId);
- LeaveCriticalSection (&lpChild->ThreadCreation);
- }
-
- void INTFUNC FetchThread(LPCHILD lpChild)
- {
- DWORD dwThreadId;
-
- EnterCriticalSection (&lpChild->ThreadCreation);
- lpChild->hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)Fetch,
- (LPVOID)lpChild, 0, &dwThreadId);
- LeaveCriticalSection (&lpChild->ThreadCreation);
- }
-
- void INTFUNC GetDataThread(LPCHILD lpChild)
- {
- DWORD dwThreadId;
-
- EnterCriticalSection (&lpChild->ThreadCreation);
- lpChild->hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)GetData,
- (LPVOID)lpChild, 0, &dwThreadId);
- LeaveCriticalSection (&lpChild->ThreadCreation);
- }
-
- void INTFUNC UpdateRowThread(LPCHILD lpChild)
- {
- DWORD dwThreadId;
-
- EnterCriticalSection (&lpChild->ThreadCreation);
- lpChild->hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)UpdateRow,
- (LPVOID)lpChild, 0, &dwThreadId);
- LeaveCriticalSection (&lpChild->ThreadCreation);
- }
-
- void INTFUNC DeleteRowThread(LPCHILD lpChild)
- {
- DWORD dwThreadId;
-
- EnterCriticalSection (&lpChild->ThreadCreation);
- lpChild->hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)DeleteRow,
- (LPVOID)lpChild, 0, &dwThreadId);
- LeaveCriticalSection (&lpChild->ThreadCreation);
- }
- #endif
-
-
- /* DoSQL -------------------------------------------------------------------
- Description: Issue a SQL statement and prepare for fetching data
- --------------------------------------------------------------------------*/
- void INTFUNC DoSQL(LPCHILD lpChild)
- {
- SQLRETURN rc;
-
- // Prepare the statement
-
- if (PrepareStmt(lpChild) == SQL_ERROR)
- return;
-
- switch(lpChild->dwOperation) {
- case OPER_SELECT:
- // Issue the request via SQLExecDirect
- Async(SQLExecDirect(lpChild->hstmt,
- (UCHAR FAR *)lpChild->sql,
- lstrlen(lpChild->sql)));
- break;
-
- case OPER_TYPES:
- // Issue a GetTypeInfo request
- Async(SQLGetTypeInfo(lpChild->hstmt, SQL_ALL_TYPES));
- break;
-
-
- case IDC_TABLE_RAD_TABLE:
- if (!*lpChild->szTable &&
- ((!*lpChild->szUser && strcmp(lpChild->szQualifier, "%") == 0)||
- (!*lpChild->szQualifier && strcmp(lpChild->szUser, "%") == 0))) { // Special qualifier enumeration
- Async(SQLTables(lpChild->hstmt,
- lpChild->szQualifier, SQL_NTS,
- lpChild->szUser, SQL_NTS,
- lpChild->szTable, SQL_NTS,
- lpChild->szType, SQL_NTS));
- }
- else
- { // Normal SQLTables call
- Async(SQLTables(lpChild->hstmt,
- NULLIFEMPTY(lpChild->szQualifier), SQL_NTS,
- NULLIFEMPTY(lpChild->szUser), SQL_NTS,
- NULLIFEMPTY(lpChild->szTable), SQL_NTS,
- NULLIFEMPTY(lpChild->szType), SQL_NTS));
- }
- break;
-
- case IDC_TABLE_RAD_PRIV:
- Async(SQLTablePrivileges(lpChild->hstmt,
- NULLIFEMPTY(lpChild->szQualifier), SQL_NTS,
- NULLIFEMPTY(lpChild->szUser), SQL_NTS,
- NULLIFEMPTY(lpChild->szTable), SQL_NTS));
-
- break;
-
- case IDC_TABLE_RAD_STATISTICS:
- Async(SQLStatistics(lpChild->hstmt,
- NULLIFEMPTY(lpChild->szQualifier), SQL_NTS,
- NULLIFEMPTY(lpChild->szUser), SQL_NTS,
- NULLIFEMPTY(lpChild->szTable), SQL_NTS,
- SQL_INDEX_ALL, // XXX
- SQL_QUICK)); // XXX
- break;
-
-
-
- case IDC_TABLE_RAD_PROC:
- Async(SQLProcedures(lpChild->hstmt,
- NULLIFEMPTY(lpChild->szQualifier), SQL_NTS,
- NULLIFEMPTY(lpChild->szUser), SQL_NTS,
- NULLIFEMPTY(lpChild->szTable), SQL_NTS));
-
- break;
-
- case IDC_TABLE_RAD_COLUMN:
- Async(SQLColumns(lpChild->hstmt,
- NULLIFEMPTY(lpChild->szQualifier), SQL_NTS,
- NULLIFEMPTY(lpChild->szUser), SQL_NTS,
- NULLIFEMPTY(lpChild->szTable), SQL_NTS,
- NULLIFEMPTY(lpChild->szColName), SQL_NTS));
-
- }
-
- if (STMTError(rc))
- return;
-
- if (ProcessResults(lpChild)) {
-
- if (lpChild->dwGuiFlags & GUIF_ALWAYSFETCH) {
- lpChild->FetchOP = SQL_FETCH_NEXT;
- Fetch(lpChild);
- }
- }
-
- AdjustMenus();
- return;
-
- }
-
- /* ProcessResults---------------------------------------------------------------
- Description: Process the results from a query or statement
- --------------------------------------------------------------------------*/
- BOOL INTFUNC ProcessResults(LPCHILD lpChild)
- {
- LPINT lptab;
- LPCOL lpcol;
- LPBYTE lpb;
- SDWORD cbMsg;
- SDWORD cbNull;
- int nLastTab;
- SWORD i;
- SQLRETURN rc;
-
-
- // Retrieve number of columns in the result set
- Async(SQLNumResultCols(lpChild->hstmt, &i));
- if (STMTError(rc))
- return FALSE;
- lpChild->ccol = ((UWORD)i < lpChild->cBind || lpChild->fBindAll
- ? i
- : lpChild->cBind);
-
- // If a result set exists, continue; otherwise, return immediately
- if (lpChild->ccol)
- lpChild->fResultSetExists = TRUE;
- else
- return FALSE;
-
- // Allocate painting related storage and row status array
-
- lpChild->rglpv = (char *)AllocPtr(sizeof(char *) * lpChild->ccol);
- lpChild->lpnTabs = (LPINT)AllocPtr(sizeof(int) * (lpChild->ccol+1));
- lpChild->lpcol = (LPCOL)AllocPtr(sizeof(COL) * lpChild->ccol);
- lpChild->lpfStatus = (LPUWORD)AllocPtr((DWORD) sizeof(UWORD)
- * lpChild->crowRowset);
-
- for (i=1, lpcol=lpChild->lpcol; i <= lpChild->ccol; i++, lpcol++) {
- lpcol->lpb = NULL;
- lpcol->lpcb = NULL;
- }
-
- cbMsg = lstrlen(g_szRowDeleted);
- cbNull = lstrlen(g_szNull);
- cbMsg = max(cbMsg, lstrlen(g_szNoRow));
- cbMsg = max(cbMsg, cbNull);
-
- // Initialize row width (in bytes) and total number of characters per line
- lpChild->cbrow = 0;
- lpChild->ccols = 0;
-
- lpcol = lpChild->lpcol;
- lptab = lpChild->lpnTabs;
-
- nLastTab =
- *lptab++ = cxBORDER;
-
- // For each bound column
- // a) Get column attributes (e.g., name, size, data type)
- // b) Add column to physical and display row widths
- // c) Determine tab location
- for (i=1; i <= lpChild->ccol; i++, lpcol++, lptab++) {
-
- // Get column name
- Async(SQLColAttribute(lpChild->hstmt, i,
- SQL_DESC_NAME,
- lpcol->szName, sizeof(lpcol->szName), NULL,
- NULL));
- if (STMTError(rc)) {
- FreeStmt(SQL_DROP, lpChild);
- return FALSE;
- }
-
- // Get actual column length (number of physical data bytes)
- // if the sample were to be used with a 3.0 driver only SQLColAttribute
- // with fattribute of SQL_DESC_OCTECT_LENGTH could be called instead.
- Async(SQLColAttributes(lpChild->hstmt, i,
- SQL_COLUMN_LENGTH,
- NULL, 0, NULL,
- &lpcol->cb));
-
-
- if (STMTError(rc)) {
- FreeStmt(SQL_DROP, lpChild);
- return FALSE;
- }
-
- // Get display width
- Async(SQLColAttribute(lpChild->hstmt, i,
- SQL_DESC_DISPLAY_SIZE,
- NULL, 0, NULL,
- &lpcol->cbc));
- if (STMTError(rc)) {
- FreeStmt(SQL_DROP, lpChild);
- return FALSE;
- }
-
-
- // if the display size is too big, force to the the maximum
- if (lpcol->cbc > lpChild->crowMaxBind)
- lpcol->cbc = lpChild->crowMaxBind;
-
- // Ensure display width is wide enough for:
- // a) Column name
- // b) Null string
- // c) Row status (for the first column only)
- if (lpcol->cbc < cbMsg)
- lpcol->cbc = cbMsg;
-
- if (lstrlen(lpcol->szName) > lpcol->cbc)
- lpcol->cbc = lstrlen(lpcol->szName);
-
- lpcol->cbc++;
-
- // Get column SQL type
- Async(SQLColAttribute(lpChild->hstmt, i,
- SQL_DESC_CONCISE_TYPE,
- NULL, 0, NULL,
- (SDWORD FAR*) &lpcol->fSqlType));
- if (STMTError(rc)) {
- FreeStmt(SQL_DROP, lpChild);
- return FALSE;
- }
-
- // Determine target C type
- lpcol->fCType = CvtSqlToCType(lpcol->fSqlType);
-
- // For hard to handle C types, let the driver convert to character
- if (lpcol->fCType == SQL_C_BIT ||
- lpcol->fCType == SQL_C_BINARY ||
- lpcol->fCType == SQL_C_DATE ||
- lpcol->fCType == SQL_C_TIME ||
- lpcol->fCType == SQL_C_TIMESTAMP ||
- lpcol->fCType == SQL_C_TYPE_DATE ||
- lpcol->fCType == SQL_C_TYPE_TIME ||
- lpcol->fCType == SQL_C_TYPE_TIMESTAMP) {
- lpcol->fCType = SQL_C_CHAR;
- lpcol->cb = lpcol->cbc;
- }
-
- // Determine next column tab (based on column width plus border)
- nLastTab =
- *lptab = nLastTab + ((int)lpcol->cbc * g_cx) + (2 * cxBORDER);
-
- // Set maximum column length for character data
- if( lpcol->cb > lpChild->crowMaxBind &&
- lpcol->fCType == SQL_C_CHAR )
- lpcol->cb = lpChild->crowMaxBind;
-
- if( lpcol->fCType == SQL_C_CHAR )
- lpcol->cb++;
-
- // Increment total phsyical row width and display width
- lpChild->cbrow += lpcol->cb;
- lpChild->ccols += (int)lpcol->cbc;
-
- cbMsg = cbNull;
- }
-
- // Include a count field for each bound column in physical row width
- lpChild->cbrow += lpChild->ccol * sizeof(SDWORD);
-
- // Add intra-column border amounts to total character width
- lpChild->ccols += (lpChild->ccol * (2 * cxBORDER)) / g_cx;
-
- // For each column, include an element in the format string
- lpb = (LPBYTE)lpChild->szFmt;
- for (i=0, lpcol=lpChild->lpcol; i < lpChild->ccol; i++, lpcol++) {
- *(lpb++) = '\t';
- *(lpb++) = '%';
- *(lpb++) = 's';
- }
- *lpb = 0;
-
- // If row-wise binding, allocate a buffer; switch to column-wise
- // if the entire row-set cannot fit into 64K minus cursor library
- // headers
- lpb = NULL;
- if (ROW_BINDING(lpChild)) {
- if ((lpChild->cbrow * lpChild->crowRowset) > 65500L) {
- DoMessage(lpChild->hwnd, IDS_BIGROWSET);
- lpChild->fBindByRow = IDC_RADIO_BINDCOL ;
- }
- else {
- lpb =
- lpChild->lpb = (LPBYTE)AllocPtr(lpChild->cbrow *
- lpChild->crowRowset);
- }
- }
-
- // Set binding type
- if (STMTError(SQLSetStmtAttr(lpChild->hstmt,
- SQL_ATTR_ROW_BIND_TYPE,
- (SQLPOINTER) (ROW_BINDING(lpChild)
- ? lpChild->cbrow
- : SQL_BIND_BY_COLUMN),
- SQL_IS_INTEGER)))
- return FALSE;
-
- // Finally, for each bound column, bind the data value
- for (i=1, lpcol=lpChild->lpcol; i <= lpChild->ccol; i++, lpcol++) {
- if (!ROW_BINDING(lpChild)) {
- lpcol->lpb = (LPBYTE)AllocPtr(lpcol->cb * lpChild->crowRowset);
- lpcol->lpcb = (LPSDWORD)AllocPtr((DWORD) sizeof(SDWORD) *
- lpChild->crowRowset);
- }
- else {
- lpcol->lpb = (LPBYTE)lpb;
- lpcol->lpcb = (LPSDWORD)(lpb + lpcol->cb);
- lpb += lpcol->cb + sizeof(SDWORD);
- }
-
- if (STMTError(SQLBindCol(lpChild->hstmt, i, (SWORD)lpcol->fCType,
- (PTR)(lpcol->lpb),
- lpcol->cb,
- lpcol->lpcb)))
- return FALSE;
- }
-
- return TRUE;
- }
-
-
- /* PrepareStmt -------------------------------------------------------------
- Description: Prepare a statement for future processing
-
- Returns: SQL_ERROR if an error occurs
- --------------------------------------------------------------------------*/
- SQLRETURN INTFUNC PrepareStmt(LPCHILD lpChild)
- {
-
- // Close the statement and drop bindings
- FreeStmt(SQL_CLOSE, lpChild);
- FreeStmt(SQL_UNBIND, lpChild);
-
- // Set scroll options
- if (!(SUCCESS(SQLSetStmtAttr(lpChild->hstmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER) lpChild->crowKeyset,
- SQL_IS_INTEGER))))
- lpChild->fNoCursorType = TRUE;
-
- if (!(SUCCESS(SQLSetStmtAttr(lpChild->hstmt,
- SQL_ATTR_CONCURRENCY,
- (SQLPOINTER) lpChild->fConcurrency,
- SQL_IS_INTEGER))))
- lpChild->fNoConcurrency = TRUE;
-
-
- if (STMTError(SQLSetStmtAttr(lpChild->hstmt,
- SQL_ATTR_ROW_ARRAY_SIZE,
- (SQLPOINTER) lpChild->crowRowset,
- SQL_IS_INTEGER)))
- return SQL_ERROR;
-
- // Set async mode (if supported by the driver)
- if (g_fAsyncSupported &&
- STMTError(SQLSetStmtAttr(lpChild->hstmt,
- SQL_ATTR_ASYNC_ENABLE,
- (SQLPOINTER) (lpChild->fAsync ? 1 : 0),
- SQL_IS_INTEGER)))
- return SQL_ERROR;
-
-
-
- return FALSE;
-
- }
-
- /* Cancel -------------------------------------------------------------------
- Description: Issue cancel request
- --------------------------------------------------------------------------*/
- void INTFUNC Cancel(LPCHILD lpChild)
- {
- SQLRETURN rc;
-
- // Call SQLCancel
- if (lpChild->hstmtTmp != SQL_NULL_HSTMT) {
- rc = SQLCancel(lpChild->hstmtTmp); // Cancel temp hstmt
- STMTError(rc);
- }
- else {
- rc = SQLCancel(lpChild->hstmt);
- STMTError(rc);
- FreeStmt(SQL_CLOSE, lpChild); // Cleanup statement
- }
-
- return;
- }
-
-
- /* Fetch -------------------------------------------------------------------
- Description: Issue fetch request
- --------------------------------------------------------------------------*/
- void INTFUNC Fetch(LPCHILD lpChild)
- {
- SQLRETURN rc;
- UDWORD crow;
- HCURSOR hcur;
- SDWORD sdwIrowLast = lpChild->irow;
- SDWORD sdwRowsAffected;
- SDWORD irow;
- UWORD fFetchType;
-
- static UWORD fFetchTypeLast = SQL_FETCH_NEXT;
-
- fFetchType = lpChild->FetchOP;
- if (fFetchType == SQL_FETCH_ABSOLUTE)
- irow = lpChild->arow;
- else if (fFetchType == SQL_FETCH_RELATIVE)
- irow = lpChild->rrow;
- else
- irow = 0;
- if (!(lpChild->fResultSetExists)) {
- STMTError(SQLRowCount(lpChild->hstmt, &sdwRowsAffected));
-
- if (sdwRowsAffected > -1) {
- UCHAR szBuffer[200];
- wsprintf(szBuffer,
- (sdwRowsAffected == 1) ? szRowAffected:szDataAffected,
- sdwRowsAffected);
-
- MessageBox(lpChild->hwnd,
- szBuffer,
- szNoDataTitle,
- MB_ICONINFORMATION);
- }
- else
- {
- MessageBox( lpChild->hwnd,
- szNoDataTitle,
- szNoData,
- MB_ICONINFORMATION);
- }
- return;
- }
-
- hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
-
- SQLSetStmtAttr(lpChild->hstmt, SQL_ATTR_ROWS_FETCHED_PTR,
- &crow, SQL_IS_POINTER);
- SQLSetStmtAttr(lpChild->hstmt, SQL_ATTR_ROW_STATUS_PTR,
- lpChild->lpfStatus, SQL_IS_POINTER);
-
- // Call SQLFetchScroll
- Async(SQLFetchScroll(lpChild->hstmt, fFetchType, irow));
-
- if ((rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) &&
- lpChild->irowPos > crow) {
- SetPos(lpChild, (UWORD) crow);
- }
-
- if (!STMTError(rc) && rc != SQL_NO_DATA) {
-
- // Reset columns retrieved count
- lpChild->ccolRetrieved = (UWORD)lpChild->ccol;
-
- // If this is the first fetch, initialize child variables
- if (!lpChild->fDataFetched) {
-
- lpChild->fDataFetched = TRUE;
-
- lpChild->irow = -((SDWORD)lpChild->crowRowset);
- lpChild->irowPos = 1;
-
- SetScrollPos(lpChild->hwndVScroll, SB_CTL, 0, FALSE);
- SetScrollPos(lpChild->hwndHScroll, SB_CTL, 0, FALSE);
-
- SetScroll(lpChild);
- AllocClipRgn(lpChild);
- }
-
- // Otherwise, maintain current row position in the row-set
- else if (lpChild->fConcurrency != SQL_CONCUR_READ_ONLY &&
- lpChild->crowKeyset != SQL_CURSOR_FORWARD_ONLY)
- SetPos(lpChild, lpChild->irowPos);
-
- // if (fFetchType == SQL_FETCH_RESUME)
- // fFetchType = fFetchTypeLast;
-
- // Adjust absolute row number by fetch amount
- switch (fFetchType) {
- case SQL_FETCH_FIRST:
- lpChild->irow = 1;
- break;
-
- case SQL_FETCH_PRIOR:
- lpChild->irow -= crow;
- if (lpChild->irow < 1)
- lpChild->irow = 1;
- break;
-
- case SQL_FETCH_NEXT:
- lpChild->irow += lpChild->crowCurrent; // Previous RS
- break;
-
- case SQL_FETCH_LAST: {
- SDWORD iRowT; // scratch variable
-
- if (STMTError(SQLGetStmtAttr(lpChild->hstmt,
- SQL_ATTR_ROW_NUMBER,
- &iRowT,
- SQL_IS_INTEGER,
- NULL))) {
- // the cursor library does not support SQL_ROW_NUMBER,
- // so use the following calculation. The result might
- // be incorrect
- STMTError(SQLRowCount(lpChild->hstmt, &iRowT));
- lpChild->irow += (iRowT - crow);
- if (lpChild->irow < 1) lpChild->irow = 1;
-
- }
- else { // the cursor library supports SQL_ROW_NUMBER
- lpChild->irow = iRowT;
- }
- }
- break;
-
- case SQL_FETCH_RELATIVE:
- lpChild->irow += irow;
- if (lpChild->irow < 1)
- lpChild->irow = 1;
- break;
-
- case SQL_FETCH_ABSOLUTE:
- if (irow > 0)
- lpChild->irow = irow;
- else {
- STMTError(SQLRowCount(lpChild->hstmt, &lpChild->irow));
- lpChild->irow = lpChild->irow + irow + 1;
- if (lpChild->irow < 1) lpChild->irow = 1;
- }
- break;
- }
-
- // Repaint window
- InvalidateRect(lpChild->hwnd, NULL, FALSE);
-
- lpChild->crowCurrent = crow;
- }
-
- fFetchTypeLast = fFetchType;
-
- AdjustMenus();
- SetCursor(hcur);
- return;
- }
-
-
- /* FreeStmt ----------------------------------------------------------------
- Description: Free SQLHSTMT and reset associated variables of a child window
- NOTE: Only SQL_CLOSE, SQL_DROP, and SQL_UNBIND are valid
- --------------------------------------------------------------------------*/
- void INTFUNC FreeStmt(UWORD fOption, LPCHILD lpChild)
- {
- SWORD i;
- LPCOL lpcol;
-
- if (!lpChild->hstmt)
- return;
-
- // Issue the real SQLFreeStmt call
- if (fOption == SQL_DROP) {
- if (STMTError(SQLFreeHandle(SQL_HANDLE_STMT, lpChild->hstmt)))
- return;
- }
- else {
- if (STMTError(SQLFreeStmt(lpChild->hstmt, fOption)))
- return;
- }
-
- // Drop data buffers for SQL_DROP and SQL_UNBIND requests
- if (fOption == SQL_DROP || fOption == SQL_UNBIND) {
- if (!ROW_BINDING(lpChild)) {
- for (i=0, lpcol=lpChild->lpcol; i < lpChild->ccol; i++, lpcol++) {
- FreePtr(lpcol->lpb); lpcol->lpb = NULL;
- FreePtr(lpcol->lpcb); lpcol->lpcb = NULL;
- }
- }
- else if (lpChild->lpb) {
- FreePtr(lpChild->lpb);
- lpChild->lpb = NULL;
- }
- }
-
- // Only drop memory for SQL_UNBIND requests
- if (fOption == SQL_UNBIND)
- return;
-
- // Clear SQLHSTMT handle for SQL_DROP
- if (fOption == SQL_DROP)
- lpChild->hstmt = SQL_NULL_HSTMT;
-
- // Always reset and free result set related variables
- lpChild->fResultSetExists = FALSE;
- lpChild->ccol = 0;
- lpChild->fDataFetched = FALSE;
- lpChild->cbrow = 0;
- lpChild->ccols = 0;
-
-
- FreePtr(lpChild->rglpv); lpChild->rglpv = NULL;
- FreePtr(lpChild->lpnTabs); lpChild->lpnTabs = NULL;
- FreePtr(lpChild->lpcol); lpChild->lpcol = NULL;
- FreePtr(lpChild->lpfStatus); lpChild->lpfStatus = NULL;
-
- if (lpChild->hrgn) {
- DeleteObject(lpChild->hrgn);
- lpChild->hrgn = NULL;
- }
-
- if (lpChild->hwnd) {
- lpChild->fVScroll = FALSE;
- lpChild->fHScroll = FALSE;
-
- ShowWindow(lpChild->hwndVScroll, SW_HIDE);
- ShowWindow(lpChild->hwndHScroll, SW_HIDE);
- InvalidateRect(lpChild->hwnd, NULL, FALSE);
- }
- return;
- }
-
-
- /* GetCurrentValue ---------------------------------------------------------
- Description: Convert to character and return column data from current
- row
- --------------------------------------------------------------------------*/
- #pragma optimize("ceglntw", off)
- void INTFUNC GetCurrentValue(LPSTR lpsz, LPCOL lpcol, LPCHILD lpChild)
- {
- LPBYTE lpb;
- SDWORD FAR *lpcb;
- UWORD irowPos;
-
- irowPos = lpChild->irowPos - 1;
-
- // Get data and count field pointers based on binding type
- if (ROW_BINDING(lpChild)) {
- lpb = lpcol->lpb + (irowPos * lpChild->cbrow);
- lpcb = (LPSDWORD)(lpb + lpcol->cb);
- }
- else {
- lpb = lpcol->lpb + (irowPos * lpcol->cb);
- lpcb = lpcol->lpcb + irowPos;
- }
-
- // Convert column data to character using the supplied buffer
- if (*lpcb == SQL_NULL_DATA) {
- lstrcpy(lpsz, g_szNull);
- return;
- }
-
- switch (lpcol->fSqlType) {
-
- case SQL_CHAR:
- case SQL_VARCHAR:
- lstrcpy(lpsz, (LPSTR)lpb);
- break;
-
- case SQL_INTEGER:
- case SQL_SMALLINT:
- case SQL_TINYINT: {
- long l;
-
- l = (lpcol->fSqlType == SQL_INTEGER
- ? *((DWORD FAR *)lpb)
- : lpcol->fSqlType == SQL_SMALLINT
- ? *((WORD FAR *)lpb)
- : *((UCHAR FAR *)lpb));
-
- _ltoa(l, lpsz, 10);
- break;
- }
-
- case SQL_REAL:
- case SQL_FLOAT:
- case SQL_DOUBLE: {
- double d;
-
- d = (lpcol->fSqlType == SQL_REAL
- ? *((float FAR *)lpb)
- : *((double FAR *)lpb));
-
- _gcvt(d, 15, lpsz);
- break;
- }
-
- default:
- *lpsz = '\0';
- break;
- }
-
- return;
- }
- #pragma optimize("ceglntw", on)
-
-
- /* GetData -----------------------------------------------------------------
- Description: Retrieve the next unbound column and display the data
- --------------------------------------------------------------------------*/
- void INTFUNC GetData(LPCHILD lpChild)
- {
- HCURSOR hcur;
- BIGCOL bcol;
- UWORD icol;
- SQLRETURN rc;
-
- // Prevent Cancel from closing statement
- lpChild->hstmtTmp = lpChild->hstmt;
-
- // Determine next unbound column index
- icol = lpChild->ccolRetrieved + 1;
-
- hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
-
- // Get column name
- Async(SQLColAttribute(lpChild->hstmt, icol,
- SQL_DESC_NAME,
- bcol.szName, sizeof(bcol.szName), NULL,
- NULL));
-
- SetCursor(hcur);
-
- if (STMTError(rc)) {
- lpChild->hstmtTmp = SQL_NULL_HSTMT;
- return;
- }
-
- bcol.lpsz = lpChild->lpsz;
-
- hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
-
- // Get the data converting it to character
- Async(SQLGetData(lpChild->hstmt, icol, SQL_C_CHAR,
- bcol.lpsz, cbBUFSIZE-1, &bcol.cb));
-
- SetCursor(hcur);
-
- lpChild->hstmtTmp = SQL_NULL_HSTMT;
-
- if (STMTError(rc) || rc == SQL_NO_DATA)
- return;
-
- // Display the retrieved data
- DialogBoxParam(g_hinst,
- MAKEINTRESOURCE(IDD_DATADLG),
- lpChild->hwnd,
- DataDlgProc,
- (LPARAM)((LPSTR)&bcol));
-
- lpChild->ccolRetrieved = icol;
- return;
- }
-
-
- /* GetTableName ------------------------------------------------------------
- Description: Extract table name from a SELECT statement
- --------------------------------------------------------------------------*/
- void INTFUNC GetTableName(LPSTR lpszTable, LPCSTR szSql)
- {
- LPCSTR lpsz;
- int cp;
- int cb;
-
- cb = lstrlen(szFROM);
-
- for (lpsz=szSql, cp=0; *lpsz; ) {
-
- while (*lpsz && ISWHITE(*lpsz)) lpsz++;
-
- if (!cp && !_fstrnicmp(lpsz, szFROM, cb) && ISWHITE(*(lpsz+cb)))
- break;
-
- if (ISLPAREN(*lpsz))
- cp++;
- else if (ISRPAREN(*lpsz))
- cp--;
-
- while (*lpsz && !ISWHITE(*lpsz)) lpsz++;
- }
-
- while (*lpsz && !ISWHITE(*lpsz)) lpsz++;
- while (*lpsz && ISWHITE(*lpsz)) lpsz++;
-
- if (*lpsz == *g_szQuoteChar) {
- *lpszTable++ = *lpsz++; // Copy beginning quote
- while (*lpsz && *lpsz != *g_szQuoteChar) *lpszTable++ = *lpsz++;
- *lpszTable++ = *lpsz++; // Copy ending quote
- }
- else // Not a quoted identifier
- while (*lpsz && !ISCOMMA(*lpsz) && !ISWHITE(*lpsz)) *lpszTable++ = *lpsz++;
-
- *lpszTable = '\0';
-
- return;
- }
-
-
- /* IsUpdateable ------------------------------------------------------------
- Description: Return TRUE if this app supports updating the particular
- SQL data type (due to limited conversion support)
- --------------------------------------------------------------------------*/
- BOOL INTFUNC IsUpdateable(SDWORD fSqlType)
- {
- switch (fSqlType) {
- case SQL_CHAR:
- case SQL_VARCHAR:
- case SQL_SMALLINT:
- case SQL_INTEGER:
- case SQL_REAL:
- case SQL_FLOAT:
- case SQL_DOUBLE:
- case SQL_TINYINT:
- return TRUE;
-
- default:
- return FALSE;
- }
- }
-
-
- /* OnDataRow ---------------------------------------------------------------
- Description: Return 0 or greater if the mouse coordinates in lparam are
- over a valid data row, Otherwise return -1
- --------------------------------------------------------------------------*/
- int INTFUNC OnDataRow(LPCHILD lpChild, LPARAM lparam)
- {
- RECT rc;
- int row;
-
- if (!(lpChild->hrgn))
- return -1;
-
- GetRgnBox(lpChild->hrgn, &rc);
-
- row = (int)HIWORD(lparam) - g_cy;
-
- if (row < 0)
- return FALSE;
-
- row /= g_cy;
-
- if (row >= 0 &&
- (UWORD)row < lpChild->crowRowset )
- return row;
- else
- return -1;
- }
-
-
- /* PaintChild --------------------------------------------------------------
- Description: Paint child window
- --------------------------------------------------------------------------*/
- void INTFUNC PaintChild(LPCHILD lpChild,
- HDC hdc,
- BOOL fTitle,
- BOOL fRefresh,
- BOOL fActive)
- {
- RECT rc;
-
- GetClientRect(lpChild->hwnd, &rc);
-
- // If no data exists, just erase the window
- if (!lpChild->fDataFetched)
- FillRect(hdc, &rc, g_hbrWin);
-
- // Otherwise paint the data in a simple scrollable grid
- else {
- HRGN hrgn;
- HFONT hfontOld;
- HBRUSH hbrOld;
- UWORD ir;
- int ic;
- int icFirst, icLast;
- LPCOL lpcol;
- UWORD row;
- int col;
- int cx, cy;
- LPINT lpnTab;
- LPSTR lpszValues;
- LPSTR lpsz;
- LPUWORD lpfStatus;
- UWORD irowLast;
- UWORD irowPos;
- COLORREF clrfTxt;
- COLORREF clrfBkg;
- char szFmt[cbSTRLEN];
-
- // Prepare the device context
- SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
-
- clrfTxt = GetTextColor(hdc);
- clrfBkg = GetBkColor(hdc);
-
- // Determine first (row,col) and corresponding (x,y) offset
- row = (UWORD)GetScrollPos(lpChild->hwndVScroll, SB_CTL);
- col = GetScrollPos(lpChild->hwndHScroll, SB_CTL);
-
- cx = col * g_cx;
- cy = row * g_cy;
-
- // Determine last row to be painted
- irowLast = (UWORD)row + ((UWORD)lpChild->crowwin < lpChild->crowRowset
- ? lpChild->crowwin
- : lpChild->crowRowset);
- if (irowLast > lpChild->crowRowset)
- irowLast--;
-
- // Get current row number as a zero based index
- irowPos = lpChild->irowPos - 1;
-
- // Determine which columns will be painted
- lpnTab = lpChild->lpnTabs;
- for (icFirst=0;
- icFirst < (lpChild->ccol-1) && (cx + cxBORDER) > *(lpnTab+1);
- icFirst++, lpnTab++);
- for (icLast=icFirst+1;
- icLast < lpChild->ccol &&
- (cx + cxBORDER + (lpChild->ccolwin * g_cx)) > *lpnTab;
- icLast++, lpnTab++);
-
- // Offset the device context to appropriate position in the rowset
- SetWindowOrgEx(hdc, cx, cy, NULL);
-
- // Set the clip region (to keep from erasing scroll bars, etc.)
-
- if (!(lpChild->hrgn))
- return;
-
- SelectClipRgn(hdc, lpChild->hrgn);
-
- // Allocate working buffer to converted data values
- lpszValues = AllocPtr((DWORD) lpChild->ccol * cbSTRLEN);
-
- // If requested, paint column titles
- if (fTitle) {
-
- // Prepare device context
- SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
- hfontOld = SelectObject(hdc, g_hfontName);
-
- // Determine bounding rectangle in logical coordinates
- rc.top = cy;
- rc.bottom = rc.top + g_cy;
- rc.left = *(lpChild->lpnTabs + icFirst) - cxBORDER;
- rc.right = *(lpChild->lpnTabs + icLast) - cxBORDER;
-
- // Fill rectangle with appropriate color
- FillRect(hdc, &rc, g_hbrBtn);
-
- // Paint white bar across the top
- PatBlt(hdc, 0, rc.top, rc.right, 1, WHITENESS);
-
- // For each visible (or partially visible) column, paint
- // separating lines and column name
- lpcol = lpChild->lpcol + icFirst;
- lpnTab = lpChild->lpnTabs + icFirst + 1;
-
- for (ic=icFirst; ic < icLast; ic++, lpcol++, lpnTab++) {
-
- PatBlt(hdc, rc.left, rc.top, 1, g_cy, WHITENESS);
-
- rc.right = *lpnTab - cxBORDER + 1;
-
- DrawText(hdc, lpcol->szName, lstrlen(lpcol->szName),
- &rc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
-
- rc.left = rc.right;
-
- PatBlt(hdc, rc.left-1, rc.top, 1, g_cy, BLACKNESS);
- }
-
- // Paint black line across the bottom
- PatBlt(hdc, 1, rc.bottom-1, rc.right-1, 1, BLACKNESS);
-
- // Reset device context
- SelectObject(hdc, hfontOld);
- SetBkColor(hdc, clrfBkg);
- }
-
- // Determine bounding rectangle for first row to be painted
- rc.top = cy + g_cy;
- rc.bottom = rc.top + g_cy - 1;
- rc.left = *(lpChild->lpnTabs + icFirst) - cxBORDER;
- rc.right = *(lpChild->lpnTabs + icLast) - cxBORDER;
-
- // Make format string from the whole format string created earlier
- #ifdef WIN32
- _fstrncpy(szFmt, lpChild->szFmt+(icFirst*3), ((icLast-icFirst)*3)+1);
- #else
- lstrcpyn(szFmt, lpChild->szFmt+(icFirst*3), ((icLast-icFirst)*3)+1);
- #endif
- szFmt[((icLast-icFirst)*3)+1] = '\0';
-
- // Offset into the row status array
- lpfStatus = lpChild->lpfStatus + row;
-
- // Prepare device context
- hfontOld = SelectObject(hdc, g_hfontData);
- hbrOld = SelectObject(hdc, g_hbrBtn);
-
- // Paint each row
- for (ir=row; ir < irowLast; ir++) {
-
- // Erase row if requested (i.e., !fRefresh) or if just
- // painting the row is insufficient to remove old data
- if (!fRefresh ||
- (ir == irowPos && !fActive) ||
- *lpfStatus == SQL_ROW_NOROW ||
- *lpfStatus == SQL_ROW_ERROR ||
- *lpfStatus == SQL_ROW_DELETED)
- FillRect(hdc, &rc, g_hbrWin);
-
- // For an empty row, write the empty row string
- if (*lpfStatus == SQL_ROW_NOROW) {
- if (icFirst)
- *lpChild->lpsz = '\0';
- else
- lstrcpy(lpChild->lpsz, g_szNoRow);
- }
-
- // For a deleted row, write the deleted row string
- else if (*lpfStatus == SQL_ROW_DELETED) {
- if (icFirst)
- *lpChild->lpsz = '\0';
- else
- lstrcpy(lpChild->lpsz, g_szRowDeleted);
- }
-
- // For an error row, write the error row string
- else if (*lpfStatus == SQL_ROW_ERROR) {
- if (icFirst)
- *lpChild->lpsz = '\0';
- else
- lstrcpy(lpChild->lpsz, g_szRowError);
- }
-
- // For all other rows, build a string of data values
- else {
- LPSTR FAR *lplpsz;
- LPBYTE lpb;
- LPSDWORD lpcb;
-
-
- // Paint updated rows in RED
- if (*lpfStatus == SQL_ROW_UPDATED)
- SetTextColor(hdc, RGB(255,0,0));
-
-
- lplpsz = (LPSTR FAR *)lpChild->rglpv;
-
- lpsz = lpszValues;
-
- lpcol = lpChild->lpcol + icFirst;
- lpnTab = lpChild->lpnTabs + icFirst;
-
- // Convert each column to character data
- for (ic=icFirst; ic < icLast; ic++, lpcol++) {
-
- lpb = lpcol->lpb + (ir * (ROW_BINDING(lpChild)
- ? lpChild->cbrow
- : lpcol->cb));
- lpcb = (ROW_BINDING(lpChild)
- ? (LPSDWORD)(lpb + lpcol->cb)
- : lpcol->lpcb + ir);
-
- if (*lpcb == SQL_NULL_DATA)
- *lplpsz++ = g_szNull;
-
- else if (lpcol->fCType == SQL_C_CHAR)
- *lplpsz++ = (LPSTR)lpb;
-
- else {
-
- if (lpcol->fCType == SQL_C_FLOAT ||
- lpcol->fCType == SQL_C_DOUBLE ) {
- double d;
-
- d = (lpcol->fCType == SQL_C_FLOAT
- ? *((float FAR *)lpb)
- : *((double FAR *)lpb));
-
- _gcvt(d, 15, lpsz);
- }
-
- else {
- long l;
-
- l = ( lpcol->fCType == SQL_C_SHORT
- ? *((short FAR *)lpb)
- : lpcol->fCType == SQL_C_LONG
- ? *((long FAR *)lpb)
- : *((signed char FAR *)lpb));
-
- _ltoa(l, lpsz, 10);
- }
-
- *lplpsz++ = lpsz;
- lpsz += cbSTRLEN;
- }
- }
-
- // Combine all columns into one string (with tab markers)
- Print(lpChild->lpsz, szFmt, lpChild->rglpv );
-
-
-
- }
-
- // Paint the row
- TabbedTextOut(hdc,
- rc.left, rc.top,
- lpChild->lpsz, lstrlen(lpChild->lpsz),
- icLast - icFirst, lpnTab, 0);
-
- // Paint bottom separator
- PatBlt(hdc, 0, rc.bottom, rc.right, 1, PATCOPY);
-
- // Paint inter-column separators
- lpnTab = lpChild->lpnTabs + icFirst + 1;
- for (ic=icFirst+1; ic < (icLast+1); ic++, lpnTab++)
- PatBlt(hdc, *lpnTab-cxBORDER, rc.top, 1, g_cy, PATCOPY);
-
- // Reset text color (if it was changed)
- if (*lpfStatus == SQL_ROW_UPDATED)
- SetTextColor(hdc, clrfTxt);
-
- // Hilite the current row
- if (ir == irowPos &&
- lpChild->fConcurrency != SQL_CONCUR_READ_ONLY &&
- fActive ) {
- RECT rcTemp, rcInvert;
-
- GetClipBox(hdc, &rcTemp);
-
- IntersectRect(&rcInvert, &rc, &rcTemp);
-
- GetClientRect(lpChild->hwnd, &rcTemp);
-
- if( rcInvert.top == rc.top )
- rcInvert.top++;
-
- if( rcInvert.bottom == rc.bottom )
- rcInvert.bottom--;
-
- if( rcInvert.left == rcTemp.left )
- rcInvert.left++;
-
- if( rcInvert.right == rcTemp.right ||
- rcInvert.right == rc.right )
- rcInvert.right--;
-
- InvertRect(hdc, &rcInvert);
- }
-
- // Advance row rectangle and status array offset
- rc.top += g_cy;
- rc.bottom += g_cy;
- lpfStatus++;
- }
-
- // Erase any partial row which may be displayed after the last
- // row of the row-set has been painted
- if (ir == lpChild->crowRowset)
- FillRect(hdc, &rc, g_hbrWin);
-
- // Erase any partial column which may be displayed after the last
- // column has been painted
- if (icLast == lpChild->ccol) {
- GetClipBox(hdc, &rc);
- rc.left = *(lpChild->lpnTabs + icLast) - cxBORDER + 1;
- FillRect(hdc, &rc, g_hbrWin);
- }
-
- FreePtr(lpszValues);
-
- // Reset clip region to paint areas outside data grid
- GetClientRect(lpChild->hwnd, &rc);
-
- hrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
-
- SelectClipRgn(hdc, hrgn);
-
- OffsetRect(&rc, cx, cy);
-
- // Paint bottom record display bar and/or the corner box
- // between the scroll bars
- rc.top = rc.bottom - g_cyHScroll + 1;
-
- PatBlt(hdc, rc.left, rc.top, rc.right, 1, BLACKNESS);
-
- SelectObject(hdc, g_hbrScroll);
-
- rc.top++;
-
- cx = (2 * cxBORDER) + g_cxRecord + g_cxRecnum + 2;
-
- if (lpChild->fHScroll) {
- if (lpChild->fVScroll)
- PatBlt(hdc,
- rc.right - g_cxVScroll + 2, rc.top,
- g_cxVScroll, g_cyHScroll,
- PATCOPY);
- }
- else
- PatBlt(hdc,
- rc.left + cx, rc.top,
- rc.right - rc.left, g_cyHScroll,
- PATCOPY);
-
- rc.right = rc.left + cx;
-
- PatBlt(hdc, rc.right, rc.top, 1, rc.bottom, BLACKNESS);
-
- rc.right--;
-
- // Paint current row number
- if (fRefresh)
- FillRect(hdc, &rc, g_hbrWin);
-
- rc.left += cxBORDER;
-
- TextOut(hdc, rc.left, rc.top, szRECORD, lstrlen(szRECORD));
-
- rc.left += g_cxRecord + 2;
-
- FillRect(hdc, &rc, g_hbrWin);
-
- wsprintf(lpChild->lpsz, szRECNUM, lpChild->irow-1 + lpChild->irowPos);
-
- TextOut(hdc, rc.left, rc.top, lpChild->lpsz, lstrlen(lpChild->lpsz));
-
- DeleteObject(hrgn);
-
- // Reset device context
- SelectObject(hdc, hbrOld);
-
- SelectObject(hdc, hfontOld);
- }
-
- return;
- }
-
-
-
- /* SetCurrentValue ---------------------------------------------------------
- Description: Set a column value from the user buffer
- --------------------------------------------------------------------------*/
- #pragma optimize("ceglntw", off)
- BOOL INTFUNC SetCurrentValue(LPSTR lpsz, LPCOL lpcol, LPCHILD lpChild)
- {
- LPBYTE lpb;
- LPSDWORD lpcb;
- BOOL fNew;
- UWORD irowPos;
-
- irowPos = lpChild->irowPos - 1;
-
- // Get data and count field pointers based on binding type
- if (ROW_BINDING(lpChild)) {
- lpb = lpcol->lpb + (irowPos * lpChild->cbrow);
- lpcb = (LPSDWORD)(lpb + lpcol->cb);
- }
- else {
- lpb = lpcol->lpb + (irowPos * lpcol->cb);
- lpcb = lpcol->lpcb + irowPos;
- }
-
- // If the data is NULL, just set the count field to SQL_NULL_DATA
- if (!lstrcmpi(lpsz, g_szNull)) {
- if (*lpcb != SQL_NULL_DATA) {
- *lpcb = SQL_NULL_DATA;
- fNew = TRUE;
- }
- }
-
- // Otherwise, convert the character data back to the appropriate type
- else switch (lpcol->fSqlType) {
-
- case SQL_CHAR:
- case SQL_VARCHAR:
- if (lstrcmp(lpsz, (LPSTR)lpb)) {
- lstrcpy((LPSTR)lpb, lpsz);
- *lpcb = lstrlen(lpsz);
- fNew = TRUE;
- }
- break;
-
- case SQL_INTEGER:
- case SQL_SMALLINT:
- case SQL_TINYINT: {
- long lNew, lCur;
- char *EndPtr;
-
- lNew = strtol(lpsz, &EndPtr, 10);
- for (; *EndPtr && ISWHITE(*EndPtr); EndPtr = AnsiNext(EndPtr));
- if (*EndPtr) { // check to see if there exists non-numeric chars
- UCHAR szBuffer[128];
-
- LoadString(g_hinst, IDS_BADNUMERIC, szBuffer, sizeof(szBuffer));
- MessageBox(lpChild->hwnd,
- szBuffer, NULL, MB_ICONSTOP);
- fNew = FALSE;
- break;
- }
-
- lCur = (lpcol->fSqlType == SQL_INTEGER
- ? *((DWORD FAR *)lpb)
- : lpcol->fSqlType == SQL_SMALLINT
- ? *((WORD FAR *)lpb)
- : *((UCHAR FAR *)lpb));
-
- if (lNew != lCur) {
-
- switch (lpcol->fSqlType) {
- case SQL_INTEGER:
- *((DWORD FAR *)lpb) = lNew;
- *lpcb = sizeof(DWORD);
- break;
-
- case SQL_SMALLINT:
- *((WORD FAR *)lpb) = (WORD)lNew;
- *lpcb = sizeof(WORD);
- break;
-
- case SQL_TINYINT:
- *((UCHAR FAR *)lpb) = (UCHAR)lNew;
- *lpcb = sizeof(UCHAR);
- break;
- }
-
- fNew = TRUE;
- }
- break;
- }
-
- case SQL_REAL:
- case SQL_FLOAT:
- case SQL_DOUBLE: {
- double dNew, dCur;
- char *EndPtr;
-
- dNew = strtod(lpsz, &EndPtr);
- for (; *EndPtr && ISWHITE(*EndPtr); EndPtr = AnsiNext(EndPtr));
- if (*EndPtr) { // check to see if there exists non-numeric chars
- UCHAR szBuffer[128];
-
- LoadString(g_hinst, IDS_BADNUMERIC, szBuffer, sizeof(szBuffer));
- MessageBox(lpChild->hwnd,
- szBuffer, NULL, MB_ICONSTOP);
- fNew = FALSE;
- break;
- }
-
- dCur = (lpcol->fSqlType == SQL_REAL
- ? *((float FAR *)lpb)
- : *((double FAR *)lpb));
-
- if (dNew != dCur) {
-
- switch (lpcol->fSqlType) {
- case SQL_REAL:
- *((float FAR *)lpb) = (float)dNew;
- *lpcb = sizeof(float);
- break;
-
- case SQL_FLOAT:
- case SQL_DOUBLE:
- *((double FAR *)lpb) = dNew;
- *lpcb = sizeof(double);
- break;
- }
-
- fNew = TRUE;
- }
- break;
- }
- }
-
- return fNew;
- }
- #pragma optimize("ceglntw", on)
-
-
- /* SetPos ------------------------------------------------------------------
- Description: Set current row, de-hilite last current row and hilite
- new current row
- --------------------------------------------------------------------------*/
- void INTFUNC SetPos(LPCHILD lpChild, UWORD irowPos)
- {
- HDC hdc;
- HFONT hfont;
- RECT rc, rcClip, rcInvert;
- int row, col;
- int cx, cy;
-
- if (!(lpChild->hrgn))
- return ;
-
- if (irowPos < 1)
- irowPos = 1;
-
- else if (irowPos > lpChild->crowRowset)
- irowPos = lpChild->crowRowset;
-
- // Call SQLSetPos to set current row in the row-set
- if (STMTError(SQLSetPos(lpChild->hstmt, irowPos, SQL_POSITION,
- SQL_LOCK_NO_CHANGE)))
- return;
-
- // Reset number of columns retrieved
- lpChild->ccolRetrieved = (UWORD)lpChild->ccol;
-
- // Obtain a device context for painting
- hdc = GetDC(lpChild->hwnd);
-
- row = GetScrollPos(lpChild->hwndVScroll, SB_CTL);
- col = GetScrollPos(lpChild->hwndHScroll, SB_CTL);
-
- cx = col * g_cx;
- cy = row * g_cy;
-
- SetWindowOrgEx(hdc, cx, cy, NULL);
-
- GetClientRect(lpChild->hwnd, &rc);
- GetRgnBox(lpChild->hrgn, &rcClip);
- OffsetRect(&rcClip, cx, cy);
-
- rcClip.top += g_cy;
-
- // Offset to last current row
- rc.top = ((lpChild->irowPos - 1) * g_cy) + g_cy;
- rc.bottom = rc.top + g_cy - 1;
- rc.left = 0;
- rc.right = *(lpChild->lpnTabs + lpChild->ccol) - cxBORDER;
-
- // De-hilite last current row
- IntersectRect(&rcInvert, &rc, &rcClip);
- InflateRect(&rcInvert, -1, -1);
- InvertRect(hdc, &rcInvert);
-
- // Save new current row
- lpChild->irowPos = irowPos;
-
- // Offset to new current row
- rc.top = ((lpChild->irowPos - 1) * g_cy) + g_cy;
- rc.bottom = rc.top + g_cy - 1;
-
- // Hilite current row (if visible)
- if (lpChild->irowPos > (UWORD)row) {
-
- IntersectRect(&rcInvert, &rc, &rcClip);
- InflateRect(&rcInvert, -1, -1);
- InvertRect(hdc, &rcInvert);
- }
-
- // Update record number
- GetClientRect(lpChild->hwnd, &rc);
- OffsetRect(&rc, cx, cy);
-
- rc.left += cxBORDER + g_cxRecord + 2;
- rc.top = rc.bottom - g_cyHScroll + 2;
- rc.right = rc.left + g_cxRecnum;
-
- FillRect(hdc, &rc, g_hbrWin);
-
- wsprintf(lpChild->lpsz, szRECNUM, lpChild->irow-1 + lpChild->irowPos);
-
- hfont = SelectObject(hdc, g_hfontData);
-
- TextOut(hdc, rc.left, rc.top, lpChild->lpsz, lstrlen(lpChild->lpsz));
-
- SelectObject(hdc, hfont);
-
- // Release device context
- ReleaseDC(lpChild->hwnd, hdc);
-
- return;
- }
-
-
- /* SetScroll ---------------------------------------------------------------
- Description: Determine if scroll bars are required and their ranges
- --------------------------------------------------------------------------*/
- void INTFUNC SetScroll(LPCHILD lpChild)
- {
- RECT rc;
- int cx, cy;
- int row, col;
-
- // Use the fInSetScroll flag to prevent recursion due WM_SIZE messages
- if (lpChild->fInSetScroll)
- return;
-
- lpChild->fInSetScroll = TRUE;
-
- // Save current scroll positions
- row = GetScrollPos(lpChild->hwndVScroll, SB_CTL);
- col = GetScrollPos(lpChild->hwndHScroll, SB_CTL);
-
- // Get window dimensions
- GetClientRect(lpChild->hwnd, &rc);
- cx = rc.right - rc.left;
- cy = rc.bottom - rc.top - g_cy - g_cyHScroll;
-
- // Assume no scrolling is required
- lpChild->fHScroll =
- lpChild->fVScroll = FALSE;
-
- // Include a vertical scroll bar if all rows do not fit
- lpChild->crowwin = cy / g_cy;
- if ((UWORD)lpChild->crowwin < lpChild->crowRowset) {
- lpChild->fVScroll = TRUE;
- cx -= g_cxVScroll;
- }
-
- // Include a horizontal scroll bar if all columns do not fit
- lpChild->ccolwin = cx / g_cx;
- if (lpChild->ccolwin < lpChild->ccols)
- lpChild->fHScroll = TRUE;
-
- // Reset scroll positions if no scrolling is necessary
- if (!lpChild->fVScroll) row = 0;
- if (!lpChild->fHScroll) col = 0;
-
- // Set scroll ranges, positions, and scroll bar visibility
- SetScrollRange(lpChild->hwndVScroll, SB_CTL, 0, lpChild->crowRowset - lpChild->crowwin, TRUE);
- SetScrollRange(lpChild->hwndHScroll, SB_CTL, 0, lpChild->ccols - lpChild->ccolwin, TRUE);
-
- SetScrollPos(lpChild->hwndVScroll, SB_CTL, row, TRUE);
- SetScrollPos(lpChild->hwndHScroll, SB_CTL, col, TRUE);
-
- ShowWindow(lpChild->hwndVScroll, (lpChild->fVScroll ? SW_SHOW : SW_HIDE));
- ShowWindow(lpChild->hwndHScroll, (lpChild->fHScroll ? SW_SHOW : SW_HIDE));
-
- // Add one extra to window depth so no white space is left between
- // the last full row and bottom record display bar
- lpChild->crowwin++;
-
- // Size and position scroll bars
- SizeScroll(lpChild);
-
- lpChild->fInSetScroll = FALSE;
-
- return;
- }
-
-
- /* SizeScroll --------------------------------------------------------------
- Description: Size and position scroll bars
- --------------------------------------------------------------------------*/
- void INTFUNC SizeScroll(LPCHILD lpChild)
- {
- RECT rc;
- int cxRecord;
-
- GetClientRect(lpChild->hwnd, &rc);
-
- // Place vertical scroll bar
- MoveWindow(lpChild->hwndVScroll,
- rc.right - g_cxVScroll + 1,
- rc.top,
- g_cxVScroll,
- rc.bottom - g_cyHScroll + 2,
- TRUE);
-
- // Place horizontal scroll bar
- cxRecord = (2 * cxBORDER) + g_cxRecord + g_cxRecnum + 2;
-
- MoveWindow(lpChild->hwndHScroll,
- rc.left + cxRecord,
- rc.bottom - g_cyHScroll + 1,
- (lpChild->fVScroll
- ? rc.right - g_cxVScroll + 2 - cxRecord
- : rc.right + 2 - cxRecord),
- g_cyHScroll,
- TRUE);
-
- return;
- }
-
-
- /* UpdateRow ---------------------------------------------------------------
- Description: Update current (positioned) row
- --------------------------------------------------------------------------*/
- void INTFUNC UpdateRow(LPCHILD lpChild)
- {
- HCURSOR hcur;
- LPSTR lpsz;
- LPSTR lpszT;
- SWORD cb;
- LPCOL lpcol;
- int cCtls;
- UWORD irowPos;
- int i;
-
- // Ensure the update request is valid
- if (!lpChild->fDataFetched) {
- DoMessage(lpChild->hwnd, IDS_NODATAFETCHED);
- return;
- }
-
- if (*(lpChild->lpfStatus + lpChild->irowPos - 1) == SQL_ROW_NOROW) {
- DoMessage(lpChild->hwnd, IDS_NOROWUPDATE);
- return;
- }
-
- if (*(lpChild->lpfStatus + lpChild->irowPos - 1) == SQL_ROW_ERROR) {
- DoMessage(lpChild->hwnd, IDS_ERRORROWUPDATE);
- return;
- }
-
- if (*(lpChild->lpfStatus + lpChild->irowPos - 1) == SQL_ROW_DELETED) {
- DoMessage(lpChild->hwnd, IDS_DELROWUPDATE);
- return;
- }
-
- if (lpChild->fConcurrency == SQL_CONCUR_READ_ONLY) {
- DoMessage(lpChild->hwnd, IDS_NOUPDATE);
- return;
- }
-
- // Count number of updateable columns
- for (cCtls=0, i=0, lpcol=lpChild->lpcol; i < lpChild->ccol; i++, lpcol++)
- if (IsUpdateable(lpcol->fSqlType))
- cCtls++;
-
- // Ensure a valid number of updateable columns exist
- if (cCtls > cMAXCOLS) {
- DoMessage(lpChild->hwnd, IDS_TOOMANYCOLS);
- return;
- }
-
- if (!cCtls) {
- DoMessage(lpChild->hwnd, IDS_CANNOTUPDATE);
- return;
- }
-
- hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
-
- lpsz = AllocPtr(2 * cbMAXSQL);
- lpszT = lpsz + cbMAXSQL;
-
- // Build and display update dialog to get new values, then issue update
- // (use a temporary SQLHSTMT for the update request)
- if (IDOK == DoDialog(lpChild->hwnd, IDD_UPDATEROW, UpdateDlgProc) &&
- !DBCError(lpChild->hwnd, SQLAllocHandle(SQL_HANDLE_STMT,g_hdbc, &lpChild->hstmtTmp))) {
-
- // Build UPDATE <table> WHERE CURRENT OF <cursor name> statement
- lstrcpy(lpsz, szUPDATE);
-
- GetTableName(lpszT, lpChild->sql);
- lstrcat(lpsz, lpszT);
-
- // Build the Set Clause
- lstrcat(lpsz, szSET);
- for (lpcol = lpChild->lpcol, i = 0; i < lpChild->ccol; i++, lpcol++) {
- if (IsUpdateable(lpcol->fSqlType)) {
- LPSDWORD lpcb;
- LPBYTE lpb;
-
- if (i == 0) wsprintf(lpszT, "%s=?", lpcol->szName);
- else wsprintf(lpszT, ",%s=?", lpcol->szName);
- lstrcat(lpsz, lpszT);
-
- irowPos = lpChild->irowPos - 1;
-
- // Get data and count field pointers based on binding type
- if (ROW_BINDING(lpChild)) {
- lpb = lpcol->lpb + (irowPos * lpChild->cbrow);
- lpcb = (LPSDWORD)(lpb + lpcol->cb);
- }
- else {
- lpb = lpcol->lpb + (irowPos * lpcol->cb);
- lpcb = lpcol->lpcb + irowPos;
- }
-
- // set parameter
- ODBCError(lpChild->hwnd, SQL_HANDLE_STMT, lpChild->hstmtTmp,
- SQLSetParam(lpChild->hstmtTmp, (UWORD) (i+1), lpcol->fCType,
- lpcol->fSqlType, (UDWORD) lpcol->cb, (SWORD) 0,
- lpb, lpcb));
- }
- }
-
- lstrcat(lpsz, szWHERE);
-
- lpszT = lpsz + lstrlen(lpsz);
-
- if (!STMTError(SQLGetCursorName(lpChild->hstmt, (UCHAR FAR *)lpszT,
- cbMAXSQL, &cb))) {
-
- // Issue update request via SQLExecDirect
- ODBCError(lpChild->hwnd, SQL_HANDLE_STMT, lpChild->hstmtTmp,
- SQLExecDirect(lpChild->hstmtTmp, (UCHAR FAR *)lpsz, SQL_NTS));
- }
-
- DBCError(lpChild->hwnd, SQLFreeHandle(SQL_HANDLE_STMT,lpChild->hstmtTmp));
- lpChild->hstmtTmp = SQL_NULL_HSTMT;
-
- }
-
- // Refresh entire row-set buffer (saving current row position)
- irowPos = lpChild->irowPos;
-
- lpChild->FetchOP = SQL_FETCH_RELATIVE;
- lpChild->rrow = 0;
- Fetch(lpChild);
-
- SetPos(lpChild, irowPos);
-
- // Repaint the row-set
- InvalidateRect(lpChild->hwnd, NULL, FALSE);
-
- FreePtr(lpsz);
-
- SetCursor(hcur);
-
- return;
- }
-
- /*--------------------------------------------------------------------
- Input: lpChild
- Output: TRUE if the option parameters are valid, FALSE otherwise
- --------------------------------------------------------------------*/
- BOOL INTFUNC ParamValid(LPCHILD lpChild)
- {
- char szBuffer[128]; // error message
- char *EndMaxBind, *EndRowset, *EndBind;
-
- // the maximum column width
- wsprintf((LPSTR) szBuffer,
- "Maximum column width must be at least 1 and at most %d",
- MAX_MAXBIND);
-
- if (lpChild->fMaxBind) { // it's been changed
- lpChild->crowMaxBind =
- (SDWORD) strtol((char*) lpChild->szMaxBind, &EndMaxBind, 10);
- for (; *EndMaxBind && ISWHITE(*EndMaxBind);
- EndMaxBind = AnsiNext(EndMaxBind));
- }
-
- if (lpChild->fBind) { // cBind has been changed
- lpChild->cBind = (UWORD) strtol((char*) lpChild->szBind, &EndBind, 10);
- for (; *EndBind && ISWHITE(*EndBind); EndBind = AnsiNext(EndBind));
- }
-
- if (lpChild->fRowset) { // rowset has been changed
- lpChild->crowRowset =
- (UWORD) strtol((char*) lpChild->szRowset, &EndRowset, 10);
- for (; *EndRowset && ISWHITE(*EndRowset);
- EndRowset = AnsiNext(EndRowset));
- }
-
- while (lpChild->fMaxBind && *EndMaxBind ||
- lpChild->crowMaxBind < 1 ||
- lpChild->crowMaxBind > MAX_MAXBIND ||
- lpChild->fRowset && *EndRowset ||
- lpChild->crowRowset < 1 ||
- lpChild->crowRowset > 4096 ||
- lpChild->fBind && *EndBind) {
-
- // the maximum column width
- if (lpChild->crowMaxBind < 1 || lpChild->crowMaxBind > MAX_MAXBIND
- || lpChild->fMaxBind && *EndMaxBind)
- MessageBox(lpChild->hwnd, szBuffer, NULL, MB_ICONSTOP);
-
- // the rowset size
- if (lpChild->crowRowset < 1 || lpChild->crowRowset > 4096
- || lpChild->fRowset && *EndRowset) {
- char szBuffer[128];
-
- LoadString(g_hinst, IDS_BADROWSET, szBuffer, sizeof(szBuffer));
- MessageBox(lpChild->hwnd, szBuffer, NULL, MB_ICONSTOP);
- }
-
- // number of bound columns
- if (lpChild->fBind && *EndBind)
- MessageBox(lpChild->hwnd,
- "Invalid number of bound columns", NULL, MB_ICONSTOP);
-
- if (IDOK != DoDialog(lpChild->hwnd, IDD_OPTION_DIALOG, OptionsDlgProc))
- return FALSE;
-
- if (lpChild->fMaxBind) { // it's been changed
- lpChild->crowMaxBind =
- (SDWORD) strtol((char*) lpChild->szMaxBind, &EndMaxBind, 10);
- for (; *EndMaxBind && ISWHITE(*EndMaxBind);
- EndMaxBind = AnsiNext(EndMaxBind));
- }
-
- if (lpChild->fBind) { // cBind has been changed
- lpChild->cBind =
- (UWORD) strtol((char*) lpChild->szBind, &EndBind, 10);
-
- for (; *EndBind && ISWHITE(*EndBind); EndBind = AnsiNext(EndBind));
- }
-
- if (lpChild->fRowset) { // rowset has been changed
- lpChild->crowRowset =
- (UWORD) strtol((char*) lpChild->szRowset, &EndRowset, 10);
- for (; *EndRowset && ISWHITE(*EndRowset);
- EndRowset = AnsiNext(EndRowset));
- }
- }
-
- return TRUE;
-
- }