DRVPROC.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

// DRVPROC.C

#include "cfiler.h"

extern HANDLE ghModule;
extern HANDLEghwndMain;
extern HFONT ghFont;
extern HANDLE ghDrvThread;
extern HANDLE ghMenu;
extern HWND ghwndDrives;
extern HWND ghwndDrv;
extern HWND ghFocusWnd;
extern LPDINFO glpDrives;
extern CRITICAL_SECTION gDrvCS;

/**********************************************************************\
* DrawItem()
*
* in parmeters
* lpdis - Information the owner window must have to determine how
* to paint the owner-draw listbox
*
* Calls DrawText to output a string with the right color in the
* rectangle contained in lpdis
\**********************************************************************/

VOID APIENTRY DrawItem(LPDRAWITEMSTRUCT lpdis) {
COLORREF crOldColor;
TCHARszFile[256];
INT i, nLen;
TCHAR szBuf[275];
TEXTMETRIC tm;
RECT rc;

if (!lpdis) {
ErrorMsg(TEXT("DrawEntireItem: lpdis is NULL."));
return;
}

GetTextMetrics(lpdis->hDC, &tm);

// Filenames such as Q&A.DOC should look correct.

ReplaceEscapeCharacters((LPTSTR)lpdis->itemData, szBuf);

nLen = lstrlen(szBuf);

if (nLen > HEADER_SIZE) {
ErrorMsg(TEXT("fnKey has been Destroyed!"));
crOldColor = SetTextColor(lpdis->hDC, RGB(140, 140, 140));
CopyRect(&rc, &lpdis->rcItem);
rc.left += 1;
lstrcpy(szFile, TEXT("RecoverMe"));
DrawText(lpdis->hDC, szFile, lstrlen(szFile), (LPRECT)&rc, DT_LEFT);
SetTextColor(lpdis->hDC, crOldColor);
return;
}

if (szBuf[0] == TEXT('|')) {

// This is an encrypted file. Select gray as the color.

crOldColor = SetTextColor(lpdis->hDC, RGB(140, 140, 140));

for (i = 0; i < nLen - 1; i++)
szFile[i] = szBuf[i + 1];

szFile[i] = TEXT('\0');
}
else if (szBuf[0] == TEXT('>')) {

// This is an encrypted and signed file.

crOldColor = SetTextColor(lpdis->hDC, RGB(255, 140, 140));

for (i = 0; i < nLen - 1; i++)
szFile[i] = szBuf[i + 1];

szFile[i] = TEXT('\0');
}
else if (szBuf[0] == TEXT(';')) {

// This is a signed only file.

crOldColor = SetTextColor(lpdis->hDC, RGB(255, 0, 0));

for (i = 0; i < nLen - 1; i++)
szFile[i] = szBuf[i + 1];

szFile[i] = TEXT('\0');
}
else
lstrcpy(szFile, szBuf);

CopyRect(&rc, &lpdis->rcItem);

rc.left += 1;

DrawText(lpdis->hDC, szFile, lstrlen(szFile), (LPRECT)&rc, DT_LEFT);

if (szBuf[0] == TEXT('|') || szBuf[0] == TEXT('>') || szBuf[0] == TEXT(';'))
SetTextColor(lpdis->hDC, crOldColor);

return;
}

/**********************************************************************\
* HandleSelectionState()
*
* in parmeters
* lpdis - Information the owner window must have to determine how
* to paint the owner-draw listbox
*
* purpose:
* Handles a change in an item selection state. This function must
* check the current background color for the rectangle contained
* in the DRAWITEMSTRUCT pointer, lpdis. The background color and
* text color must be changed appropriately.
\**********************************************************************/

VOID APIENTRY HandleSelectionState(LPDRAWITEMSTRUCT lpdis)
{
if (!lpdis) {
ErrorMsg(TEXT("HandleSelectionState: lpdis is NULL."));
return;
}

if (lpdis->itemState & ODS_SELECTED) {
if (GetBkColor(lpdis->hDC) == GetSysColor(COLOR_HIGHLIGHT)) {
return;
}
else {
SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
DrawItem(lpdis);
return;
}
}
else {
if (GetBkColor(lpdis->hDC) != GetSysColor(COLOR_WINDOW)) {
return;
}
else {
SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
DrawItem(lpdis);
return;
}
}
}

/**********************************************************************\
* DrawEntireItem()
*
* in parmeters
* lpdis - Information the owner window must have to determine how
* to paint the owner-draw listbox
*
* Sets the background color and the text color and calls DrawItem()
\**********************************************************************/

VOID APIENTRY DrawEntireItem(LPDRAWITEMSTRUCT lpdis)
{
if (!lpdis) {
ErrorMsg(TEXT("DrawEntireItem: lpdis is NULL."));
return;
}

SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));

DrawItem(lpdis);

__try {
if (!lpdis) {
ErrorMsg(TEXT("DrawEntireItem: lpdis is NULL."));
return;
}

if (!lpdis->itemData) {
ErrorMsg(TEXT("DrawEntireItem: lpdis->itemData is NULL."));
return;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
ErrorMsg(TEXT("DrawEntireItem: lpdis is BOGUS."));
return;
}

/* Draw or erase appropriate frames */
__try {
HandleSelectionState(lpdis);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
ErrorMsg(TEXT("DrawEntireItem: Attempt to call HandleSelectionState raised an exception."));
return;
}
}

LRESULT WINAPI DrvWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
LPDRAWITEMSTRUCT lpdis;
LPMEASUREITEMSTRUCT lpmis;
LPCOMPAREITEMSTRUCT lpcis;

DWORD dwDirStyle = WS_BORDER | WS_CHILD | WS_VISIBLE |
LBS_NOINTEGRALHEIGHT | LBS_NOTIFY |
LBS_HASSTRINGS | LBS_WANTKEYBOARDINPUT |
LBS_DISABLENOSCROLL | WS_HSCROLL |
WS_VSCROLL |LBS_USETABSTOPS;

DWORD dwFileStyle = WS_BORDER | WS_CHILD | WS_VISIBLE |
LBS_NOINTEGRALHEIGHT | LBS_NOTIFY |
LBS_OWNERDRAWFIXED | LBS_WANTKEYBOARDINPUT |
LBS_DISABLENOSCROLL | WS_HSCROLL |
LBS_EXTENDEDSEL | LBS_MULTIPLESEL |
LBS_MULTICOLUMN | LBS_SORT;

switch (message){

//
// Creates the text and listbox windows for this Drv child and
// saves its handle in the per Drv child DRVCHILDINFO data structure.
//
case WM_CREATE: {
LPCINFO lpCInfo;

DWORD dwLoop;

LPDINFO lpWalk;

LONG lTabs = LISTBOX_TAB_SIZE;

//
// Initialize DRVCHILDINFO structure
//
lpCInfo = (LPCINFO) ((LPCREATESTRUCT) lParam)->lpCreateParams;

if (!lpCInfo) {
ErrorMsg(TEXT("DrvWndProc: lpCInfo is NULL."));
return 0;
}

lpCInfo->hwnd = hwnd;

// Create text window
lpCInfo->hTextWnd = CreateWindow(TEXT("TextClass"), NULL,
SS_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER,
0, 0, 0, 0,
lpCInfo->hwnd,
(HMENU) TEXT_WINDOW_ID,
ghModule,
NULL);

if (!lpCInfo->hTextWnd) {
ErrorMsg(TEXT("DrvWndProc: WM_CREATE: CreateWindow failed."));
return 0;
}

// Create Directory and File List boxes
lpCInfo->hDirLB = CreateWindow(TEXT("LISTBOX"), NULL,
dwDirStyle,
0, 0, 0, 0,
lpCInfo->hwnd,
(HMENU) LISTDIR_ID,
ghModule,
NULL);

if (!lpCInfo->hDirLB) {
ErrorMsg(TEXT("DrvWndProc: WM_CREATE: CreateWindow failed."));
return 0;
}

// Create directory listbox string table.

lpCInfo->DirTable = TableNew();

if (!lpCInfo->DirTable) {
ErrorMsg(TEXT("WM_CREATE: TableNew failed."));
return 0;
}

lpCInfo->hFileLB = CreateWindow(TEXT("LISTBOX"), NULL,
dwFileStyle,
0, 0, 0, 0,
lpCInfo->hwnd,
(HMENU) LISTFILE_ID,
ghModule,
NULL);

if (!lpCInfo->hFileLB) {
ErrorMsg(TEXT("DrvWndProc: WM_CREATE: CreateWindow failed."));
return 0;
}

lpCInfo->FileTable = TableNew();

if (!lpCInfo->FileTable) {
ErrorMsg(TEXT("WM_CREATE: TableNew failed."));
return 0;
}

if (!Logon(hwnd)) {
MessageBox(hwnd, TEXT("DrvWndProc: WM_CREATE: Logon failed. Terminating application."), NULL, MB_OK);
exit(1);
return 0;
}

//
// fDirLeft indicates whether the Directory ListBox defaults to
// the left side of each of the two drive windows.
// fDirExpand indicates whether the Directory Listbox defaults
// to full expansion.
//
lpCInfo->fDirLeft = TRUE;
lpCInfo->fDirExpand = FALSE;
lpCInfo->fSuicide = FALSE;

//
// Create Mutex associated with each list box
//
lpCInfo->hDirMutex = CreateMutex(NULL, FALSE, NULL);
lpCInfo->hFileMutex = CreateMutex(NULL, FALSE, NULL);

//
// Associate window with the current directory LPDINFO structure
// from the Drives linked list
//

dwLoop = GetCurrentDirectory( DIRECTORY_STRING_SIZE,
lpCInfo->CaptionBarText);

CharUpper(lpCInfo->CaptionBarText);

WaitForSingleObject(ghDrvThread, INFINITE);
EnterCriticalSection(&gDrvCS);

lpWalk = glpDrives;

if(dwLoop && dwLoop <= DIRECTORY_STRING_SIZE) {
while(lpWalk && tolower(lpWalk->DriveName[0])
!= tolower((lpCInfo->CaptionBarText)[0]))
lpWalk = lpWalk->next;

if( !lpWalk ){
ErrorMsg(TEXT("Drive Child Create: Drive list failure."));
LeaveCriticalSection(&gDrvCS);
return(-1);
}
}
else{
ErrorMsg(TEXT("Drive Child Create: GetCurrentDir failure."));
LeaveCriticalSection(&gDrvCS);
return(-1);
}

LeaveCriticalSection(&gDrvCS);

lpCInfo->lpDriveInfo = lpWalk;

//
// Save the handle to DRVCHILDINFO in our window structure
//
SetWindowLong(hwnd, GWL_USERDATA, (LONG) lpCInfo);

//
// Initialize child windows
//
if( !SendMessage(lpCInfo->hDirLB, LB_SETTABSTOPS, (WPARAM)1,
(LPARAM)&lTabs) )
ErrorMsg(TEXT("Drv window Create: Set tab stop failure."));


//
// Set default font.
//
SendMessage(lpCInfo->hDirLB, WM_SETFONT, (WPARAM)ghFont, (LPARAM)FALSE);
SendMessage(lpCInfo->hFileLB, WM_SETFONT, (WPARAM)ghFont, (LPARAM)FALSE);

SendMessage(hwnd, WM_COMMAND, (WPARAM)MM_REFRESH, (LPARAM)NULL);

return 1;
}

case WM_COMMAND: {
static LPCINFO lpCInfo;
static SELECTINFO Select;

//
// Retrieving this child window's DRVCHILDINFO data for displaying
// messages in the text window
//
lpCInfo = (LPCINFO) GetWindowLong(hwnd, GWL_USERDATA);

if (!lpCInfo) {
ErrorMsg(TEXT("DrvWndProc: WM_COMMAND: lpCInfo is NULL."));
return FALSE;
}

switch (LOWORD(wParam)){

//
// Clears the selection in the active window.
// Sent when user hits escape key.
//
case MM_ESCAPE:{
//
// If there is a directory expand in process, kill the
// thread, and leave the listbox in a semi-expanded state.
// Else, clear file selection, and switch to command window.
//
if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT)
== WAIT_TIMEOUT ){
lpCInfo->fSuicide = TRUE;
lpCInfo->fEscape = TRUE;
}
else
ReleaseMutex( lpCInfo->hDirMutex );

SendMessage(lpCInfo->hFileLB, LB_SETCURSEL, (WPARAM)-1,
(LPARAM)0);

return 1;
}

case MM_ENCRYPT_DECRYPT: {
if( ghFocusWnd == lpCInfo->hFileLB ) {
RunListBoxItem(lpCInfo, ENCRYPT_DECRYPT);
}
else
if( ghFocusWnd == lpCInfo->hDirLB ){
if( !PostMessage(hwnd, WM_COMMAND, MM_FILLDIR,
(LPARAM)0) ){
ErrorMsg(TEXT("MM_ENCRYPT_DECRYPT: Filldir failure."));
return 0;
}
}

return 1;
}

case MM_SIGN: {
if( ghFocusWnd == lpCInfo->hFileLB ) {
RunListBoxItem(lpCInfo, SIGN);
}
else
if( ghFocusWnd == lpCInfo->hDirLB ){
if( !PostMessage(hwnd, WM_COMMAND, MM_FILLDIR,
(LPARAM)0) ){
ErrorMsg(TEXT("MM_SIGN: Filldir failure."));
return 0;
}
}

return 1;
}

case MM_VERIFY: {
if( ghFocusWnd == lpCInfo->hFileLB ) {
RunListBoxItem(lpCInfo, VERIFY);
}
else
if( ghFocusWnd == lpCInfo->hDirLB ){
if( !PostMessage(hwnd, WM_COMMAND, MM_FILLDIR,
(LPARAM)0) ){
ErrorMsg(TEXT("MM_VERIFY: Filldir failure."));
return 0;
}
}

return 1;
}

case MM_EXPAND:{

lpCInfo->fDirExpand = !lpCInfo->fDirExpand;

if( lpCInfo->fDirExpand )
CheckMenuItem( ghMenu, MM_EXPAND,
MF_BYCOMMAND | MF_CHECKED);
else
CheckMenuItem( ghMenu, MM_EXPAND,
MF_BYCOMMAND | MF_UNCHECKED);

if( !SendMessage( (HWND)lpCInfo->hwnd, WM_COMMAND,
(WPARAM)MM_REFRESH, (LPARAM)0 ) ){
ErrorMsg(TEXT("MM_EXPAND: MM_REFRESH failure."));
return 0;
}
return 1;
}

//
// refreshes contents of directory and file ListBoxes.
//
case MM_REFRESH:{

DWORD dwThreadID;
INT i, N;

if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT)
== WAIT_TIMEOUT )
//
// If the full directory expand has been cancled, kill the
// existing thread.
//
if( !lpCInfo->fDirExpand && !lpCInfo->fSuicide){
lpCInfo->fSuicide = TRUE;
return 1;
}
else{
return 0;
}

// if set, clear the expand dir. user abort (escape key) flag.
if( lpCInfo->fEscape ){
lpCInfo->fEscape = FALSE;
ReleaseMutex( lpCInfo->hDirMutex );
return 1;
}

// At this point, the Dir LB mutex has been grabbed.

// Clear directory LB. If expand flag is set, expand all
// directories. Refill File LB.
//

N = GetSize(lpCInfo->DirTable);

for (i = 0; i < N; i++)
TableRemove(lpCInfo->DirTable, 0);

if( SendMessage( lpCInfo->hDirLB, LB_RESETCONTENT,
(WPARAM)0, (LPARAM)0 ) < 0 ){
ErrorMsg(TEXT("Refresh Drv window: Reset Dir LB content failure."));
ReleaseMutex( lpCInfo->hDirMutex );
return 0;
}

//
// This call puts the default root entry back into the empty
// LB. Set suicide flag to false to ensure it will complete.
//
lpCInfo->fSuicide = FALSE;
ExpDir( lpCInfo );

//
// All the Dir LB work is done. Release Dir LB Mutex.
//
ReleaseMutex( lpCInfo->hDirMutex );

if( lpCInfo->fDirExpand ){

CloseHandle( lpCInfo->hDirThread );

lpCInfo->hDirThread = CreateThread( NULL, 0,
(LPTHREAD_START_ROUTINE)FullExpand,
(LPVOID)lpCInfo, 0, &dwThreadID);

if( !lpCInfo->hDirThread ){
ErrorMsg(TEXT("MM_REFRESH: FullExpand CreateThread failure."));
return 0;
}
}
else
ExpDir( lpCInfo );

if( !PostMessage(hwnd, WM_COMMAND, MM_FILLFILE,
(LPARAM)0) ){
ErrorMsg(TEXT("Refresh Drv window: Fillfile failure."));
return 0;
}

return 1;
}

//
// Fill listbox in lParam with directory from Drv child's drive.
// Sent by MM_REFRESH.
//
// lParam == 0
//
case MM_FILLDIR:{

DWORD dwThreadID;

lpCInfo->fSuicide = FALSE;

CloseHandle( lpCInfo->hDirThread );

lpCInfo->hDirThread = CreateThread( NULL, 0,
(LPTHREAD_START_ROUTINE)ExpDir,
(LPVOID)lpCInfo, 0, &dwThreadID);

if( !(lpCInfo->hDirThread) ){
ErrorMsg(TEXT("MM_FILLDIR: ExpDir CreateThread failure."));
return 0;
}

return 1;
}

//
// Fill listbox in lParam with files from current directory.
// Sent by MM_REFRESH & LBN_DBLCLK in DrvWndProc.
//
// lParam == 0
//
case MM_FILLFILE:
ghFocusWnd = lpCInfo->hFileLB;
return FillFile(lpCInfo, hwnd);
break;

//
// The following WM_COMMAND messages are sent by the listboxes
//
// HIWORD(wParam) = LB notification message
// lParam = LB window handle
//
case LISTFILE_ID:{
switch( HIWORD(wParam) ){
//
// In case of double click on a directory, expand the file
// Listbox. if on a file name, run or edit file.
//
case LBN_DBLCLK:{
RunListBoxItem(lpCInfo, ENCRYPT_DECRYPT);
return 1;
}
break;

case LBN_SETFOCUS:{
ghFocusWnd = lpCInfo->hFileLB;
}
break;

default:
return 1;
}
} // LISTFILE_ID
break;

//
// Notification from the Directory ListBox
//
case LISTDIR_ID:{
switch( HIWORD(wParam) ){

case LBN_SETFOCUS:{
ghFocusWnd = lpCInfo->hDirLB;
}
break;

//
// Expand subdirectories in dir listbox
//
case LBN_DBLCLK:{

if( !PostMessage(hwnd, WM_COMMAND, MM_FILLDIR,
(LPARAM)0) ){
ErrorMsg(TEXT("Dir ListBox Notify: Filldir failure."));
return 0;
}
return 1;
}
break;

case LBN_SELCHANGE:{
//
// for the Directory LB, fill the
// corresp. File LB with items in the newly selected dir.
//
LONG lIndex;

if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT)
== WAIT_TIMEOUT ){
ErrorMsg(TEXT("Dir LB Notify: Dir LB Mutex Timeout."));
return 0;
}

//
// Retrieve selected (careted) item.
//
lIndex = SendMessage( (HWND)lParam, LB_GETCARETINDEX,
(WPARAM)NULL, (LPARAM)NULL );

if( !ConstructDirName(lpCInfo, lIndex,
lpCInfo->CaptionBarText) ){
ErrorMsg(TEXT("Dir LB Notify: ConstructDirName failure."));
ReleaseMutex( lpCInfo->hDirMutex );
return 0;
}

ReleaseMutex( lpCInfo->hDirMutex );

if( !PostMessage(hwnd, WM_COMMAND, MM_FILLFILE,
(LPARAM)0) ){
ErrorMsg(TEXT("Dir ListBox Notify: Fillfile failure."));
return 0;
}
} // LBN_SELCHANGE
break;

default:
return 1;
}
} // LISTDIR_ID
break;

default:
return 1;
}
}
break;

//
// Whenever the Drv child window is resized, its children has to be
// resized accordingly. The GetWindowLong GWL_USERDATA values
// contain the height of the windows queried, set in their respective
// WM_CREATE cases.
//
case WM_SIZE: {
LPCINFO lpCInfo;

int nListHeight,
nListWidth;

HWND hLeftLB,
hRightLB;

//
// First, get the text window's handle from the per Drv child
// DRVCHILDINFO data structure
//
lpCInfo = (LPCINFO)GetWindowLong(hwnd, GWL_USERDATA);

if (!lpCInfo) {
ErrorMsg(TEXT("DrvWndProc: WM_SIZE: lpCInfo is NULL."));
return 0;
}

nListHeight = HIWORD(lParam) -
GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA)
- LIST_BORDER * 2;

nListWidth = (LOWORD(lParam) - LIST_BORDER) / 2 - LIST_BORDER;

//
// Always, put the text window at the top of the Drv window.
// Increasing sides and bottom extents by 1 to overlap border
// with Drv child border
//
MoveWindow(lpCInfo->hTextWnd,
-1,
0,
LOWORD(lParam) + 2,
GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA) + 1,
TRUE);

if( lpCInfo->fDirLeft ){
hLeftLB = lpCInfo->hDirLB;
hRightLB = lpCInfo->hFileLB;
}
else{
hLeftLB = lpCInfo->hFileLB;
hRightLB = lpCInfo->hDirLB;
}

MoveWindow(hLeftLB,
LIST_BORDER,
GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA) + 1
+ LIST_BORDER,
nListWidth,
nListHeight,
TRUE);

MoveWindow(hRightLB,
(LOWORD(lParam) + LIST_BORDER) / 2,
GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA) + 1
+ LIST_BORDER,
nListWidth,
nListHeight,
TRUE);

break;
}

case WM_PARENTNOTIFY:{
LPCINFO lpCInfo;

if(wParam == WM_LBUTTONDOWN){
lpCInfo = (LPCINFO) GetWindowLong(hwnd, GWL_USERDATA);
if(lpCInfo == NULL){
ErrorMsg(TEXT("Drv child: Parent notify failure."));
return 1;
}
if(HIWORD(wParam) == LISTDIR_ID)
SetFocus(lpCInfo->hDirLB);
else
if(HIWORD(wParam) == LISTFILE_ID)
SetFocus(lpCInfo->hFileLB);
else
if(HIWORD(wParam) == TEXT_WINDOW_ID)
SetFocus(lpCInfo->hTextWnd);
}

break;
}

//
// Same as MainWndProc's MM_ACTIVEDRV case. The initial PostMessage
// is so the currently active Drv child will not process the message
// until it is no longer in focus.
//
case WM_MOUSEACTIVATE:{
LPCINFO lpCInfo;

PostMessage(ghwndDrv, WM_COMMAND, (WPARAM)MM_TOGGLE,
(LPARAM)NULL);
ghwndDrv = hwnd;
SendMessage(ghwndDrv, WM_COMMAND, (WPARAM)MM_TOGGLE,
(LPARAM)NULL);

lpCInfo = (LPCINFO) GetWindowLong(hwnd, GWL_USERDATA);

if (!lpCInfo) {
ErrorMsg(TEXT("DrvWndProc: lpCInfo is NULL."));
return FALSE;
}

SendMessage(ghwndDrives, WM_COMMAND, MM_ACTIVEDRV,
(LPARAM)lpCInfo->lpDriveInfo);

break;
}

//
// Free the DRVCHILDINFO data that associates with this window
// also, reset the menu.
//
case WM_CLOSE: {
LPCINFO lpCInfo;

lpCInfo = (LPCINFO)GetWindowLong(hwnd, GWL_USERDATA);

if (!lpCInfo) {
ErrorMsg(TEXT("DrvWndProc: WM_CLOSE: lpCInfo is NULL."));
return 0;
}

CloseHandle(lpCInfo->hDirThread);
CloseHandle(lpCInfo->hDirMutex );
CloseHandle(lpCInfo->hFileMutex );
TableFree(lpCInfo->DirTable);
TableFree(lpCInfo->FileTable);

break;
}

// case WM_DELETEITEM:
case WM_DRAWITEM: {

// Get pointer to the DRAWITEMSTRUCT
lpdis = (LPDRAWITEMSTRUCT)lParam;

switch (lpdis->itemAction)

{ 
case ODA_DRAWENTIRE:
DrawEntireItem(lpdis);
break;

case ODA_SELECT:
HandleSelectionState(lpdis);
break;

}

// Return TRUE meaning that we processed this message.
return 1;
}

case WM_MEASUREITEM:{

lpmis = (LPMEASUREITEMSTRUCT)lParam;


// All the items are the same height since the list box style is
// LBS_OWNERDRAWFIXED
//
lpmis->itemHeight = 15;
return 1;
}

case WM_COMPAREITEM: {
INT cv;

lpcis = (LPCOMPAREITEMSTRUCT)lParam;

if (!lpcis->itemData1)
ErrorMsg(TEXT("WM_COMPAREITEM: lpcis->itemData1 is NULL."));

if (!lpcis->itemData2)
ErrorMsg(TEXT("WM_COMPAREITEM: lpcis->itemData2 is NULL."));

cv = CFilerlstrcmp((LPTSTR)(lpcis->itemData1), (LPTSTR)(lpcis->itemData2));

if (cv < 0)
return -1;
else if (cv == 0)
return 0;
else if (cv > 0)
return 1;

}

default:
return DefWindowProc(hwnd, message, wParam, lParam);

} //switch
return DefWindowProc(hwnd, message, wParam, lParam);
}

/*************************************************************************************\
* TextWndProc()
*
* Text Window procedure for displaying miscellaneous messages to user.
\*************************************************************************************/

LRESULT WINAPI TextWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

switch (message)
{
case WM_CREATE:
{
HDC hDC;
HGDIOBJ hOldFont;
TEXTMETRIC tm;
LONG lHeight;

hDC = GetDC(hwnd);

hOldFont = SelectObject(hDC, ghFont);
GetTextMetrics(hDC, &tm);

//
// base the height of the window on size of text
//
lHeight = tm.tmHeight + GetSystemMetrics(SM_CYBORDER) + 6;

//
// saved the height for later reference
//
SetWindowLong(hwnd, GWL_USERDATA, lHeight);

if(hOldFont)
SelectObject(hDC, hOldFont);

ReleaseDC(hwnd, hDC);
break;
}

case WM_SETTEXT:
DefWindowProc(hwnd, message, wParam, lParam);
if( !InvalidateRect(hwnd, NULL, TRUE) ){
ErrorMsg(TEXT("Textwindow: Set text failure."));
return 1;
}
UpdateWindow(hwnd);
return 1;

case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
TCHAR ach[BUF_SIZE];
int len, nxBorder, nyBorder;
HFONT hOldFont = NULL;
HBRUSH hBrush;

BeginPaint(hwnd, &ps);

GetClientRect(hwnd,&rc);

len = GetWindowText(hwnd, ach, BUF_SIZE);

SetBkMode(ps.hdc, TRANSPARENT);

if( GetParent(hwnd) == ghwndDrv ){
hBrush = CreateSolidBrush( GetSysColor(COLOR_ACTIVECAPTION) );
SetTextColor( ps.hdc, GetSysColor(COLOR_CAPTIONTEXT) );
}
else{
hBrush = CreateSolidBrush( GetSysColor(COLOR_INACTIVECAPTION) );
SetTextColor( ps.hdc, GetSysColor(COLOR_INACTIVECAPTIONTEXT) );
}

hOldFont = SelectObject(ps.hdc, ghFont);

FillRect(ps.hdc, &rc, hBrush);

nxBorder = GetSystemMetrics(SM_CXBORDER);
rc.left += 9*nxBorder;
rc.right -= 9*nxBorder;

nyBorder = GetSystemMetrics(SM_CYBORDER);
rc.top += 3*nyBorder;
rc.bottom -= 3*nyBorder;

ExtTextOut(ps.hdc, rc.left+2*nxBorder, rc.top, ETO_CLIPPED,
&rc, ach, len, NULL);

SetBkMode(ps.hdc, OPAQUE);

if (hOldFont)
SelectObject(ps.hdc, hOldFont);

DeleteObject(hBrush);

EndPaint(hwnd, &ps);
return 1;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}