#include "precomp.h"


//
// USR.CPP
// Update Sender/Receiver
//
// Copyright(c) Microsoft 1997-
//

#define MLZ_FILE_ZONE  ZONE_NET

//
// USR strategy when network packets cannot be allocated.
//
// The USR sends three different types of packets:
//
//  - font negotiation packets
//  - order packets
//  - screen data packets
//
// Font negotiation packets are sent by the USR_Periodic function.  If the
// packet cannot be sent first time then the USR will retry (on each call
// to the USR_Periodic function) until it has succesfully sent the packet.
// The only dependency on font packets is that until the systems in a share
// have been able to exchange font negotiation packets they will not be
// able to send text output as orders - they will simply send text as
// screen data.
//
// The USR function UP_SendUpdates sends all update packets (both order
// packets and screen data packets).  Order packets must be sent first and
// screen data packets are only sent if all the orders have been
// succesfully sent.  When sending screen data packets they are only sent
// if the corresponding palette packets have been sent - otherwise they are
// re-absorbed into the screen data to be transmitted later.
//
//



//
// USR_ShareStarting()
// Creates share resources
//
BOOL ASShare::USR_ShareStarting(void)
{
    BOOL    rc = FALSE;
    BITMAPINFOHEADER    bitmapInfo;
    HDC                 hdcDesktop = NULL;

    DebugEntry(ASShare::USR_ShareStarting);

    //
    // Set the black bitmap data and hatch bitmap data flags which can be
    // used as an aid for debugging.  These are false unless there is an
    // entry in the ini file to override them.
    //
    COM_ReadProfInt(DBG_INI_SECTION_NAME, USR_INI_HATCHSCREENDATA, FALSE,
            &m_usrHatchScreenData);

    COM_ReadProfInt(DBG_INI_SECTION_NAME, USR_INI_HATCHBMPORDERS, FALSE,
            &m_usrHatchBitmaps);

    //
    // Double-check the order packet sizes are OK
    //
    ASSERT(SMALL_ORDER_PACKET_SIZE < LARGE_ORDER_PACKET_SIZE);
    ASSERT(LARGE_ORDER_PACKET_SIZE <= TSHR_MAX_SEND_PKT);

    //
    // Allocate a chunk of memory big enough to contain the largest packet
    // an application can receive from the network.  This is required to
    // store uncompressed bitmaps and repeated general use by the USR.
    //
    m_usrPBitmapBuffer = new BYTE[TSHR_MAX_SEND_PKT];
    if (!m_usrPBitmapBuffer)
    {
        ERROR_OUT(("USR_ShareStarted: failed to alloc memory m_usrPBitmapBuffer"));

        //
        // To continue the share would cause a GP fault as soon as anything
        // tries to use this buffer so delete this person from the share.
        // The reason is lack of resources.
        //
        DC_QUIT;
    }

    //
    // Create the transfer bitmaps for screen data and bitmap orders
    //

    USR_InitDIBitmapHeader(&bitmapInfo, g_usrScreenBPP);

    //
    // Create the transfer bitmaps.  These are used for both outgoing and
    // incoming data.
    //
    // To avoid having to recreate the bitmaps whenever the parties in the
    // share change, (and hence the various bpp may change) from r2.0 we
    // now use a fixed vertical size and if necessary can handle incoming
    // bitmaps in multiple bands.
    //
    // These are the resulting heights for 256 pixel wide segments.
    //
    // TSHR_MAX_SEND_PKT - sizeof(DATAPACKETHEADER) / bytes per scan line
    //
    //     4bpp -->    (32000 - 4)    /     128              = 249
    //     8bpp -->    (32000 - 4)    /     256              = 124
    //    24bpp -->    (32000 - 4)    /     768              =  41
    //
    //

    //
    // NOTE:
    // The VGA driver has a problem when the bitmap ends exactly on a 4K
    // (page) boundary.  So we create the bitmaps one pixel taller.
    //
    // BOGUS BUGBUG LAURABU
    // Is this really true anymore?  If not, save some memory and make these
    // the right size.
    //

    hdcDesktop = GetDC(NULL);
    if (!hdcDesktop)
    {
        ERROR_OUT(("USR_ShareStarting: can't get screen DC"));
        DC_QUIT;
    }

    // The large bitmap is short.  The rest are medium height.
    bitmapInfo.biWidth      = 1024;
    bitmapInfo.biHeight     = MaxBitmapHeight(MEGA_WIDE_X_SIZE, 8) + 1;
    m_usrBmp1024 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0,  NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp1024)
    {
        ERROR_OUT(("USR_ShareStarting: failed to reate m_usrBmp1024"));
        DC_QUIT;
    }

    bitmapInfo.biHeight     = MaxBitmapHeight(MEGA_X_SIZE, 8) + 1;

    bitmapInfo.biWidth      = 256;
    m_usrBmp256 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp256)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp256"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 128;
    m_usrBmp128 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp128)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp128"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 112;
    m_usrBmp112 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp112)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp112"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 96;
    m_usrBmp96  = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp96)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp96"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 80;
    m_usrBmp80  = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp80)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp80"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 64;
    m_usrBmp64  = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp64)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp64"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 48;
    m_usrBmp48  = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp48)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp48"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 32;
    m_usrBmp32  = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp32)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp32"));
        DC_QUIT;
    }

    bitmapInfo.biWidth      = 16;
    m_usrBmp16  = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
            DIB_RGB_COLORS);
    if (!m_usrBmp16)
    {
        ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp16"));
        DC_QUIT;
    }

    rc = TRUE;

DC_EXIT_POINT:
    if (hdcDesktop)
    {
        ReleaseDC(NULL, hdcDesktop);
    }

    DebugExitBOOL(ASShare::USR_ShareStarting, rc);
    return(rc);
}



//
// USR_ShareEnded()
// Cleans up share resources
//
void ASShare::USR_ShareEnded(void)
{
    DebugEntry(ASShare::USR_ShareEnded);

    //
    // Delete Transfer Bitmaps.
    //
    if (m_usrBmp1024)
    {
        DeleteBitmap(m_usrBmp1024);
        m_usrBmp1024= NULL;
    }

    if (m_usrBmp256)
    {
        DeleteBitmap(m_usrBmp256);
        m_usrBmp256 = NULL;
    }

    if (m_usrBmp128)
    {
        DeleteBitmap(m_usrBmp128);
        m_usrBmp128 = NULL;
    }

    if (m_usrBmp112)
    {
        DeleteBitmap(m_usrBmp112);
        m_usrBmp112 = NULL;
    }

    if (m_usrBmp96)
    {
        DeleteBitmap(m_usrBmp96);
        m_usrBmp96 = NULL;
    }

    if (m_usrBmp80)
    {
        DeleteBitmap(m_usrBmp80);
        m_usrBmp80 = NULL;
    }

    if (m_usrBmp64)
    {
        DeleteBitmap(m_usrBmp64);
        m_usrBmp64 = NULL;
    }

    if (m_usrBmp48)
    {
        DeleteBitmap(m_usrBmp48);
        m_usrBmp48 = NULL;
    }

    if (m_usrBmp32)
    {
        DeleteBitmap(m_usrBmp32);
        m_usrBmp32 = NULL;
    }

    if (m_usrBmp16)
    {
        DeleteBitmap(m_usrBmp16);
        m_usrBmp16 = NULL;
    }

    //
    // Free Bitmap Buffer.
    //
    if (m_usrPBitmapBuffer != NULL)
    {
        delete[] m_usrPBitmapBuffer;
        m_usrPBitmapBuffer = NULL;
    }

    DebugExitVOID(ASShare::USR_ShareEnded);
}




//
// USR_RecalcCaps()
//
// DESCRIPTION:
//
// Enumerates the bitmap capabilities of all parties currently in the
// share, and determines the common capabilities.
//
// PARAMETERS: None.
//
// RETURNS: TRUE if there are good common caps, or false on failure (which
// has the effect of rejecting a new party from joining the share).
//
//
void  ASShare::USR_RecalcCaps(BOOL fJoiner)
{
    ASPerson *  pasT;
    UINT        capsMaxBPP;
    UINT        capsMinBPP;
    UINT        capsSupports4BPP;
    UINT        capsSupports8BPP;
    UINT        capsSupports24BPP;
    UINT        capsOldBPP;

    DebugEntry(ASShare::USR_RecalcCaps);

    if (!m_pHost)
    {
        // Nothing to do
        DC_QUIT;
    }

    ValidatePerson(m_pasLocal);

    capsOldBPP = m_pHost->m_usrSendingBPP;

    //
    // Init the caps
    //
    capsSupports4BPP    = m_pasLocal->cpcCaps.screen.capsSupports4BPP;
    capsSupports8BPP    = m_pasLocal->cpcCaps.screen.capsSupports8BPP;
    capsSupports24BPP   = m_pasLocal->cpcCaps.screen.capsSupports24BPP;
    capsMaxBPP          = 0;
    capsMinBPP          = 0xFFFFFFFF;

    for (pasT = m_pasLocal->pasNext; pasT != NULL; pasT = pasT->pasNext)
    {
        //
        // Check the bpps supported.
        //
        if (pasT->cpcCaps.screen.capsSupports4BPP != CAPS_SUPPORTED)
        {
            capsSupports4BPP = CAPS_UNSUPPORTED;
        }
        if (pasT->cpcCaps.screen.capsSupports8BPP != CAPS_SUPPORTED)
        {
            capsSupports8BPP = CAPS_UNSUPPORTED;
        }
        if (pasT->cpcCaps.screen.capsSupports24BPP != CAPS_SUPPORTED)
        {
            capsSupports24BPP = CAPS_UNSUPPORTED;
        }

        //
        // Set the combined bpp to the maximum so far found.
        // (If we send data at this bpp then one of the remote systems can
        // usefully process this number of colors).
        //
        capsMaxBPP = max(capsMaxBPP, pasT->cpcCaps.screen.capsBPP);
        capsMinBPP = min(capsMinBPP, pasT->cpcCaps.screen.capsBPP);
    }

    //
    // Now figure out what BPP we will transmit at.
    //
    //
    // Limit the combined caps bpp (which is currently the maximum bpp that
    // any system in the share wants) to the local bpp, since there is no
    // point sending at higher bpp than the local machine has.
    //
    capsMaxBPP = min(capsMaxBPP, g_usrScreenBPP);
    if (!capsMaxBPP)
        capsMaxBPP = g_usrScreenBPP;

    capsMinBPP = min(capsMinBPP, g_usrScreenBPP);

    //
    // m_usrSendingBPP is most often going to be 8.  So it's easier to assume
    // it, then check for cases where it won't be.
    //
    m_pHost->m_usrSendingBPP = 8;

    if ((capsMaxBPP <= 4) && (capsSupports4BPP == CAPS_SUPPORTED))
    {
        m_pHost->m_usrSendingBPP = 4;
    }
    else if ((capsMinBPP >= 24) &&
             (g_asSettings & SHP_SETTING_TRUECOLOR) &&
             (capsSupports24BPP == CAPS_SUPPORTED))
    {
        m_pHost->m_usrSendingBPP = 24;
    }

    if (capsOldBPP != m_pHost->m_usrSendingBPP)
    {
        //
        // If switching to/from palettized, we need to update the
        // "need to send palette" flag.  Note that 4bpp is also a
        // palettized color depth.
        //
        if ((capsOldBPP <= 8) && (m_pHost->m_usrSendingBPP > 8))
            m_pHost->m_pmMustSendPalette = FALSE;
        else if ((capsOldBPP > 8) && (m_pHost->m_usrSendingBPP <= 8))
            m_pHost->m_pmMustSendPalette = TRUE;

#ifdef _DEBUG
        if (capsOldBPP == 24)
        {
            WARNING_OUT(("TRUE COLOR SHARING is now FINISHED"));
        }
        else if (m_pHost->m_usrSendingBPP == 24)
        {
            WARNING_OUT(("TRUE COLOR SHARING is now STARTING"));
        }
#endif

        if (!fJoiner)
        {
            //
            // Sending BPP changed.  Repaint all shared stuff.
            // NOTE:
            // We recalc the sendBPP at three points:
            //      * When we start to share
            //      * When a person joins
            //      * When a person leaves
            //
            // In the first two cases, shared stuff is repainted,
            // so everybody gets the new sendBPP data.  Only in the
            // leave case do we need to force this.
            //
            m_pHost->HET_RepaintAll();
        }
    }

DC_EXIT_POINT:
    DebugExitVOID(ASShare::USR_RecalcCaps);
}


//
// USR_HostStarting()
//
BOOL ASHost::USR_HostStarting(void)
{
    BOOL    rc = FALSE;
    HDC     hdc;

    DebugEntry(ASHost::USR_HostStarting);

    //
    // Create scratch DC
    //
    hdc = GetDC(NULL);
    if (!hdc)
    {
        ERROR_OUT(("USR_HostStarting: can't get screen DC"));
        DC_QUIT;
    }

    m_usrWorkDC = CreateCompatibleDC(hdc);
    ReleaseDC(NULL, hdc);

    if (!m_usrWorkDC)
    {
        ERROR_OUT(("USR_HostStarting: can't create m_usrWorkDC"));
        DC_QUIT;
    }

    m_pShare->USR_RecalcCaps(TRUE);

    rc = TRUE;

DC_EXIT_POINT:
    DebugExitBOOL(ASHost::USR_HostStarting, rc);
    return(rc);
}



//
// USR_HostEnded()
//
void ASHost::USR_HostEnded(void)
{
    DebugEntry(ASHost::USR_HostEnded);

    if (m_usrWorkDC != NULL)
    {
        DeleteDC(m_usrWorkDC);
        m_usrWorkDC = NULL;
    }

    DebugExitVOID(ASHost::USR_HostEnded);
}




//
// USR_ScrollDesktop
//
void  ASShare::USR_ScrollDesktop
(
    ASPerson *  pasPerson,
    int         xNew,
    int         yNew
)
{
    int         xOld;
    int         yOld;

    DebugEntry(ASShare::USR_ScrollDesktop);

    ValidateView(pasPerson);

    //
    // If the origin has changed then do the update.
    //
    xOld = pasPerson->m_pView->m_dsScreenOrigin.x;
    yOld = pasPerson->m_pView->m_dsScreenOrigin.y;

    if ((xOld != xNew) || (yOld != yNew))
    {
        pasPerson->m_pView->m_dsScreenOrigin.x = xNew;
        pasPerson->m_pView->m_dsScreenOrigin.y = yNew;

        //
        // We must ensure that data written to the ScreenBitmap is not
        // clipped
        //
        OD_ResetRectRegion(pasPerson);

        //
        // Offset the existing bitmap by the change in desktop origins.
        //

        BitBlt(pasPerson->m_pView->m_usrDC,
                          0,
                          0,
                          pasPerson->cpcCaps.screen.capsScreenWidth,
                          pasPerson->cpcCaps.screen.capsScreenHeight,
                          pasPerson->m_pView->m_usrDC,
                          xNew - xOld,
                          yNew - yOld,
                          SRCCOPY);

        //
        // Offset the shadow cursor pos -- same place on remote screen
        // but now different place in VD
        //
        pasPerson->cmPos.x += xNew - xOld;
        pasPerson->cmPos.y += yNew - yOld;

        //
        // Repaint the view
        //
        VIEW_InvalidateRgn(pasPerson, NULL);
    }

    DebugExitVOID(ASShare::USR_ScrollDesktop);
}



//
// FUNCTION: USR_InitDIBitmapHeader
//
// DESCRIPTION:
//
// Initialises a Device Independent bitmap header to be the given bits per
// pel.
//
// PARAMETERS:
//
// pbh - pointer to the bitmap header to be initialised.
// bpp - bpp to be used for the bitmap
//
// RETURNS: VOID
//
//
void  ASShare::USR_InitDIBitmapHeader
(
    BITMAPINFOHEADER *  pbh,
    UINT                bpp
)
{
    DebugEntry(ASShare::USR_InitDIBitmapHeader);

    pbh->biSize          = sizeof(BITMAPINFOHEADER);
    pbh->biPlanes        = 1;
    pbh->biBitCount      = (WORD)bpp;
    pbh->biCompression   = BI_RGB;
    pbh->biSizeImage     = 0;
    pbh->biXPelsPerMeter = 10000;
    pbh->biYPelsPerMeter = 10000;
    pbh->biClrUsed       = 0;
    pbh->biClrImportant  = 0;

    DebugExitVOID(ASShare::USR_InitDIBitmapHeader);
}



//
// USR_ViewStarting()
//
// Called when someone we're viewing starts to host.  We create the desktop
// bitmap for them plus scratch objects
//
BOOL  ASShare::USR_ViewStarting(ASPerson *  pasPerson)
{
    BOOL   rc;

    DebugEntry(ASShare::USR_ViewStarting);

    ValidateView(pasPerson);

    //
    // Create a bitmap for this new party
    //
    rc = USRCreateRemoteDesktop(pasPerson);

    DebugExitBOOL(ASShare::USR_ViewStarting, rc);
    return(rc);
}


//
// FUNCTION: USRCreateRemoteDesktop
//
// DESCRIPTION:
//
// Creates the shadow bitmap for a remote party.
//
// PARAMETERS:
//
// personID - person to create the shadow bitmap for.
//
// RETURNS: TRUE if successful, FALSE otherwise.
//
//
BOOL  ASShare::USRCreateRemoteDesktop(ASPerson * pasPerson)
{
    BOOL            rc = FALSE;
    HDC             hdcDesktop = NULL;
    RECT            desktopRect;

    DebugEntry(ASShare::USRCreateRemoteDesktop);

    ValidateView(pasPerson);

    ASSERT(pasPerson->m_pView->m_usrDC == NULL);
    ASSERT(pasPerson->m_pView->m_usrBitmap == NULL);
    ASSERT(pasPerson->m_pView->m_usrOldBitmap == NULL);

    hdcDesktop = GetDC(NULL);

    //
    // Create the scratch DC
    //
    pasPerson->m_pView->m_usrWorkDC = CreateCompatibleDC(hdcDesktop);
    if (!pasPerson->m_pView->m_usrWorkDC)
    {
        ERROR_OUT(("Couldn't create workDC for person [%d]", pasPerson->mcsID));
        DC_QUIT;
    }

    //
    // Create the DC that keeps the screen bitmap for this party
    //
    pasPerson->m_pView->m_usrDC = CreateCompatibleDC(hdcDesktop);
    if (!pasPerson->m_pView->m_usrDC)
    {
        ERROR_OUT(("Couldn't create usrDC for person [%d]", pasPerson->mcsID));
        DC_QUIT;
    }

    //
    // We can't use this person's usrDC, since that currently has a MONO
    // bitmap selected into it.
    //
    pasPerson->m_pView->m_usrBitmap = CreateCompatibleBitmap(hdcDesktop, pasPerson->cpcCaps.screen.capsScreenWidth, pasPerson->cpcCaps.screen.capsScreenHeight);
    if (pasPerson->m_pView->m_usrBitmap == NULL)
    {
        ERROR_OUT(("Couldn't create screen bitmap for [%d]", pasPerson->mcsID));
        DC_QUIT;
    }

    //
    // Select the screen bitmap into the person's DC, and save the previous
    // 1x1 bitmap away, so we can deselect it when done.
    //
    pasPerson->m_pView->m_usrOldBitmap = SelectBitmap(pasPerson->m_pView->m_usrDC, pasPerson->m_pView->m_usrBitmap);

    //
    // Fill the Screen Bitmap with grey.
    //
    // In practice the Shadow Window Presenter(SWP) should never display
    // any area of the Screen Bitmap that has not been updated with data
    // from a remote system.
    //
    // Therefore this operation is just "insurance" in case the SWP goes
    // wrong and momentarily displays a non-updated area - a flash of grey
    // is better than a flash of garbage.
    //
    desktopRect.left = 0;
    desktopRect.top = 0;
    desktopRect.right = pasPerson->cpcCaps.screen.capsScreenWidth;
    desktopRect.bottom = pasPerson->cpcCaps.screen.capsScreenHeight;

    FillRect(pasPerson->m_pView->m_usrDC, &desktopRect, GetSysColorBrush(COLOR_APPWORKSPACE));
    rc = TRUE;

DC_EXIT_POINT:

    if (hdcDesktop != NULL)
    {
        ReleaseDC(NULL, hdcDesktop);
    }

    DebugExitBOOL(ASShare::USRCreateRemoteDesktop, rc);
    return(rc);
}



//
// USR_ViewEnded()
//
// Called when person we're viewing stops hosting.  We get rid of their
// desktop bitmap.
//
void  ASShare::USR_ViewEnded(ASPerson *  pasPerson)
{
    ValidateView(pasPerson);

    //
    // Delete the desktop bitmap for the party that has left
    //
    USRDeleteRemoteDesktop(pasPerson);
}


//
// FUNCTION: USRDeleteRemoteDesktop
//
// DESCRIPTION:
//
// Deletes a remote party's shadow bitmap.
//
// PARAMETERS:
//
// personID - party whose shadow bitmap is to be deleted.
//
// RETURNS: Nothing.
//
//
void  ASShare::USRDeleteRemoteDesktop(ASPerson * pasPerson)
{
    DebugEntry(ASShare::USRDeleteRemoteDesktop);

    ValidateView(pasPerson);

    if (pasPerson->m_pView->m_usrOldBitmap != NULL)
    {
        // Deselect screen bitmap
        SelectBitmap(pasPerson->m_pView->m_usrDC, pasPerson->m_pView->m_usrOldBitmap);
        pasPerson->m_pView->m_usrOldBitmap = NULL;
    }

    if (pasPerson->m_pView->m_usrBitmap != NULL)
    {
        // Delete the screen bitmap
        DeleteBitmap(pasPerson->m_pView->m_usrBitmap);
        pasPerson->m_pView->m_usrBitmap = NULL;
    }

    if (pasPerson->m_pView->m_usrDC != NULL)
    {
        //
        // Delete the screen DC.  Created objects should have
        // been selected out of it before now.
        //
        DeleteDC(pasPerson->m_pView->m_usrDC);
        pasPerson->m_pView->m_usrDC = NULL;
    }

    if (pasPerson->m_pView->m_usrWorkDC != NULL)
    {
        DeleteDC(pasPerson->m_pView->m_usrWorkDC);
        pasPerson->m_pView->m_usrWorkDC = NULL;
    }

    DebugExitVOID(ASShare::USRDeleteRemoteDesktop);
}




//
// This function is a mess! First because it ought to be an FH API
// function, and secondly because it mixes portable code and Windows API
// calls. The details of what is to be done with it are deferred until the
// UNIX port of FH is designed, though. STOPPRESS! Function replaced by new
// FH_CreateAndSelectFont, which combines old USR_UseFont and
// FH_CreateAndSelectFont - you have to write an NT version.
//
//
// USR_UseFont()
//
BOOL  ASShare::USR_UseFont
(
    HDC             surface,
    HFONT*          pHFont,
    TEXTMETRIC*     pFontMetrics,
    LPSTR           pName,
    UINT            codePage,
    UINT            MaxHeight,
    UINT            Height,
    UINT            Width,
    UINT            Weight,
    UINT            flags
)
{
    BOOL      rc = FALSE;
    HFONT     hNewFont;
    HFONT     hOldFont;

    DebugEntry(ASShare::USR_UseFont);

    rc = FH_CreateAndSelectFont(surface,
                                &hNewFont,
                                &hOldFont,
                                pName,
                                codePage,
                                MaxHeight,
                                Height,
                                Width,
                                Weight,
                                flags);

    if (rc == FALSE)
    {
        //
        // Failed to create or select the font.
        //
        DC_QUIT;
    }

    //
    // Select in the new font which ensures that the old one is deselected.
    //
    // NB.  We do not delete the font we are deselecting, rather the old
    // one that was passed to us.  This is beacuse multiple components use
    // "surface", and so the deselected font may not be the current
    // component's last font at all - the important thing is that by
    // selecting in the new font we are ensuring that the old font is not
    // the selected one.
    //
    SelectFont(surface, hNewFont);
    if (*pHFont)
    {
        DeleteFont(*pHFont);
    }

    //
    // If a pointer to font metrics was passed in then we need to query
    // the metrics now.
    //
    if (pFontMetrics)
        GetTextMetrics(surface, pFontMetrics);

    //
    // Update the record of the last font we selected.
    //
    *pHFont = hNewFont;
    rc = TRUE;

DC_EXIT_POINT:
    DebugExitDWORD(ASShare::USR_UseFont, rc);
    return(rc);
}

//
// USR_ScreenChanged()
//
void  ASShare::USR_ScreenChanged(ASPerson * pasPerson)
{
    DebugEntry(ASShare::USR_ScreenChanged);

    ValidatePerson(pasPerson);

    pasPerson->cpcCaps.screen.capsScreenWidth = pasPerson->cpcCaps.screen.capsScreenWidth;
    pasPerson->cpcCaps.screen.capsScreenHeight = pasPerson->cpcCaps.screen.capsScreenHeight;

    if (pasPerson->m_pView)
    {
        //
        // Recreate screen bitmap
        //

        //
        // Discard the remote users current shadow bitmap
        //
        USRDeleteRemoteDesktop(pasPerson);

        //
        // Create a new shadow bitmap for remote user that is of the new size
        //
        USRCreateRemoteDesktop(pasPerson);
    }

    VIEW_ScreenChanged(pasPerson);

    DebugExitVOID(ASShare::USR_ScreenChanged);
}