//**********************************************************************
// File name: IDT.CPP
//
//      Implementation file for CDropTarget
//
// Functions:
//
//      See IDT.H for class definition
//
// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
//**********************************************************************

#include "pre.h"
#include "iocs.h"
#include "ias.h"
#include "app.h"
#include "site.h"
#include "doc.h"
#include "idt.h"

extern CLIPFORMAT g_cfObjectDescriptor;


//**********************************************************************
//
// CDropTarget::QueryDrop
//
// Purpose:
//
//      Check if the desired drop operation (identified by the given key
//      state) is possible at the current mouse position (pointl).
//
// Parameters:
//
//      DWORD grfKeyState       - current key state
//      POINTL pointl           - position of mouse
//      BOOL fDragScroll        - TRUE if drag scrolling cursor should
//                                be shown.
//      LPDWORD pdwEffect       - (OUT) drag effect that should occur
//
// Return Value:
//
//      BOOL                    - TRUE if drop could take place,
//                                else FALSE
//
// Function Calls:
//      Function                    Location
//
//      OleStdGetDropEffect         OLE2UI API
//
//
//********************************************************************

BOOL CDropTarget::QueryDrop (
    DWORD           grfKeyState,
    POINTL          pointl,
    BOOL            fDragScroll,
    LPDWORD         pdwEffect
)
{
    DWORD      dwScrollEffect = 0L;
    DWORD      dwOKEffects = m_pDoc->m_lpApp->m_dwTargetEffect & *pdwEffect;

    /* check if the cursor is in the active scroll area, if so need the
    **    special scroll cursor.
    */
    if (fDragScroll)
        dwScrollEffect = DROPEFFECT_SCROLL;

    /* if we have already determined that the source does NOT have any
    **    acceptable data for us, the return NO-DROP
    */
    if (! m_fCanDropCopy && ! m_fCanDropLink)
        goto dropeffect_none;

    /* OLE2NOTE: determine what type of drop should be performed given
    **    the current modifier key state. we rely on the standard
    **    interpretation of the modifier keys:
    **          no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
    **          SHIFT       -- DROPEFFECT_MOVE
    **          CTRL        -- DROPEFFECT_COPY
    **          CTRL-SHIFT  -- DROPEFFECT_LINK
    */

    *pdwEffect = OleStdGetDropEffect(grfKeyState);
    if (*pdwEffect == 0)
    {
        // No modifier keys given. Try in order MOVE, COPY, LINK.
        if ((DROPEFFECT_MOVE & dwOKEffects) && m_fCanDropCopy)
            *pdwEffect = DROPEFFECT_MOVE;
        else if ((DROPEFFECT_COPY & dwOKEffects) && m_fCanDropCopy)
            *pdwEffect = DROPEFFECT_COPY;
        else if ((DROPEFFECT_LINK & dwOKEffects) && m_fCanDropLink)
            *pdwEffect = DROPEFFECT_LINK;
        else
            goto dropeffect_none;
    }
    else
    {
        /* OLE2NOTE: we should check if the drag source application allows
        **    the desired drop effect.
        */
        if (!(*pdwEffect & dwOKEffects))
            goto dropeffect_none;

        if ((*pdwEffect == DROPEFFECT_COPY || *pdwEffect == DROPEFFECT_MOVE)
                && ! m_fCanDropCopy)
            goto dropeffect_none;

        if (*pdwEffect == DROPEFFECT_LINK && ! m_fCanDropLink)
            goto dropeffect_none;
    }

    *pdwEffect |= dwScrollEffect;
    return TRUE;

dropeffect_none:

    *pdwEffect = DROPEFFECT_NONE;
    return FALSE;
}


//**********************************************************************
//
// CDropTarget::QueryDrop
//
// Purpose:
//
//     Check to see if Drag scroll operation should be initiated.
//
// Parameters:
//
//      POINTL pointl           - position of mouse
//
// Return Value:
//
//      BOOL                    - TRUE if scroll cursor should be given
//                                else FALSE
//
// Function Calls:
//      Function                    Location
//
//      ScreenToClient              WINDOWS API
//      GetClientRect               WINDOWS API
//
// Comments:
//     A Drag scroll operation should be initiated when the mouse has
//     remained in the active scroll area (11 pixels frame around border
//     of window) for a specified amount of time (50ms).
//
//********************************************************************

BOOL CDropTarget::DoDragScroll (POINTL pointl)
{
    DWORD dwScrollDir = SCROLLDIR_NULL;
    DWORD dwTime = GetCurrentTime();
    int nScrollInset = m_pDoc->m_lpApp->m_nScrollInset;
    int nScrollDelay = m_pDoc->m_lpApp->m_nScrollDelay;
    int nScrollInterval = m_pDoc->m_lpApp->m_nScrollInterval;
    POINT point;
    RECT rect;

    point.x = (int)pointl.x;
    point.y = (int)pointl.y;

    ScreenToClient( m_pDoc->m_hDocWnd, &point);
    GetClientRect ( m_pDoc->m_hDocWnd, (LPRECT) &rect );

    if (rect.top <= point.y && point.y<=(rect.top+nScrollInset))
        dwScrollDir = SCROLLDIR_UP;
    else if ((rect.bottom-nScrollInset) <= point.y && point.y <= rect.bottom)
        dwScrollDir = SCROLLDIR_DOWN;
    else if (rect.left <= point.x && point.x <= (rect.left+nScrollInset))
        dwScrollDir = SCROLLDIR_LEFT;
    else if ((rect.right-nScrollInset) <= point.x && point.x <= rect.right)
        dwScrollDir = SCROLLDIR_RIGHT;

    if (m_dwTimeEnterScrollArea)
    {
        /* cursor was already in Scroll Area */

        if (! dwScrollDir)
        {
            /* cusor moved OUT of scroll area.
            **      clear "EnterScrollArea" time.
            */
            m_dwTimeEnterScrollArea = 0L;
            m_dwNextScrollTime = 0L;
            m_dwLastScrollDir = SCROLLDIR_NULL;

        }
        else
           if (dwScrollDir != m_dwLastScrollDir)
           {
            /* cusor moved into a different direction scroll area.
            **      reset "EnterScrollArea" time to start a new 50ms delay.
            */
            m_dwTimeEnterScrollArea = dwTime;
            m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;
            m_dwLastScrollDir = dwScrollDir;

           }
           else
              if (dwTime && dwTime >= m_dwNextScrollTime)
              {
                 m_pDoc->Scroll ( dwScrollDir );    // Scroll document now
                 m_dwNextScrollTime = dwTime + (DWORD)nScrollInterval;
              }
    }
    else
    {
        if (dwScrollDir)
        {
            /* cusor moved INTO a scroll area.
            **   reset "EnterScrollArea" time to start a new 50ms delay.
            */
            m_dwTimeEnterScrollArea = dwTime;
            m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;
            m_dwLastScrollDir = dwScrollDir;
        }
    }

    return (dwScrollDir ? TRUE : FALSE);
}


// Support functions/macros
#define SetTopLeft(rc, pt)		\
	((rc)->top = (pt)->y,(rc)->left = (pt)->x)
#define SetBottomRight(rc, pt)		\
	((rc)->bottom = (pt)->y,(rc)->right = (pt)->x)
#define OffsetPoint(pt, dx, dy)		\
	((pt)->x += dx, (pt)->y += dy)


/* HighlightRect
** -------------
**    Invert rectangle on screen. used for drop target feedback.
*/

static int HighlightRect(HWND hwnd, HDC hdc, LPRECT rc)
{
    POINT pt1, pt2;
    int old = SetROP2(hdc, R2_NOT);
    HPEN hpen;
    HGDIOBJ hold;

    pt1.x = rc->left;
    pt1.y = rc->top;
    pt2.x = rc->right;
    pt2.y = rc->bottom;

    ScreenToClient(hwnd, &pt1);
    ScreenToClient(hwnd, &pt2);

    hold = SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));
    hpen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 2,
                          GetSysColor(COLOR_ACTIVEBORDER)));

    Rectangle(hdc, pt1.x, pt1.y, pt2.x, pt2.y);

    SetROP2(hdc, old);

    hold = SelectObject(hdc, hold);
    hpen = (HPEN) SelectObject(hdc, hpen);

    DeleteObject(hpen);

  return 0;
}


//**********************************************************************
//
// CDropTarget::InitDragFeedback
//
// Purpose:
//
//      Initialize data used to draw drop target feedback.
//      As feedback we draw a rectangle the size of the object.
//
// Parameters:
//
//      LPDATAOBJECT pDataObj   - IDataObject from Drop source
//      POINTL pointl           - position of mouse
//
// Return Value:
//
//      none.
//
// Function Calls:
//      Function                    Location
//
//      IDataObject::GetData        Object
//      XformSizeInHimetricToPixels OLE2UI Library
//      GlobalLock                  WINDOWS API
//      GlobalUnlock                WINDOWS API
//      ReleaseStgMedium            OLE2 API
//      OffsetPoint                 IDT.CPP
//      SetTopLeft                  IDT.CPP
//      SetBottomRight              IDT.CPP
//
// Comments:
//      In order to know the size of the object before the object
//      is actually dropped, we render CF_OBJECTDESCRIPTOR format.
//      this data format tells us both the size of the object as
//      well as which aspect is the object is displayed as in the
//      source. If the object is currently displayed as DVASPECT_ICON
//      then we want to create the object also as DVASPECT_ICON.
//
//********************************************************************

void CDropTarget::InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl)
{
    FORMATETC fmtetc;
    STGMEDIUM stgmed;
    POINT pt;
    int height, width;
    HRESULT hrErr;

    height = width = 100; // some default values
    pt.x = (int)pointl.x;
    pt.y = (int)pointl.y;

    // do a GetData for CF_OBJECTDESCRIPTOR format to get the size of the
    // object as displayed in the source. using this size, initialize the
    // size for the drag feedback rectangle.
    fmtetc.cfFormat = g_cfObjectDescriptor;
    fmtetc.ptd = NULL;
    fmtetc.lindex = -1;
    fmtetc.dwAspect = DVASPECT_CONTENT;
    fmtetc.tymed = TYMED_HGLOBAL;

    hrErr = pDataObj->GetData(&fmtetc, &stgmed);
    if (hrErr == NOERROR)
    {
        LPOBJECTDESCRIPTOR pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stgmed.hGlobal);
        if (pOD != NULL)
        {
            XformSizeInHimetricToPixels(NULL, &pOD->sizel, &pOD->sizel);

            width = (int)pOD->sizel.cx;
            height = (int)pOD->sizel.cy;
            m_dwSrcAspect = pOD->dwDrawAspect;
        }

        GlobalUnlock(stgmed.hGlobal);
        ReleaseStgMedium(&stgmed);
    }

    m_ptLast = pt;
    m_fDragFeedbackDrawn = FALSE;
	
    OffsetPoint(&pt, -(width/2), -(height/2));
    SetTopLeft(&m_rcDragRect, &pt);

    OffsetPoint(&pt, width, height);
    SetBottomRight(&m_rcDragRect, &pt);
}


//**********************************************************************
//
// CDropTarget::UndrawDragFeedback
//
// Purpose:
//
//      Erase any drop target feedback.
//      As feedback we draw a rectangle the size of the object.
//
// Parameters:
//
//      none.
//
// Return Value:
//
//      none.
//
// Function Calls:
//      Function                    Location
//
//      GetDC                       WINDOWS API
//      ReleaseDC                   WINDOWS API
//      HighlightRect               IDT.CPP
//
// Comments:
//      In order to know the size of the object before the object
//      is actually dropped, we render CF_OBJECTDESCRIPTOR format.
//      this data format tells us both the size of the object as
//      well as which aspect is the object is displayed as in the
//      source. if the object is currently displayed as DVASPECT_ICON
//      then we want to create the object also as DVASPECT_ICON.
//
//********************************************************************

void CDropTarget::UndrawDragFeedback( void )
{
    if (m_fDragFeedbackDrawn)
    {
        m_fDragFeedbackDrawn = FALSE;
        HDC hDC = GetDC(m_pDoc->m_hDocWnd);
        HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
        ReleaseDC(m_pDoc->m_hDocWnd, hDC);
    }
}


//**********************************************************************
//
// CDropTarget::DrawDragFeedback
//
// Purpose:
//
//      Compute new position of drop target feedback rectangle and
//      erase old rectangle and draw new rectangle.
//      As feedback we draw a rectangle the size of the object.
//
// Parameters:
//
//      POINTL pointl           - position of mouse
//
// Return Value:
//
//      none.
//
// Function Calls:
//      Function                    Location
//
//      OffsetPoint                 IDT.CPP
//      OffsetRect                  IDT.CPP
//      HighlightRect               IDT.CPP
//      GetDC                       WINDOWS API
//      ReleaseDC                   WINDOWS API
//
//
//********************************************************************

void CDropTarget::DrawDragFeedback( POINTL pointl )
{
    POINT ptDiff;

    ptDiff.x = (int)pointl.x - m_ptLast.x;
    ptDiff.y = (int)pointl.y - m_ptLast.y;

    if (m_fDragFeedbackDrawn && (ptDiff.x == 0 && ptDiff.y == 0))
        return;     // mouse did not move; leave rectangle as drawn

    HDC hDC = GetDC(m_pDoc->m_hDocWnd);
    if (m_fDragFeedbackDrawn)
    {
        m_fDragFeedbackDrawn = FALSE;
        HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
    }

    OffsetRect(&m_rcDragRect, ptDiff.x, ptDiff.y);
    HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
    m_fDragFeedbackDrawn = TRUE;
	 m_ptLast.x = (int)pointl.x;
    m_ptLast.y = (int)pointl.y;
	 ReleaseDC(m_pDoc->m_hDocWnd, hDC);
}


//**********************************************************************
//
// CDropTarget::QueryInterface
//
// Purpose:
//
//      Used for interface negotiation
//
// Parameters:
//
//      REFIID riid         -   ID of interface to be returned
//      LPVOID FAR* ppvObj  -   Location to return the interface
//
// Return Value:
//
//      S_OK                -   Interface supported
//      E_NOINTERFACE       -   Interface NOT supported
//
// Function Calls:
//      Function                    Location
//
//      TestDebugOut           Windows API
//      CSimpleDoc::QueryInterface  DOC.CPP
//
//
//********************************************************************

STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
    TestDebugOut("In IDT::QueryInterface\r\n");

    // delegate to the document
    return m_pDoc->QueryInterface(riid, ppvObj);
}


//**********************************************************************
//
// CDropTarget::AddRef
//
// Purpose:
//
//      Increments the reference count of CSimpleDoc. Since CDropTarget is
//      a nested class of CSimpleDoc, we don't need a separate reference
//      count for CDropTarget. We can safely use the reference count of
//      CSimpleDoc.
//
// Parameters:
//
//      None
//
// Return Value:
//
//      The new reference count of CSimpleDoc
//
// Function Calls:
//      Function                    Location
//
//      CSimpleDoc::AddReff         DOC.CPP
//      TestDebugOut           Windows API
//
//
//********************************************************************

STDMETHODIMP_(ULONG) CDropTarget::AddRef()
{
    TestDebugOut("In IDT::AddRef\r\n");

    // delegate to the document Object
    return m_pDoc->AddRef();
}

//**********************************************************************
//
// CDropTarget::Release
//
// Purpose:
//
//      Decrements the reference count of CSimpleDoc. Since CDropTarget is
//      a nested class of CSimpleDoc, we don't need a separate reference
//      count for CDropTarget. We can safely use the reference count of
//      CSimpleDoc.
//
// Parameters:
//
//      None
//
// Return Value:
//
//      The new reference count of CSimpleDoc
//
// Function Calls:
//      Function                    Location
//
//      CSimpleDoc::Release         DOC.CPP
//      TestDebugOut           Windows API
//
//
//********************************************************************

STDMETHODIMP_(ULONG) CDropTarget::Release()
{
    TestDebugOut("In IDT::Release\r\n");

    // delegate to the document object
    return m_pDoc->Release();
}


//**********************************************************************
//
// CDropTarget::DragEnter
//
// Purpose:
//
//      Called when the mouse first enters our DropTarget window
//
// Parameters:
//
//      LPDATAOBJECT pDataObj   - IDataObject from Drop source
//      DWORD grfKeyState       - current key state
//      POINTL pointl           - position of mouse
//      LPDWORD pdwEffect       - (IN-OUT) drag effect that should occur
//                                ON INPUT, this is dwOKEffects that source
//                                passed to DoDragDrop API.
//                                ON OUTPUT, this is the effect that we
//                                want to take effect (used to determine
//                                cursor feedback).
//
// Return Value:
//
//      NOERROR
//
// Function Calls:
//      Function                    Location
//
//      TestDebugOut           Windows API
//      OleQueryCreateFromData      OLE2 API
//      DoDragScroll                IDT.CPP
//      QueryDrop                   IDT.CPP
//      InitDragFeedback            IDT.CPP
//      DrawDragFeedback            IDT.CPP
//
// Comments:
//      Callee should honor the dwEffects as passed in to determine
//      if the caller allows DROPEFFECT_MOVE.
//
//********************************************************************

STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
                                     POINTL pointl, LPDWORD pdwEffect)
{
    TestDebugOut("In IDT::DragEnter\r\n");

    /* Determine if the drag source data object offers a data format
    **  that we understand. we accept only creating embedded objects.
    */
    m_fCanDropCopy = ((OleQueryCreateFromData(pDataObj) == NOERROR) ?
            TRUE : FALSE);
    m_fCanDropLink = FALSE; // linking NOT supported in this simple sample

    if (m_fCanDropCopy || m_fCanDropLink)
        InitDragFeedback(pDataObj, pointl);

    BOOL fDragScroll = DoDragScroll ( pointl );

    if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))
    {
        DrawDragFeedback( pointl );
    }

    // with our drag drop optimization, pDataObj will actually be a
    // wrapper data object.  QueryGetData calls (currently) will be
    // propogated to the drag source (whereas EnumFormatetc is handled
    // locally).  Make sure we can do a QueryGetData.

    FORMATETC formatetc;
    formatetc.cfFormat = CF_METAFILEPICT;
    formatetc.tymed = TYMED_MFPICT;
    formatetc.ptd = NULL;
    formatetc.lindex = -1;
    formatetc.dwAspect = DVASPECT_CONTENT;

    // E_FAIL is usually returned if we could not get the drag source
    // data object.
    if( pDataObj->QueryGetData(&formatetc) == E_FAIL )
    {
	TestDebugOut("WARNING! QueryGetData failed!");
    }

    return NOERROR;
}


//**********************************************************************
//
// CDropTarget::DragOver
//
// Purpose:
//
//      Called when the mouse moves, key state changes, or a time
//      interval passes while the mouse is still within our DropTarget
//      window.
//
// Parameters:
//
//      DWORD grfKeyState       - current key state
//      POINTL pointl           - position of mouse
//      LPDWORD pdwEffect       - (IN-OUT) drag effect that should occur
//                                ON INPUT, this is dwOKEffects that source
//                                passed to DoDragDrop API.
//                                ON OUTPUT, this is the effect that we
//                                want to take effect (used to determine
//                                cursor feedback).
//
// Return Value:
//
//      NOERROR
//
// Function Calls:
//      Function                    Location
//
//      TestDebugOut           Windows API
//      DoDragScroll                IDT.CPP
//      QueryDrop                   IDT.CPP
//      DrawDragFeedback            IDT.CPP
//      UndrawDragFeedback          IDT.CPP
//
// Comments:
//      Callee should honor the dwEffects as passed in to determine
//      if the caller allows DROPEFFECT_MOVE. OLE pulses the DragOver
//      calls in order that the DropTarget can implement drag scrolling
//
//********************************************************************

STDMETHODIMP CDropTarget::DragOver (DWORD grfKeyState, POINTL pointl,
                                    LPDWORD pdwEffect)
{
    TestDebugOut("In IDT::DragOver\r\n");

    BOOL fDragScroll = DoDragScroll ( pointl );

    if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))
    {
        DrawDragFeedback( pointl );
    }
    else
    {
        UndrawDragFeedback();
    }

    return NOERROR;
}


//**********************************************************************
//
// CDropTarget::DragLeave
//
// Purpose:
//
//      Called when the mouse leaves our DropTarget window
//
// Parameters:
//
//      none.
//
// Return Value:
//
//      S_OK
//
// Function Calls:
//      Function                    Location
//
//      TestDebugOut           Windows API
//      UndrawDragFeedback          IDT.CPP
//      ResultFromScode             OLE2 API
//
//
//********************************************************************

STDMETHODIMP CDropTarget::DragLeave ()
{
    TestDebugOut("In IDT::DragLeave\r\n");

    UndrawDragFeedback();

    return ResultFromScode(S_OK);
}


//**********************************************************************
//
// CDropTarget::Drop
//
// Purpose:
//
//      Called when a Drop operation should take place.
//
// Parameters:
//
//      LPDATAOBJECT pDataObj   - IDataObject from Drop source
//      DWORD grfKeyState       - current key state
//      POINTL pointl           - position of mouse
//      LPDWORD pdwEffect       - (IN-OUT) drag effect that should occur
//                                ON INPUT, this is dwOKEffects that source
//                                passed to DoDragDrop API.
//                                ON OUTPUT, this is the effect that we
//                                want to take effect (used to determine
//                                cursor feedback).
//
// Return Value:
//
//      S_OK if sucess or HRESULT of the error code if fails
//
// Function Calls:
//      Function                    Location
//
//      TestDebugOut           Windows API
//      CSimpleSite::Create         SITE.CPP
//      CSimpleSite::InitObject     SITE.CPP
//      OleCreateFromData           OLE2 API
//      DoDragScroll                IDT.CPP
//      QueryDrop                   IDT.CPP
//      InitDragFeedback            IDT.CPP
//      DrawDragFeedback            IDT.CPP
//      UndrawDragFeedback          IDT.CPP
//      GetScode                    OLE2 API
//      ResultFromScode             OLE2 API
//
// Comments:
//      Callee should honor the dwEffects as passed in to determine
//      if the caller allows DROPEFFECT_MOVE.
//
//********************************************************************

STDMETHODIMP CDropTarget::Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState,
                                POINTL pointl, LPDWORD pdwEffect)
{
	 FORMATETC fmtetc;
    SCODE sc = S_OK;
	
    TestDebugOut("In IDT::Drop\r\n");

    UndrawDragFeedback();

    if (pDataObj && QueryDrop(grfKeyState,pointl,FALSE,pdwEffect))
    {
        m_pDoc->m_lpSite = CSimpleSite::Create(m_pDoc);
        if (!m_pDoc->m_lpSite)
        {
           /* memory allocation problem. cannot continue.
            */
           return(ResultFromScode(E_OUTOFMEMORY));
        }

        // keep same aspect as drop source
        m_pDoc->m_lpSite->m_dwDrawAspect = m_dwSrcAspect;

        // in order to specify a particular drawing Aspect we must
        // pass a FORMATETC* to OleCreateFromData
 	     fmtetc.cfFormat = NULL; 			// use whatever for drawing
	     fmtetc.ptd = NULL;
	     fmtetc.lindex = -1;
	     fmtetc.dwAspect = m_dwSrcAspect;	// desired drawing aspect
	     fmtetc.tymed = TYMED_NULL;

        HRESULT hrErr = OleCreateFromData (
                            pDataObj,
                            IID_IOleObject,
                            OLERENDER_DRAW,
                            &fmtetc,
                            &m_pDoc->m_lpSite->m_OleClientSite,
                            m_pDoc->m_lpSite->m_lpObjStorage,
                            (LPVOID FAR *)&m_pDoc->m_lpSite->m_lpOleObject);

        if (hrErr == NOERROR)
        {
            m_pDoc->m_lpSite->InitObject(FALSE /* fCreateNew */);
            m_pDoc->DisableInsertObject();
        }
        else
            sc = GetScode(hrErr);
    }

    return ResultFromScode(sc);
}