MAIN.C

/* 
PROGRAM: QURYDEMO
========

PURPOSE:
========
demonstrates a simple MDI application that allows a user to
simultaneously connect to multiple hetrogeneous databases
and perform SQL queries to get results.

FUNCTIONS:
==========
WinMain() - main routine
MainWndProc() - processes Main Application Window messages
MDIChildProc() - processes MDI child window messages
ToolbarProc() - processes tool bar messages
StatusbarProc() - processes Status bar messages
ConnectDlgProc() - processes Connection Dialog box messages
DisconnectDlgProc() - processes Disconnect Dialog box messages
AboutDlgProc() - processes messages for About dialog box
MDIChildDlgProc() - processes messages for dummy child dialog box
in MDI child window
DrawBitmap() - draws bitmaps for toolbuttons

COMMENTS:
=========
Created by Microsoft Corporation.
*/

#include <stdio.h>
#include <string.h>
#include <time.h>

#include <windows.h>
#ifdef WIN32
#include <windowsx.h>
#else
#include "w16macro.h"
#endif
#include "qurydemo.h"

CONSTSTR(szKeyWord, "query demo, features");


/*
FUNCTION: WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
COMMENTS: Application Entry Routine.
Register Classes. Create Main Window and MDI Child Window.
Process Main Message Loop.
*/

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; //msg structure
WNDCLASS wc; //class structure
HICON hMainIcon; //App Icon
HICON hMDIChildIcon; //MDI Child Icon
HWND hWndMDIChild; //temp MDI Child Window Handle
char szBuffer[MAXBUFLEN+1]; //temp string buffer to check class name
BOOL bDialogMessage = FALSE; //temp boolean to check dilogbox msgs
HACCEL hAccel; //accelerator table handle

hAppInstance = hInstance;

// check if application is already running, if
// so make it active and bring it in focus

if (hWndFrame = FindWindow(ODBCFRAMECLASS, NULL)) {
hWndFrame = GetLastActivePopup(hWndFrame);
if (IsIconic(hWndFrame))
OpenIcon(hWndFrame);
else
BringWindowToTop(hWndFrame);
ACTIVATEWINDOW(hWndFrame);
return (FALSE);
}

// initialize ODBC Driver Manager Interface

if (!InitSQLEnvironment()) {
MessageBox(hWndFrame, INITERROR, EXECERROR, MB_OK|MB_ICONHAND);
return (FALSE);
}

// register window classes for the application - Main Window Class

wc.style = 0;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hAppInstance;
wc.hIcon = hMainIcon = LoadIcon(hAppInstance, APPICON);
wc.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
wc.lpszMenuName = QURYDEMOMENU;
wc.lpszClassName = ODBCFRAMECLASS;

if (!RegisterClass(&wc)) {
MessageBox(hWndFrame, CLASSERROR, EXECERROR, MB_OK|MB_ICONHAND|MB_TASKMODAL);
return (FALSE);
}

// register Toolbar Class

wc.hIcon = (HICON)NULL;
wc.lpszMenuName = NULL;
wc.lpfnWndProc = ToolbarProc;
wc.lpszClassName = ODBCTOOLCLASS;

if (!RegisterClass(&wc)) {
MessageBox(hWndFrame, CLASSERROR, EXECERROR, MB_OK|MB_ICONHAND|MB_TASKMODAL);
return (FALSE);
}

// register Statusbar Class

wc.lpfnWndProc = StatusbarProc;
wc.lpszClassName = ODBCSTATUSCLASS;

if (!RegisterClass(&wc)) {
MessageBox(hWndFrame, CLASSERROR, EXECERROR, MB_OK|MB_ICONHAND|MB_TASKMODAL);
return (FALSE);
}

// register MDI Child Window Class

wc.hIcon = hMDIChildIcon = LoadIcon(hAppInstance, QUERYWINDOWICON);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.cbWndExtra = CBWNDEXTRA;
wc.lpszClassName = ODBCMDICLASS;
wc.lpfnWndProc = MDIChildProc;

if (!RegisterClass(&wc)) {
MessageBox(hWndFrame, CLASSERROR, EXECERROR, MB_OK|MB_ICONHAND|MB_TASKMODAL);
return (FALSE);
}

// create Main window and the MDI Client window

if (!(hWndFrame = CreateWindow(ODBCFRAMECLASS, APPTITLE, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
(HWND)NULL, (HMENU)NULL, hAppInstance, NULL))) {
MessageBox(hWndFrame, CREATEMAINERR, EXECERROR, MB_OK|MB_ICONHAND|MB_TASKMODAL);
return (FALSE);
}

ShowWindow(hWndFrame, nCmdShow);
UpdateWindow(hWndFrame);

// load accelerators

hAccel = LoadAccelerators(hAppInstance, APPACCELERATOR);

// acquire and dispatch messages until a WM_QUIT message is received

while (GetMessage(&msg, (HWND)NULL, 0, 0)) {

// check for App accelerators

if (TranslateAccelerator(hWndFrame, hAccel, &msg))
continue;

// check for MDI accelerators

if (TranslateMDISysAccel(hWndMDIClient, &msg))
continue;

// each MDI Child has a modeless dialog in its client area
// to provide tab controls. Check for Modeless Dialog msgs.

for (hWndMDIChild = GetWindow(hWndMDIClient, GW_CHILD); hWndMDIChild; hWndMDIChild = GetWindow(hWndMDIChild, GW_HWNDNEXT)) {
GetClassName(hWndMDIChild, szBuffer, MAXBUFLEN);
if (strcmp(szBuffer, ODBCMDICLASS))
continue;
if (IsDialogMessage((HWND)GetWindowLong(hWndMDIChild, GWLAPP_HDLG), &msg)) {
bDialogMessage = TRUE;
break;
}
}

if (bDialogMessage) {
bDialogMessage = FALSE;
continue;
}

// if the message does not need special processing, dispatch it

TranslateMessage(&msg);
DispatchMessage(&msg);
}

// free memory used by ODBC Driver Manager interface

FreeSQLEnvironment();


// free Icon resources

if (hMainIcon)
DestroyIcon(hMainIcon);

if (hMDIChildIcon)
DestroyIcon(hMDIChildIcon);

return (msg.wParam);
}

/*
FUNCTION: MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: Windows Callback procedure to handle Window messages.
Menu Commands and System Command messages are handled by
this main window.
*/

long CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
static int iToolY; //remember Toolbar height for resize
static int iStatusY; //remember Statusbar height for resize

case WM_CREATE:
{
CLIENTCREATESTRUCT ccs; //MDIclient window structure
HDC hDC; //Device Context handle
SIZE sizeBar; //Size of a text bar
RECT rectCombo; //Size of combo box

// Create child windows
//1. combobox to display connections - DSN, SQLHDBC
//2. combobox to display SQLHSTMT on current SQLHDBC
//3. Toolbar to put toolbuttons
//4. Statusbat to display current action, date and time
//5. MDI Client Window to process MDI children

hWndCrsrList = CreateWindow(COMBOBOXCLASS, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
WS_VSCROLL | CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL,
5, 2, 180, 150, hWnd,
(HMENU)IDW_CRSRLIST, hAppInstance, NULL);

hWndStmtList = CreateWindow(COMBOBOXCLASS, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
WS_VSCROLL | CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL,
190, 2, 150, 150, hWnd,
(HMENU)IDW_STMTLIST, hAppInstance, NULL);

hWndToolbar = CreateWindow(ODBCTOOLCLASS, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
0, 0, 0, 0, hWnd, (HMENU)IDW_TOOLBAR, hAppInstance, NULL);

hWndStatusbar = CreateWindow(ODBCSTATUSCLASS, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
0, 0, 0, 0, hWnd, (HMENU)IDW_STATUSBAR, hAppInstance, NULL);

ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd), WINDOWMENUPLACE);
ccs.idFirstChild = IDM_MDICHILD;

hWndMDIClient = CreateWindow(MDICLIENTCLASS, NULL,
WS_CHILD | WS_CLIPSIBLINGS |
WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
0, 0, 0, 0, hWnd,
(HMENU)IDW_MDICLIENT, hAppInstance, (LPSTR)&ccs);

// check to see if any of the above window creation failed

if (!hWndCrsrList || !hWndStmtList || !hWndToolbar || !hWndStatusbar || !hWndMDIClient) {
MessageBox(hWnd, CREATEMAINERR, EXECERROR, MB_OK|MB_ICONHAND|MB_TASKMODAL);
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
// calculate proper text height for tool and status bars

GetWindowRect(hWndStmtList, &rectCombo);
iToolY = rectCombo.bottom - rectCombo.top + TOOLBARMARGINY;

if (hDC = GetDC(hWndStatusbar)) {
GetTextExtentPoint(hDC, ALPHABETS, strlen(ALPHABETS), &sizeBar);
ReleaseDC(hWndStatusbar, hDC);
iStatusY = sizeBar.cy + STATUSBARMARGINY;
}
else {
iStatusY = 0;
DestroyWindow(hWndStatusbar);
}

break;
}

case WM_GETMINMAXINFO:

// limit minimum size of the main window

((MINMAXINFO FAR*)lParam)->ptMinTrackSize.x =
max(MINWIDTH, rectStatusText.right-rectStatusText.left+iTimex+iDatex+14);
((MINMAXINFO FAR*)lParam)->ptMinTrackSize.y = MINHEIGHT;
break;

case WM_SIZE: // resize children
{
WORD wWidth = LOWORD(lParam); //width of rectangle
WORD wHeight = HIWORD(lParam); //height of rectangle

MoveWindow(hWndToolbar, 0, 0, wWidth, iToolY, TRUE);
MoveWindow(hWndStatusbar, 0, wHeight-iStatusY, wWidth, iStatusY, TRUE);
InvalidateRect(hWndStatusbar, NULL, TRUE);
MoveWindow(hWndMDIClient, 0, iToolY, wWidth, wHeight-iStatusY-iToolY, TRUE);
break;
}

case WM_SYSCOLORCHANGE: // inform 3D controls of color change

// Ctl3dColorChange();
break;

case WM_SYSCOMMAND: // close comboboxes if dropped down

SendMessage(hWndCrsrList, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
SendMessage(hWndStmtList, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
return (DefFrameProc(hWnd, hWndMDIClient, message, wParam, lParam));

case WM_INITMENUPOPUP: // initialize popup menus
{
int iMenuId; //Menu ID being processed
int nItems; //# of menu items
int nPos; //Menu Position

//ignore the msg if it is for a system menu

if (HIWORD(lParam))
break;

// Go through the menu items for current popup menu
// and enable/disable menu item, if required

nItems = GetMenuItemCount((HMENU)wParam);
for (nPos = 0; nPos < nItems; nPos++)
switch (iMenuId = GetMenuItemID((HMENU)wParam, nPos)) {
case IDM_DISCONNECT:
case IDM_NEW:

EnableMenuItem((HMENU)wParam, iMenuId, MF_BYCOMMAND|
((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) > 0)
? MF_ENABLED
: MF_GRAYED));
break;

case IDM_QUERY:
case IDM_TILE:
case IDM_CASCADE:
case IDM_ICONS:
case IDM_CLOSEALL:

EnableMenuItem((HMENU)wParam, iMenuId, MF_BYCOMMAND|
(GetWindow(hWndMDIClient, GW_CHILD)
? MF_ENABLED
: MF_GRAYED));
break;

default:

break;
}
break;
}

case WM_MENUSELECT: // update status bar to reflect menu selection
{
int iMenuFlag; //Check menu type
HMENU hMenu; //Menu Handle
char szMenuName[MAXBUFLEN+1];//Menu Name

// store Menuitem ID as a state value for text display

wStatusText = GET_WM_MENUSELECT_CMD(wParam, lParam);

// process popup menus ie non menuitem selections

iMenuFlag = GET_WM_MENUSELECT_FLAGS(wParam, lParam);

// if the selected menu is a system popup menu

if (wStatusText && (iMenuFlag & MF_SYSMENU) && (iMenuFlag & MF_POPUP))
wStatusText = IDM_POPUPAPPSYS;

// else if the selected menu is a popup menu check menu names
// OR check if it is a control popup menu of maximized MDI Child window

else if (wStatusText && (iMenuFlag & MF_POPUP)) {
hMenu = (HMENU)wStatusText;
GetMenuString(hMenu, 0, szMenuName, MAXBUFLEN, MF_BYPOSITION);
if (!strcmp(szMenuName, MENUITEMCONNECT))
wStatusText = IDM_POPUPLOGIN;
else if (!strcmp(szMenuName, MENUITEMQUERY))
wStatusText = IDM_POPUPQUERY;
else if (!strcmp(szMenuName, MENUITEMTILE))
wStatusText = IDM_POPUPWINDOW;
else if (!strcmp(szMenuName, MENUITEMAPPHELP))
wStatusText = IDM_POPUPHELP;
else if (GetMenuString(hMenu, SC_NEXTWINDOW, szMenuName, MAXBUFLEN, MF_BYCOMMAND)>0)
wStatusText = IDM_POPUPMDISYS;
else
wStatusText = 0;
}

// invalidate status bar for repaint

InvalidateRect(hWndStatusbar, &rectStatusText, TRUE);
break;
}

case WM_COMMAND: // process menu commands

switch (GET_WM_COMMAND_ID(wParam, lParam)) {

case IDM_CONNECT: // bring up connect dialog & do connect processing

DialogBox(hAppInstance, CONNECTDIALOG, hWnd,ConnectDlgProc);
break;

case IDM_DRIVERCONNECT: // let the driver do the dialogs

DriverConnectDatabase(hWnd);
break;

case IDM_DISCONNECT: // bringup disconnect dlg and do disconnects

DialogBox(hAppInstance, DISCONNECTDIALOG, hWnd,DisconnectDlgProc);
break;

case IDM_QUERY: // process execute query request

ExecuteQuery();
break;

case IDM_EXIT: // process exit request

SendMessage(hWndFrame, WM_CLOSE, 0, 0);
break;

case IDM_NEW: // create a new query window on current connect

NewQueryWindow();
break;

case IDM_TILE: // let MDI Client tile the MDI children

SendMessage(hWndMDIClient, WM_MDITILE, 0, 0);
break;

case IDM_CASCADE: // let MDI Client cascade MDI children

SendMessage(hWndMDIClient, WM_MDICASCADE, 0, 0);
break;

case IDM_ICONS: // let MDI Client arrange iconic MDI children

SendMessage(hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
break;

case IDM_CLOSEALL: // Close all open windows and free hstmts
{
HWND hWndTemp; //temp window handle

// hide MDI Client Windows to avoid repaints

ShowWindow(hWndMDIClient,SW_HIDE);
while (hWndTemp = GetWindow(hWndMDIClient, GW_CHILD))
SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndTemp, 0);
ShowWindow(hWndMDIClient, SW_SHOW);
break;
}

case IDM_APPHELP: // bring up Samples Help file

WinHelp(hWnd, SAMPLESHELPFILE, HELP_KEY,(DWORD)(LPTSTR)szKeyWord);
break;

case IDM_ABOUT: // bringup About dialog

DialogBox(hAppInstance, ABOUTDIALOG, hWnd, AboutDlgProc);
break;

case IDW_CRSRLIST: // change current cursor ?

if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
ChangeCurrentCursor(GET_WM_COMMAND_HWND(wParam, lParam));
else if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_KILLFOCUS)
PostMessage(GET_WM_COMMAND_HWND(wParam, lParam), CB_SHOWDROPDOWN,
(WPARAM)FALSE, 0);
else
DefFrameProc(hWnd, hWndMDIClient, WM_COMMAND, wParam, lParam);
break;

case IDW_STMTLIST: // change current hstmt?

if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
ChangeCurrentQuery(GET_WM_COMMAND_HWND(wParam, lParam));
else if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_KILLFOCUS)
PostMessage(GET_WM_COMMAND_HWND(wParam, lParam), CB_SHOWDROPDOWN,
(WPARAM)FALSE, 0);
else
DefFrameProc(hWnd, hWndMDIClient, WM_COMMAND, wParam, lParam);
break;

default:

DefFrameProc(hWnd, hWndMDIClient, WM_COMMAND, wParam, lParam);
break;
}
break;

case WM_CLOSE: //close all MDI windows, hdbcs & hstmts, else fail

return (CloseDatabases()
? DefFrameProc(hWnd, hWndMDIClient, message, wParam, lParam)
: FALSE);

case WM_DESTROY:

// Close Help File if open

WinHelp(hWnd, SAMPLESHELPFILE, HELP_QUIT, 0);
PostQuitMessage(0);
break;

default:

return (DefFrameProc(hWnd, hWndMDIClient, message, wParam, lParam));
}
return (0);
}

/*
FUNCTION: MDIChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: Window Procedure for MDI Child windows
*/

long CALLBACK MDIChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
HWND hWndTemp; //temporary window handle
DLGPROC lpDlgProc; //procedure address for modeless dialog

case WM_CREATE:

// create child windows
// 1. Modeless Dialog box in the background to process tabs
// 2. Static Text to display prompt
// 3. Edit Control to type SQL text
// 4. List Box to display results
// store dialog handle for future reference
// set focus to edit control

// if create failed due to low system resources

if (!hWnd)
break;

hWndActiveChild = hWnd;
hWndTemp = CreateDialog(hAppInstance, MDICHILDDIALOG, hWndActiveChild, MDIChildDlgProc);

// check to see if the dialog was created?, if not destroy this window

if (!hWndTemp) {
return (-1);
}

SetWindowLong(hWnd, GWLAPP_HDLG, (LONG)hWndTemp);
SetFocus(GetDlgItem(hWndTemp, IDTEXT_SQL));
break;

case WM_SIZE: {
WORD wWidth; //New Width of MDI Child
WORD wHeight; //New Height of MDI Child
HDC hDC; //Device Context
char szBuffer[MAXBUFLEN+1]; //Static Control Text
int nStrLen; //Buffer Length
SIZE size; //Screen size for text display

// call default procedure first, to let MDI position the child & then move its children

DefMDIChildProc(hWnd, message, wParam, lParam);

// move child windows with proper screen size for text display

wWidth = LOWORD(lParam);
wHeight = HIWORD(lParam);
hWndTemp = (HWND)GetWindowLong(hWnd, GWLAPP_HDLG);

nStrLen = GetWindowText(GetDlgItem(hWndTemp, IDTEXT_PRMPT), szBuffer, MAXBUFLEN);
hDC = GetDC(hWnd);
GetTextExtentPoint(hDC, szBuffer, nStrLen, &size);
ReleaseDC(hWnd, hDC);

MoveWindow(hWndTemp, 0, 0, wWidth, wHeight, TRUE);
MoveWindow(GetDlgItem(hWndTemp, IDTEXT_PRMPT), 0, 0, size.cx+2, size.cy+2, TRUE);
MoveWindow(GetDlgItem(hWndTemp, IDTEXT_SQL), size.cx+3, 0, wWidth - (size.cx+2), size.cy+2, TRUE);
MoveWindow(GetDlgItem(hWndTemp, IDLIST_RSLT), 0, size.cy+3, wWidth, wHeight - (size.cy+2), TRUE);
break;
}

case WM_MENUSELECT: // update status bar to reflect menu selection
{
int iMenuFlag; //Check menu type

// store the Menu Item Id as a state value for text display

wStatusText = GET_WM_MENUSELECT_CMD(wParam, lParam);

// if none of the menuitems was selected, check if
// the control popup menu is selected.

iMenuFlag = GET_WM_MENUSELECT_FLAGS(wParam, lParam);

// if the selected menu is a system popup menu

if (wStatusText && (iMenuFlag & MF_SYSMENU) && (iMenuFlag & MF_POPUP))
wStatusText = IDM_POPUPMDISYS;

// invalidate status bar for repaint

InvalidateRect(hWndStatusbar, &rectStatusText, TRUE);
break;
}

case WM_MDIACTIVATE:

// check if the display of comboboxes require a change

if (GET_WM_MDIACTIVATE_FACTIVATE(hWnd, wParam, lParam) &&
(hWndActiveChild) && (hWndActiveChild != hWnd)) {
hWndActiveChild = hWnd;
DisplayNewCrsrAndStmt();
}
break;

case WM_MOUSEACTIVATE:

// current window has changed, update comboboxes.

hWndActiveChild = hWnd;
DisplayNewCrsrAndStmt();
break;

case WM_SETFOCUS:

// pass on the focus to the edit box for user to type in SQL

SetFocus(GetDlgItem((HWND)GetWindowLong(hWnd, GWLAPP_HDLG), IDTEXT_SQL));
break;

case WM_DESTROY:

// check if the window was being destroyed while creation failed

if (!hWnd)
break;

// close the window and free instance thunk for modeless dialog

CloseQueryWindow(hWnd);
lpDlgProc = (DLGPROC)GetWindowLong((HWND)GetWindowLong(hWnd, GWLAPP_HDLG), DWL_DLGPROC);
DestroyWindow((HWND)GetWindowLong(hWnd, GWLAPP_HDLG));
FreeProcInstance(lpDlgProc);
if (hWnd == hWndActiveChild)
hWndActiveChild = (HWND)NULL;
break;

default:

return (DefMDIChildProc(hWnd, message, wParam, lParam));
}
return (0);
}

/*
FUNCTION: ToolbarProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: callback window procedure for toolbar window.
Handle pain and mouse messages to paint the toolbar and
provide default button behaviour for toolbar buttons.
*/

long CALLBACK ToolbarProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
static HBITMAP hbmpNewQuery; //btn1 bitmap handle
static HBITMAP hbmpRunQuery; //btn2 bitmap handle
static RECT stNewQuery; //btn1 rectangle
static RECT stRunQuery; //btn2 rectangle
POINT stMousePosition; //current mouse pos
BOOL bButtonPosition; //mouse pos flag
static BOOL bNewQueryBtnDown = FALSE; //was btn1 down before?
static BOOL bRunQueryBtnDown = FALSE; //was btn2 down before?
static int nLastButtonDown = 0; //Which btn was down before?

case WM_CREATE:

// load bitmaps for buttons
// initialize static rectangles for button positions on toolbar
// initialize state variable for status text display

hbmpNewQuery = LoadBitmap(hAppInstance, BMP_NEWQUERY);
hbmpRunQuery = LoadBitmap(hAppInstance, BMP_RUNQUERY);

stNewQuery.left = BTTNX;
stNewQuery.right = BTTNX+BTTNWIDTH+1;
stNewQuery.top = BTTNY;
stNewQuery.bottom = BTTNY+BTTNHEIGHT+1;

stRunQuery.left = BTTNX+BTTNWIDTH+BTTNMARGIN;
stRunQuery.right = BTTNX+BTTNWIDTH+BTTNMARGIN+BTTNWIDTH+1;
stRunQuery.top = BTTNY;
stRunQuery.bottom = BTTNY+BTTNHEIGHT+1;

wStatusText = 0;
break;

case WM_DESTROY:

// delete bitmap handles

if (hbmpNewQuery)
DeleteObject(hbmpNewQuery);
if (hbmpRunQuery)
DeleteObject(hbmpRunQuery);
break;

case WM_LBUTTONDOWN:

// Check if the mouse key lies on any one of the buttons
// if so, set state variable to reflect that button and
// invalidate proper regions on tool & status bars for update.
// set capture on mouse movements till the mouse key is
// released.

stMousePosition.x = LOWORD(lParam);
stMousePosition.y = HIWORD(lParam);

if (PtInRect(&stNewQuery, stMousePosition)) {
bNewQueryBtnDown = TRUE;
wStatusText = nLastButtonDown = IDM_NEW;
SetCapture(hWnd);
InvalidateRect(hWnd, &stNewQuery, TRUE);
InvalidateRect(hWndStatusbar, &rectStatusText, TRUE);
}
else if (PtInRect(&stRunQuery, stMousePosition)) {
bRunQueryBtnDown = TRUE;
wStatusText = nLastButtonDown = IDM_QUERY;
SetCapture(hWnd);
InvalidateRect(hWnd, &stRunQuery, TRUE);
InvalidateRect(hWndStatusbar, &rectStatusText, TRUE);
}
break;

case WM_LBUTTONUP:

// check if the mouse movements from key down movements
// were captured, if so process the key release state.
// if the key was released in the same button where it
// was pressed, it is equivalent to a button click.

if (hWnd != GetCapture())
break;

stMousePosition.x = LOWORD(lParam);
stMousePosition.y = HIWORD(lParam);

if (bNewQueryBtnDown && PtInRect(&stNewQuery, stMousePosition)) {
bNewQueryBtnDown = FALSE;
nLastButtonDown = 0;
InvalidateRect(hWnd, &stNewQuery, TRUE);
PostMessage(hWndFrame, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_NEW, 0, 0));
SendMessage(hWndCrsrList, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
SendMessage(hWndStmtList, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
}
else if (bRunQueryBtnDown && PtInRect(&stRunQuery, stMousePosition)) {
bRunQueryBtnDown = FALSE;
nLastButtonDown = 0;
InvalidateRect(hWnd, &stRunQuery, TRUE);
PostMessage(hWndFrame, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_QUERY, 0, 0));
SendMessage(hWndCrsrList, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
SendMessage(hWndStmtList, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
}

ReleaseCapture();
wStatusText = 0;
InvalidateRect(hWndStatusbar, &rectStatusText, TRUE);
break;

case WM_MOUSEMOVE:

// process mouse movement only if the mouse key was pressed
// down and its movements were being captured. If the mouse
// moves outside of the currently depressed button, it needs
// to be drawn again with normal state.

if (hWnd != GetCapture())
break;

stMousePosition.x = LOWORD(lParam);
stMousePosition.y = HIWORD(lParam);

if (nLastButtonDown == IDM_NEW) {
bButtonPosition = PtInRect(&stNewQuery, stMousePosition);
if (bNewQueryBtnDown != bButtonPosition) {
bNewQueryBtnDown = bButtonPosition;
InvalidateRect(hWnd, &stNewQuery, TRUE);
}
}
else if (nLastButtonDown == IDM_QUERY) {
bButtonPosition = PtInRect(&stRunQuery, stMousePosition);
if (bRunQueryBtnDown != bButtonPosition) {
bRunQueryBtnDown = bButtonPosition;
InvalidateRect(hWnd, &stRunQuery, TRUE);
}
}
break;

case WM_PAINT:
{
PAINTSTRUCT ps; //paint structure
RECT rect; //rectangle for tool bar
HDC hDC; //device context handle
int iWidth; //tool bar width
int iHeight; //tool bar height
HPEN hLtGrayPen; //buttonface color pen
HPEN hGrayPen; //buttonshadow color pen
int btnx; //button x coordinate position

if (!(hDC = BeginPaint(hWnd, &ps)))
break;

GetClientRect(hWnd, &rect);
iWidth = rect.right;
iHeight = rect.bottom;

hLtGrayPen = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNFACE));
hGrayPen = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));

// draw background and border

SelectObject(hDC, GetStockObject(LTGRAY_BRUSH));
SelectObject(hDC, hLtGrayPen);
Rectangle(hDC, 0, 0, iWidth, iHeight);

SelectObject(hDC, GetStockObject(BLACK_PEN));
MoveToEx(hDC, 0, iHeight-1, NULL);
LineTo(hDC, iWidth, iHeight-1);

SelectObject(hDC, GetStockObject(WHITE_PEN));
MoveToEx(hDC, 0, 0, NULL);
LineTo(hDC, iWidth, 0);

// draw tool bar buttons (new query, run query)

// check state variables to draw proper button state 

btnx = BTTNX;
SelectObject(hDC, GetStockObject(BLACK_PEN));
DRAWBTTNRECT(hDC, btnx, BTTNY, BTTNWIDTH, BTTNHEIGHT);
DrawBitmap(hDC, (bNewQueryBtnDown?btnx+3:btnx+2), (bNewQueryBtnDown?BTTNY+3:BTTNY+2), hbmpNewQuery);
SelectObject(hDC, (bNewQueryBtnDown ? hGrayPen : GetStockObject(WHITE_PEN)));
DRAWBTTNLIFT1(hDC, btnx, BTTNY, BTTNWIDTH, BTTNHEIGHT);
SelectObject(hDC, (bNewQueryBtnDown ? hLtGrayPen : hGrayPen));
DRAWBTTNLIFT2(hDC, btnx, BTTNY, BTTNWIDTH, BTTNHEIGHT);

btnx += BTTNWIDTH+BTTNMARGIN;
SelectObject(hDC, GetStockObject(BLACK_PEN));
DRAWBTTNRECT(hDC, btnx, BTTNY, BTTNWIDTH, BTTNHEIGHT);
DrawBitmap(hDC, (bRunQueryBtnDown?btnx+3:btnx+2), (bRunQueryBtnDown?BTTNY+3:BTTNY+2), hbmpRunQuery);
SelectObject(hDC, (bRunQueryBtnDown ? hGrayPen : GetStockObject(WHITE_PEN)));
DRAWBTTNLIFT1(hDC, btnx, BTTNY, BTTNWIDTH, BTTNHEIGHT);
SelectObject(hDC, (bRunQueryBtnDown ? hLtGrayPen : hGrayPen));
DRAWBTTNLIFT2(hDC, btnx, BTTNY, BTTNWIDTH, BTTNHEIGHT);

SelectObject(hDC, GetStockObject(WHITE_PEN));
EndPaint(hWnd, &ps);

// delete create objects

if (hLtGrayPen)
DeleteObject(hLtGrayPen);
if (hGrayPen)
DeleteObject(hGrayPen);
break;
}

default:

return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}

/*
FUNCTION: StatusbarProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: callback window procedure for status bar.
process paint messages and timer messages to update current
state, date and time
*/

long CALLBACK StatusbarProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
static RECT DateTimeRect; // remember for frequent updates

case WM_CREATE:
{
HDC hDC; // device context
SIZE sizeText; // size of status text box
SIZE sizeTime; // size of time display box
SIZE sizeDate; // size of date display box

// start a timer for periodic updates to date and time display
// find out width of status text, date and time display boxes

SetTimer(hWnd, (UINT)IDT_STATUSTIMER, (UINT)TIMERDELAY, NULL);

iTimex = iDatex = 0;
rectStatusText.left = 2;
rectStatusText.top = 3;

if (hDC = GetDC(hWnd)) {
GetTextExtentPoint(hDC, STATUSNEW, strlen(STATUSNEW), &sizeText);
GetTextExtentPoint(hDC, TIMETEXT, strlen(TIMETEXT), &sizeTime);
GetTextExtentPoint(hDC, DATETEXT, strlen(DATETEXT), &sizeDate);
ReleaseDC(hWnd, hDC);
rectStatusText.right = sizeText.cx + rectStatusText.left;
iTimex = sizeTime.cx;
iDatex = sizeDate.cx;
}
break;
}

case WM_TIMER:

// invalidate only the date&time area for update

InvalidateRect(hWnd, &DateTimeRect, TRUE);
break;

case WM_PAINT:
{
HDC hDC; //device context
PAINTSTRUCT ps; //paint structure
RECT rect; //status bar rect
int iWidth; //status bar width
int iHeight; //status bar height
HPEN hLtGrayPen; //btnface color pen
HPEN hGrayPen; //btnshadow color pen
char szText[MAXBUFLEN]; //text buffer for display
time_t tCurrentTime; //current date&time
struct tm stTime; //date&time structure

if (!(hDC = BeginPaint(hWnd, &ps)))
break;

GetClientRect(hWnd, &rect);
iWidth = rect.right;
iHeight = rect.bottom;
rectStatusText.bottom = iHeight-2;

hLtGrayPen = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNFACE));
hGrayPen = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));

// paint background and border

SelectObject(hDC, GetStockObject(LTGRAY_BRUSH));
SelectObject(hDC, hLtGrayPen);
Rectangle(hDC, 0, 0, iWidth, iHeight);

SelectObject(hDC, GetStockObject(BLACK_PEN));
MoveToEx(hDC, 0, 0, NULL);
LineTo(hDC, iWidth, 0);
SelectObject(hDC, GetStockObject(WHITE_PEN));
MoveToEx(hDC, 0, 1, NULL);
LineTo(hDC, iWidth, 1);

// draw text boxes for status, time and date display

SelectObject(hDC, hGrayPen);
MoveToEx(hDC, rectStatusText.left, rectStatusText.bottom, NULL);
LineTo(hDC, rectStatusText.left, rectStatusText.top);
LineTo(hDC, rectStatusText.right, rectStatusText.top);
SelectObject(hDC, GetStockObject(WHITE_PEN));
LineTo(hDC, rectStatusText.right, rectStatusText.bottom);
LineTo(hDC, rectStatusText.left, rectStatusText.bottom);

SelectObject(hDC, hGrayPen);
MoveToEx(hDC, iWidth-2, 3, NULL);
LineTo(hDC, iWidth-iDatex-2, 3);
LineTo(hDC, iWidth-iDatex-2, iHeight-2);
SelectObject(hDC, GetStockObject(WHITE_PEN));
LineTo(hDC, iWidth-2, iHeight-2);
LineTo(hDC, iWidth-2, 3);

SelectObject(hDC, hGrayPen);
MoveToEx(hDC, iWidth-iDatex-6, 3, NULL);
LineTo(hDC, iWidth-iTimex-iDatex-6, 3);
LineTo(hDC, iWidth-iTimex-iDatex-6, iHeight-2);
SelectObject(hDC, GetStockObject(WHITE_PEN));
LineTo(hDC, iWidth-iDatex-6, iHeight-2);
LineTo(hDC, iWidth-iDatex-6, 3);

// draw status text in the display box based on current
// value of wStatusText global flag

SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT));

switch (wStatusText) {
case IDM_POPUPAPPSYS:

strcpy(szText, STATUSPOPUPAPPSYS);
break;

case IDM_POPUPMDISYS:

strcpy(szText, STATUSPOPUPMDISYS);
break;

case SC_RESTORE:

strcpy(szText, STATUSRESTORE);
break;

case SC_MOVE:

strcpy(szText, STATUSMOVE);
break;

case SC_SIZE:

strcpy(szText, STATUSSIZE);
break;

case SC_MINIMIZE:

strcpy(szText, STATUSMINIMIZE);
break;

case SC_MAXIMIZE:

strcpy(szText, STATUSMAXIMIZE);
break;

case SC_CLOSE:

strcpy(szText, STATUSCLOSE);
break;

case SC_NEXTWINDOW:

strcpy(szText, STATUSNEXTWINDOW);
break;

case SC_PREVWINDOW:

strcpy(szText, STATUSPREVWINDOW);
break;

case SC_TASKLIST:

strcpy(szText, STATUSTASKLIST);
break;

case IDM_POPUPLOGIN:

strcpy(szText, STATUSPOPUPLOGIN);
break;

case IDM_CONNECT:

strcpy(szText, STATUSCONNECT);
break;

case IDM_DRIVERCONNECT:

strcpy(szText, STATUSDRIVERCONNECT);
break;

case IDM_DISCONNECT:

strcpy(szText, STATUSDISCONNECT);
break;

case IDM_EXIT:

strcpy(szText, STATUSEXIT);
break;

case IDM_POPUPQUERY:

strcpy(szText, STATUSPOPUPQUERY);
break;

case IDM_QUERY:

strcpy(szText, STATUSQUERY);
break;

case IDM_NEW:

strcpy(szText, STATUSNEW);
break;

case IDM_POPUPWINDOW:

strcpy(szText, STATUSPOPUPWINDOW);
break;

case IDM_TILE:

strcpy(szText, STATUSTILE);
break;

case IDM_CASCADE:

strcpy(szText, STATUSCASCADE);
break;

case IDM_ICONS:

strcpy(szText, STATUSICONS);
break;

case IDM_CLOSEALL:

strcpy(szText, STATUSCLOSEALL);
break;

case IDM_POPUPHELP:

strcpy(szText, STATUSPOPUPHELP);
break;

case IDM_APPHELP:

strcpy(szText, STATUSAPPHELP);
break;

case IDM_ABOUT:

strcpy(szText, STATUSABOUT);
break;

default:

if (wStatusText >= IDM_MDICHILD)
sprintf(szText, STATUSMDICHILD, wStatusText-IDM_MDICHILD+1);
else
strcpy(szText, STATUSDEFAULT);
break;
}

DrawText(hDC, szText, strlen(szText), &rectStatusText, DT_LEFT);

// get current date and time and display time in time box

time(&tCurrentTime);
stTime = *localtime(&tCurrentTime);
strftime(szText, MAXBUFLEN, TIMEFORMAT, &stTime);
rect.top = rectStatusText.top;
rect.bottom = rectStatusText.bottom;
rect.left = iWidth-iTimex-iDatex-6;
rect.right = iWidth-iDatex-6;
DrawText(hDC, szText, strlen(szText), &rect, DT_LEFT);

// display date in date box

strftime(szText, MAXBUFLEN, DATEFORMAT, &stTime);
rect.left = iWidth-iDatex-2;
rect.right = iWidth-2;
DrawText(hDC, szText, strlen(szText), &rect, DT_LEFT);

// remember the date&time rectangle to minimize painting

DateTimeRect.left = iWidth-iTimex-iDatex-6;
DateTimeRect.right = iWidth-2;
DateTimeRect.top = rect.top;
DateTimeRect.bottom = rect.bottom;

EndPaint(hWnd, &ps);

// delete created objects

if (hLtGrayPen)
DeleteObject(hLtGrayPen);
if (hGrayPen)
DeleteObject(hGrayPen);
break;
}

default:

return (DefWindowProc(hWnd, message, wParam, lParam));
break;
}
return (0);
}

/*
FUNCTION: ConnectDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: Callback dialog box procedure for connect menu command
displays a list of available data sources, asks for user
name and password to pass default connection parameters
for a data source connection
*/

BOOL CALLBACK ConnectDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
HCURSOR hOldCursor; // Default Cursor Shape

case WM_INITDIALOG:

// display list of available data sources

hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));
DisplayDatabases(GetDlgItem(hWnd, IDCOMBO_DATASOURCE));
SetCursor(hOldCursor);
break;

case WM_COMMAND:

switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDOK: // make a connection using the supplied values

hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));

// check if a DSN was provided for connection

if (SendDlgItemMessage(hWnd, IDCOMBO_DATASOURCE, WM_GETTEXTLENGTH, 0, 0))
EndDialog(hWnd, ConnectDatabase(hWnd));
else
MessageBox(hWnd, NODSNERR, MOREINFO, MB_OK|MB_ICONHAND);

SetCursor(hOldCursor);
break;

case IDCANCEL:

EndDialog(hWnd, FALSE);
break;

default:

return (FALSE);
break;
}
break;

default:

return (FALSE);
break;
}
return (TRUE);
}

/*
FUNCTION: DisconnectDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: Callback dialog box procedure for disconnect dialog.
provides a list of available SQLHDBCs and a list of SQLHSTMTs
for currently selected SQLHDBC. Allows closure of all SQLHDBCs
and SQLHSTMTs one by one or in groups.
*/

BOOL CALLBACK DisconnectDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
static HWND hListhdbc; //listbox that displays hdbc(s)
static HWND hListstmt; //listbox that displays hstmt(s)
static HWND hPushOk; //pushbutton to free hdbc
static HWND hPushClose; //pushbutton to free hstmt
static HWND hPushCancel; //pushbutton to close dialog

case WM_INITDIALOG:

// store handles for future reference

hListhdbc = GetDlgItem(hWnd, IDLIST_HDBC);
hListstmt = GetDlgItem(hWnd, IDLIST_STMT);
hPushOk = GetDlgItem(hWnd, IDDISCONNECT);
hPushCancel = GetDlgItem(hWnd, IDCANCEL);
hPushClose = GetDlgItem(hWnd, IDCLOSE_ACTVTY);

// display connected database handles and statements

DisplayConnections(hListhdbc);
DisplayQueries(hListstmt, hListhdbc, 0);

// enable or disable pushbuttons & listboxes to match available hdbc & hstmt

if (SendMessage(hListhdbc, LB_GETCOUNT, 0, 0)>0) {
EnableWindow(hPushOk, TRUE);
if (SendMessage(hListstmt, LB_GETCOUNT, 0, 0)>0) {
EnableWindow(hPushClose, TRUE);
SetFocus(hPushClose);
SendMessage(hPushClose, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
else {
EnableWindow(hListstmt, FALSE);
EnableWindow(hPushClose, FALSE);
SetFocus(hPushOk);
SendMessage(hPushOk, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
}
else {
EnableWindow(hListhdbc, FALSE);
EnableWindow(hListstmt, FALSE);
EnableWindow(hPushOk, FALSE);
SetFocus(hPushCancel);
SendMessage(hPushCancel, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}

// return FALSE to prevent default focus.

return (FALSE);

case WM_COMMAND:

switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDDISCONNECT:

// Free current hdbc, display available hdbc(s)

FreeConnect(hListhdbc);
SendMessage(hListstmt, LB_RESETCONTENT, 0, 0);
DisplayConnections(hListhdbc);

// update displayed hstmt(s) for current hdbc
// enable or disable pushbuttons to match available
// hdbc(s) and hstmt(s) for closure

if (SendMessage(hListhdbc, LB_GETCOUNT, 0, 0) > 0) {
SendMessage(hListhdbc, LB_SETCURSEL, 0, 0);
EnableWindow(hListstmt, TRUE);
DisplayQueries(hListstmt, hListhdbc, 0);
if (SendMessage(hListstmt, LB_GETCOUNT, 0, 0)>0) {
EnableWindow(hPushClose, TRUE);
SetFocus(hPushClose);
SendMessage(hPushClose, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
else {
EnableWindow(hListstmt, FALSE);
EnableWindow(hPushClose, FALSE);
SetFocus(hPushOk);
SendMessage(hPushOk, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
}
else {
EnableWindow(hListhdbc, FALSE);
EnableWindow(hPushOk, FALSE);
EnableWindow(hPushClose, FALSE);
SetFocus(hPushCancel);
SendMessage(hPushCancel, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
break;

case IDCANCEL:

// close dialog

EndDialog(hWnd, FALSE);
break;

case IDCLOSE_ACTVTY:
{
int nIndex; // counter to search for selected hstmt(s)

// go through all displayed hstmt(s) and free all highlighted ones

for (nIndex = (int)SendMessage(hListstmt, LB_GETCOUNT, 0, 0)-1;
nIndex >= 0; nIndex--)
if (SendMessage(hListstmt, LB_GETSEL, nIndex, 0))
FreeQuery(hListstmt, hListhdbc, nIndex);

// reset both hdbc(s) and hstmt(s) display

nIndex = (int)SendMessage(hListhdbc, LB_GETCURSEL, 0, 0);
DisplayConnections(hListhdbc);
SendMessage(hListhdbc, LB_SETCURSEL, nIndex, 0);
DisplayQueries(hListstmt, hListhdbc, nIndex);

// enable or disable pushbuttons to match available
// hdbc(s) and hstmt(s) for closure

if (SendMessage(hListstmt, LB_GETCOUNT, 0, 0)>0) {
EnableWindow(hPushClose, TRUE);
SetFocus(hPushClose);
SendMessage(hPushClose, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
else {
EnableWindow(hListstmt, FALSE);
EnableWindow(hPushClose, FALSE);
SetFocus(hPushOk);
SendMessage(hPushOk, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
}
break;
}

case IDLIST_HDBC:

// If the current selection in hdbc(s) has changed
// update the list of hstmt(s) to match the new hdbc

if (GET_WM_COMMAND_CMD(wParam, lParam) == LBN_SELCHANGE)
DisplayQueries(hListstmt, hListhdbc,
(UINT)SendMessage(GET_WM_COMMAND_HWND(wParam, lParam), LB_GETCURSEL, 0, 0));

// Enable or disable hstmt listbox and close pushbutton accordingly

EnableWindow(hListstmt, (SendMessage(hListstmt, LB_GETCOUNT, 0, 0)>0));
EnableWindow(hPushClose, (SendMessage(hListstmt, LB_GETCOUNT, 0, 0)>0));
break;

default:

return (FALSE);
}
break;

default:

return (FALSE);
}

return (TRUE);
}

/*
FUNCTION: AboutDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: Callback dialog box procedure for About dialog box
displays the about information and closes upon selection of
ok button
*/

BOOL CALLBACK AboutDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_COMMAND) {
EndDialog(hWnd, TRUE);
return (TRUE);
}
else
return (FALSE);
}

/*
FUNCTION: MDIChildDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
COMMENTS: Callback dialog box procedure for modeless child dialog box
in each MDI Child Window. This dialog box simply processes
the tab messages (by default) to allow switching from edit
control (SQL Text) to list box control (Query results).
*/

BOOL CALLBACK MDIChildDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return (FALSE);
}

/*
FUNCTION: DrawBitmap(HDC hDC, int iLeft, int iTop, HBITMAP hBitmap
COMMENTS: Draws a bitmap on given Device context with given bitmap
handle at given location
*/

VOID FAR PASCAL DrawBitmap(HDC hDC, int iLeft, int iTop, HBITMAP hBitmap)
{
HDC hMemDC; // Device Context in Memory
POINT stPoint; // point structure for conversion from device to logical units
BITMAP stBitmap;
HGDIOBJ hObject;

// create a compatible device context in memory and select the bitmap
// in to it.

if (!(hMemDC = CreateCompatibleDC(hDC))) return;

hObject = SelectObject(hMemDC, hBitmap);
SetMapMode(hMemDC, GetMapMode(hDC));

// Get bitmap size and convert it to logical units from device units.

GetObject(hBitmap, sizeof(BITMAP), &stBitmap);
stPoint.x = stBitmap.bmWidth;
stPoint.y = stBitmap.bmHeight;
DPtoLP(hDC, &stPoint, 1);

// bit block transfer the bitmap from memory device context to given
// device context at specified location

BitBlt(hDC, iLeft, iTop, stPoint.x, stPoint.y, hMemDC, 0, 0, SRCCOPY);

// select original object in the memory device context and destroy it

SelectObject(hMemDC, hObject);
DeleteDC(hMemDC);
}

/********************************************* END OF FILE **************************************************/