/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    coverpg.c

Abstract:

    Functions for working with cover pages

Environment:

        Windows NT fax driver user interface

Revision History:

        02/05/96 -davidx-
                Created it.

        mm/dd/yy -author-
                description

--*/

#include "faxcpl.h"
#include <shlobj.h>
#include <shellapi.h>
#include <commdlg.h>

#define FAXUTIL_DEBUG
#define FAXUTIL_MEM
#define FAXUTIL_REG
#define FAXUTIL_ADAPTIVE
#include "faxutil.h"


//
// Find the filename portion given a filename:
//  return a pointer to the '.' character if successful
//  NULL if there is no extension
//

#define FindFilenameExtension(pFilename) _tcsrchr(pFilename, TEXT(FILENAME_EXT))



VOID
AddCoverPagesToList(
    PCPDATA     pCPInfo,
    HWND        hwndList,
    INT         dirIndex
    )

/*++

Routine Description:

    Add the cover page files in the specified directory to a list

Arguments:

    pCPInfo - Points to cover page information
    hwndList - Handle to a list window
    dirIndex - Cover page directory index

Return Value:

    NONE

--*/

{
    WIN32_FIND_DATA findData;
    TCHAR           filename[MAX_PATH];
    HANDLE          hFindFile;
    LPTSTR          pDirPath, pFilename, pExtension;
    INT             listIndex, dirLen, fileLen, flags;

    //
    // Copy the directory path to a local buffer
    //

    flags = dirIndex;
    pDirPath = pCPInfo->pDirPath[dirIndex];

    if (IsEmptyString(pDirPath))
        return;

    if ((dirLen = _tcslen(pDirPath)) >= MAX_PATH - MAX_FILENAME_EXT - 1) {

        Error(("Directory name too long: %ws\n", pDirPath));
        return;
    }

    _tcscpy(filename, pDirPath);

    //
    // Go through the following loop twice:
    //  Once to add the files with .ncp extension
    //  Again to add the files with .lnk extension
    //
    // Don't chase links for server based cover pages
    //

    do {

        //
        // Generate a specification for the files we're interested in
        //

        pFilename = &filename[dirLen];
        *pFilename = TEXT('*');
        _tcscpy(pFilename+1, (flags & CPFLAG_LINK) ? LNK_FILENAME_EXT : CP_FILENAME_EXT);

        //
        // Call FindFirstFile/FindNextFile to enumerate the files
        // matching our specification
        //

        hFindFile = FindFirstFile(filename, &findData);

        if (hFindFile != INVALID_HANDLE_VALUE) {

            do {

                //
                // Exclude directories and hidden files
                //

                if (findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_DIRECTORY))
                    continue;

                //
                // Make sure we have enough room to store the full pathname
                //

                if ((fileLen = _tcslen(findData.cFileName)) <= MAX_FILENAME_EXT)
                    continue;

                if (fileLen + dirLen >= MAX_PATH) {

                    Error(("Filename too long: %ws%ws\n", pDirPath, findData.cFileName));
                    continue;
                }

                //
                // If we're chasing links, make sure the link refers to
                // a cover page file.
                //

                if (flags & CPFLAG_LINK) {

                    _tcscpy(pFilename, findData.cFileName);

                    if (! IsCoverPageShortcut(filename))
                        continue;
                }

                //
                // Don't display the filename extension
                //

                if (pExtension = FindFilenameExtension(findData.cFileName))
                    *pExtension = NUL;

                //
                // Add the cover page name to the list window
                //

                listIndex = SendMessage(hwndList,
                                        LB_ADDSTRING,
                                        0,
                                        (LPARAM) findData.cFileName);

                if (listIndex != LB_ERR)
                    SendMessage(hwndList, LB_SETITEMDATA, listIndex, flags);

            } while (FindNextFile(hFindFile, &findData));

            FindClose(hFindFile);
        }

        flags ^= CPFLAG_LINK;

    } while ((flags & CPFLAG_LINK) && ! pCPInfo->serverCP);
}



VOID
InitCoverPageList(
    PCPDATA pCPInfo,
    HWND    hDlg
    )

/*++

Routine Description:

    Generate a list of available cover pages

Arguments:

    pCPInfo - Points to cover page information
    hDlg - Handle to the dialog window containing cover page list

Return Value:

    NONE

--*/

{
    HWND    hwndList;
    INT     index, lastSel;

    if ((hwndList = GetDlgItem(hDlg, IDC_COVERPG_LIST)) && pCPInfo) {

        //
        // Disable redraw on the list and reset its content
        //

        if ((lastSel = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) == LB_ERR)
            lastSel = 0;

        SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
        SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

        //
        // Add cover pages to the list
        //

        for (index=0; index < pCPInfo->nDirs; index++)
            AddCoverPagesToList(pCPInfo, hwndList, index);

        //
        // Highlight the first cover page in the list
        //

        if ((index = SendMessage(hwndList, LB_GETCOUNT, 0, 0)) > 0 && lastSel >= index)
            lastSel = index - 1;

        SendMessage(hwndList, LB_SETCURSEL, lastSel, 0);

        //
        // Enable redraw on the list window
        //

        SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);

    } else if (hwndList) {

        SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
    }

    UpdateCoverPageControls(hDlg);
}



INT
GetSelectedCoverPage(
    PCPDATA pCPInfo,
    HWND    hwndList,
    LPTSTR  pBuffer
    )

/*++

Routine Description:

    Retrieve the currently selected cover page filename

Arguments:

    pCPInfo - Points to cover page information
    hwndList - Handle to the list window
    pBuffer - Points to a buffer for storing the selected cover page filename
        The size of the buffer is assumed to be MAX_PATH characters.
        if pBuffer is NULL, we assume the called is interested in the item flags

Return Value:

    Flags associated with the currently selected item
    Negative if there is an error

--*/

{
    LPTSTR      pDirPath;
    INT         selIndex, itemFlags;

    //
    // Default to empty string in case of an error
    //

    if (pBuffer)
        pBuffer[0] = NUL;

    if (pCPInfo == NULL || hwndList == NULL)
        return LB_ERR;

    //
    // Get currently selected item index
    //

    if ((selIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) == LB_ERR)
        return selIndex;

    //
    // Get the flags associated with the currently selected item
    //

    itemFlags = SendMessage(hwndList, LB_GETITEMDATA, selIndex, 0);

    if (itemFlags == LB_ERR || !pBuffer)
        return itemFlags;

    Assert((itemFlags & CPFLAG_DIRINDEX) < pCPInfo->nDirs);
    pDirPath = pCPInfo->pDirPath[itemFlags & CPFLAG_DIRINDEX];

    //
    // Assemble the full pathname for the cover page file
    //  directory prefix
    //  display name
    //  filename extension
    //

    while (*pBuffer++ = *pDirPath++)
        NULL;

    pBuffer--;

    SendMessage(hwndList, LB_GETTEXT, selIndex, (LPARAM) pBuffer);
    _tcscat(pBuffer, (itemFlags & CPFLAG_LINK) ? LNK_FILENAME_EXT : CP_FILENAME_EXT);

    return itemFlags;
}



BOOL
GetServerCoverPageDirs(
    PCPDATA pCPInfo
    )

/*++

Routine Description:

    Find the directories in which the server cover pages are stored

Arguments:

    hPrinter - Handle to a printer object
    pCPInfo - Points to cover page information

Return Value:

    TRUE if successful, FALSE otherwise

--*/

{
    BOOL            status = FALSE;
    DWORD           cbNeeded;
    LPTSTR          pServerDir;


    //
    // Find the driver directory on the printer server
    //

    cbNeeded = (_tcslen(gConfigData->pServerName) + _tcslen(SERVER_CP_DIRECTORY) + 16) * sizeof(TCHAR);

    if (pServerDir = MemAllocZ(cbNeeded)) {

        _tcscpy( pServerDir, gConfigData->pServerName );
        _tcscat( pServerDir, SERVER_CP_DIRECTORY );

        Assert(pCPInfo->nDirs == 0);
        pCPInfo->nDirs = 1;
        pCPInfo->pDirPath[0] = pServerDir;
        status = TRUE;

    }

    //
    // Clean up before returning to caller
    //

    if (! status) {
        MemFree(pServerDir);
    }

    return status;
}



VOID
AppendPathSeparator(
    LPTSTR  pDirPath
    )

/*++

Routine Description:

    Append a path separator (if necessary) at the end of a directory name

Arguments:

    pDirPath - Points to a directory name

Return Value:

    NONE

--*/

{
    INT length;


    //
    // Calculate the length of directory string
    //

    length = _tcslen(pDirPath);

    if (length >= MAX_PATH-1 || length < 1)
        return;

    //
    // If the last character is not a path separator,
    // append a path separator at the end
    //

    if (pDirPath[length-1] != TEXT(PATH_SEPARATOR)) {

        pDirPath[length] = TEXT(PATH_SEPARATOR);
        pDirPath[length+1] = NUL;
    }
}



PCPDATA
AllocCoverPageInfo(
    BOOL serverCP
    )

/*++

Routine Description:

    Allocate memory to hold cover page information

Arguments:

    serverCP - Is the caller interested in server or user cover pages
    hPrinter - Handle to a printer object if serverCP is TRUE

Return Value:

    Pointer to a CPDATA structure, NULL if there is an error

NOTE:

    Put this inside a critical section is the caller is concerned about
    being thread safe.

--*/

{
    PCPDATA pCPInfo;
    INT     nDirs;
    LPTSTR  pDirPath, pUserCPDir, pSavedPtr;


    if (pCPInfo = MemAllocZ(sizeof(CPDATA))) {

        if (pCPInfo->serverCP = serverCP) {

            //
            // Find the directory in which the server cover pages are stored
            //

            if (! GetServerCoverPageDirs(pCPInfo))
                Error(("Couldn't get server cover page directories\n"));

        } else if (pUserCPDir = pSavedPtr = GetUserCoverPageDir()) {

            //
            // Find the directory in which the user cover pages are stored
            //

            while (*pUserCPDir && pCPInfo->nDirs < MAX_COVERPAGE_DIRS) {

                LPTSTR  pNextDir = pUserCPDir;

                //
                // Find the next semicolon character
                //

                while (*pNextDir && *pNextDir != TEXT(';'))
                    pNextDir++;

                if (*pNextDir != NUL)
                    *pNextDir++ = NUL;

                //
                // Make sure the directory name is not too long
                //

                if (_tcslen(pUserCPDir) < MAX_PATH) {

                    if (! (pDirPath = AllocStringZ(MAX_PATH)))
                        break;

                    pCPInfo->pDirPath[pCPInfo->nDirs++] = pDirPath;
                    _tcscpy(pDirPath, pUserCPDir);
                }

                pUserCPDir = pNextDir;
            }

            MemFree(pSavedPtr);
        }

        //
        // Append path separators at the end if necessary
        //

        for (nDirs=0; nDirs < pCPInfo->nDirs; nDirs++) {

            AppendPathSeparator(pCPInfo->pDirPath[nDirs]);
            Verbose(("Cover page directory: %ws\n", pCPInfo->pDirPath[nDirs]));
        }
    }

    return pCPInfo;
}



VOID
FreeCoverPageInfo(
    PCPDATA pCPInfo
    )

/*++

Routine Description:

    Free up memory used for cover page information

Arguments:

    pCPInfo - Points to cover page information to be freed

Return Value:

    NONE

--*/

{
    if (pCPInfo) {

        INT index;

        for (index=0; index < pCPInfo->nDirs; index++)
            MemFree(pCPInfo->pDirPath[index]);

        MemFree(pCPInfo);
    }
}



LPTSTR
MakeQuotedParameterString(
    LPTSTR  pInputStr
    )

/*++

Routine Description:

    Make a copy of the input string and make sure it's in the same form
    as expected by SHELLEXECUTEINFO.lpParameters.

Arguments:

    pInputStr - Specifies the input string

Return Value:

    Pointer to the processed parameter string

--*/

#define QUOTE   TEXT('"')

{
    LPTSTR  pStr, pDestStr;
    INT     length;

    //
    // Special case: if the input string is NULL, simply return NULL
    //

    if (pInputStr == NULL)
        return NULL;

    //
    // Figure out how long the resulting string is.
    // Initial value is 3 = two extra quotes plus NUL terminator.
    //

    for (pStr=pInputStr, length=3; *pStr; pStr++)
        length += (*pStr == QUOTE) ? 3 : 1;

    //
    // Copy the input string and replace quote characters
    //

    if (pStr = pDestStr = MemAlloc(length * sizeof(TCHAR))) {

        *pStr++ = QUOTE;

        while (*pInputStr) {

            if ((*pStr++ = *pInputStr++) == QUOTE) {

                *pStr++ = QUOTE;
                *pStr++ = QUOTE;
            }
        }

        *pStr++ = QUOTE;
        *pStr = NUL;
    }

    return pDestStr;
}



VOID
HandleOpenCoverPage(
    HWND    hDlg,
    PCPDATA pCPInfo,
    HWND    hwndList,
    LPTSTR  pSelected,
    INT     action
    )

/*++

Routine Description:

    Edit the currently selected cover page file or
    create a new cover page file

Arguments:

    hDlg - Handle to the dialog window on which the list of cover pages is displayed
    pCPInfo - Points to cover page information
    hwndList - Handle to cover page listbox window
    pSelected - Currently selected cover page filename
    action - Open an existing cover page file or create a new one

Return Value:

    NONE

--*/

{
    TCHAR       filename[MAX_PATH];
    LPTSTR      pExecutableName, pDirPath, pFilename;

    SHELLEXECUTEINFO shellExeInfo = {

        sizeof(SHELLEXECUTEINFO),
        SEE_MASK_NOCLOSEPROCESS,
        hDlg,
        NULL,
        NULL,
        NULL,
        NULL,
        SW_SHOWNORMAL,
    };

    //
    // Determine the default directory to run the cover page editor in:
    //

    if (action == CPACTION_NEW) {

        //
        // When creating a new cover page, the default directory is either
        // the server cover page directory or the user cover page directory
        // depending on whether the user is doing server adminstration.
        //

        pDirPath = pCPInfo->pDirPath[0];
        pFilename = NULL;

    } else {

        INT flags;

        //
        // If the currently selected file is a link, resolve it first
        //

        _tcscpy(filename, pSelected);

        if (!IsEmptyString(pSelected) &&
            (flags = GetSelectedCoverPage(pCPInfo, hwndList, NULL)) > 0 &&
            (flags & CPFLAG_LINK) &&
            !ResolveShortcut(pSelected, filename))
        {
            DisplayMessageDialog(hDlg, 0, 0, IDS_RESOLVE_LINK_FAILED, pSelected);
            return;
        }

        //
        // Separate the filename into directory and filename components
        //

        if (pFilename = _tcsrchr(filename, TEXT(PATH_SEPARATOR))) {

            *pFilename++ = NUL;
            pDirPath = filename;

        } else {

            pFilename = filename;
            pDirPath = NULL;
        }
    }

    //
    // Find the "Cover Page Editor" executable
    //

    if ((pExecutableName = GetCoverPageEditor()) == NULL) {

        DisplayMessageDialog(hDlg, 0, 0, IDS_CANNOT_FIND_CPEDITOR);
        return;
    }

    //
    // Start cover page editor and wait for it to exit before proceeding
    //

    shellExeInfo.lpFile = pExecutableName;
    shellExeInfo.lpDirectory = pDirPath;
    shellExeInfo.lpParameters = MakeQuotedParameterString(pFilename);

    Verbose(("Cover page editor: %ws\n", pExecutableName));
    Verbose(("Initial working directory: %ws\n", pDirPath));
    Verbose(("Cover page filename: %ws\n", shellExeInfo.lpParameters));

    if (! ShellExecuteEx(&shellExeInfo)) {

        DisplayMessageDialog(hDlg, 0, 0, IDS_CANNOT_OPEN_CPEDITOR, pExecutableName);
        MemFree(shellExeInfo.lpParameters);
        MemFree(pExecutableName);
        return;
    }

    //
    // Refresh the list of cover page files when we're done
    //

    MemFree(shellExeInfo.lpParameters);
    MemFree(pExecutableName);

    if (WaitForSingleObject(shellExeInfo.hProcess, INFINITE) != WAIT_FAILED)
        InitCoverPageList(pCPInfo, hDlg);
}



VOID
HandleBrowseCoverPage(
    HWND    hDlg,
    PCPDATA pCPInfo,
    HWND    hwndList,
    LPTSTR  pSelected
    )

/*++

Routine Description:

    Remove the currently selected cover page file

Arguments:

    hDlg - Handle to the dialog window on which the list of cover pages is displayed
    pCPInfo - Points to cover page information
    hwndList - Handle to cover page listbox window
    pSelected - Currently selected cover page filename

Return Value:

    NONE

--*/

{
    TCHAR   filename[MAX_PATH];
    TCHAR   title[MAX_TITLE_LEN];
    TCHAR   filter[MAX_TITLE_LEN];
    LPTSTR  pExtension, pFilename;
    LPTSTR  pCPDir;
    INT     n;

    OPENFILENAME ofn = {

        sizeof(OPENFILENAME),
        hDlg,
        ghInstance,
        filter,
        NULL,
        0,
        1,
        filename,
        MAX_PATH,
        NULL,
        0,
        NULL,
        title,
        OFN_FILEMUSTEXIST | OFN_NODEREFERENCELINKS | OFN_HIDEREADONLY,
        0,
        0,
        NULL,
        0,
        NULL,
        NULL,
    };

    //
    // Figure out what the initial directory should be
    //

    if (! IsEmptyString(pSelected)) {

        INT flags;

        //
        // Find out if the currently selected cover page file is a
        // user cover page and whether it's a link
        //

        if ((flags = GetSelectedCoverPage(pCPInfo, hwndList, NULL)) > 0 &&
            (flags & CPFLAG_LINK) &&
            ResolveShortcut(pSelected, filename))
        {
            //
            // Set the initial directory to the link destination
            //

            _tcscpy(pSelected, filename);

            if (pFilename = _tcsrchr(pSelected, TEXT(PATH_SEPARATOR))) {

                *pFilename = NUL;
                ofn.lpstrInitialDir = pSelected;
            }
        }
    }

    //
    // Compose the file-type filter string
    //

    LoadString(ghInstance, IDS_CP_FILETYPE, title, MAX_TITLE_LEN);
    wsprintf(filter, TEXT("%s%c*%s%c"), title, NUL, CP_FILENAME_EXT, NUL);

    LoadString(ghInstance, IDS_BROWSE_COVERPAGE, title, MAX_TITLE_LEN);
    filename[0] = NUL;

    //
    // Present the "Open File" dialog
    //

    if (! GetOpenFileName(&ofn))
        return;

    //
    // Make sure the selected filename has the correct extension
    //

    if ((pExtension = FindFilenameExtension(filename)) == NULL ||
         _tcsicmp(pExtension, CP_FILENAME_EXT) != EQUAL_STRING)
    {
        DisplayMessageDialog(hDlg, 0, 0, IDS_BAD_CP_EXTENSION, CP_FILENAME_EXT);
        return;
    }

    //
    // Check if the selected file is already inside one of the
    // cover page directories
    //

    for (n=0; n < pCPInfo->nDirs; n++) {

        if (_tcsnicmp(filename, pCPInfo->pDirPath[n], ofn.nFileOffset) == EQUAL_STRING) {

            DisplayMessageDialog(hDlg, 0, 0, IDS_CP_DUPLICATE, filename);
            return;
        }
    }

    //
    // Add the selected cover page file to the first cover page directory
    // Create the cover page directory if necessary
    //

    pCPDir = pCPInfo->pDirPath[0];

    if (!pCPDir || IsEmptyString(pCPDir)) {

        DisplayMessageDialog(hDlg, 0, 0, IDS_NO_COVERPG_DIR);
        return;
    }

    CreateDirectory(pCPDir, NULL);

    pFilename = &filename[ofn.nFileOffset];
    _tcscpy(pSelected, pCPDir);
    n = _tcslen(pSelected);

    if (n + _tcslen(pFilename) >= MAX_PATH - MAX_FILENAME_EXT || pFilename >= pExtension) {

        DisplayMessageDialog(hDlg, 0, 0, IDS_FILENAME_TOOLONG);
        return;
    }

    _tcsncpy(pSelected + n, pFilename, pExtension - pFilename);
    n += pExtension - pFilename;

    if (pCPInfo->serverCP) {

        //
        // Copy the physical file for server cover pages
        //

        _tcscpy(pSelected + n, CP_FILENAME_EXT);

        if (! CopyFile(filename, pSelected, FALSE)) {

            DisplayMessageDialog(hDlg, 0, 0, IDS_COPY_FILE_FAILED, filename, pSelected);
            return;
        }

    } else {

        //
        // Create the shortcut file for user cover page
        //

        _tcscpy(pSelected + n, LNK_FILENAME_EXT);

        if (! CreateShortcut(pSelected, filename)) {

            DisplayMessageDialog(hDlg, 0, 0, IDS_CREATE_LINK_FAILED, pSelected, filename);
            return;
        }
    }

    //
    // Refresh the cover page list - we're being lazy here in that
    // we reset the entire list content
    //

    InitCoverPageList(pCPInfo, hDlg);
}



VOID
HandleRemoveCoverPage(
    HWND    hDlg,
    PCPDATA pCPInfo,
    HWND    hwndList,
    LPTSTR  pFilename
    )

/*++

Routine Description:

    Remove the currently selected cover page file

Arguments:

    hDlg - Handle to the dialog window on which the list of cover pages is displayed
    pCPInfo - Points to cover page information
    hwndList - Handle to cover page listbox window
    pFilename - Currently selected cover page filename

Return Value:

    NONE

--*/

{
    //
    // Display the confirmation dialog before proceeding
    //

    if (DisplayMessageDialog(hDlg,
                             MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2,
                             IDS_CONFIRM_DELETE,
                             IDS_DELETE_PROMPT,
                             pFilename) == IDYES)
    {
        if (DeleteFile(pFilename)) {

            //
            // Update the list box if the file is successfully removed
            //

            INT selIndex, count;

            if ((selIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) != LB_ERR) {

                SendMessage(hwndList, LB_DELETESTRING, selIndex, 0);

                if ((count = SendMessage(hwndList, LB_GETCOUNT, 0, 0)) > 0) {

                    count --;
                    SendMessage(hwndList, LB_SETCURSEL, min(selIndex, count), 0);
                }
            }

            UpdateCoverPageControls(hDlg);

        } else
            DisplayMessageDialog(hDlg, 0, 0, IDS_DELETE_FAILED, pFilename);
    }
}



VOID
ManageCoverPageList(
    HWND    hDlg,
    PCPDATA pCPInfo,
    HWND    hwndList,
    INT     action
    )

/*++

Routine Description:

    Perform various action to manage the list of cover pages

Arguments:

    hDlg - Handle to the dialog window on which the list of cover pages is displayed
    pCPInfo - Points to cover page information
    hwndList - Handle to cover page listbox window
    action - What action to perform on the cover page list

Return Value:

    NONE

--*/

{
    TCHAR   filename[MAX_PATH];

    //
    // Get the name of currently selected cover page file
    //

    if (pCPInfo == NULL || hwndList == NULL)
        return;

    GetSelectedCoverPage(pCPInfo, hwndList, filename);

    //
    // Call appropriate function depends on the action parameter
    //

    switch (action) {

    case CPACTION_OPEN:

        if (IsEmptyString(filename))
            break;

    case CPACTION_NEW:

        HandleOpenCoverPage(hDlg, pCPInfo, hwndList, filename, action);
        break;

    case CPACTION_BROWSE:

        HandleBrowseCoverPage(hDlg, pCPInfo, hwndList, filename);
        break;

    case CPACTION_REMOVE:

        if (! IsEmptyString(filename))
            HandleRemoveCoverPage(hDlg, pCPInfo, hwndList, filename);
        break;
    }
}



VOID
UpdateCoverPageControls(
    HWND    hDlg
    )

/*++

Routine Description:

    Enable/disable buttons for manage cover page files

Arguments:

    hDlg - Handle to the property page containing the cover page controls

Return Value:

    NONE

--*/

{
    HWND    hwndOpen, hwndRemove;

    //
    // If all buttons are disabled, leave them alone here
    //

    if (! IsWindowEnabled(GetDlgItem(hDlg, IDC_COVERPG_NEW)))
        return;

    hwndOpen = GetDlgItem(hDlg, IDC_COVERPG_OPEN);
    hwndRemove = GetDlgItem(hDlg, IDC_COVERPG_REMOVE);

    if (SendDlgItemMessage(hDlg, IDC_COVERPG_LIST, LB_GETCURSEL, 0, 0) != LB_ERR) {

        EnableWindow(hwndOpen, TRUE);
        EnableWindow(hwndRemove, TRUE);

    } else {

        if (GetFocus() == hwndOpen || GetFocus() == hwndRemove)
            SetFocus(GetDlgItem(hDlg, IDC_COVERPG_NEW));

        EnableWindow(hwndOpen, FALSE);
        EnableWindow(hwndRemove, FALSE);
    }
}