/* picture.c - This file contains OLE object handling routines.
 *
 * Created by Microsoft Corporation.
 */

#include "packager.h"
#include "dialogs.h"


static OLECLIENTVTBL clientTbl;
static OLESTREAMVTBL streamTbl;


static VOID PicGetBounds(LPOLEOBJECT lpObject, LPRECT lprc);

/* InitClient() - Initialize the OLE client structures.
 */
BOOL
InitClient(
    VOID
    )
{
    gcfFileName  = (OLECLIPFORMAT)RegisterClipboardFormat("FileName");
    gcfLink      = (OLECLIPFORMAT)RegisterClipboardFormat("ObjectLink");
    gcfNative    = (OLECLIPFORMAT)RegisterClipboardFormat("Native");
    gcfOwnerLink = (OLECLIPFORMAT)RegisterClipboardFormat("OwnerLink");

    glpclient = PicCreateClient(&CallBack, (LPOLECLIENTVTBL)&clientTbl);

    if (!(glpStream = (LPAPPSTREAM)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM))))
        goto Error;

    glpStream->lpstbl = (LPOLESTREAMVTBL)&streamTbl;
    streamTbl.Get = (DWORD (CALLBACK*)(LPOLESTREAM, void FAR*, DWORD))ReadStream;
    streamTbl.Put = (DWORD (CALLBACK*)(LPOLESTREAM, OLE_CONST void FAR*, DWORD))WriteStream;

    return TRUE;

Error:
    if (glpStream)
    {
        GlobalFree(glpStream);
    	glpStream = NULL;
    }

    if (glpclient)
    {
        GlobalFree(glpclient);
        glpclient = NULL;
    }

    return FALSE;
}



/* EndClient() - Clean up for termination.
 */
VOID
EndClient(
    VOID
    )
{
    if (glpStream)
    {
	GlobalFree(glpStream);
        glpStream = NULL;
    }

    if (glpclient)
    {
	GlobalFree(glpclient);
        glpclient = NULL;
    }
}



/* PicCreate() -
 */
LPPICT
PicCreate(
    LPOLEOBJECT lpObject,
    LPRECT lprcObject
    )
{
    HANDLE hpict = NULL;
    LPPICT lppict = NULL;
    RECT rc;

    if (lpObject)
    {
        if (!(hpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(PICT)))
            || !(lppict = (LPPICT)GlobalLock(hpict)))
            goto errRtn;

        //
        // If size of window is specified, use it; otherwise, retrieve
        // the size of the item synchronously.
        //
        if (lprcObject)
            rc = *lprcObject;
        else {
            SetRectEmpty(&rc);
            PicGetBounds(lpObject, &rc);
        }

        // Store the data in the window itself
        lppict->hdata = hpict;
        lppict->lpObject = lpObject;
        lppict->rc = rc;
        lppict->fNotReady = FALSE;
    }

    return lppict;

errRtn:
    ErrorMessage(E_FAILED_TO_CREATE_CHILD_WINDOW);

    if (lppict)
        GlobalUnlock(hpict);

    if (hpict)
        GlobalFree(hpict);

    return NULL;
}



/* PicDelete() - Deletes an object (called when the item window is destroyed).
 */
VOID
PicDelete(
    LPPICT lppict
    )
{
    HANDLE hdata;
    LPOLEOBJECT lpObject;

    if (!lppict)
        return;

    if (lppict && lppict->lpObject)
    {
        lpObject = lppict->lpObject;
        lppict->lpObject = NULL;
        // Wait until the object isn't busy
        WaitForObject(lpObject);

        if (Error(OleDelete(lpObject)))
            ErrorMessage(E_FAILED_TO_DELETE_OBJECT);

        // Wait until the object deletion is complete
        WaitForObject(lpObject);
    }

    GlobalUnlock(hdata = lppict->hdata);
    GlobalFree(hdata);
}



/* PicDraw() - Draws the item associated with hwnd in the DC hDC.
 */
BOOL
PicDraw(
    LPPICT lppict,
    HDC hDC,
    LPRECT lprc,
    INT xHSB,
    INT yVSB,
    BOOL fPicture,
    BOOL fFocus
    )
{
    BOOL fSuccess = FALSE;
    DWORD ot;
    HANDLE hdata;
    HFONT hfont;
    LPOLEOBJECT lpObjectUndo;
    LPSTR lpdata;
    RECT rc;
    RECT rcFocus;
    CHAR szDesc[CBMESSAGEMAX];
    CHAR szFileName[CBPATHMAX];
    CHAR szMessage[CBMESSAGEMAX + CBPATHMAX];
    INT iDelta;
    INT iPane;

    iPane = (lppict == glpobj[CONTENT]);
    lpObjectUndo = (gptyUndo[iPane] == PICTURE)
        ? ((LPPICT)glpobjUndo[iPane])->lpObject : NULL;

    // If drawing the Picture, offset by scroll bars and draw
    if (fPicture)
    {
        if (IsRectEmpty(&(lppict->rc)))
            PicGetBounds(lppict->lpObject, &(lppict->rc));

        rc = lppict->rc;

        // If image is smaller than pane, center horizontally
        if ((iDelta = lprc->right - lppict->rc.right) > 0)
            OffsetRect(&rc, iDelta >> 1, 0);
        else /* else, use the scroll bar value */
            OffsetRect(&rc, -xHSB, 0);

        // If image is smaller than pane, center vertically
        if ((iDelta = lprc->bottom - lppict->rc.bottom) > 0)
            OffsetRect(&rc, 0, iDelta >> 1);
        else /* else, use the scroll bar value */
            OffsetRect(&rc, 0, -yVSB);

        // If we have an object, call OleDraw()
        fSuccess = !Error(OleDraw(lppict->lpObject, hDC, &rc, NULL, NULL));

        if (fFocus)
            DrawFocusRect(hDC, &rc);

        return fSuccess;
    }

    // Otherwise, draw the description string
    OleQueryType(lppict->lpObject, &ot);

    if ((ot == OT_LINK
        && Error(OleGetData(lppict->lpObject, gcfLink, &hdata)))
        || (ot == OT_EMBEDDED
        && Error(OleGetData(lppict->lpObject, gcfOwnerLink, &hdata)))
        || (ot == OT_STATIC
        && (!lpObjectUndo || Error(OleGetData(lpObjectUndo, gcfOwnerLink,
        &hdata)))))
    {
        LoadString(ghInst, IDS_OBJECT, szFileName, CBMESSAGEMAX);
        LoadString(ghInst, IDS_FROZEN, szDesc, CBMESSAGEMAX);
        goto DrawString;
    }

    if (hdata && (lpdata = GlobalLock(hdata)))
    {
        switch (ot)
        {
            case OT_LINK:
                while (*lpdata++)
                    ;
                
                // return value ignored
                if(SUCCEEDED(StringCchCopy(szFileName, ARRAYSIZE(szFileName), lpdata)))
                {
                    Normalize(szFileName);
                    LoadString(ghInst, IDS_LINKTOFILE, szDesc, CBMESSAGEMAX);
                }

                break;

            case OT_EMBEDDED:
                RegGetClassId(szFileName, ARRAYSIZE(szFileName), lpdata);
                LoadString(ghInst, IDS_EMBEDFILE, szDesc, CBMESSAGEMAX);
                break;

            case OT_STATIC:
                RegGetClassId(szFileName, ARRAYSIZE(szFileName), lpdata);
                LoadString(ghInst, IDS_FROZEN, szDesc, CBMESSAGEMAX);
                break;
        }

        GlobalUnlock(hdata);

DrawString:
        if(SUCCEEDED(StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szDesc, szFileName)))  // return value ignored
        {

            hfont = SelectObject(hDC, ghfontChild);
            DrawText(hDC, szMessage, -1, lprc,
                DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);

            if (fFocus)
            {
                rcFocus = *lprc;
                DrawText(hDC, szMessage, -1, &rcFocus,
                    DT_CALCRECT | DT_NOPREFIX | DT_LEFT | DT_TOP | DT_SINGLELINE);
                OffsetRect(&rcFocus, (lprc->left + lprc->right - rcFocus.right) / 2,
                    (lprc->top + lprc->bottom - rcFocus.bottom) / 2);
                DrawFocusRect(hDC, &rcFocus);
            }

            if (hfont)
                SelectObject(hDC, hfont);

            fSuccess = TRUE;
        }
    }

    return fSuccess;
}



/* PicPaste() - Retrieves an object from the clipboard.
 */
LPPICT
PicPaste(
    BOOL fPaste,
    LPSTR lpstrName
    )
{
    LPOLEOBJECT lpObject;

    if (!OpenClipboard(ghwndFrame))
        return NULL;                    /* Couldn't open the clipboard */

    Hourglass(TRUE);

    // Don't replace the current object unless we're successful
    if (fPaste)
    {
        if (Error(OleCreateFromClip(gszProtocol, glpclient, glhcdoc, lpstrName,
            &lpObject, olerender_draw, 0)))
        {
            if (Error(OleCreateFromClip(gszSProtocol, glpclient, glhcdoc,
                lpstrName, &lpObject, olerender_draw, 0)))
                lpObject = NULL;

        }
    }
    else if (Error(OleCreateLinkFromClip(
        gszProtocol, glpclient, glhcdoc, lpstrName, &lpObject,
        olerender_draw, 0)))
    {
        lpObject = NULL;
    }

    CloseClipboard();
    Hourglass(FALSE);

    if (!lpObject)
        return NULL;

    return PicCreate(lpObject, NULL);
}



/* Error() - check for OLE function error conditions
 *
 * This function increments gcOleWait as appropriate.
 *
 * Pre:      Initialize ghwndError to where the focus should return.
 *
 * Returns:  TRUE  if an immediate error occurred.
 */
BOOL
Error(
    OLESTATUS olestat
    )
{
    DWORD ot;
    INT iPane;

    switch (olestat)
    {
        case OLE_WAIT_FOR_RELEASE:
            gcOleWait++;
            return FALSE;

        case OLE_OK:
            return FALSE;

        case OLE_ERROR_STATIC:              /* Only happens w/ dbl click */
            ErrorMessage(W_STATIC_OBJECT);
            break;

        case OLE_ERROR_ADVISE_PICT:
        case OLE_ERROR_OPEN:                /* Invalid link? */
        case OLE_ERROR_NAME:
            iPane = (GetTopWindow(ghwndFrame) == ghwndPane[CONTENT]);
            if ((LPPICT)glpobj[iPane] == NULL)
            {
                ErrorMessage(E_FAILED_TO_CREATE_OBJECT);
                return FALSE;
            }
            else
            {
                OleQueryType(((LPPICT)glpobj[iPane])->lpObject, &ot);
                if (ot == OT_LINK)
                {
                    if (ghwndError == ghwndFrame)
                    {
                        if (DialogBoxAfterBlock (
                            MAKEINTRESOURCE(DTINVALIDLINK), ghwndError,
                            fnInvalidLink) == IDD_CHANGE)
                            PostMessage(ghwndFrame, WM_COMMAND, IDM_LINKS, 0L);
                    }
                    else
                    {
                        // Failed, but already in Link Properties!!
                        ErrorMessage(E_FAILED_TO_UPDATE_LINK);
                    }

                    return FALSE;
                }
            }

            break;

        default:
            break;
    }

    return TRUE;
}



/* CallBack() - Routine that OLE client DLL calls when events occur.
 *
 * This routine is called when the object has been updated and may
 * need to be redisplayed; if asynchronous operations have completed;
 * and if the application allows the user to cancel long operations
 * (like Painting, or other asynchronous operations).
 */
INT CALLBACK
CallBack(
    LPOLECLIENT lpclient,
    OLE_NOTIFICATION flags,
    LPOLEOBJECT lpObject
    )
{
    INT iPane;

    switch (flags)
    {
        case OLE_CLOSED:
            if (gfInvisible)
                PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
            else
                SetFocus(ghwndError);

            break;

        case OLE_SAVED:
        case OLE_CHANGED:
            {
                //
                // The OLE libraries make sure that we only receive
                // update messages according to the Auto/Manual flags.
                //
                iPane = (gpty[CONTENT] == PICTURE
                    && ((LPPICT)glpobj[CONTENT])->lpObject == lpObject);

                if (gpty[iPane] == PICTURE)
                {
                    ((LPPICT)glpobj[iPane])->fNotReady = FALSE;
                    InvalidateRect(ghwndPane[iPane], NULL, TRUE);
                    SetRect(&(((LPPICT)glpobj[iPane])->rc), 0, 0, 0, 0);
                    Dirty();
                }

                break;
            }

        case OLE_RELEASE:
            {
                if (gcOleWait)
                    gcOleWait--;
                else
                    ErrorMessage(E_UNEXPECTED_RELEASE);

                switch (Error(OleQueryReleaseError(lpObject)))
                {
                    case FALSE:
                        switch (OleQueryReleaseMethod(lpObject))
                        {
                            case OLE_SETUPDATEOPTIONS:
                                iPane = (gpty[CONTENT] == PICTURE
                                    && ((LPPICT)glpobj[CONTENT])->lpObject ==
                                    lpObject);

                                PostMessage(ghwndPane[iPane], WM_COMMAND,
                                    IDM_LINKDONE, 0L);

                            default:
                                break;
                        }

                        break;

                    case TRUE:
                        switch (OleQueryReleaseMethod(lpObject))
                        {
                            case OLE_DELETE:
                                ErrorMessage(E_FAILED_TO_DELETE_OBJECT);
                                break;

                            case OLE_LOADFROMSTREAM:
                                ErrorMessage(E_FAILED_TO_READ_OBJECT);
                                break;

                            case OLE_LNKPASTE:
                                ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED);
                                break;

                            case OLE_ACTIVATE:
                                ErrorMessage(E_FAILED_TO_LAUNCH_SERVER);
                                break;

                            case OLE_UPDATE:
                                ErrorMessage(E_FAILED_TO_UPDATE);
                                break;

                            case OLE_RECONNECT:
                                ErrorMessage(E_FAILED_TO_RECONNECT_OBJECT);
                                break;
                        }

                        break;
                }

                break;
            }

        case OLE_QUERY_RETRY:
            // if lpObject doesn't match any one of these 4 objects, it means
            // that PicDelete() has been called on lpObject, so there is no
            // point in continueing the RETRIES.
            // See PicDelete() code for more info.
            if ((glpobj[CONTENT]
                && lpObject == ((LPPICT)glpobj[CONTENT])->lpObject)
                || (glpobj[APPEARANCE]
                && lpObject == ((LPPICT) glpobj[APPEARANCE])->lpObject)
                || (glpobjUndo[CONTENT]
                && lpObject == ((LPPICT) glpobjUndo[CONTENT])->lpObject)
                || (glpobjUndo[APPEARANCE]
                && lpObject == ((LPPICT) glpobjUndo[APPEARANCE])->lpObject))
            {
                return TRUE;
            }
            else
            {
                return FALSE;
            }

        case OLE_QUERY_PAINT:
            return TRUE;

        default:
            break;
    }

    return 0;
}



/* WaitForObject() - Waits, dispatching messages, until the object is free.
 *
 * If the object is busy, spin in a dispatch loop.
 */
VOID
WaitForObject(
    LPOLEOBJECT lpObject
    )
{
    while (OleQueryReleaseStatus(lpObject) == OLE_BUSY)
        ProcessMessage();
}



/* PicSetUpdateOptions() - Sets the update options of the object.
 *
 * Returns:  TRUE if the command completed synchronously.
 */
BOOL
PicSetUpdateOptions(
    LPPICT lppict,
    UINT idCmd
    )
{
    OLESTATUS olestat = OLE_ERROR_GENERIC;

    olestat = OleSetLinkUpdateOptions(
        lppict->lpObject,
        (idCmd == IDD_AUTO) ? oleupdate_always : oleupdate_oncall);

    if (Error(olestat))
        ErrorMessage(E_FAILED_TO_UPDATE_LINK);

    return (olestat == OLE_OK);
}



/* PicReadFromNative() - Reads an object from the pointer lpstr.
 *
 * SIDE EFFECT:  Advances the pointer past the object.
 */
LPPICT
PicReadFromNative(
    LPSTR *lplpstr,
    LPSTR lpstrName
    )
{
    LPOLEOBJECT lpObject;
    LPSTR lpstrStart;
    RECT rcObject;
    WORD w;

    // Save current position of file pointer
    lpstrStart = *lplpstr;
    SetFile(SOP_MEMORY, 0, lplpstr);

    // Load the new object
    if (Error(OleLoadFromStream((LPOLESTREAM)glpStream, gszProtocol, glpclient,
        glhcdoc, lpstrName, &lpObject)))
    {
        // Reset file pointer, and try again
        *lplpstr = lpstrStart;
        SetFile(SOP_MEMORY, 0, lplpstr);

        // Read it with the "Static" protocol
        if (Error(OleLoadFromStream((LPOLESTREAM)glpStream, gszSProtocol,
            glpclient, glhcdoc, lpstrName, &lpObject)))
            return NULL;
    }

    MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
    rcObject.left = (INT)w;
    MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
    rcObject.top = (INT)w;
    MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
    rcObject.right = (INT)w;
    MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
    rcObject.bottom = (INT)w;

    // Create a window at the right place, and display the object
    return PicCreate(lpObject, &rcObject);
}



/* PicWriteToNative() - Writes an object to memory.
 *
 * SIDE EFFECT:  Moves pointer to end of written object
 */
DWORD
PicWriteToNative(
    LPPICT lppict,
    LPOLEOBJECT lpObject,
    LPSTR *lplpstr
    )
{
    DWORD cb = 0L;
    WORD w;

    // Save the object
    SetFile(SOP_MEMORY, 0, lplpstr);

    if (Error(OleSaveToStream(lpObject, (LPOLESTREAM)glpStream)))
        goto Done;

    cb += gcbObject;

    if (lplpstr)
    {
        w = (WORD)lppict->rc.left;
        MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
        w = (WORD)lppict->rc.top;
        MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
        w = (WORD)lppict->rc.right;
        MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
        w = (WORD)lppict->rc.bottom;
        MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
    }

    cb += (DWORD)(4 * sizeof(WORD));

Done:
    return cb;
}



/* Hourglass() - Puts up the hourglass as needed.
 */
VOID
Hourglass(
    BOOL fOn
    )
{
    static HCURSOR hcurSaved = NULL;    // Cursor saved when hourglass is up
    static UINT cWait = 0;              // Number of "Hourglass"es up

    if (fOn)
    {
        if (!(cWait++))
            hcurSaved = SetCursor(ghcurWait);
    }
    else
    {
        if (!(--cWait) && hcurSaved)
        {
            SetCursor(hcurSaved);
            hcurSaved = NULL;
        }
    }
}



VOID
PicActivate(
    LPPICT lppict,
    UINT idCmd
    )
{
    DWORD ot;
    DWORD ot2;
    RECT rc;
    INT iPane;
    BOOL bAlreadyOpen = FALSE;

    iPane = (lppict == glpobj[CONTENT]);
    OleQueryType(lppict->lpObject, &ot);
    if (ot != OT_STATIC)
    {
        // Compute the window dimensions
        GetClientRect(ghwndPane[iPane], &rc);
        bAlreadyOpen = (OleQueryOpen(lppict->lpObject) == OLE_OK);

        // Open the object
        if (Error(OleActivate(lppict->lpObject,
            (idCmd == IDD_PLAY ? OLE_PLAY : OLE_EDIT),
            TRUE, TRUE, ghwndPane[iPane], &rc)))
        {
            ErrorMessage(E_FAILED_TO_LAUNCH_SERVER);
            goto errRtn;
        }
        else
        {
            WaitForObject(lppict->lpObject);
            if (!glpobj[iPane])
                goto errRtn;

            OleQueryType(lppict->lpObject, &ot2);
            if (ot2 == OT_EMBEDDED)
                Error(OleSetHostNames(lppict->lpObject, gszAppClassName,
                    (iPane == CONTENT) ? szContent : szAppearance));
        }

        return;
    }
    else
    {
        ErrorMessage(W_STATIC_OBJECT);
    }

errRtn:
    if (gfInvisible && !bAlreadyOpen)
        PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
}



VOID
PicUpdate(
    LPPICT lppict
    )
{
    DWORD ot;

    OleQueryType(lppict->lpObject, &ot);
    if (ot == OT_LINK)
    {
        if (Error(OleUpdate(lppict->lpObject)))
            ErrorMessage(E_FAILED_TO_UPDATE);
    }
}



VOID
PicFreeze(
    LPPICT lppict
    )
{
    DWORD ot;
    LPOLEOBJECT lpObject;
    INT iPane;

    iPane = (lppict == glpobj[CONTENT]);
    OleQueryType(lppict->lpObject, &ot);
    if (ot != OT_STATIC)
    {
        if (Error(OleObjectConvert(lppict->lpObject, gszSProtocol, glpclient,
             glhcdoc, gszCaption[iPane], &lpObject)))
        {
            ErrorMessage(E_FAILED_TO_FREEZE);
            return;
        }

        if (Error(OleDelete(lppict->lpObject)))
            ErrorMessage(E_FAILED_TO_DELETE_OBJECT);

        lppict->lpObject = lpObject;

        // Redraw the list box contents
        PostMessage(ghwndError, WM_REDRAW, 0, 0L);
    }
}



VOID
PicChangeLink(
    LPPICT lppict
    )
{
    HANDLE hData;
    OLESTATUS olestat;

    // Change the link information
    olestat = OleGetData(lppict->lpObject, gcfLink, &hData);
    if (!Error(olestat) && hData)
    {
        hData = OfnGetNewLinkName(ghwndError, hData);
        if (hData && !Error(OleSetData(lppict->lpObject, gcfLink, hData)))
            PostMessage(ghwndError, WM_REDRAW, 0, 0L);
    }
}



/* PicCopy() - Puts an object onto the clipboard.
 *
 * Returns:  TRUE iff successful.
 */
BOOL
PicCopy(
    LPPICT lppict
    )
{
    BOOL fSuccess = FALSE;

    // If we can't open the clipboard, fail
    if (!lppict->lpObject || !OpenClipboard(ghwndFrame))
        return FALSE;

    // Empty the clipboard
    EmptyClipboard();

    // Successful if we managed to copy to the clipboard
    fSuccess = !Error(OleCopyToClipboard(lppict->lpObject));

    CloseClipboard();
    return fSuccess;
}



/* PicGetBounds() -
 */
static VOID
PicGetBounds(
    LPOLEOBJECT lpObject,
    LPRECT lprc
    )
{
    if (IsRectEmpty(lprc))
    {
        switch (OleQueryBounds(lpObject, lprc))
        {
            case OLE_WAIT_FOR_RELEASE:
                Hourglass(TRUE);
                gcOleWait++;
                WaitForObject(lpObject);
                Hourglass(FALSE);

            case OLE_OK:
                // Map from HIMETRIC into screen coordinates
                lprc->right = MulDiv(giXppli,
                    lprc->right - lprc->left, HIMETRIC_PER_INCH);
                lprc->bottom = MulDiv (giYppli,
                    lprc->top - lprc->bottom, HIMETRIC_PER_INCH);
                lprc->left = 0;
                lprc->top = 0;

            default:
                break;
        }
    }
}


/* PicSaveUndo() - Saves a copy of the object for Undo.
 */
VOID
PicSaveUndo(
    LPPICT lppict
    )
{
    INT iPane = (lppict == glpobj[CONTENT]);
    LPOLEOBJECT lpObject;

    // Clone the object
    if (Error(OleClone(lppict->lpObject, glpclient, glhcdoc, gszTemp, &lpObject))
        || !lpObject)
    {
        ErrorMessage(W_FAILED_TO_CLONE_UNDO);
    }
    else
    {
        // Save the undo, delete the prior Undo
        DeletePane(iPane, FALSE);
        OleRename(lpObject, gszCaption[iPane]);
        glpobj[iPane] = PicCreate(lpObject, &(lppict->rc));
        gpty[iPane] = PICTURE;

        if (iPane == CONTENT)
            EnableWindow(ghwndPict, TRUE);
    }
}



/* PicPaste() - Creates object from a file
 */
LPPICT
PicFromFile(
    BOOL fEmbedded,
    LPSTR szFile
    )
{
    HRESULT hr;
    LPOLEOBJECT lpObject;

    Hourglass(TRUE);

    // Don't replace the current object unless we're successful
    if (fEmbedded)
    {
        hr = OleCreateFromFile(gszProtocol, glpclient, NULL, szFile,
                    glhcdoc, gszCaption[CONTENT], &lpObject, olerender_draw, 0);
    }
    else
    {
        hr = OleCreateLinkFromFile(gszProtocol, glpclient, NULL, szFile,
                    NULL, glhcdoc, gszCaption[CONTENT], &lpObject, olerender_draw, 0);
    }

    Hourglass(FALSE);

    if (FAILED(hr))
        return NULL;

    WaitForObject(lpObject);

    return PicCreate(lpObject, NULL);
}



LPOLECLIENT
PicCreateClient(
    PCALL_BACK fnCallBack,
    LPOLECLIENTVTBL lpclivtbl
    )
{
    LPOLECLIENT pclient;
    if (!(pclient = (LPOLECLIENT)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT))))
        return NULL;

    pclient->lpvtbl = lpclivtbl;
    pclient->lpvtbl->CallBack = fnCallBack;

    return pclient;
}
