CRSRDEMO.C
/*-------------------------------------------------------------------------- 
  Crsrdemo.C --- Cursors main file 
 
  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. 
 
    CRSRDEMO.C contains the standard functions used in a Windows program 
    (such as, WinMain) plus two functions shared between all the files. 
    These functions are: 
 
      DoMessage       - Issue a message 
      EndInstance     - Clean up an instance of this program 
      InitApplication - Prepare the first instance of this program 
      InitInstance    - Prepare an instance of this program 
      ODBCError       - Retrieve and display an ODBC error 
      WinMain         - Main Windows entry point 
 
    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) 
#define  INCL_GLOBAL 
#include    "resource.h" 
#include "crsrdemo.h" 
 
 
// Prototypes -------------------------------------------------------------- 
void INTFUNC EndInstance(void); 
BOOL INTFUNC InitApplication(void); 
BOOL INTFUNC InitInstance(int); 
int  INTFUNC WinMain(HINSTANCE, HINSTANCE, LPSTR, int); 
 
 
/* DoMessage --------------------------------------------------------------- 
   Description: Issue a message 
   --------------------------------------------------------------------------*/ 
void INTFUNC DoMessage(HWND hwnd, UINT id) 
{ 
   char  sz[cbSTRLEN]; 
 
   LoadString(g_hinst, id, sz, sizeof(sz)); 
   MessageBox(hwnd, sz, g_szTITLE, MB_ICONINFORMATION | MB_OK); 
   return; 
} 
 
 
/* EndInstance ------------------------------------------------------------- 
   Description: Free instance related data 
   --------------------------------------------------------------------------*/ 
void INTFUNC EndInstance(void) 
{ 
   if (g_hfontName)  DeleteObject(g_hfontName); 
   if (g_hfontData)  DeleteObject(g_hfontData); 
 
   if (g_hbrWin)     DeleteObject(g_hbrWin); 
   if (g_hbrBtn)     DeleteObject(g_hbrBtn); 
   if (g_hbrScroll)  DeleteObject(g_hbrScroll); 
 
   return; 
} 
 
 
/* InitApplication --------------------------------------------------------- 
   Description: Prepare application by registering window classes 
   --------------------------------------------------------------------------*/ 
BOOL INTFUNC InitApplication(void) 
{ 
   WNDCLASS  wc; 
 
   wc.style         = CS_HREDRAW | CS_VREDRAW; 
   wc.lpfnWndProc   = FrameProc; 
   wc.cbClsExtra    = 0; 
   wc.cbWndExtra    = 0; 
   wc.hInstance     = g_hinst; 
   wc.hIcon         = LoadIcon(g_hinst, MAKEINTRESOURCE(IDR_MAIN)); 
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW); 
   wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); 
   wc.lpszMenuName  = NULL; 
   wc.lpszClassName = szFRAMECLASS; 
 
   if (!RegisterClass(&wc)) 
      return FALSE; 
 
   wc.style         = CS_HREDRAW | CS_VREDRAW; 
   wc.lpfnWndProc   = ChildProc; 
   wc.cbClsExtra    = 0; 
   wc.cbWndExtra    = sizeof(LPCHILD); 
   wc.hInstance     = g_hinst; 
   wc.hIcon         = LoadIcon(g_hinst, MAKEINTRESOURCE(IDR_CHILD)); 
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW); 
   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
   wc.lpszMenuName  = NULL; 
   wc.lpszClassName = szCHILDCLASS; 
 
   if (!RegisterClass(&wc)) 
      return FALSE; 
 
   return TRUE; 
} 
 
 
/* InitInstance ------------------------------------------------------------ 
   Description: Prepare instance by initializing global variables and 
                creating main frame window 
                --------------------------------------------------------------------------*/ 
BOOL INTFUNC InitInstance(int nCmdShow) 
{ 
   RECT     rc; 
   HDC         hdc; 
   HFONT    hfont; 
   TEXTMETRIC  tm; 
   char     sz[cbSTRLEN]; 
   SIZE        size; 
 
   // Initialize global variables 
   g_hwnd       = 
      g_hwndClient = NULL; 
 
   g_haccel     = NULL; 
 
   g_hmenuInit        = 
      g_hmenuInitWindow  = 
         g_hmenuFrame       = 
            g_hmenuFrameWindow = 
               g_hmenuChild       = 
                  g_hmenuChildWindow = NULL; 
 
   g_hfontName = 
      g_hfontData = NULL; 
 
   g_hbrWin    = 
      g_hbrBtn    = 
         g_hbrScroll = NULL; 
 
   g_henv = SQL_NULL_HENV; 
   g_hdbc = SQL_NULL_HDBC; 
 
   g_haccel = LoadAccelerators(g_hinst, MAKEINTRESOURCE(IDR_MAIN)); 
 
   g_hmenuInit  = LoadMenu(g_hinst, MAKEINTRESOURCE(IDR_INIT)); 
   g_hmenuFrame = LoadMenu(g_hinst, MAKEINTRESOURCE(IDR_MAIN)); 
   g_hmenuChild = LoadMenu(g_hinst, MAKEINTRESOURCE(IDR_CHILD)); 
 
   g_hmenuInitWindow  = GetSubMenu(g_hmenuInit,  IDM_WINDOWINIT); 
   g_hmenuFrameWindow = GetSubMenu(g_hmenuFrame, IDM_WINDOWFRAME); 
   g_hmenuChildWindow = GetSubMenu(g_hmenuChild, IDM_WINDOWCHILD); 
 
   g_cxVScroll = GetSystemMetrics(SM_CXVSCROLL); 
   g_cyHScroll = GetSystemMetrics(SM_CYHSCROLL); 
 
   LoadString(g_hinst, IDS_TABLE,      g_szTable,      sizeof(g_szTable)); 
   LoadString(g_hinst, IDR_MAIN,       g_szTITLE,      sizeof(g_szTITLE)); 
   LoadString(g_hinst, IDS_NOROW,      g_szNoRow,      sizeof(g_szNoRow)); 
   LoadString(g_hinst, IDS_ROWERROR,   g_szRowError,  sizeof(g_szRowError)); 
   LoadString(g_hinst, IDS_NULL,       g_szNull,       sizeof(g_szNull)); 
   LoadString(g_hinst, IDS_ROWDELETED, g_szRowDeleted, sizeof(g_szRowDeleted)); 
   LoadString(g_hinst, IDS_UNKNOWN,    g_szUnknown,    sizeof(g_szUnknown)); 
 
   // Create main window in upper 3/4 of desktop 
   GetWindowRect(GetDesktopWindow(), &rc); 
 
   g_hwnd = CreateWindow(szFRAMECLASS, 
                         g_szTITLE, 
                         WS_OVERLAPPEDWINDOW, 
                         rc.left, 
                         rc.top, 
                         rc.right - rc.left, 
                         ((rc.bottom - rc.top) / 4) * 3, 
                         HWND_DESKTOP, 
                         g_hmenuInit, 
                         g_hinst, 
                         NULL); 
   if (!g_hwnd) 
      return FALSE; 
 
   // Create fonts used in painting child windows 
   hdc = GetDC(g_hwnd); 
 
   g_hfontName = CreateFont((GetDeviceCaps(hdc, LOGPIXELSY) * cPOINTS) / 72, 
                            0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, 
                            szFONT); 
 
   hfont = SelectObject(hdc, g_hfontName); 
 
   GetTextMetrics(hdc, &tm); 
   g_cx = tm.tmMaxCharWidth; 
   g_cy = tm.tmHeight + tm.tmInternalLeading; 
 
   g_hfontData = CreateFont((GetDeviceCaps(hdc, LOGPIXELSY) * cPOINTS) / 72, 
                            0, 0, 0, FW_NORMAL, 0, 0, 0, 0, 0, 0, 0, 0, 
                            szFONT); 
 
   SelectObject(hdc, g_hfontData); 
 
   // Determine font size characteristics 
   GetTextMetrics(hdc, &tm); 
   g_cx = max(g_cx, tm.tmMaxCharWidth); 
   g_cy = max(g_cy, tm.tmHeight + tm.tmInternalLeading); 
 
   GetTextExtentPoint(hdc, szRECORD, lstrlen(szRECORD), &size); 
   g_cxRecord = size.cx; 
 
   wsprintf(sz, szRECNUM, 999999); 
 
   GetTextExtentPoint(hdc, sz, lstrlen(sz), &size); 
   g_cxRecnum = size.cx; 
 
   SelectObject(hdc, hfont); 
 
   ReleaseDC(g_hwnd, hdc); 
 
   // Allocate brushes 
   g_hbrWin    = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); 
   g_hbrBtn    = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); 
   g_hbrScroll = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR)); 
 
   // Allocate ODBC environment and connection handles; register as a 3.0 app 
   if (ENVError(g_hwnd, SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HENV,&g_henv))) 
      return FALSE; 
   if (ENVError(g_hwnd, SQLSetEnvAttr(g_henv, SQL_ATTR_ODBC_VERSION, 
                                      (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER))) 
      return FALSE; 
   if (ENVError(g_hwnd, SQLAllocHandle(SQL_HANDLE_DBC,g_henv, &g_hdbc))) 
      return FALSE; 
 
   // Always use the cursor library 
   if (DBCError(g_hwnd, SQLSetConnectAttr(   g_hdbc, 
                                          SQL_ATTR_ODBC_CURSORS, 
                                          (void *)SQL_CUR_USE_ODBC,0))) { 
      return FALSE; 
   } 
 
 
 
 
   // Complete variable initialization 
   g_cbName          = 0; 
   g_fConnected      = FALSE; 
   g_fAsyncSupported = FALSE; 
   g_szDSN[0]        = '\0'; 
   g_cChild          = 0; 
   g_cCursor         = 0; 
 
   g_mrows      = 1000; 
 
   g_hwndClient = GetWindow(g_hwnd, GW_CHILD); 
 
   // Set initial menu state 
   AdjustMenus(); 
 
   // Show frame window 
   ShowWindow(g_hwnd, nCmdShow); 
   UpdateWindow(g_hwnd); 
   return TRUE; 
} 
 
 
/* ODBCError --------------------------------------------------------------- 
   Description: Fetch and display an ODBC error message 
                NOTE: SQL_NO_DATA and SQL_STILL_EXECUTING are 
                      not considered errors 
                      --------------------------------------------------------------------------*/ 
BOOL INTFUNC ODBCError(HWND hwnd, SWORD fHandleType, SQLHANDLE handle, SQLRETURN rc) 
{ 
   if (rc == SQL_SUCCESS) 
      return FALSE; 
 
   if (rc == SQL_NO_DATA) { 
      DoMessage(hwnd, IDS_NODATAFOUND); 
      return FALSE; 
   } 
 
   if (rc == SQL_STILL_EXECUTING) { 
      DoMessage(hwnd, IDS_STILLEXEC); 
      return FALSE; 
   } 
 
   { 
      SDWORD   fNative; 
      SWORD cbError; 
      LPSTR lpszFmt; 
      LPSTR lpszSQLState; 
      LPSTR lpszError; 
      LPSTR lpsz; 
      SWORD sMsgNum = 1; 
 
      // Allocate storage 
      lpsz = AllocPtr(1024 + cbSTRLEN + 6 + SQL_MAX_MESSAGE_LENGTH); 
 
      lpszFmt      = lpsz + 1024; 
      lpszSQLState = lpszFmt + cbSTRLEN; 
      lpszError    = lpszSQLState + 6; 
      LoadString(g_hinst, IDS_MSGFMT, lpszFmt, cbSTRLEN); 
 
      // sometimes handle comes in as NULL 
      if (handle) { 
         // Retrieve and display errors until there are no more 
         while (SQLGetDiagRec(fHandleType, handle, sMsgNum++, 
                              (UCHAR FAR *)lpszSQLState, 
                              &fNative, 
                              (UCHAR FAR *)lpszError, 
                              SQL_MAX_MESSAGE_LENGTH-1, 
                              &cbError) != SQL_NO_DATA) { 
            if (lstrcmpi(lpszSQLState, szDATATRUNC)) { 
               wsprintf(lpsz, lpszFmt, lpszSQLState, fNative, lpszError); 
 
               MessageBox(hwnd, lpsz, g_szTITLE, 
                          strncmp(lpszSQLState, "01", 2) 
                          ? MB_ICONSTOP | MB_OK 
                          : MB_ICONINFORMATION | MB_OK); 
            } 
         } 
      } 
      else { 
         MessageBox(hwnd, "Invalid handle", g_szTITLE, 
                    MB_ICONSTOP | MB_OK); 
      } 
 
      // Free storage 
      FreePtr(lpsz); 
   } 
 
   return (!SUCCESS(rc)); 
} 
 
 
/* WinMain ----------------------------------------------------------------- 
   Description: Standard WinMain function 
   --------------------------------------------------------------------------*/ 
int INTFUNC WinMain(HINSTANCE   hinstCur, 
                    HINSTANCE   hinstPrev, 
                    LPSTR       lpszCmdLine, 
                    int         nCmdShow) 
{ 
   MSG msg; 
 
   UNREF_PARAM(lpszCmdLine); 
   g_hinst = hinstCur; 
 
   if (!hinstPrev) 
      if (!InitApplication()) 
         return (FALSE); 
 
   if (!InitInstance(nCmdShow)) { 
      EndInstance(); 
      return (FALSE); 
   } 
 
   while (GetMessage(&msg, (HWND)NULL, (UINT)NULL, (UINT)NULL)) 
      if (!TranslateMDISysAccel(g_hwndClient, &msg) && 
          !TranslateAccelerator(g_hwnd, g_haccel, &msg) && 
          (!(g_hwndChildDialog) || (!IsDialogMessage(g_hwndChildDialog, &msg)))) { 
         TranslateMessage(&msg); 
         DispatchMessage(&msg); 
      } 
 
   EndInstance(); 
 
   return msg.wParam; 
}