/*  BACKDLG.C
**
**  Copyright (C) Microsoft, 1993, All Rights Reserved.
**
**
**  History:
**
*/

#include "precomp.h"
#include "shlwapi.h"

#define MAX_RHS    256

TCHAR g_szPattern[] = TEXT("pattern");
TCHAR szDesktop[] = TEXT("desktop");
TCHAR szWallpaper[] = TEXT("wallpaper");
TCHAR szTileWall[] = TEXT("TileWallpaper");
TCHAR szDotBMP[] = TEXT(".bmp");
TCHAR szBMP[] = TEXT("\\*.bmp");
TCHAR szDefExt[] = TEXT("bmp");
BOOL g_bValidBitmap = FALSE;    // the currently selected wallpaper is valid

TCHAR g_szCurPattern[MAX_PATH];
TCHAR g_szCurWallpaper[MAX_PATH];
TCHAR g_szTempItem[MAX_PATH];      // which is more of a waste, stack or data?

BOOL g_Back_bInit = TRUE;       // assume we are in initialization process
BOOL g_Back_bChanged = FALSE;   // changes have been made

static void NukeExt(LPTSTR sz);
static void AddExt(LPTSTR sz, LPTSTR x);
static LPTSTR NEAR PASCAL NiceName(LPTSTR sz);

INT_PTR CALLBACK PatternDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);

#include "help.h"

const static DWORD FAR aBckgrndHelpIds[] = {
        IDC_NO_HELP_1,   IDH_COMM_GROUPBOX,
        IDC_NO_HELP_2,   IDH_COMM_GROUPBOX,
        IDC_PATLIST,     IDH_DSKTPBACKGROUND_PATTLIST,
        IDC_EDITPAT,     IDH_DSKTPBACKGROUND_EDITPAT,
        IDC_WALLLIST,    IDH_DSKTPBACKGROUND_WALLLIST,
        IDC_BROWSEWALL,  IDH_DSKTPBACKGROUND_BROWSE,
        IDC_TXT_DISPLAY, IDH_DSKTPBACKGROUND_DISPLAY,
        IDC_TILE,        IDH_DSKTPBACKGROUND_TILE,
        IDC_CENTER,      IDH_DSKTPBACKGROUND_CENTER,
        IDC_BACKPREV,    IDH_DSKTPBACKGROUND_MONITOR,

        0, 0
};

static const TCHAR szRegStr_Desktop[] = REGSTR_PATH_DESKTOP;
static const TCHAR szRegStr_Setup[] = REGSTR_PATH_SETUP TEXT("\\Setup");
static const TCHAR szSharedDir[] = TEXT("SharedDir");

// we're mainly trying to filter multilingual upgrade cases
// where the text for "(None)" is unpredictable
//
BOOL NEAR PASCAL IsProbablyAValidPattern( LPCTSTR pat )
{
    BOOL sawanumber = FALSE;

    while( *pat )
    {
        if( ( *pat < TEXT('0') ) || ( *pat > TEXT('9') ) )
        {
            // it's not a number, it better be a space
            if( *pat != TEXT(' ') )
                return FALSE;
        }
        else
            sawanumber = TRUE;

        // NOTE: we avoid the need for AnsiNext by only advancing on US TCHARs
        pat++;
    }

    // TRUE if we saw at least one digit and there were only digits and spaces
    return sawanumber;
}


#ifdef DEBUG

#define REG_INTEGER  1000
int  fTraceRegAccess = 0;

void NEAR PASCAL  RegDetails(int iWrite, HKEY hk, LPCTSTR lpszSubKey,
    LPCTSTR lpszValueName, DWORD dwType, LPTSTR  lpszString, int iValue)
{
  TCHAR Buff[256];
  TCHAR far *lpszReadWrite[] = { TEXT("DESK.CPL:Read"), TEXT("DESK.CPL:Write") };

  if(!fTraceRegAccess)
     return;

  switch(dwType)
    {
      case REG_SZ:
          wsprintf(Buff, TEXT("%s String:hk=%#08lx, %s:%s=%s\n\r"), lpszReadWrite[iWrite],
                           hk, lpszSubKey, lpszValueName, lpszString);
          break;

      case REG_INTEGER:
          wsprintf(Buff, TEXT("%s int:hk=%#08lx, %s:%s=%d\n\r"), lpszReadWrite[iWrite],
                           hk, lpszSubKey, lpszValueName, iValue);
          break;

      case REG_BINARY:
          wsprintf(Buff, TEXT("%s Binary:hk=%#08lx, %s:%s=%#0lx;DataSize:%d\r\n"), lpszReadWrite[iWrite],
                           hk, lpszSubKey, lpszValueName, lpszString, iValue);
          break;
    }
  OutputDebugString(Buff);
}

#endif  // DEBUG


//---------------------------------------------------------------------------
//  GetIntFromSubKey
//      hKey is the handle to the subkey
//      (already pointing to the proper location).
//---------------------------------------------------------------------------

int NEAR PASCAL GetIntFromSubkey(HKEY hKey, LPCTSTR lpszValueName, int iDefault)
{
  TCHAR  szValue[20];
  DWORD dwSizeofValueBuff = sizeof(szValue);
  DWORD dwType;
  int   iRetValue = iDefault;

  if((RegQueryValueEx(hKey, lpszValueName, NULL, &dwType,
                        (LPBYTE)szValue,
                &dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
  {
    // BOGUS: This handles only the string type entries now!
    if(dwType == REG_SZ)
        iRetValue = (int)StrToInt(szValue);
#ifdef DEBUG
    else
        OutputDebugString(TEXT("String type expected from Registry\n\r"));
#endif
  }
#ifdef DEBUG
  RegDetails(0, hKey, TEXT(""), lpszValueName, REG_INTEGER, NULL, iRetValue);
#endif
  return(iRetValue);
}

//---------------------------------------------------------------------------
//  GetIntFromReg()
//       Opens the given subkey and gets the int value.
//---------------------------------------------------------------------------

int NEAR PASCAL GetIntFromReg(HKEY   hKey,
                                        LPCTSTR lpszSubkey,
                                        LPCTSTR lpszNameValue, int iDefault)
{
  HKEY hk;
  int   iRetValue = iDefault;

  // See if the key is present.
  if(RegOpenKey(hKey, lpszSubkey, &hk) == ERROR_SUCCESS)
    {
      iRetValue = GetIntFromSubkey(hk, lpszNameValue, iDefault);
      RegCloseKey(hk);
    }
  return(iRetValue);
}

BOOL NEAR PASCAL GetStringFromReg(HKEY   hKey,
                                        LPCTSTR lpszSubkey,
                                        LPCTSTR lpszValueName,
                                        LPCTSTR lpszDefault,
                                        LPTSTR lpszValue,
                                        DWORD cchSizeofValueBuff)
{
  HKEY hk;
  DWORD dwType;
  BOOL  fSuccess = FALSE;

  cchSizeofValueBuff *= sizeof(TCHAR);

  // See if the key is present.
  if(RegOpenKey(hKey, lpszSubkey, &hk) == ERROR_SUCCESS)
    {
      if((RegQueryValueEx(hk, lpszValueName, NULL, &dwType,
                        (LPBYTE)lpszValue,
                &cchSizeofValueBuff) == ERROR_SUCCESS) && cchSizeofValueBuff)
        {
          // BOGUS: This handles only the string type entries now!
#ifdef DEBUG
          if(dwType != REG_SZ)
            {
              OutputDebugString(TEXT("String type expected from Registry\n\r"));
            }
          else
#endif
            fSuccess = TRUE;
        }
      RegCloseKey(hk);
    }

  // If failure, use the default string.
  if(!fSuccess && lpszDefault)
      lstrcpy(lpszValue, lpszDefault);

#ifdef DEBUG
  RegDetails(0, hKey, lpszSubkey, lpszValueName, REG_SZ, lpszValue, 0);
#endif
  return(fSuccess);
}

//---------------------------------------------------------------------------
//
//  UpdateRegistry:
//      This updates a given value of any data type at a given
//      location in the registry.
//
//  The value name is passed in as an Id to a string in USER's String table.
//
//---------------------------------------------------------------------------

BOOL FAR PASCAL UpdateRegistry(HKEY     hKey,
                                LPCTSTR   lpszSubkey,
                                LPCTSTR   lpszValueName,
                                DWORD   dwDataType,
                                LPVOID  lpvData,
                                DWORD   dwDataSize)
{
  HKEY  hk;

  if(RegCreateKey(hKey, lpszSubkey, &hk) == ERROR_SUCCESS)
    {
      RegSetValueEx(hk, lpszValueName,
                        0L, dwDataType,
                        (const UCHAR *) lpvData,
                        dwDataSize);
#ifdef DEBUG
      RegDetails(1, hKey, lpszSubkey, lpszValueName, dwDataType, (LPTSTR)lpvData, (int)dwDataSize);
#endif
      RegCloseKey(hk);
      return(TRUE);
    }
  return(FALSE);
}

/*-------------------------------------------------------------
** force the update of the preview.
**-------------------------------------------------------------*/
void NEAR PASCAL UpdatePreview(HWND hDlg, WORD flags)
{
    if (IsDlgButtonChecked(hDlg, IDC_TILE))
        flags |= BP_TILE;

    SendDlgItemMessage(hDlg, IDC_BACKPREV, WM_SETBACKINFO, flags, 0L);

    if (!g_Back_bInit && !g_Back_bChanged)
    {
        SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);

        g_Back_bChanged = TRUE;
    }
}

/*------------------------------------------------------------------
** read in all of the entries (LHS only) in a section.
**
** return: handle to local (fixed) memory containing names
**------------------------------------------------------------------*/
HANDLE PASCAL GetSection(LPTSTR lpIniFile, LPTSTR lpSection)
{
    int nCount;
    int cchSize = 4096;
    int cbSize = (cchSize * sizeof(TCHAR));
    HANDLE hLocal, hTemp;

    if (!(hLocal = LocalAlloc(LPTR, cbSize)))
        return(NULL);

    while (1)
    {
        nCount = GetPrivateProfileString(lpSection, NULL, g_szNULL, (LPTSTR)hLocal, cchSize, lpIniFile);

        if (nCount <= (cchSize-1))
            break;

        // need to grow the buffer
        cchSize += 2048;
        cbSize = (cchSize * sizeof(TCHAR));
        hTemp = hLocal;
        if (!(hLocal = LocalReAlloc(hTemp, cbSize, LMEM_MOVEABLE)))
        {
            LocalFree(hTemp);
            return(NULL);
        }
    }

    return(hLocal);
}

static void NukeExt(LPTSTR sz)
{
    int len;

    len = lstrlen(sz);

    if (len > 4 && sz[len-4] == TEXT('.'))
        sz[len-4] = 0;
}

static void AddExt(LPTSTR sz, LPTSTR x)
{
    int len;

    len = lstrlen(sz);

    if (len <= 4 || sz[len-4] != TEXT('.'))
    {
        lstrcat(sz, TEXT("."));
        lstrcat(sz, x);
    }
}

static void NameOnly(LPTSTR sz)
{
    LPTSTR p = sz;
    LPTSTR s = NULL;

    while( *p )
    {
        if( ( *p == TEXT('\\') ) || ( *p == TEXT(':') ) )
            s = p;
#if defined(DBCS) || (defined(FE_SB) && !defined(UNICODE))
        p = AnsiNext(p);
#else
        p++;
#endif
    }

    if( s )
    {
        p = sz;

        while( *s++ )
        {
            *p++ = *s;
        }
    }
}

static BOOL PathOnly(LPTSTR sz)
{
    LPTSTR p = sz;
    LPTSTR s = NULL;

    while( *p )
    {
        if( *p == TEXT('\\') )
        {
            s = p;
        }
        else if( *p == TEXT(':') )
        {
            s = p + 1;
        }
#if defined(DBCS) || (defined(FE_SB) && !defined(UNICODE))
        p = AnsiNext(p);
#else
        p++;
#endif
    }

    if( s )
    {
        if( s == sz )
            s++;

        *s = TEXT('\0');
        return TRUE;
    }

    return FALSE;
}

static LPTSTR NEAR PASCAL NiceName(LPTSTR sz)
{
    NukeExt(sz);

    if (IsCharUpper(sz[0]) && IsCharUpper(sz[1]))
    {
        CharLower(sz);
        CharUpperBuff(sz, 1);
    }

    return sz;
}

int NEAR PASCAL AddAFileToLB( HWND hwndList, LPCTSTR szDir, LPTSTR szFile )
{
    int index = LB_ERR;

    LPTSTR szPath = (LPTSTR)LocalAlloc( LPTR,
        (( szDir? lstrlen( szDir ) : 0 ) + lstrlen( szFile ) + 2) * sizeof(TCHAR) );

    if( szPath )
    {
        if( szDir )
        {
            lstrcpy( (LPTSTR)szPath, (LPTSTR)szDir );
            lstrcat( (LPTSTR)szPath, TEXT("\\") );
        }
        else
            *szPath = TEXT('\0');

        lstrcat( (LPTSTR)szPath, szFile );
        NameOnly( szFile );
        NiceName( szFile );

        index = (int)SendMessage( hwndList, LB_ADDSTRING, 0,
            (LPARAM)(LPTSTR)szFile );

        if( index >= 0 )
        {
            SendMessage( hwndList, LB_SETITEMDATA, (WPARAM)index,
                (LPARAM)(LPTSTR)szPath );
        }
        else
            LocalFree( (HANDLE)szPath );
    }

    return index;
}

void NEAR PASCAL AddFilesToLB(HWND hwndList, LPTSTR pszDir, LPTSTR szSpec)
{
    WIN32_FIND_DATA fd;
    HANDLE h;
    TCHAR szBuf[MAX_PATH];

    lstrcpy(szBuf, pszDir);
    lstrcat(szBuf, szSpec);

    h = FindFirstFile(szBuf, &fd);

    if (h != INVALID_HANDLE_VALUE)
    {
        do
        {
            AddAFileToLB(hwndList, pszDir, fd.cFileName);
        }
        while (FindNextFile(h, &fd));

        FindClose(h);
    }
}

/*-------------------------------------------------------------
** set a new wallpaper and notify the right places.
**
** the new name is in g_szCurWallpaper
**-------------------------------------------------------------*/
void NEAR PASCAL SetNewWallpaper(HWND hDlg, LPTSTR szFile, BOOL bCanAdd)
{
    HWND hwndList = GetDlgItem(hDlg, IDC_WALLLIST);

    if(!szFile || !lstrcmpi(szFile, g_szNone))
        szFile = TEXT("");

    if(
#if defined(DBCS) || (defined(FE_SB) && !defined(UNICODE))
        !IsDBCSLeadByte(szFile[0]) &&
#endif
        (szFile[1] == TEXT(':')) )
    {
        TCHAR szDrive[3];
        TCHAR szNet[MAX_PATH];
        ULONG lenNet = ARRAYSIZE(szNet);

        lstrcpyn(szDrive, szFile, ARRAYSIZE(szDrive));
        if ((NO_ERROR == WNetGetConnection(szDrive, szNet, &lenNet)) &&
            (szNet[0] == TEXT('\\')) && (szNet[1] == TEXT('\\')))
        {
            lstrcat(szNet, szFile+2);
            lstrcpy(szFile, szNet);
        }
    }

    lstrcpy(g_szCurWallpaper, szFile);
    UpdatePreview(hDlg, BP_NEWWALL);

    if(bCanAdd && *szFile && g_bValidBitmap)
    {
        TCHAR szName[MAX_PATH];
        int sel;

        lstrcpy(szName, szFile);
        NameOnly(szName);
        NiceName(szName);

        if ((sel = (int)SendMessage(hwndList, LB_FINDSTRINGEXACT, (WPARAM)-1,
            (LPARAM)(LPTSTR)szName)) == LB_ERR)
        {
            sel = AddAFileToLB(hwndList, NULL, szFile);
        }

        SendMessage(hwndList, LB_SETCURSEL, (WPARAM)sel, 0L);
    }

    {
        BOOL bEnable = (*szFile) ? TRUE : FALSE;

        EnableWindow( GetDlgItem(hDlg, IDC_TXT_DISPLAY), bEnable );
        EnableWindow( GetDlgItem(hDlg, IDC_TILE), bEnable );
        EnableWindow( GetDlgItem(hDlg, IDC_CENTER), bEnable );
    }
}

void NEAR PASCAL InitBackgroundDialog(HWND hDlg)
{
    HANDLE hSection;
    HWND hwndList;
    LPTSTR pszBuffer;
    TCHAR szBuf[MAX_PATH];
    TCHAR szCurPatBits[MAX_PATH];

    g_szCurPattern[0] = 0;
    g_szCurWallpaper[0] = 0;
    g_Back_bChanged = FALSE;

    /*
    ** initialize the pattern list
    */
    // get the current pattern.
    // GetProfileString(szDesktop, g_szPattern, g_szNULL, szCurPatBits, ARRAYSIZE(szCurPatBits));
    szCurPatBits[0] = 0; //Initialize
    GetStringFromReg(HKEY_CURRENT_USER, szRegStr_Desktop,
                                        g_szPattern, g_szNULL, szCurPatBits,
                                        ARRAYSIZE(szCurPatBits));
    if (!(*szCurPatBits))
        lstrcpy(g_szCurPattern, g_szNone);
    else
        *g_szCurPattern = 0;

    hwndList = GetDlgItem(hDlg, IDC_PATLIST);
    if (hSection = GetSection(g_szControlIni, g_szPatterns))
    {
        BOOL bAddedNone = FALSE;
        /* Put the patterns into the combo box. */
        for (pszBuffer = (LPTSTR) LocalLock(hSection); *pszBuffer; pszBuffer += (lstrlen(pszBuffer)+1))
        {
            if (GetPrivateProfileString(g_szPatterns, pszBuffer, g_szNULL, szBuf, ARRAYSIZE(szBuf), g_szControlIni))
            {
                BOOL bIsNone = !bAddedNone && !lstrcmpi( g_szNone, szBuf );

                /* if there's a right-hand side, add it to the list box */
                if( bIsNone || IsProbablyAValidPattern( szBuf ) )
                {
                    if( bIsNone )
                        bAddedNone = TRUE;

                    SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pszBuffer);

                    // if haven't found current pattern name, maybe this is it.
                    if (!(*g_szCurPattern) && (!lstrcmpi(szBuf, szCurPatBits)))
                    {
                        // same pattern bits.  we have a name
                        lstrcpy(g_szCurPattern, pszBuffer);
                    }
                }
            }
        }
        LocalUnlock(hSection);
        LocalFree(hSection);
    }

    // if our patternTEXT('s bits weren')t in the list, use a fake name
    if (!(*g_szCurPattern))
        LoadString(hInstance, IDS_UNLISTEDPAT, g_szCurPattern, ARRAYSIZE(g_szCurPattern));

    SendMessage(hwndList, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPTSTR)g_szCurPattern);
    UpdatePreview(hDlg, BP_NEWPAT);

    // exclude TEXT("none") pattern
    if( (int)SendDlgItemMessage(hDlg,IDC_PATLIST,LB_GETCURSEL,0,0l) <= 0 )
    {
        HWND epat = GetDlgItem( hDlg, IDC_EDITPAT );

        if( GetFocus() == epat )
        {
            SendMessage( hDlg, WM_NEXTDLGCTL,
                (WPARAM)GetDlgItem( hDlg, IDC_PATLIST ), (LPARAM)TRUE );
        }

        EnableWindow( epat, FALSE );
    }

    /*
    ** initialize the tile/center buttons
    */
    if(GetIntFromReg(HKEY_CURRENT_USER, szRegStr_Desktop, szTileWall, 1))
        CheckRadioButton(hDlg, IDC_CENTER, IDC_TILE, IDC_TILE);
    else
        CheckRadioButton(hDlg, IDC_CENTER, IDC_TILE, IDC_CENTER);

    /*
    ** initialize the wallpaper list
    */
    hwndList = GetDlgItem(hDlg, IDC_WALLLIST);

    if (!GetWindowsDirectory(szBuf, ARRAYSIZE(szBuf)))
    {
        szBuf[0] = 0;
    }

    // override with net home dir on shared copies of windows
    GetStringFromReg(HKEY_LOCAL_MACHINE, szRegStr_Setup, szSharedDir, (LPTSTR)NULL, szBuf, ARRAYSIZE(szBuf));
    AddFilesToLB(hwndList, szBuf, szBMP);

    //GetProfileString(szDesktop, szWallpaper, g_szNone, szBuf, sizeof(szBuf));
    GetStringFromReg(HKEY_CURRENT_USER, szRegStr_Desktop, szWallpaper, g_szNone, szBuf, ARRAYSIZE(szBuf));

    SetNewWallpaper(hDlg, szBuf, TRUE); // will add and select if not in list

    // and don't forget the 'none' option
    if (SendMessage(hwndList, LB_INSERTSTRING, 0, (LPARAM)(LPTSTR)g_szNone) !=
        LB_ERR)
    {
        int sel = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0L);

        if (sel == -1)
            sel = 0;

        SendMessage(hwndList, LB_SETCURSEL, (WPARAM)sel, 0L);
        if (!sel) {
            EnableWindow( GetDlgItem(hDlg, IDC_TILE), FALSE );
            EnableWindow( GetDlgItem(hDlg, IDC_CENTER), FALSE );
            EnableWindow( GetDlgItem(hDlg, IDC_TXT_DISPLAY), FALSE );
        }
    }

    // allow people to drag wallpapers to this page
    DragAcceptFiles(hDlg, TRUE);
}

//the intl tools cannot handle embedded nulls in strings
//hack: use the vertical bar and convert
void NEAR PASCAL
ConvertPipesToNull(LPTSTR szFilter)
{
#if defined(DBCS) || (defined(FE_SB) && !defined(UNICODE))
    if (IsDBCSLeadByte('|'))
        return;
#endif

    while (*szFilter)
    {
        LPTSTR p = CharNext(szFilter);

        if (*szFilter == TEXT('|'))
            *szFilter = TEXT('\0');

        szFilter = p;
    }
}

void NEAR PASCAL BrowseForWallpaper(HWND hDlg)
{
    TCHAR szPath[MAX_PATH];
    static TCHAR szWorkDir[MAX_PATH] = TEXT("");
    OPENFILENAME ofn;

    TCHAR szTitle[CCH_MAX_STRING];
    TCHAR szFilter[CCH_MAX_STRING];

    LoadString(hInstance, IDS_BROWSETITLE, szTitle, ARRAYSIZE(szTitle));
    if (LoadString(hInstance, IDS_BROWSEFILTER, szFilter, ARRAYSIZE(szFilter)))
        ConvertPipesToNull(szFilter);


    if (!PathOnly(szWorkDir))
    {
        if (!GetWindowsDirectory(szWorkDir, ARRAYSIZE(szWorkDir)))
        {
            szWorkDir[0] = 0;
        }
    }

    szPath[0] = TEXT('\0');

    ofn.lStructSize       = sizeof(ofn);
    ofn.hwndOwner         = hDlg;
    ofn.hInstance         = NULL;
    ofn.lpstrFilter       = szFilter;
    ofn.lpstrCustomFilter = NULL;
    ofn.nFilterIndex      = 1;
    ofn.nMaxCustFilter    = 0;
    ofn.lpstrFile         = szPath;
    ofn.nMaxFile          = ARRAYSIZE(szPath);
    ofn.lpstrInitialDir   = (szWorkDir[0] ? szWorkDir : NULL);
    ofn.lpstrTitle        = szTitle;
    ofn.Flags             = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
    ofn.lpfnHook          = NULL;
    ofn.lpstrDefExt       = szDefExt;
    ofn.lpstrFileTitle    = NULL;

    if (GetOpenFileName(&ofn) && (lstrcmpi(g_szCurWallpaper, szPath) != 0))
    {
        CharUpper(szPath); // will be nicenamed (best we can do...)
        SetNewWallpaper(hDlg, szPath, TRUE);
    }

    if (!GetCurrentDirectory(ARRAYSIZE(szWorkDir), szWorkDir))
    {
        szWorkDir[0] = 0;
    }
}

void NEAR PASCAL HandleWallpaperDrop(HWND hDlg, HDROP hDrop)
{
    TCHAR szPath[MAX_PATH];

    if (DragQueryFile(hDrop, 1, szPath, ARRAYSIZE(szPath)) &&
        (lstrcmpi(g_szCurWallpaper, szPath) != 0))
    {
        int len = lstrlen(szPath);

        if (len > 4 && !lstrcmpi(szPath+len-4, szDotBMP))
            SetNewWallpaper(hDlg, szPath, TRUE);
    }

    DragFinish(hDrop);
}


INT_PTR APIENTRY  BackgroundDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
{
    NMHDR FAR *lpnm;
    TCHAR szTiled[] = TEXT("0");
    TCHAR szBuf[MAX_PATH];
    TCHAR szBuf2[50];
    int  iTemp;

    switch(message)
    {
        case WM_NOTIFY:
            lpnm = (NMHDR FAR *)lParam;
            switch(lpnm->code)
            {
                case PSN_APPLY: {
                    DWORD dwRet = PSNRET_NOERROR;
                    if (g_Back_bChanged)
                    {
                        HCURSOR old = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
                        HWND cover;

                        if (!g_bValidBitmap)
                        {
                            LoadString(hInstance, IDS_BADWALLPAPER, szBuf, ARRAYSIZE(szBuf));
                            GetWindowText(GetParent(hDlg), szBuf2, ARRAYSIZE(szBuf2));
                            MessageBox(hDlg, szBuf, szBuf2, MB_OK | MB_ICONEXCLAMATION);
                            dwRet = PSNRET_INVALID_NOCHANGEPAGE;
                        }

                        // do this after whimpering
                        cover = CreateCoverWindow( COVER_NOPAINT );

                        // need to write out tile first
                        szTiled[0] += (TCHAR)IsDlgButtonChecked(hDlg, IDC_TILE);
                        UpdateRegistry(HKEY_CURRENT_USER, szRegStr_Desktop,
                            szTileWall, REG_SZ, szTiled, SIZEOF(TCHAR)*(lstrlen(szTiled)+1));

                        if (g_bValidBitmap)
                        {
                            SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, g_szCurWallpaper,
                                SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
                        }

                        if (GetPrivateProfileString(g_szPatterns, g_szCurPattern, g_szNULL, szBuf, ARRAYSIZE(szBuf), g_szControlIni))
                        {
                            SystemParametersInfo(SPI_SETDESKPATTERN, 0, szBuf,
                                        SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
                        }

                        // we're back to no changes
                        g_Back_bChanged = FALSE;

                        if( cover )
                            PostMessage( cover, WM_CLOSE, 0, 0L );

                        SetCursor( old );
                    }
                    SetWindowLongPtr(hDlg, DWLP_MSGRESULT, dwRet );
                    return TRUE;
                }

                case PSN_RESET:
                    break;
            }
            break;

        case WM_INITDIALOG:
            g_Back_bInit = TRUE;
            InitBackgroundDialog(hDlg);
            g_Back_bInit = FALSE;               // no longer initializing
            break;

        case WM_SYSCOLORCHANGE:
        case WM_DISPLAYCHANGE:
            g_Back_bInit = TRUE;    // fake init so we don't do PSM_CHANGED
            UpdatePreview(hDlg, BP_REINIT | BP_NEWPAT );
            g_Back_bInit = FALSE;
            break;

        case WM_DESTROY:
        {
            int count = (int)SendDlgItemMessage(hDlg, IDC_WALLLIST,
                LB_GETCOUNT, 0, 0L);

            while (count--)
            {
                LPTSTR sz = (LPTSTR)SendDlgItemMessage(hDlg, IDC_WALLLIST,
                    LB_GETITEMDATA, count, 0L);

                if (sz)
                    LocalFree ((HANDLE)sz);
            }
            break;
        }


        case WM_HELP:
            WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, TEXT("display.hlp"),
                HELP_WM_HELP, (DWORD_PTR) (LPTSTR) aBckgrndHelpIds);
            return TRUE;

        case WM_CONTEXTMENU:      // right mouse click
            WinHelp((HWND) wParam, TEXT("display.hlp"), HELP_CONTEXTMENU,
                (DWORD_PTR) (LPTSTR) aBckgrndHelpIds);
            return TRUE;

        case WM_DROPFILES:
            HandleWallpaperDrop(hDlg, (HDROP)wParam);
            return TRUE;

        case WM_QUERYNEWPALETTE:
        case WM_PALETTECHANGED:
            SendDlgItemMessage(hDlg, IDC_BACKPREV, message, wParam, lParam);
            return TRUE;

        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case IDC_PATLIST:
                    if(HIWORD(wParam) == LBN_SELCHANGE)
                    {
                        iTemp = (int)SendDlgItemMessage(hDlg,IDC_PATLIST,
                            LB_GETCURSEL,0,0l);
                        if(iTemp >= 0)
                        {
                            SendDlgItemMessage(hDlg, IDC_PATLIST, LB_GETTEXT,
                                iTemp, (LPARAM)(LPTSTR)szBuf);

                            if (lstrcmpi(szBuf, g_szCurPattern) == 0)
                                break;

                            lstrcpy(g_szCurPattern, szBuf);
                            UpdatePreview(hDlg, BP_NEWPAT);
                        }

                        EnableWindow( GetDlgItem( hDlg, IDC_EDITPAT ),
                            ( iTemp > 0 ) );  // exclude "none" pattern
                    }
                    break;

                case IDC_WALLLIST:
                    if(HIWORD(wParam) == LBN_SELCHANGE)
                    {
                        LPTSTR pBuf = NULL;

                        iTemp = (int)SendDlgItemMessage(hDlg,IDC_WALLLIST,
                            LB_GETCURSEL,0,0l);

                        if(iTemp >= 0)
                        {
                            pBuf = (LPTSTR)SendDlgItemMessage(hDlg,
                                IDC_WALLLIST, LB_GETITEMDATA, iTemp, 0L);
                        }

                        SetNewWallpaper(hDlg, pBuf, FALSE);
                    }
                    break;

                case IDC_CENTER:
                case IDC_TILE:
                    if ((HIWORD(wParam) == BN_CLICKED) &&
                                (!IsDlgButtonChecked(hDlg, LOWORD(wParam))))
                    {
                        CheckRadioButton(hDlg, IDC_CENTER, IDC_TILE, LOWORD(wParam));
                        UpdatePreview(hDlg, 0);
                    }
                    break;

                case IDC_BROWSEWALL:
                    BrowseForWallpaper(hDlg);
                    break;
            }
            break;
    }
    return FALSE;
}