//
// arcdlg.cpp: Autoreconnect dialog box
//             modeless dialog box for autoreconnection status
//
// Copyright Microsoft Corportation 2001
// (nadima)
//

#include "adcg.h"

#define TRC_GROUP TRC_GROUP_UI
#define TRC_FILE  "arcdlg.cpp"
#include <atrcapi.h>

#include "arcdlg.h"
#include "axresrc.h"

#define TRANSPARENT_MASK_COLOR RGB(105, 139, 228)

#ifdef OS_WINCE
#define RGB_TOPBAND RGB(0, 52, 156)
#define RGB_MIDBAND RGB(49,101,206)
#endif

//
// Runtime debug flags instrumentation for 611316
//
#define ARCDLG_DEBUG_DESTROYCALLED      0x0001
#define ARCDLG_DEBUG_WMDESTROYCALLED    0x0002
#define ARCDLG_DEBUG_WMDESTROYSUCCEED   0x0004
#define ARCDLG_DEBUG_SETNULLINSTPTR     0x0008
DWORD g_dwArcDlgDebug = 0;
#define ARC_DBG_SETINFO(x)   g_dwArcDlgDebug |= x;

LPTSTR
FormatMessageVArgs(LPCTSTR pcszFormat, ...)

{
    LPTSTR      pszOutput;
    va_list     argList;

    va_start(argList, pcszFormat);
    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
                      pcszFormat,
                      0, 0,
                      reinterpret_cast<LPTSTR>(&pszOutput), 0,
                      &argList) == 0)
    {
        pszOutput = NULL;
    }

    va_end(argList);
    return(pszOutput);
}


///////////////////////////////////////////////////////////////////////////////
//
// ARC UI base class
//
CAutoReconnectUI::CAutoReconnectUI(
                    HWND hwndOwner,
                    HINSTANCE hInst,
                    CUI* pUi) :
                    _hwndOwner(hwndOwner),
                    _hInstance(hInst),
                    _hwnd(NULL),
                    _pUi(pUi)
{
    DC_BEGIN_FN("CAutoReconnectUI");

#ifndef OS_WINCE
    _hGDI = LoadLibrary(_T("gdi32.dll"));
    if (_hGDI) {
        _pfnSetLayout = (PFNGDI_SETLAYOUT)GetProcAddress(_hGDI, "SetLayout");
        if (!_pfnSetLayout) {
            TRC_ERR((TB,_T("GetProcAddress 'SetLayout' failed: 0x%x"),
                     GetLastError()));
        }
    }
#else
    _hGDI = NULL;
    _pfnSetLayout = NULL;
#endif

    DC_END_FN();
}

CAutoReconnectUI::~CAutoReconnectUI()
{
    DC_BEGIN_FN("CAutoReconnectUI");

#ifndef OS_WINCE
    if (_hGDI) {
        _pfnSetLayout = NULL;
        FreeLibrary(_hGDI);
        _hGDI = NULL;
    }
#endif
    
    DC_END_FN();
}

//
//  PaintBitmap
//
//  Params:  hdcDestination  =   HDC to paint into.
//              prcDestination  =   RECT in HDC to paint into.
//              hbmSource       =   HBITMAP to paint.
//              prcSource       =   RECT from HBITMAP to paint from.
//
//  Returns:    <none>
//
//  Purpose:    Wraps blitting a bitmap.
//
//  Modified from version in shell code
//
VOID
CAutoReconnectUI::PaintBitmap(
    HDC hdcDestination,
    const RECT* prcDestination,
    HBITMAP hbmSource,
    const RECT *prcSource
    )
{
    HDC     hdcBitmap;

    DC_BEGIN_FN("PaintBitmap");

    hdcBitmap = CreateCompatibleDC(NULL);
    if (hdcBitmap != NULL)
    {
        BOOL        fEqualWidthAndHeight;
        INT         iWidthSource, iHeightSource;
        INT         iWidthDestination, iHeightDestination;
        INT         iStretchBltMode;
#ifndef OS_WINCE
        DWORD       dwLayout;
#endif
        HBITMAP     hbmSelected;
        RECT        rcSource;
        BITMAP      bitmap;

        if (prcSource == NULL)
        {
            if (GetObject(hbmSource, sizeof(bitmap), &bitmap) == 0)
            {
                bitmap.bmWidth = prcDestination->right - prcDestination->left;
                bitmap.bmHeight = prcDestination->bottom - prcDestination->top;
            }
            SetRect(&rcSource, 0, 0, bitmap.bmWidth, bitmap.bmHeight);
            prcSource = &rcSource;
        }
        hbmSelected = static_cast<HBITMAP>(SelectObject(hdcBitmap, hbmSource));
        iWidthSource = prcSource->right - prcSource->left;
        iHeightSource = prcSource->bottom - prcSource->top;
        iWidthDestination = prcDestination->right - prcDestination->left;
        iHeightDestination = prcDestination->bottom - prcDestination->top;
        fEqualWidthAndHeight = (iWidthSource == iWidthDestination) &&
                               (iHeightSource == iHeightDestination);
        if (!fEqualWidthAndHeight) {
#ifndef OS_WINCE
            iStretchBltMode = SetStretchBltMode(hdcDestination, HALFTONE);
#endif
        }
        else {
            iStretchBltMode = 0;
        }

#ifndef OS_WINCE
        if (_pfnSetLayout) {
            dwLayout = _pfnSetLayout(hdcDestination,
                                     LAYOUT_BITMAPORIENTATIONPRESERVED);
        }
#endif
        if (!StretchBlt(hdcDestination,
                    prcDestination->left,
                    prcDestination->top,
                    iWidthDestination,
                    iHeightDestination,
                    hdcBitmap,
                    prcSource->left,
                    prcSource->top,
                    iWidthSource,
                    iHeightSource,
                    SRCCOPY)) {
            TRC_ERR((TB,_T("Blt failed")));
        }

#ifndef OS_WINCE
        if (_pfnSetLayout) {
            _pfnSetLayout(hdcDestination, dwLayout);
        }

        if (!fEqualWidthAndHeight) {
            (int)SetStretchBltMode(hdcDestination, iStretchBltMode);
        }
#endif
        (HGDIOBJ)SelectObject(hdcBitmap, hbmSelected);
        DeleteDC(hdcBitmap);
    }

    DC_END_FN();
}


VOID
CAutoReconnectUI::CenterWindow(
    HWND hwndCenterOn,
    INT xRatio,
    INT yRatio
    )
{
    RECT  childRect;
    RECT  parentRect;
    DCINT xPos;
    DCINT yPos;

    LONG  desktopX = GetSystemMetrics(SM_CXSCREEN);
    LONG  desktopY = GetSystemMetrics(SM_CYSCREEN);

    BOOL center = TRUE;

    DC_BEGIN_FN("CenterWindowOnParent");

    TRC_ASSERT(_hwnd, (TB, _T("_hwnd is NULL...was it set in WM_INITDIALOG?\n")));
    if (!_hwnd)
    {
        TRC_ALT((TB, _T("Window doesn't exist")));
        DC_QUIT;
    }
    if (!xRatio)
    {
        xRatio = 2;
    }
    if (!yRatio)
    {
        yRatio = 2;
    }

    GetClientRect(hwndCenterOn, &parentRect);
    GetWindowRect(_hwnd, &childRect);

    //
    // Calculate the top left - centered in the parent window.
    //
    xPos = ( (parentRect.right + parentRect.left) -
             (childRect.right - childRect.left)) / xRatio;
    yPos = ( (parentRect.bottom + parentRect.top) -
             (childRect.bottom - childRect.top)) / yRatio;

    //
    // Constrain to the desktop
    //
    if (xPos < 0)
    {
        xPos = 0;
    }
    else if (xPos > (desktopX - (childRect.right - childRect.left)))
    {
        xPos = desktopX - (childRect.right - childRect.left);
    }
    if (yPos < 0)
    {
        yPos = 0;
    }
    else if (yPos > (desktopY - (childRect.bottom - childRect.top)))
    {
        yPos = desktopY - (childRect.bottom - childRect.top);
    }

    TRC_DBG((TB, _T("Set dialog position to %u %u"), xPos, yPos));
    SetWindowPos(_hwnd,
                 NULL,
                 xPos, yPos,
                 0, 0,
                 SWP_NOSIZE | SWP_NOACTIVATE);

DC_EXIT_POINT:
    DC_END_FN();

    return;
} // CenterWindowOnParent


#ifndef ARC_MINIMAL_UI

///////////////////////////////////////////////////////////////////////////////
//
// ARC UI - Rich UI - dialog with status text and progress band
//

CAutoReconnectDlg::CAutoReconnectDlg(HWND hwndOwner,
                                     HINSTANCE hInst,
                                     CUI* pUi) :
                    CAutoReconnectUI(hwndOwner, hInst, pUi),
                    _fInitialized(FALSE),
                    _hfntTitle(NULL),
                    _pProgBand(NULL),
                    _hPalette(NULL)
{
#ifndef OS_WINCE
    BOOL fUse8BitDepth = FALSE;
#else
    BOOL fUse8BitDepth = TRUE;
#endif
    LOGFONT     logFont;
#ifndef OS_WINCE
    HDC hdcScreen;
    char        szPixelSize[10];
#else
    WCHAR        szPixelSize[10];
#endif
    BITMAP bitmap;
    INT logPixelsY = 100;

    DC_BEGIN_FN("CAutoReconnectDlg");

    _nArcTimerID = 0;
    _elapsedArcTime = 0;
    _fContinueReconAttempts = TRUE; 

#ifndef OS_WINCE
    //
    // Get color depth
    //
    hdcScreen = GetDC(NULL);
    if (hdcScreen) {
        fUse8BitDepth = (GetDeviceCaps(hdcScreen, BITSPIXEL) <= 8);
        logPixelsY = GetDeviceCaps(hdcScreen, LOGPIXELSY);
        ReleaseDC(NULL, hdcScreen);
        hdcScreen = NULL;
    }
#endif

    //
    // Load bitmaps
    //
    _hbmBackground = (HBITMAP)LoadImage(
                                _hInstance,
                                MAKEINTRESOURCE(fUse8BitDepth ?
                                    IDB_ARC_BACKGROUND8 :IDB_ARC_BACKGROUND24),
                                IMAGE_BITMAP,
                                0,
                                0,
#ifndef OS_WINCE
                                LR_CREATEDIBSECTION);
#else
                                0);
#endif
    if ((_hbmBackground != NULL) &&
        (GetObject(_hbmBackground,
                   sizeof(bitmap), &bitmap) >= sizeof(bitmap))) {
        SetRect(&_rcBackground, 0, 0, bitmap.bmWidth, bitmap.bmHeight);
    }

    _hbmFlag = (HBITMAP)LoadImage(
                                _hInstance,
                                MAKEINTRESOURCE(fUse8BitDepth ?
                                    IDB_ARC_WINFLAG8 :IDB_ARC_WINFLAG24),
                                IMAGE_BITMAP,
                                0,
                                0,
#ifndef OS_WINCE
                                LR_CREATEDIBSECTION);
#else
                                0);
#endif
    if ((_hbmFlag != NULL) &&
        (GetObject(_hbmFlag,
                   sizeof(bitmap), &bitmap) >= sizeof(bitmap))) {
        SetRect(&_rcFlag, 0, 0, bitmap.bmWidth, bitmap.bmHeight);
    }

#ifndef OS_WINCE
    _hbmDisconImg = (HBITMAP)LoadImage(
                                _hInstance,
                                MAKEINTRESOURCE(fUse8BitDepth ?
                                    IDB_ARC_DISCON8 :IDB_ARC_DISCON24),
                                IMAGE_BITMAP,
                                0,
                                0,
                                LR_CREATEDIBSECTION);
    if ((_hbmDisconImg != NULL) &&
        (GetObject(_hbmDisconImg,
                   sizeof(bitmap), &bitmap) >= sizeof(bitmap))) {
        SetRect(&_rcDisconImg, 0, 0, bitmap.bmWidth, bitmap.bmHeight);
    }

    _hPalette = CUT::UT_GetPaletteForBitmap(NULL, _hbmBackground);
#endif


    //
    //  Create fonts. Load the font name and size from resources.
    //

    ZeroMemory(&logFont, sizeof(logFont));
#ifndef OS_WINCE
    if (LoadStringA(_hInstance,
                    IDS_ARC_TITLE_FACESIZE,
                    szPixelSize,
                    sizeof(szPixelSize)) != 0)
#else
    if (LoadString(_hInstance,
                    IDS_ARC_TITLE_FACESIZE,
                    szPixelSize,
                    sizeof(szPixelSize)/sizeof(WCHAR)) != 0)
#endif
    {
#ifndef OS_WINCE
        logFont.lfHeight = -MulDiv(atoi(szPixelSize),
                                   logPixelsY, 72);
#else
        logFont.lfHeight = -(_wtoi(szPixelSize)/logPixelsY*72);
#endif
        if (LoadString(_hInstance,
                       IDS_ARC_TITLE_FACENAME,
                       logFont.lfFaceName,
                       LF_FACESIZE) != 0)
        {
            logFont.lfWeight = FW_BOLD;
            logFont.lfQuality = DEFAULT_QUALITY;
            _hfntTitle = CreateFontIndirect(&logFont);
        }
    }

    _szConnectAttemptStringTmpl[0] = NULL;
    if (!LoadString(_hInstance,
                   IDS_ARC_CONATTEMPTS,
                   _szConnectAttemptStringTmpl,
                   sizeof(_szConnectAttemptStringTmpl)/sizeof(TCHAR)) != 0)
    {
        TRC_ERR((TB,_T("Failed to load IDS_ARC_CONATTEMPTS")));
    }

    _lastDiscReason = NL_DISCONNECT_LOCAL;

#ifdef OS_WINCE
    _hbrTopBand = CreateSolidBrush(RGB_TOPBAND);
    _hbrMidBand = CreateSolidBrush(RGB_MIDBAND);
#endif
    

    _fInitialized = (_hbmBackground &&
                     _hbmFlag       &&
                     _hfntTitle     &&
                     _pUi           &&
                     _szConnectAttemptStringTmpl[0]); 
    if (!_fInitialized) {
        TRC_ERR((TB,_T("Failed to properly init arc dlg")));
    }

    DC_END_FN();
}

CAutoReconnectDlg::~CAutoReconnectDlg()
{
    if (_hbmBackground) {
        DeleteObject(_hbmBackground);
        _hbmBackground = NULL;
    }

    if (_hbmFlag) {
        DeleteObject(_hbmFlag);
        _hbmFlag = NULL;
    }

#ifndef OS_WINCE
    if (_hbmDisconImg) {
        DeleteObject(_hbmDisconImg);
        _hbmDisconImg = NULL;
    }
#endif

    if (_hfntTitle) {
        DeleteObject(_hfntTitle);
        _hfntTitle = NULL;
    }

    if (_hPalette) {
        DeleteObject(_hPalette);
        _hPalette = NULL;
    }

    if (_pProgBand) {
        delete _pProgBand;
        _pProgBand = NULL;
    }

#ifdef OS_WINCE
    if (_hbrTopBand) {
        DeleteObject(_hbrTopBand);
        _hbrTopBand = NULL;
    }

    if (_hbrMidBand) {
        DeleteObject(_hbrMidBand);
        _hbrMidBand = NULL;
    }
#endif
}

HWND CAutoReconnectDlg::StartModeless()
{
    LONG_PTR dwStyle;
    DC_BEGIN_FN("StartModeless");

    if (!_fInitialized) {
        TRC_ERR((TB,_T("failing startmodeless fInitialized is FALSE")));
        return NULL;
    }

    _hwnd = CreateDialogParam(_hInstance,
                                 MAKEINTRESOURCE(IDD_ARCDLG),
                                 _hwndOwner,
                                 StaticDialogBoxProc,
                                 (LPARAM)this);

    if (_hwnd) {
        //
        // Make the dialog a child of the parent
        //
        dwStyle = GetWindowLongPtr(_hwnd, GWL_STYLE);
        dwStyle &= ~WS_POPUP;
        dwStyle |= WS_CHILD;
        SetParent(_hwnd, _hwndOwner);
        SetWindowLongPtr(_hwnd, GWL_STYLE, dwStyle);
    }
    else {
        TRC_ERR((TB,_T("CreateDialog failed: 0x%x"), GetLastError()));
    }

    DC_END_FN();
    return _hwnd;
}

BOOL CAutoReconnectDlg::ShowTopMost()
{
    BOOL rc = FALSE;
    DC_BEGIN_FN("ShowTopMost");

    if (!_hwnd) {
        DC_QUIT;
    }

    ShowWindow(_hwnd, SW_SHOWNORMAL);

    //
    // Bring the window to the TOP of the Z order
    //
    SetWindowPos( _hwnd,
                  HWND_TOPMOST,
                  0, 0, 0, 0,
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );

    rc = TRUE;

DC_EXIT_POINT:
    DC_END_FN();
    return rc;
}

VOID
CAutoReconnectDlg::OnParentSizePosChange()
{
    DC_BEGIN_FN("OnParentSizePosChange");

    //
    // Reposition the dialog to 1/2 down the middle
    // of the owner window
    //
    if (_hwnd && _hwndOwner) {
        CenterWindow(_hwndOwner, 2, 2);
    }

    DC_END_FN();
}

//
// Handler for WM_ERASEBKGND (See platform sdk docs)
//
VOID
CAutoReconnectDlg::OnEraseBkgnd(
    HWND hwnd,
    HDC hdc
    )
{
    RECT    rc;
    HPALETTE hPaletteOld = NULL;
    DC_BEGIN_FN("OnEraseBkgnd");

    TRC_ASSERT(_hbmBackground, (TB,_T("_hbmBackground is NULL")));

    if (GetClientRect(hwnd, &rc)) {

        hPaletteOld = SelectPalette(hdc, _hPalette, FALSE);
        RealizePalette(hdc);

        PaintBitmap(hdc, &rc, _hbmBackground, &_rcBackground);

        SelectPalette(hdc, hPaletteOld, FALSE);
        RealizePalette(hdc);

    }

    DC_END_FN();
}


//
// Handler for WM_PRINTCLIENT
//
VOID
CAutoReconnectDlg::OnPrintClient(
    HWND hwnd,
    HDC hdcPrint,
    DWORD dwOptions)
{
    DC_BEGIN_FN("OnPrintClient");

#ifndef OS_WINCE
    if ((dwOptions & (PRF_ERASEBKGND | PRF_CLIENT)) != 0)
    {
        OnEraseBkgnd(hwnd, hdcPrint);
    }
#endif
    DC_END_FN();
}

#ifndef OS_WINCE
void xDrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,
                           short yStart, COLORREF cTransparentColor)
{
   BITMAP     bm;
   COLORREF   cColor;
   HBITMAP    bmAndBack, bmAndObject, bmAndMem, bmSave;
   HBITMAP    bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
   HDC        hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
   POINT      ptSize;

   hdcTemp = CreateCompatibleDC(hdc);
   SelectObject(hdcTemp, hBitmap);   // Select the bitmap

   GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
   ptSize.x = bm.bmWidth;            // Get width of bitmap
   ptSize.y = bm.bmHeight;           // Get height of bitmap
   DPtoLP(hdcTemp, &ptSize, 1);      // Convert from device

                                     // to logical points

   // Create some DCs to hold temporary data.
   hdcBack   = CreateCompatibleDC(hdc);
   hdcObject = CreateCompatibleDC(hdc);
   hdcMem    = CreateCompatibleDC(hdc);
   hdcSave   = CreateCompatibleDC(hdc);

   // Create a bitmap for each DC. DCs are required for a number of
   // GDI functions.

   // Monochrome DC
   bmAndBack   = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);

   // Monochrome DC
   bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);

   bmAndMem    = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
   bmSave      = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);

   // Each DC must select a bitmap object to store pixel data.
   bmBackOld   = (HBITMAP)SelectObject(hdcBack, bmAndBack);
   bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject);
   bmMemOld    = (HBITMAP)SelectObject(hdcMem, bmAndMem);
   bmSaveOld   = (HBITMAP)SelectObject(hdcSave, bmSave);

   // Set proper mapping mode.
   SetMapMode(hdcTemp, GetMapMode(hdc));

   // Save the bitmap sent here, because it will be overwritten.
   BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);

   // Set the background color of the source DC to the color.
   // contained in the parts of the bitmap that should be transparent
   cColor = SetBkColor(hdcTemp, cTransparentColor);

   // Create the object mask for the bitmap by performing a BitBlt
   // from the source bitmap to a monochrome bitmap.
   BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
          SRCCOPY);

   // Set the background color of the source DC back to the original
   // color.
   SetBkColor(hdcTemp, cColor);

   // Create the inverse of the object mask.
   BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
          NOTSRCCOPY);

   // Copy the background of the main DC to the destination.
   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,
          SRCCOPY);

   // Mask out the places where the bitmap will be placed.
   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);

   // Mask out the transparent colored pixels on the bitmap.
   BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);

   // XOR the bitmap with the background on the destination DC.
   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);

   // Copy the destination to the screen.
   BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,
          SRCCOPY);

   // Place the original bitmap back into the bitmap sent here.
   BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);

   // Delete the memory bitmaps.
   DeleteObject(SelectObject(hdcBack, bmBackOld));
   DeleteObject(SelectObject(hdcObject, bmObjectOld));
   DeleteObject(SelectObject(hdcMem, bmMemOld));
   DeleteObject(SelectObject(hdcSave, bmSaveOld));

   // Delete the memory DCs.
   DeleteDC(hdcMem);
   DeleteDC(hdcBack);
   DeleteDC(hdcObject);
   DeleteDC(hdcSave);
   DeleteDC(hdcTemp);
} 

//
// Handler for WM_DRAWITEM  (see platform sdk)
// Handles owner draw items
//
//
VOID
CAutoReconnectDlg::OnDrawItem(
    HWND hwnd,
    const DRAWITEMSTRUCT *pDIS
    )
{
    DC_BEGIN_FN("OnDrawItem");

    HPALETTE    hPaletteOld = NULL;
    HFONT       hfntSelected;
    int         iBkMode;
    COLORREF    colorText;
    RECT        rc;
    SIZE        size;
    TCHAR       szText[256];

    
    hPaletteOld = SelectPalette(pDIS->hDC, _hPalette, FALSE);
    (UINT)RealizePalette(pDIS->hDC);
    switch (pDIS->CtlID)
    {
        case IDC_TITLE_ARCING:
        {
            //  Draw the title of the dialog "AutoReconecting".
            hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC,
                                                           _hfntTitle));
            colorText = SetTextColor(pDIS->hDC, 0x00FFFFFF);
            iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
            (int)GetWindowText(GetDlgItem(hwnd, pDIS->CtlID),
                               szText,
                               sizeof(szText)/sizeof(szText[0]));
            GetTextExtentPoint(pDIS->hDC, szText, lstrlen(szText), &size);
            CopyRect(&rc, &pDIS->rcItem);
            InflateRect(&rc, 0, -((rc.bottom - rc.top - size.cy) / 2));
            DrawText(pDIS->hDC, szText, -1, &rc, 0);
            SetBkMode(pDIS->hDC, iBkMode);
            SetTextColor(pDIS->hDC, colorText);
            SelectObject(pDIS->hDC, hfntSelected);
        }
        break;

        case IDC_TITLE_FLAG:
        {
            BITMAP      bitmap;
    
            GetClientRect(pDIS->hwndItem, &rc);
            if (GetObject(_hbmFlag, sizeof(bitmap), &bitmap) != 0)
            {
                rc.left += ((rc.right - rc.left) - bitmap.bmWidth) / 2;
                rc.right = rc.left + bitmap.bmWidth;
                rc.top += ((rc.bottom - rc.top) - bitmap.bmHeight) / 2;
                rc.bottom = rc.top + bitmap.bmHeight;
            }
            PaintBitmap(pDIS->hDC, &rc, _hbmFlag, &_rcFlag);
        }
        break;
        case IDC_ARC_STATIC_DISCBMP:
        {
            xDrawTransparentBitmap(pDIS->hDC, _hbmDisconImg,
                                   0, 0,
                                   TRANSPARENT_MASK_COLOR);
        }
        break;
    }
    (HGDIOBJ)SelectPalette(pDIS->hDC, hPaletteOld, FALSE);
    (UINT)RealizePalette(pDIS->hDC);


    DC_END_FN();
}
#endif

//
// StaticDialogBoxProc
// Params: see platform sdk for wndproc
//
// Delegates work to appropriate instance
//
//
INT_PTR CALLBACK
CAutoReconnectDlg::StaticDialogBoxProc(
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    )
{
    //
    // Delegate to appropriate instance
    // (only works for single instance dialogs)
    //
    DC_BEGIN_FN("StaticDialogBoxProc");
    DCINT retVal = 0;
    CAutoReconnectDlg* pDlg;

    if(WM_INITDIALOG != uMsg) {
        //
        // Need to retreive the instance pointer from the window class
        //
        pDlg = (CAutoReconnectDlg*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
    }
    else {
        //
        // WM_INITDIALOG need to grab and set instance pointer
        //

        //
        // lParam contains this pointer (passed in DialogBoxParam)
        //
        pDlg = (CAutoReconnectDlg*) lParam;
        TRC_ASSERT(pDlg,(TB,_T("Got null instance pointer (lParam) in WM_INITDIALOG")));
        if(!pDlg) {
            DC_QUIT;
        }
        //
        // Store the dialog pointer in the windowclass
        //
        SetLastError(0);
        if(!SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)pDlg)) {
            if(GetLastError()) {
                TRC_ERR((TB,_T("SetWindowLongPtr failed 0x%x"),
                         GetLastError()));
                DC_QUIT;
            }
        }
    }

    if (pDlg) {
        retVal = pDlg->DialogBoxProc(hwndDlg, uMsg, wParam, lParam);
    }

DC_EXIT_POINT:
    DC_END_FN();
    return retVal;
}


//
// Name: DialogBoxProc
//
// Purpose: Handles AutoReconnect dialog box proc
//
// Returns: TRUE if message dealt with
//          FALSE otherwise
//
// Params: See windows documentation
//
//
INT_PTR CALLBACK CAutoReconnectDlg::DialogBoxProc (HWND hwndDlg,
                                          UINT uMsg,
                                          WPARAM wParam,
                                          LPARAM lParam)
{
    INT_PTR rc = FALSE;
    DC_BEGIN_FN("DialogBoxProc");

    switch (uMsg)
    {
        case WM_INITDIALOG:
        {
            //
            // Center
            //
            _hwnd = hwndDlg;
            CenterWindow(_hwndOwner, 2, 2);
            UpdateConnectionAttempts(0, 0);

            //
            // The band is positioned a fixed ratio of the way
            // down the height of this dialog to match up with the
            // background image
            //
            RECT cliRect;
            LONG nBandPos = 0;
            GetClientRect(hwndDlg, &cliRect);
            nBandPos = (INT)((cliRect.bottom - cliRect.top) * 42.0/193.0);

            _pProgBand = new CProgressBand(hwndDlg,
                                           _hInstance,
                                           nBandPos,
                                           IDB_ARC_BAND24,
                                           IDB_ARC_BAND8,
                                           NULL);
            if (_pProgBand) {
                if (!_pProgBand->Initialize()) {
                    TRC_ERR((TB,_T("Progress band failed to init")));
                    delete _pProgBand;
                    _pProgBand = NULL;
                }
            }

            //
            // Subclass the cancel button to do the correct key handling
            // this is important because the message loop is driven by
            // the container application so we can't just rely on it
            // calling IsDialogMessage(). In other words we need to manually
            // handle the appropriate keymapping code.
            //
#ifndef OS_WINCE
            if (!SetWindowSubclass(GetDlgItem(hwndDlg, IDCANCEL),
                                   CancelBtnSubclassProc, IDCANCEL,
                                   reinterpret_cast<DWORD_PTR>(this))) {

                TRC_ERR((TB,_T("SetWindowSubclass failed: 0x%x"),
                         GetLastError()));

            }
#else
            _lOldCancelProc = (WNDPROC )SetWindowLong(GetDlgItem(hwndDlg, IDCANCEL), 
                            GWL_WNDPROC, (LONG )CancelBtnSubclassProc);
            SetWindowLong(GetDlgItem(hwndDlg, IDCANCEL), GWL_USERDATA, reinterpret_cast<DWORD_PTR>(this));
#endif
            //
            // Set the focus on the cancel button
            // and make it the default button
            //
            SendMessage(hwndDlg, DM_SETDEFID, IDCANCEL, 0);

            //SetFocus(GetDlgItem(hwndDlg, IDCANCEL));
            SetFocus(hwndDlg);

            if (_pProgBand) {
                _pProgBand->StartSpinning();
            }

            rc = 1;
        }
        break;

        case WM_COMMAND:
        {
            switch(DC_GET_WM_COMMAND_ID(wParam))
            {
                case IDCANCEL:
                {
                    TRC_NRM((TB,_T("AutoReconnect cancel was pressed")));

                    if (_pProgBand) {
                        _pProgBand->StopSpinning();
                    }

                    _pUi->UI_UserInitiatedDisconnect(_lastDiscReason);

                    //
                    // Disable the cancel button and set the cancel flag.
                    // This will take effect on the next autoreconnection
                    // notification.
                    //
                    EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
                    _fContinueReconAttempts = FALSE;
                }
                break;
            }
        }
        break; //WM_COMMAND

        case WM_DESTROY:
        {
            ARC_DBG_SETINFO(ARCDLG_DEBUG_WMDESTROYCALLED);
#ifndef OS_WINCE
            RemoveWindowSubclass(GetDlgItem(hwndDlg, IDCANCEL),
                                 CancelBtnSubclassProc, IDCANCEL);
#else
            SetWindowLong(GetDlgItem(hwndDlg, IDCANCEL),
                          GWL_WNDPROC, (LONG )_lOldCancelProc);
#endif
            //
            // Clear the instance data to prevent further processing
            // after the dialog is deleted
            //
            SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)NULL);
        }
        break;

#ifndef OS_WINCE
        case WM_DRAWITEM:
        {
            OnDrawItem(hwndDlg, (DRAWITEMSTRUCT*)(lParam));
        }
        break;
#endif

        case WM_TIMER:
        {
            if (_pProgBand) {
                _pProgBand->OnTimer((INT)wParam);
            }
        }
        break;

        case WM_ERASEBKGND:
        {
            OnEraseBkgnd(hwndDlg, (HDC)wParam);

            if (_pProgBand) {
                _pProgBand->OnEraseParentBackground((HDC)wParam);
            }
            rc = 1;
        }
        break;

        case WM_CTLCOLORDLG:
        {
            SetBkMode((HDC)wParam, TRANSPARENT);
            rc = (INT_PTR)GetStockObject(NULL_BRUSH);
        }
        break;

        case WM_CTLCOLORSTATIC:
        {
            SetTextColor((HDC)wParam, RGB(255,255,255));
            SetBkMode((HDC)wParam, TRANSPARENT);
#ifndef OS_WINCE
            rc = (INT_PTR)GetStockObject(NULL_BRUSH);
#else
            LONG lId = GetWindowLong((HWND)lParam, GWL_ID);
            rc = (INT_PTR)((lId == IDC_TITLE_ARCING) ? _hbrTopBand : _hbrMidBand);
#endif
        }
        break;

#ifndef OS_WINCE
        case WM_PRINTCLIENT:
        {
            OnPrintClient(hwndDlg, (HDC)wParam, (DWORD)lParam);
            rc = 1;
        }
        break;
#endif

        default:
        {
            rc = 0;
        }
        break;
    }

    DC_END_FN();

    return(rc);

} /* DialogBoxProc */

VOID CAutoReconnectDlg::UpdateConnectionAttempts(
    ULONG conAttempts,
    ULONG maxConAttempts)
{
    LPTSTR szFormattedString = NULL;
    HWND hwndStatic;

    DC_BEGIN_FN("UpdateConnectionAttempts");

    hwndStatic = GetDlgItem(GetHwnd(), IDC_ARC_STATIC_INFO);

    szFormattedString = FormatMessageVArgs(
        _szConnectAttemptStringTmpl,
        conAttempts,
        maxConAttempts
        );

    if (szFormattedString) {
        SetDlgItemText(GetHwnd(),
                       IDC_ARC_STATIC_INFO,
                       szFormattedString);
        LocalFree(szFormattedString);

        //
        // Invalidate the static control to trigger a repaint
        //
        if (hwndStatic) {
            RECT rc;
            if (GetWindowRect(hwndStatic, &rc)) {
                MapWindowPoints(HWND_DESKTOP, GetHwnd(),
                                (LPPOINT)&rc,sizeof(RECT)/sizeof(POINT));
                InvalidateRect(GetHwnd(), &rc, TRUE);
                UpdateWindow(GetHwnd());
            }
        }
    }

    DC_END_FN();
}

//
// Called to notify us that we got disconnected
// this means the last connection attempt failed
//
// Params:
//      discReason   - disconnect major reason code
//      attemptCount - attempt count so far
//      pfContinueArc - [OUT] set to FALSE to stop ARC
//
VOID
CAutoReconnectDlg::OnNotifyAutoReconnecting(
        UINT  discReason,
        ULONG attemptCount,
        ULONG maxAttemptCount,
        BOOL* pfContinueArc
        )
{
    DC_BEGIN_FN("OnNotifyDisconnected");

    _lastDiscReason = discReason;

    if (_fContinueReconAttempts) {
        _connectionAttempts = attemptCount;
        UpdateConnectionAttempts(attemptCount, maxAttemptCount);
    }
    else {
        TRC_NRM((TB,_T("Stopping arc - _fContinueReconAttempts is FALSE")));
    }

    *pfContinueArc = _fContinueReconAttempts;

    DC_END_FN();
}

//
// Called to notify us that we have connected
//
VOID CAutoReconnectDlg::OnNotifyConnected()
{
    DC_BEGIN_FN("OnNotifyConnected");

    _fContinueReconAttempts = FALSE;

    DC_END_FN();
}

//
// Destory
// Called to kill and cleanup the dialog
// 
//
BOOL
CAutoReconnectDlg::Destroy()
{
    DC_BEGIN_FN("Destroy");

    ARC_DBG_SETINFO(ARCDLG_DEBUG_DESTROYCALLED);

    if (!DestroyWindow(_hwnd)) {
        TRC_ERR((TB,_T("DestroyWindow failed: 0x%x"),
                GetLastError()));
    }
    else {
        ARC_DBG_SETINFO(ARCDLG_DEBUG_WMDESTROYSUCCEED);
    }

    //
    // Clear the instance data to prevent further processing
    // after the dialog is deleted
    //
    ARC_DBG_SETINFO(ARCDLG_DEBUG_SETNULLINSTPTR);

    SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)NULL);

    DC_END_FN();
    return TRUE;
}

#ifndef OS_WINCE
LRESULT CALLBACK
CAutoReconnectDlg::CancelBtnSubclassProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam,
    UINT_PTR uiID,
    DWORD_PTR dwRefData
    )
#else
LRESULT CALLBACK
CAutoReconnectDlg::CancelBtnSubclassProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    )
#endif
{
    LRESULT rc = 0;
    CAutoReconnectDlg* pThis = NULL;

    DC_BEGIN_FN("CancelBtnSubclassProc");

#ifndef OS_WINCE
    pThis = reinterpret_cast<CAutoReconnectDlg*>(dwRefData);
#else
    pThis = reinterpret_cast<CAutoReconnectDlg*>(GetWindowLong(hwnd, GWL_USERDATA));
#endif
    TRC_ASSERT(pThis, (TB,_T("pThis == NULL")));

    switch (uMsg)
    {
        case WM_KEYUP:
        {
            //
            // Hitting 'Esc' or 'Return' on the Cancel button
            // are the same as pressing it
            //
            if (VK_ESCAPE == wParam ||
                VK_RETURN == wParam) {
                SendMessage(hwnd, BM_CLICK, NULL, NULL);
            }
        }
        //
        // Intentional fallthru
        //

        default:
        {
#ifndef OS_WINCE
            rc = DefSubclassProc(hwnd, uMsg, wParam, lParam);
#else
            rc = CallWindowProc(pThis->_lOldCancelProc, hwnd, uMsg, wParam, lParam);
#endif
        }
        break;
    }

    DC_END_FN();
    return rc;
}

#else  // ARC_MINIMAL_UI

#include "res_inc.c"

CAutoReconnectPlainUI::CAutoReconnectPlainUI(HWND hwndOwner,
                                     HINSTANCE hInst,
                                     CUI* pUi) :
                    CAutoReconnectUI(hwndOwner, hInst, pUi),
                    _fInitialized(FALSE),
                    _hPalette(NULL),
                    _fIsUiVisible(FALSE)
{
#ifndef OS_WINCE
    BOOL fUse8BitDepth = FALSE;
#else
    BOOL fUse8BitDepth = TRUE;
#endif
    LOGFONT     logFont;
#ifndef OS_WINCE
    HDC hdcScreen;
#else
#endif
    BITMAP bitmap;
    INT logPixelsY = 100;

    DC_BEGIN_FN("CAutoReconnectPlainUI");

    _nFlashingTimer = 0;
    _fContinueReconAttempts = TRUE; 

#ifndef OS_WINCE
    //
    // Get color depth
    //
    hdcScreen = GetDC(NULL);
    if (hdcScreen) {
        fUse8BitDepth = (GetDeviceCaps(hdcScreen, BITSPIXEL) <= 8);
        logPixelsY = GetDeviceCaps(hdcScreen, LOGPIXELSY);

        //
        // Load bitmaps
        //
        LPBYTE pBitmapBits = fUse8BitDepth ? (LPBYTE)g_DisconImage8Bits :
                                             (LPBYTE)g_DisconImageBits;
        ULONG  cbBitmapLen = fUse8BitDepth ? g_cbDisconImage8Bits :
                                             g_cbDisconImageBits;
                                             
        _hbmDisconImg = (HBITMAP)LoadImageFromMemory(
                                            hdcScreen,
                                            (LPBYTE)pBitmapBits,
                                            cbBitmapLen
                                            );
        if ((_hbmDisconImg != NULL) &&
            (GetObject(_hbmDisconImg,
                       sizeof(bitmap), &bitmap) >= sizeof(bitmap))) {
            SetRect(&_rcDisconImg, 0, 0, bitmap.bmWidth, bitmap.bmHeight);

            _hPalette = CUT::UT_GetPaletteForBitmap(NULL, _hbmDisconImg);
        }
        ReleaseDC(NULL, hdcScreen);
        hdcScreen = NULL;
    }

#endif

    _fInitialized = (_hbmDisconImg && _pUi); 
    if (!_fInitialized) {
        TRC_ERR((TB,_T("Failed to properly init arc dlg")));
    }

    DC_END_FN();
}

CAutoReconnectPlainUI::~CAutoReconnectPlainUI()
{
#ifndef OS_WINCE
    if (_hbmDisconImg) {
        DeleteObject(_hbmDisconImg);
        _hbmDisconImg = NULL;
    }
#endif

    if (_hPalette) {
        DeleteObject(_hPalette);
        _hPalette = NULL;
    }
}

#define ARC_PLAIN_WNDCLASS _T("ARCICON")
HWND CAutoReconnectPlainUI::StartModeless()
{
    LONG_PTR    dwStyle;
    WNDCLASS    tmpWndClass;
    WNDCLASS    plainArcWndClass;
    ATOM        registerClassRc;

    DC_BEGIN_FN("StartModeless");

    if (!_fInitialized) {
        TRC_ERR((TB,_T("failing startmodeless fInitialized is FALSE")));
        return NULL;
    }

    //
    // Create a window to host the UI   
    //
    //
    // Register the class for the Main Window
    //
    if (!GetClassInfo(_hInstance, ARC_PLAIN_WNDCLASS, &tmpWndClass))
    {
        TRC_NRM((TB, _T("Register Main Window class")));
        plainArcWndClass.style         = CS_DBLCLKS;
        plainArcWndClass.lpfnWndProc   = StaticPlainArcWndProc;
        plainArcWndClass.cbClsExtra    = 0;
        plainArcWndClass.cbWndExtra    = sizeof(void*); //store 'this' pointer
        plainArcWndClass.hInstance     = _hInstance;
        plainArcWndClass.hIcon         = NULL;
        plainArcWndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        plainArcWndClass.hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
        plainArcWndClass.lpszMenuName  = NULL;
        plainArcWndClass.lpszClassName = ARC_PLAIN_WNDCLASS;

        registerClassRc = RegisterClass (&plainArcWndClass);

        if (registerClassRc == 0)
        {
            TRC_ERR((TB,_T("RegisterClass failed: 0x%x"), GetLastError()));
            DC_QUIT;
        }
    }

    _hwnd = CreateWindow(ARC_PLAIN_WNDCLASS,
                NULL,
                WS_CHILD | WS_CLIPSIBLINGS,
                0,
                0,
                _rcDisconImg.right - _rcDisconImg.left,
                _rcDisconImg.bottom - _rcDisconImg.top,
                _hwndOwner,
                NULL,
                _hInstance,
                this
                );

    if (_hwnd) {
        //
        // Move window to the parent's top-right and then show the window
        //
        MoveToParentTopRight();
        ShowTopMost();
        _fIsUiVisible = TRUE;
    }
    else {
        TRC_ERR((TB,_T("CreateWindow failed: 0x%x"), GetLastError()));
    }

DC_EXIT_POINT:
    DC_END_FN();
    return _hwnd;
}

BOOL CAutoReconnectPlainUI::ShowTopMost()
{
    BOOL rc = FALSE;
    DC_BEGIN_FN("ShowTopMost");

    if (!_hwnd) {
        DC_QUIT;
    }

    ShowWindow(_hwnd, SW_SHOWNORMAL);

    //
    // Bring the window to the TOP of the Z order
    //
    SetWindowPos( _hwnd,
                  HWND_TOPMOST,
                  0, 0, 0, 0,
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );

    rc = TRUE;

DC_EXIT_POINT:
    DC_END_FN();
    return rc;
}

//
// Position offset from the edge
//
#define ICON_POSITION_OFFSET 20

VOID
CAutoReconnectPlainUI::MoveToParentTopRight()
{
    RECT rcParent;
    INT  xPos, yPos;
    DC_BEGIN_FN("OnParentSizePosChange");

    //
    // Reposition the dialog to the top right
    // of the owner window
    //
    if (_hwnd && _hwndOwner) {
        //
        // Position the window in the top-right of the parent
        //
        GetClientRect(_hwndOwner, &rcParent);
        xPos = rcParent.right - ICON_POSITION_OFFSET -
               (_rcDisconImg.right - _rcDisconImg.left);
        yPos = rcParent.top + ICON_POSITION_OFFSET;
        
        SetWindowPos(_hwnd,
                     NULL,
                     xPos, yPos,
                     0, 0,
                     SWP_NOSIZE | SWP_NOACTIVATE);
    }

    DC_END_FN();
}

VOID
CAutoReconnectPlainUI::OnParentSizePosChange()
{
    MoveToParentTopRight();
}

//
// Handler for WM_ERASEBKGND (See platform sdk docs)
//
VOID
CAutoReconnectPlainUI::OnEraseBkgnd(
    HWND hwnd,
    HDC hdc
    )
{
    RECT    rc;
    HPALETTE hPaletteOld = NULL;
    DC_BEGIN_FN("OnEraseBkgnd");

    TRC_ASSERT(_hbmDisconImg, (TB,_T("_hbmBackground is NULL")));

    if (GetClientRect(hwnd, &rc)) {

        hPaletteOld = SelectPalette(hdc, _hPalette, FALSE);
        RealizePalette(hdc);

        PaintBitmap(hdc, &rc, _hbmDisconImg, &_rcDisconImg);

        SelectPalette(hdc, hPaletteOld, FALSE);
        RealizePalette(hdc);

    }

    DC_END_FN();
}


//
// Handler for WM_PRINTCLIENT
//
VOID
CAutoReconnectPlainUI::OnPrintClient(
    HWND hwnd,
    HDC hdcPrint,
    DWORD dwOptions)
{
    DC_BEGIN_FN("OnPrintClient");

#ifndef OS_WINCE
    if ((dwOptions & (PRF_ERASEBKGND | PRF_CLIENT)) != 0)
    {
        OnEraseBkgnd(hwnd, hdcPrint);
    }
#endif
    DC_END_FN();
}

//
// StaticPlainArcWndProc
// Params: see platform sdk for wndproc
//
// Delegates work to appropriate instance
//
//
LRESULT CALLBACK
CAutoReconnectPlainUI::StaticPlainArcWndProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    )
{
    INT                     retVal = 0;
    CAutoReconnectPlainUI*  pUI;

    DC_BEGIN_FN("StaticPlainArcWndProc");

    pUI = (CAutoReconnectPlainUI*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    if(WM_CREATE == uMsg)
    {
        //pull out the this pointer and stuff it in the window class
        LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
        pUI = (CAutoReconnectPlainUI*)lpcs->lpCreateParams;

        SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pUI);
    }
    
    //
    // Delegate the message to the appropriate instance
    //

    if(pUI) {
        return pUI->WndProc(hwnd, uMsg, wParam, lParam);
    }
    else {
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

DC_EXIT_POINT:
    DC_END_FN();
    return retVal;
}

#define ARC_PLAIN_UI_TIMERID 1
#define ARC_ANIM_TIME        400
//
// Name: WndProc
//
// Purpose: Handles AutoReconnect dialog box proc
//
// Returns: TRUE if message dealt with
//          FALSE otherwise
//
// Params: See windows documentation
//
//
LRESULT CALLBACK CAutoReconnectPlainUI::WndProc(HWND hwnd,
                                            UINT uMsg,
                                            WPARAM wParam,
                                            LPARAM lParam)
{
    INT_PTR rc = FALSE;
    DC_BEGIN_FN("DialogBoxProc");

    switch (uMsg)
    {
        case WM_CREATE:
        {
            _nFlashingTimer = SetTimer(hwnd, ARC_PLAIN_UI_TIMERID,
                                       ARC_ANIM_TIME,
                                       NULL
                                       );
            if (_nFlashingTimer) {
                SetFocus(hwnd);
            }
            else {
                TRC_ERR((TB,_T("SetTimer failed - 0x%x"),
                         GetLastError()));
                rc = -1;
            }
        }
        break;


        case WM_DESTROY:
        {
            if (_nFlashingTimer) {
                KillTimer(hwnd, _nFlashingTimer);
                _nFlashingTimer = 0;
            }
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)NULL);
        }
        break;


        case WM_TIMER:
        {
            //
            // DO animation stuff
            //
            OnAnimFlashTimer();
        }
        break;

        case WM_ERASEBKGND:
        {
            OnEraseBkgnd(hwnd, (HDC)wParam);
            rc = 1;
        }
        break;

        case WM_KEYUP:
        {
            if (VK_ESCAPE == wParam) {
                TRC_NRM((TB,_T("ARC ESC pressed, disconnect")));
                _pUi->UI_UserInitiatedDisconnect(_lastDiscReason);
                _fContinueReconAttempts = FALSE;
            }
        }
        break;

        case WM_SETFOCUS:
        {
            TRC_NRM((TB,_T("Setfocus to arc")));
        }
        break;

        case WM_KILLFOCUS:
        {
            TRC_NRM((TB,_T("killfocus to arc: 0x%x 0x%x"), wParam, lParam));
        }
        break;


#ifndef OS_WINCE
        case WM_PRINTCLIENT:
        {
            OnPrintClient(hwnd, (HDC)wParam, (DWORD)lParam);
            rc = 1;
        }
        break;
#endif

        default:
        {
            return DefWindowProc( hwnd, uMsg, wParam, lParam);
        }
        break;
    }

    DC_END_FN();

    return(rc);

} /* DialogBoxProc */


VOID
CAutoReconnectPlainUI::OnAnimFlashTimer()
{
    //
    // Toggle UI hide state
    //
    _fIsUiVisible = !_fIsUiVisible;
    ShowWindow(_hwnd, _fIsUiVisible ? SW_SHOWNORMAL : SW_HIDE);
}

//
// Called to notify us that we got disconnected
// this means the last connection attempt failed
//
// Params:
//      discReason   - disconnect major reason code
//      attemptCount - attempt count so far
//      pfContinueArc - [OUT] set to FALSE to stop ARC
//
VOID
CAutoReconnectPlainUI::OnNotifyAutoReconnecting(
        UINT  discReason,
        ULONG attemptCount,
        ULONG maxAttemptCount,
        BOOL* pfContinueArc
        )
{
    DC_BEGIN_FN("OnNotifyDisconnected");

    _lastDiscReason = discReason;

    if (!_fContinueReconAttempts) {
        TRC_NRM((TB,_T("Stopping arc - _fContinueReconAttempts is FALSE")));
    }

    *pfContinueArc = _fContinueReconAttempts;

    DC_END_FN();
}

//
// Called to notify us that we have connected
//
VOID CAutoReconnectPlainUI::OnNotifyConnected()
{
    DC_BEGIN_FN("OnNotifyConnected");

    _fContinueReconAttempts = FALSE;

    DC_END_FN();
}

//
// Destory
// Called to kill and cleanup the dialog
// 
//
BOOL
CAutoReconnectPlainUI::Destroy()
{
    DC_BEGIN_FN("Destroy");

    if (!DestroyWindow(_hwnd)) {
        TRC_ERR((TB,_T("DestroyWindow failed: 0x%x"),
                GetLastError()));
    }

    DC_END_FN();
    return TRUE;
}

//
// Load a bitmap from memory
//
// Params:
//   pbBitmapBits - pointer to bitmap bits (e.g. can pass in file mapping
//                  to a BMP file).
//
//   cbLen        - length of pbBitmapBits
//
// Returns:
//   HBITMAP      - handle to the bitmap
//
HBITMAP
CAutoReconnectPlainUI::LoadImageFromMemory(
                            HDC hdc,
                            LPBYTE pbBitmapBits,
                            ULONG cbLen
                            )
{
    HRESULT hr;
    HBITMAP hbmp = NULL;
    LPBITMAPINFO pbmi = NULL;
    ULONG   cbBmiLen = 0;
    PBYTE   pBitmapBits = NULL;
    ULONG   cbBitmapBits = 0;

    hr = LoadImageBits(
            pbBitmapBits,
            cbLen,
            &pbmi,
            &cbBmiLen,
            &pBitmapBits,
            &cbBitmapBits
            );
    if (SUCCEEDED(hr)) {

        hbmp = CreateDIBitmap(hdc,
                              &pbmi->bmiHeader,
                              CBM_INIT,
                              pBitmapBits,
                              pbmi,
                              DIB_RGB_COLORS
                              );

        delete pBitmapBits;
        delete pbmi;
    }

    return hbmp;
}


#define BMP_24_BITSPERPIXEL 24
#define BMP_16_BITSPERPIXEL 16
#define BMP_32_BITSPERPIXEL 32

//
// Worker function for image load, caller frees outparam bits
//
HRESULT
CAutoReconnectPlainUI::LoadImageBits(
                            LPBYTE pbBitmapBits, ULONG cbLen,
                            LPBITMAPINFO* ppBitmapInfo, PULONG pcbBitmapInfo,
                            LPBYTE* ppBits, PULONG pcbBits
                            )
{
    HRESULT          hr = ResultFromScode(S_OK);
    BITMAPFILEHEADER bmfh;
    BITMAPCOREHEADER *pbch;
    BITMAPINFOHEADER bih;
    LPBYTE           pbStart;
    ULONG            cbi = 0;
    ULONG            cbData;
    LPBITMAPINFO     pbi = NULL;
    LPBYTE           pbData = NULL;
    DWORD            dwSizeOfHeader;

    //
    // Record the starting position
    //

    pbStart = pbBitmapBits;

    //
    // First validate the buffer for size
    //

    if (cbLen < sizeof(BITMAPFILEHEADER))
    {
         return(ResultFromScode(E_FAIL));
    }

    //
    // Now get the bitmap file header
    //
    memcpy(&bmfh, pbBitmapBits, sizeof(BITMAPFILEHEADER));

    //
    // Validate the header
    //

    if (!(bmfh.bfType == 0x4d42) && (bmfh.bfOffBits <= cbLen))
    {
         return E_FAIL;
    }

    //
    // Get the next 4 bytes which will represent the size of the
    // next structure and allow us to determine the type
    //

    if (SUCCEEDED(hr))
    {
         pbBitmapBits += sizeof(BITMAPFILEHEADER);
         memcpy(&dwSizeOfHeader, pbBitmapBits, sizeof(DWORD));

         if (dwSizeOfHeader == sizeof(BITMAPCOREHEADER))
         {
              pbch = (BITMAPCOREHEADER *)pbBitmapBits;
              memset(&bih, 0, sizeof(BITMAPINFOHEADER));

              bih.biSize = sizeof(BITMAPINFOHEADER);
              bih.biWidth = pbch->bcWidth;
              bih.biHeight = pbch->bcHeight;
              bih.biPlanes = pbch->bcPlanes;
              bih.biBitCount = pbch->bcBitCount;

              pbBitmapBits += sizeof(BITMAPCOREHEADER);
         }
         else if (dwSizeOfHeader == sizeof(BITMAPINFOHEADER))
         {
              memcpy(&bih, pbBitmapBits, sizeof(BITMAPINFOHEADER));

              pbBitmapBits += sizeof(BITMAPINFOHEADER);
         }
         else
         {
              hr = ResultFromScode(E_FAIL);
         }
    }

    //
    // Check if biClrUsed is set since we do not handle that
    // case at this time
    //

    if (SUCCEEDED(hr))
    {
         if (bih.biClrUsed != 0)
         {
              hr = ResultFromScode(E_FAIL);
         }
    }

    //
    // Now we need to calculate the size of the BITMAPINFO we need
    // to allocate including any palette information
    //

    if (SUCCEEDED(hr))
    {
         //
         // First the size of the header
         //

         cbi = sizeof(BITMAPINFOHEADER);

         //
         // Now the palette
         //

         if (bih.biBitCount == BMP_24_BITSPERPIXEL)
         {
              //
              // Just add on the 1 RGBQUAD for the structure but
              // there is no palette
              //

              cbi += sizeof(RGBQUAD);
         }
         else if ((bih.biBitCount == BMP_16_BITSPERPIXEL) ||
                  (bih.biBitCount == BMP_32_BITSPERPIXEL))
         {
              //
              // Add on the 3 DWORD masks which are used to
              // get the colors out of the data
              //

              cbi += (3 * sizeof(DWORD));
         }
         else
         {
              //
              // Anything else we just use the bit count to calculate
              // the number of entries
              //

              cbi += ((1 << bih.biBitCount) * sizeof(RGBQUAD));
         }

         //
         // Now allocate the BITMAPINFO
         //

         pbi = (LPBITMAPINFO) new BYTE [cbi];
         if (pbi == NULL)
         {
              hr = ResultFromScode(E_OUTOFMEMORY);
         }
    }

    //
    // Fill in the BITMAPINFO data structure and get the bits
    //

    if (SUCCEEDED(hr))
    {
         //
         // First copy the header data
         //

         memcpy(&(pbi->bmiHeader), &bih, sizeof(BITMAPINFOHEADER));

         //
         // Now the palette data
         //

         if (bih.biBitCount == BMP_24_BITSPERPIXEL)
         {
              //
              // No palette data to copy
              //
         }
         else if ((bih.biBitCount == BMP_16_BITSPERPIXEL) ||
                  (bih.biBitCount == BMP_32_BITSPERPIXEL))
         {
              //
              // Copy the 3 DWORD masks
              //

              memcpy(&(pbi->bmiColors), pbBitmapBits, 3*sizeof(DWORD));
         }
         else
         {
              //
              // If we were a BITMAPCOREHEADER type then we have our
              // palette data in the form of RGBTRIPLEs so we must
              // explicitly copy each.  Otherwise we can just memcpy
              // the RGBQUADs
              //

              if (dwSizeOfHeader == sizeof(BITMAPCOREHEADER))
              {
                   ULONG     cPalEntry = (1 << bih.biBitCount);
                   ULONG     cCount;
                   RGBTRIPLE *argbt = (RGBTRIPLE *)pbBitmapBits;

                   for (cCount = 0; cCount < cPalEntry; cCount++)
                   {
                        pbi->bmiColors[cCount].rgbRed =
                                           argbt[cCount].rgbtRed;
                        pbi->bmiColors[cCount].rgbGreen =
                                           argbt[cCount].rgbtGreen;
                        pbi->bmiColors[cCount].rgbBlue =
                                           argbt[cCount].rgbtBlue;

                        pbi->bmiColors[cCount].rgbReserved = 0;
                   }
              }
              else
              {
                   ULONG cbPalette = (1 << bih.biBitCount) * sizeof(RGBQUAD);

                   memcpy(&(pbi->bmiColors), pbBitmapBits, cbPalette);
              }
         }

         //
         // Now find out where the bits are
         //

         pbBitmapBits = pbStart + bmfh.bfOffBits;

         //
         // Get the size to copy
         //

         cbData = cbLen - bmfh.bfOffBits;

         //
         // Allocate the buffer to hold the bits
         //

         pbData = new BYTE [cbData];
         if (pbData == NULL)
         {
              hr = ResultFromScode(E_OUTOFMEMORY);
         }

         if (SUCCEEDED(hr))
         {
              memcpy(pbData, pbBitmapBits, cbData);
         }
    }

    //
    // If everything succeeded record the data
    //

    if (SUCCEEDED(hr))
    {
         //
         // Record the info
         //

         *pcbBitmapInfo = cbi;
         *ppBitmapInfo = pbi;

         //
         // Record the data
         //

         *ppBits = pbData;
         *pcbBits = cbData;
    }
    else
    {
         //
         // Cleanup
         //

         delete pbi;
         delete pbData;
    }

    return(hr);
}
#endif // ARC_MINIMAL_UI