Annotation of mstools/ole20/samples/outline/clipbrd.c, revision 1.1.1.1

1.1       root        1: /*************************************************************************
                      2: ** 
                      3: **    OLE 2 Sample Code
                      4: **    
                      5: **    clipbrd.c
                      6: **    
                      7: **    This file contains the major interfaces, methods and related support
                      8: **    functions for implementing clipboard data transfer. The code
                      9: **    contained in this file is used by BOTH the Container and Server
                     10: **    (Object) versions of the Outline sample code.
                     11: **    (see file dragdrop.c for Drag/Drop support implementation)
                     12: **    
                     13: **    OleDoc Object
                     14: **      exposed interfaces:
                     15: **          IDataObject
                     16: **    
                     17: **    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
                     18: **
                     19: *************************************************************************/
                     20: 
                     21: #include "outline.h"
                     22: #include <enumfetc.h>
                     23: #include <geticon.h>
                     24: 
                     25: OLEDBGDATA
                     26: 
                     27: extern LPOUTLINEAPP             g_lpApp;
                     28: 
                     29: // REVIEW: should use string resource for messages
                     30: char ErrMsgPasting[] = "Could not paste data from clipboard!";
                     31: char ErrMsgBadFmt[] = "Invalid format selected!";
                     32: char ErrMsgPasteFailed[] = "Could not paste data from clipboard!";
                     33: 
                     34: 
                     35: 
                     36: /*************************************************************************
                     37: ** OleDoc::IDataObject interface implementation
                     38: *************************************************************************/
                     39: 
                     40: STDMETHODIMP OleDoc_DataObj_QueryInterface (
                     41:         LPDATAOBJECT        lpThis,
                     42:         REFIID              riid,
                     43:         LPVOID FAR*         lplpvObj
                     44: )
                     45: {
                     46:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                     47: 
                     48:     return OleDoc_QueryInterface((LPOLEDOC)lpOleDoc, riid, lplpvObj);
                     49: }
                     50: 
                     51: 
                     52: STDMETHODIMP_(ULONG) OleDoc_DataObj_AddRef(LPDATAOBJECT lpThis)
                     53: {
                     54:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                     55: 
                     56:     OleDbgAddRefMethod(lpThis, "IDataObject");
                     57: 
                     58:     return OleDoc_AddRef((LPOLEDOC)lpOleDoc);
                     59: }
                     60: 
                     61: 
                     62: STDMETHODIMP_(ULONG) OleDoc_DataObj_Release (LPDATAOBJECT lpThis)
                     63: {
                     64:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                     65: 
                     66:     OleDbgReleaseMethod(lpThis, "IDataObject");
                     67: 
                     68:     return OleDoc_Release((LPOLEDOC)lpOleDoc);
                     69: }
                     70: 
                     71: 
                     72: STDMETHODIMP OleDoc_DataObj_GetData (
                     73:         LPDATAOBJECT        lpThis,
                     74:         LPFORMATETC         lpFormatetc,
                     75:         LPSTGMEDIUM         lpMedium
                     76: )
                     77: {
                     78:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                     79:     HRESULT hrErr;
                     80: 
                     81:     OLEDBG_BEGIN2("OleDoc_DataObj_GetData\r\n")
                     82: 
                     83: #if defined( OLE_SERVER )
                     84:     // Call OLE Server specific version of this function
                     85:     hrErr = ServerDoc_GetData((LPSERVERDOC)lpOleDoc, lpFormatetc, lpMedium);
                     86: 
                     87: #elif defined( OLE_CNTR )
                     88:     // Call OLE Container specific version of this function
                     89:     hrErr = ContainerDoc_GetData(
                     90:             (LPCONTAINERDOC)lpOleDoc,
                     91:             lpFormatetc,
                     92:             lpMedium
                     93:     );
                     94: #endif
                     95: 
                     96:     OLEDBG_END2
                     97:     return hrErr;
                     98: }
                     99: 
                    100: 
                    101: STDMETHODIMP OleDoc_DataObj_GetDataHere (
                    102:         LPDATAOBJECT        lpThis,
                    103:         LPFORMATETC         lpFormatetc,
                    104:         LPSTGMEDIUM         lpMedium
                    105: )
                    106: {
                    107:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    108:     HRESULT hrErr;
                    109: 
                    110:     OLEDBG_BEGIN2("OleDoc_DataObj_GetDataHere\r\n")
                    111: 
                    112: #if defined( OLE_SERVER )
                    113:     // Call OLE Server specific version of this function
                    114:     hrErr = ServerDoc_GetDataHere(
                    115:             (LPSERVERDOC)lpOleDoc,
                    116:             lpFormatetc,
                    117:             lpMedium
                    118:     );
                    119: 
                    120: #elif defined( OLE_CNTR )
                    121:     // Call OLE Container specific version of this function
                    122:     hrErr = ContainerDoc_GetDataHere(
                    123:             (LPCONTAINERDOC)lpOleDoc,
                    124:             lpFormatetc,
                    125:             lpMedium
                    126:     );
                    127: #endif
                    128: 
                    129:     OLEDBG_END2
                    130:     return hrErr;
                    131: }
                    132: 
                    133: 
                    134: STDMETHODIMP OleDoc_DataObj_QueryGetData (
                    135:         LPDATAOBJECT        lpThis,
                    136:         LPFORMATETC         lpFormatetc
                    137: )
                    138: {
                    139:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    140:     HRESULT hrErr;
                    141: 
                    142:     OLEDBG_BEGIN2("OleDoc_DataObj_QueryGetData\r\n");
                    143: 
                    144: #if defined( OLE_SERVER )
                    145:     // Call OLE Server specific version of this function
                    146:     hrErr = ServerDoc_QueryGetData((LPSERVERDOC)lpOleDoc, lpFormatetc);
                    147: 
                    148: #elif defined( OLE_CNTR )
                    149:     // Call OLE Container specific version of this function
                    150:     hrErr = ContainerDoc_QueryGetData((LPCONTAINERDOC)lpOleDoc, lpFormatetc);
                    151: #endif
                    152: 
                    153:     OLEDBG_END2
                    154:     return hrErr;
                    155: }
                    156: 
                    157: 
                    158: STDMETHODIMP OleDoc_DataObj_GetCanonicalFormatEtc(
                    159:         LPDATAOBJECT        lpThis,
                    160:         LPFORMATETC         lpformatetc,
                    161:         LPFORMATETC         lpformatetcOut
                    162: )
                    163: {
                    164:     OleDbgOut2("OleDoc_DataObj_GetCanonicalFormatEtc\r\n");
                    165: 
                    166:     return ResultFromScode(E_NOTIMPL);
                    167: }
                    168: 
                    169: 
                    170: STDMETHODIMP OleDoc_DataObj_SetData (
                    171:         LPDATAOBJECT    lpThis,
                    172:         LPFORMATETC     lpFormatetc,
                    173:         LPSTGMEDIUM     lpMedium,
                    174:         BOOL            fRelease
                    175: )
                    176: {
                    177:     LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    178:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    179:     LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                    180:     SCODE sc;
                    181: 
                    182:     OLEDBG_BEGIN2("OleDoc_DataObj_SetData\r\n")
                    183: 
                    184:     /* OLE2NOTE: a document that is used to transfer data (either via
                    185:     **    the clipboard or drag/drop) does NOT accept SetData on ANY
                    186:     **    format!
                    187:     */
                    188:     if (lpOutlineDoc->m_fDataTransferDoc) {
                    189:         sc = E_FAIL;
                    190:         goto error;
                    191:     }
                    192: 
                    193: #if defined( OLE_SERVER )
                    194:     {
                    195:         HRESULT hrErr;
                    196: 
                    197:         if (lpFormatetc->cfFormat == lpOutlineApp->m_cfOutline) {
                    198: 
                    199:             OLEDBG_BEGIN2("ServerDoc_SetData: CF_OUTLINE\r\n");
                    200: 
                    201:             OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
                    202:             OutlineDoc_ClearAllLines(lpOutlineDoc);
                    203:             OutlineDoc_PasteOutlineData(lpOutlineDoc,lpMedium->u.hGlobal,-1);
                    204:             OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
                    205: 
                    206:             OLEDBG_END3
                    207: 
                    208:         } else if (lpFormatetc->cfFormat == CF_TEXT) {
                    209: 
                    210:             OLEDBG_BEGIN2("ServerDoc_SetData: CF_TEXT\r\n");
                    211: 
                    212:             OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
                    213:             OutlineDoc_ClearAllLines(lpOutlineDoc);
                    214:             OutlineDoc_PasteTextData(lpOutlineDoc,lpMedium->u.hGlobal,-1);
                    215:             OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
                    216: 
                    217:             OLEDBG_END3
                    218: 
                    219:         } else {
                    220:             sc = DATA_E_FORMATETC;
                    221:             goto error;
                    222:         }
                    223: 
                    224:         OLEDBG_END2
                    225:         return hrErr;
                    226:     }
                    227: 
                    228: #elif defined( OLE_CNTR )
                    229:     {
                    230:         /* the Container-Only version of Outline does NOT offer
                    231:         **    IDataObject interface from its User documents. this is
                    232:         **    required by objects which can be embedded or linked. the
                    233:         **    Container-only app only allows linking to its contained
                    234:         **    objects, NOT the data of the container itself.
                    235:         */
                    236:         OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
                    237:         sc = E_NOTIMPL;
                    238:         goto error;
                    239:     }
                    240: #endif
                    241: 
                    242: error:
                    243:     OLEDBG_END2
                    244:     return ResultFromScode(sc);
                    245: 
                    246: }
                    247: 
                    248: 
                    249: STDMETHODIMP OleDoc_DataObj_EnumFormatEtc(
                    250:         LPDATAOBJECT            lpThis,
                    251:         DWORD                   dwDirection,
                    252:         LPENUMFORMATETC FAR*    lplpenumFormatEtc
                    253: )
                    254: {
                    255:     LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    256:     HRESULT hrErr;
                    257: 
                    258:     OLEDBG_BEGIN2("OleDoc_DataObj_EnumFormatEtc\r\n")
                    259: 
                    260:     /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
                    261:     *lplpenumFormatEtc = NULL;
                    262: 
                    263: #if defined( OLE_SERVER )
                    264:     /* OLE2NOTE: a user document only needs to enumerate the static list
                    265:     **    of formats that are registered for our app in the
                    266:     **    registration database. OLE provides a default enumerator
                    267:     **    which enumerates from the registration database. this default
                    268:     **    enumerator is requested by returning OLE_S_USEREG. it is NOT
                    269:     **    required that a user document (ie. non-DataTransferDoc)
                    270:     **    enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or
                    271:     **    CF_EMBEDDEDOBJECT. 
                    272:     */
                    273:     if (! ((LPOUTLINEDOC)lpOleDoc)->m_fDataTransferDoc) 
                    274:         return ResultFromScode(OLE_S_USEREG);
                    275: 
                    276:     // Call OLE Server specific version of this function
                    277:     hrErr = ServerDoc_EnumFormatEtc(
                    278:             (LPSERVERDOC)lpOleDoc,
                    279:             dwDirection,
                    280:             lplpenumFormatEtc
                    281:     );
                    282: #elif defined( OLE_CNTR )
                    283:     // Call OLE Container specific version of this function
                    284:     hrErr = ContainerDoc_EnumFormatEtc(
                    285:             (LPCONTAINERDOC)lpOleDoc,
                    286:             dwDirection,
                    287:             lplpenumFormatEtc
                    288:     );
                    289: #endif
                    290: 
                    291:     OLEDBG_END2
                    292:     return hrErr;
                    293: }
                    294: 
                    295: 
                    296: STDMETHODIMP OleDoc_DataObj_DAdvise(
                    297:         LPDATAOBJECT        lpThis,
                    298:         FORMATETC FAR*      lpFormatetc,
                    299:         DWORD               advf,
                    300:         LPADVISESINK        lpAdvSink,
                    301:         DWORD FAR*          lpdwConnection
                    302: )
                    303: {
                    304:     LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    305:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    306:     SCODE sc;
                    307: 
                    308:     OLEDBG_BEGIN2("OleDoc_DataObj_DAdvise\r\n")
                    309: 
                    310:     /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
                    311:     *lpdwConnection = 0;
                    312: 
                    313:     /* OLE2NOTE: a document that is used to transfer data (either via
                    314:     **    the clipboard or drag/drop) does NOT support Advise notifications.
                    315:     */
                    316:     if (lpOutlineDoc->m_fDataTransferDoc) {
                    317:         sc = OLE_E_ADVISENOTSUPPORTED;
                    318:         goto error;
                    319:     }
                    320: 
                    321: #if defined( OLE_SERVER )
                    322:     {
                    323:         HRESULT hrErr;
                    324:         LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
                    325: 
                    326:         if (lpServerDoc->m_lpDataAdviseHldr == NULL &&
                    327:             CreateDataAdviseHolder(&lpServerDoc->m_lpDataAdviseHldr) 
                    328:                                                                 != NOERROR) {
                    329:                 sc = E_OUTOFMEMORY;
                    330:                 goto error;
                    331:         }
                    332: 
                    333:         OLEDBG_BEGIN2("IDataAdviseHolder::Advise called\r\n");
                    334:         hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Advise(
                    335:                 lpServerDoc->m_lpDataAdviseHldr,
                    336:                 (LPDATAOBJECT)&lpOleDoc->m_DataObject,
                    337:                 lpFormatetc,
                    338:                 advf,
                    339:                 lpAdvSink,
                    340:                 lpdwConnection
                    341:         );
                    342:         OLEDBG_END2
                    343: 
                    344:         OLEDBG_END2
                    345:         return hrErr;
                    346:     }
                    347: 
                    348: #elif defined( OLE_CNTR )
                    349:     {
                    350:         /* the Container-Only version of Outline does NOT offer
                    351:         **    IDataObject interface from its User documents. this is
                    352:         **    required by objects which can be embedded or linked. the
                    353:         **    Container-only app only allows linking to its contained
                    354:         **    objects, NOT the data of the container itself.
                    355:         */
                    356:         OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
                    357:         sc = E_NOTIMPL;
                    358:         goto error;
                    359:     }
                    360: #endif
                    361: 
                    362: error:
                    363:     OLEDBG_END2
                    364:     return ResultFromScode(sc);
                    365: }
                    366: 
                    367: 
                    368: STDMETHODIMP OleDoc_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection)
                    369: {
                    370:     LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    371:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    372:     SCODE sc;
                    373: 
                    374:     OLEDBG_BEGIN2("OleDoc_DataObj_DUnadvise\r\n")
                    375: 
                    376:     /* OLE2NOTE: a document that is used to transfer data (either via
                    377:     **    the clipboard or drag/drop) does NOT support Advise notifications.
                    378:     */
                    379:     if (lpOutlineDoc->m_fDataTransferDoc) {
                    380:         sc = OLE_E_ADVISENOTSUPPORTED;
                    381:         goto error;
                    382:     }
                    383: 
                    384: #if defined( OLE_SERVER )
                    385:     {
                    386:         LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
                    387:         HRESULT hrErr;
                    388: 
                    389:         if (lpServerDoc->m_lpDataAdviseHldr == NULL) {
                    390:             sc = E_FAIL;
                    391:             goto error;
                    392:         }
                    393: 
                    394:         OLEDBG_BEGIN2("IDataAdviseHolder::Unadvise called\r\n");
                    395:         hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Unadvise(
                    396:                 lpServerDoc->m_lpDataAdviseHldr,
                    397:                 dwConnection
                    398:         );
                    399:         OLEDBG_END2
                    400: 
                    401:         OLEDBG_END2
                    402:         return hrErr;
                    403:     }
                    404: #elif defined( OLE_CNTR )
                    405:     {
                    406:         /* the Container-Only version of Outline does NOT offer
                    407:         **    IDataObject interface from its User documents. this is
                    408:         **    required by objects which can be embedded or linked. the
                    409:         **    Container-only app only allows linking to its contained
                    410:         **    objects, NOT the data of the container itself.
                    411:         */
                    412:         OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
                    413:         sc = E_NOTIMPL;
                    414:         goto error;
                    415:     }
                    416: #endif
                    417: 
                    418: error:
                    419:     OLEDBG_END2
                    420:     return ResultFromScode(sc);
                    421: }
                    422: 
                    423: 
                    424: STDMETHODIMP OleDoc_DataObj_EnumDAdvise(
                    425:         LPDATAOBJECT        lpThis,
                    426:         LPENUMSTATDATA FAR* lplpenumAdvise
                    427: )
                    428: {
                    429:     LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;
                    430:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    431:     SCODE sc;
                    432: 
                    433:     OLEDBG_BEGIN2("OleDoc_DataObj_EnumDAdvise\r\n")
                    434: 
                    435:     /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
                    436:     *lplpenumAdvise = NULL;
                    437: 
                    438:     /* OLE2NOTE: a document that is used to transfer data (either via
                    439:     **    the clipboard or drag/drop) does NOT support Advise notifications.
                    440:     */
                    441:     if (lpOutlineDoc->m_fDataTransferDoc) {
                    442:         sc = OLE_E_ADVISENOTSUPPORTED;
                    443:         goto error;
                    444:     }
                    445: 
                    446: #if defined( OLE_SERVER )
                    447:     {
                    448:         LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
                    449:         HRESULT hrErr;
                    450: 
                    451:         if (lpServerDoc->m_lpDataAdviseHldr == NULL) {
                    452:             sc = E_FAIL;
                    453:             goto error;
                    454:         }
                    455: 
                    456:         OLEDBG_BEGIN2("IDataAdviseHolder::EnumAdvise called\r\n");
                    457:         hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->EnumAdvise(
                    458:                 lpServerDoc->m_lpDataAdviseHldr,
                    459:                 lplpenumAdvise
                    460:         );
                    461:         OLEDBG_END2
                    462: 
                    463:         OLEDBG_END2
                    464:         return hrErr;
                    465:     }
                    466: #elif defined( OLE_CNTR )
                    467:     {
                    468:         /* the Container-Only version of Outline does NOT offer
                    469:         **    IDataObject interface from its User documents. this is
                    470:         **    required by objects which can be embedded or linked. the
                    471:         **    Container-only app only allows linking to its contained
                    472:         **    objects, NOT the data of the container itself.
                    473:         */
                    474:         OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");
                    475:         sc = E_NOTIMPL;
                    476:         goto error;
                    477:     }
                    478: #endif
                    479: 
                    480: error:
                    481:     OLEDBG_END2
                    482:     return ResultFromScode(sc);
                    483: }
                    484: 
                    485: 
                    486: 
                    487: /*************************************************************************
                    488: ** OleDoc Supprt Functions common to both Container and Server versions
                    489: *************************************************************************/
                    490: 
                    491: /* OleDoc_PasteCommand
                    492: ** -------------------
                    493: **    Paste default format data from the clipboard.
                    494: **    In this function we choose the highest fidelity format that the
                    495: **    source clipboard IDataObject* offers that we understand.
                    496: **
                    497: **    OLE2NOTE: clipboard handling in an OLE 2.0 application is
                    498: **    different than normal Windows clipboard handling. Data from the
                    499: **    clipboard is retieved by getting the IDataObject* pointer
                    500: **    returned by calling OleGetClipboard.
                    501: */
                    502: void OleDoc_PasteCommand(LPOLEDOC lpOleDoc)
                    503: {
                    504:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    505:     LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                    506:     LPDATAOBJECT lpClipboardDataObj = NULL;
                    507:     BOOL fLink = FALSE;
                    508:     BOOL fLocalDataObj = FALSE;
                    509:     BOOL fStatus;
                    510:     HRESULT hrErr;
                    511: 
                    512:     hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);
                    513:     if (hrErr != NOERROR)
                    514:         return;     // Clipboard seems to be empty or can't be accessed
                    515: 
                    516:     OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
                    517: 
                    518:     /* check if the data on the clipboard is local to our application
                    519:     **    instance.
                    520:     */
                    521:     if (lpOutlineApp->m_lpClipboardDoc) {
                    522:         LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
                    523:         if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)
                    524:             fLocalDataObj = TRUE;
                    525:     }
                    526: 
                    527:     fStatus = OleDoc_PasteFromData(
                    528:             lpOleDoc,
                    529:             lpClipboardDataObj,
                    530:             fLocalDataObj,
                    531:             fLink
                    532:     );
                    533: 
                    534:     OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
                    535: 
                    536:     if (! fStatus)
                    537:         OutlineApp_ErrorMessage(g_lpApp,"Could not paste data from clipboard!");
                    538: 
                    539:     if (lpClipboardDataObj)
                    540:         OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
                    541: }
                    542: 
                    543: 
                    544: /* OleDoc_PasteSpecialCommand
                    545: ** --------------------------
                    546: **    Allow the user to paste data in a particular format from the
                    547: **    clipboard. The paste special command displays a dialog to the
                    548: **    user that allows him to choose the format to be pasted from the
                    549: **    list of formats available.
                    550: **
                    551: **    OLE2NOTE: the PasteSpecial dialog is one of the standard OLE 2.0
                    552: **    UI dialogs for which the dialog is implemented and in the OLE2UI
                    553: **    library.
                    554: **
                    555: **    OLE2NOTE: clipboard handling in an OLE 2.0 application is
                    556: **    different than normal Windows clipboard handling. Data from the
                    557: **    clipboard is retieved by getting the IDataObject* pointer
                    558: **    returned by calling OleGetClipboard.
                    559: */
                    560: void OleDoc_PasteSpecialCommand(LPOLEDOC lpOleDoc)
                    561: {
                    562:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    563:     LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                    564:     LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
                    565:     LPDATAOBJECT lpClipboardDataObj = NULL;
                    566:     CLIPFORMAT cfFormat;
                    567:     int nFmtEtc;
                    568:     UINT uInt;
                    569:     BOOL fLink = FALSE;
                    570:     BOOL fLocalDataObj = FALSE;
                    571:     BOOL fStatus;
                    572:     HRESULT hrErr;
                    573:     OLEUIPASTESPECIAL ouiPasteSpl;
                    574:     BOOL fDisplayAsIcon;
                    575: 
                    576:     hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);
                    577:     if (hrErr != NOERROR)
                    578:         return;     // Clipboard seems to be empty or can't be accessed
                    579: 
                    580:     /* check if the data on the clipboard is local to our application
                    581:     **    instance.
                    582:     */
                    583:     if (lpOutlineApp->m_lpClipboardDoc) {
                    584:         LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
                    585:         if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)
                    586:             fLocalDataObj = TRUE;
                    587:     }
                    588: 
                    589:     /* Display the PasteSpecial dialog and allow the user to select the
                    590:     **    format to paste.
                    591:     */
                    592:     ouiPasteSpl.cbStruct = sizeof(OLEUIPASTESPECIAL);       //Structure Size
                    593:     ouiPasteSpl.dwFlags =  PSF_SELECTPASTE | PSF_SHOWHELP;                 //IN-OUT:  Flags
                    594:     ouiPasteSpl.hWndOwner = lpOutlineApp->m_lpDoc->m_hWndDoc;        //Owning window
                    595:     ouiPasteSpl.lpszCaption = "Paste Special";    //Dialog caption bar contents
                    596:     ouiPasteSpl.lpfnHook = NULL;                  //Hook callback
                    597:     ouiPasteSpl.lCustData = 0;                    //Custom data to pass to hook
                    598:     ouiPasteSpl.hInstance = NULL;      //Instance for customized template name
                    599:     ouiPasteSpl.lpszTemplate = NULL;   //Customized template name
                    600:     ouiPasteSpl.hResource = NULL;      //Customized template handle
                    601: 
                    602:     ouiPasteSpl.arrPasteEntries = lpOleApp->m_arrPasteEntries;
                    603:     ouiPasteSpl.cPasteEntries = lpOleApp->m_nPasteEntries;
                    604:     ouiPasteSpl.lpSrcDataObj = lpClipboardDataObj;
                    605:     ouiPasteSpl.arrLinkTypes = lpOleApp->m_arrLinkTypes;
                    606:     ouiPasteSpl.cLinkTypes = lpOleApp->m_nLinkTypes;
                    607: 
                    608: 
                    609:     OLEDBG_BEGIN3("OleUIPasteSpecial called\r\n")
                    610:     uInt = OleUIPasteSpecial(&ouiPasteSpl);
                    611:     OLEDBG_END3
                    612: 
                    613:     fDisplayAsIcon =
                    614:             (ouiPasteSpl.dwFlags & PSF_CHECKDISPLAYASICON ? TRUE : FALSE);
                    615: 
                    616:     if (uInt == OLEUI_OK) {
                    617:         nFmtEtc = ouiPasteSpl.nSelectedIndex;
                    618:         fLink =  ouiPasteSpl.fLink;
                    619: 
                    620:         if (nFmtEtc < 0 || nFmtEtc >= lpOleApp->m_nPasteEntries) {
                    621:             OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgBadFmt);
                    622:             goto error;
                    623:         }
                    624: 
                    625:         OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );
                    626: 
                    627:         cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat;
                    628: 
                    629:         fStatus = OleDoc_PasteFormatFromData(
                    630:                 lpOleDoc,
                    631:                 cfFormat,
                    632:                 lpClipboardDataObj,
                    633:                 fLocalDataObj,
                    634:                 fLink,
                    635:                 fDisplayAsIcon,
                    636:                 ouiPasteSpl.hMetaPict
                    637:         );
                    638: 
                    639:         OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );
                    640: 
                    641:         if (! fStatus) {
                    642:             OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPasteFailed);
                    643:             goto error;
                    644:         }
                    645: 
                    646:         if (ouiPasteSpl.hMetaPict) {
                    647:             // clean up metafile
                    648:             OleUIMetafilePictIconFree(ouiPasteSpl.hMetaPict);
                    649:         }
                    650: 
                    651:     }
                    652: 
                    653:     if (lpClipboardDataObj)
                    654:         OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
                    655: 
                    656:     return;
                    657: 
                    658: error:
                    659: 
                    660:     if (lpClipboardDataObj)
                    661:         OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
                    662: 
                    663:     if (uInt == OLEUI_OK && ouiPasteSpl.hMetaPict)
                    664:         // clean up metafile
                    665:         OleUIMetafilePictIconFree(ouiPasteSpl.hMetaPict);
                    666: }
                    667: 
                    668: 
                    669: /* OleDoc_PasteFromData
                    670: ** --------------------
                    671: **
                    672: **    Paste data from an IDataObject*. The IDataObject* may come from
                    673: **    the clipboard (GetClipboard) or from a drag/drop operation.
                    674: **    In this function we choose the best format that we prefer.
                    675: **
                    676: **    Returns TRUE if data was successfully pasted.
                    677: **            FALSE if data could not be pasted.
                    678: */
                    679: 
                    680: BOOL OleDoc_PasteFromData(
                    681:         LPOLEDOC            lpOleDoc,
                    682:         LPDATAOBJECT        lpSrcDataObj,
                    683:         BOOL                fLocalDataObj,
                    684:         BOOL                fLink
                    685: )
                    686: {
                    687:     LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;
                    688:     CLIPFORMAT      cfFormat;
                    689:     BOOL            fDisplayAsIcon = FALSE;
                    690:     HGLOBAL         hMem = NULL;
                    691:     HGLOBAL         hMetaPict = NULL;
                    692:     STGMEDIUM       medium;
                    693: 
                    694:     if (fLink) {
                    695: #if defined( OLE_SERVER )
                    696: 
                    697:         return FALSE;       // server version of app does NOT support links
                    698: 
                    699: #elif defined( OLE_CNTR )
                    700: 
                    701:         // container version of app only supports OLE object type links
                    702:         cfFormat = lpOleApp->m_cfLinkSource;
                    703: #endif
                    704: 
                    705:     } else {
                    706: 
                    707:         int nFmtEtc;
                    708: 
                    709:         nFmtEtc = OleStdGetPriorityClipboardFormat(
                    710:                 lpSrcDataObj,
                    711:                 lpOleApp->m_arrPasteEntries,
                    712:                 lpOleApp->m_nPasteEntries
                    713:         );
                    714: 
                    715:         if (nFmtEtc < 0)
                    716:             return FALSE;   // there is no format we like
                    717: 
                    718:         cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat;
                    719:     }
                    720: 
                    721:     /* OLE2NOTE: we need to check what dwDrawAspect is being
                    722:     **    transfered. if the data is an object that is displayed as an
                    723:     **    icon in the source, then we want to keep it as an icon. the
                    724:     **    aspect the object is displayed in at the source is transfered
                    725:     **    via the CF_OBJECTDESCRIPTOR format for a Paste operation. 
                    726:     */
                    727:     if (hMem = OleStdGetData(
                    728:             lpSrcDataObj,
                    729:             lpOleApp->m_cfObjectDescriptor,
                    730:             NULL,
                    731:             DVASPECT_CONTENT,
                    732:             (LPSTGMEDIUM)&medium)) {
                    733:         LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem);
                    734:         fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE);
                    735:         GlobalUnlock(hMem);
                    736:         ReleaseStgMedium((LPSTGMEDIUM)&medium);     // equiv to GlobalFree
                    737: 
                    738:         if (fDisplayAsIcon) {
                    739:             hMetaPict = OleStdGetData(
                    740:                     lpSrcDataObj,
                    741:                     CF_METAFILEPICT,
                    742:                     NULL,
                    743:                     DVASPECT_ICON,
                    744:                     (LPSTGMEDIUM)&medium
                    745:             );
                    746:             if (hMetaPict == NULL) 
                    747:                 fDisplayAsIcon = FALSE; // give up; failed to get icon MFP
                    748:         }
                    749:     }
                    750: 
                    751:     return OleDoc_PasteFormatFromData(
                    752:             lpOleDoc,
                    753:             cfFormat,
                    754:             lpSrcDataObj,
                    755:             fLocalDataObj,
                    756:             fLink,
                    757:             fDisplayAsIcon,
                    758:             hMetaPict
                    759:     );
                    760: 
                    761:     if (hMetaPict)
                    762:         ReleaseStgMedium((LPSTGMEDIUM)&medium);  // properly free METAFILEPICT
                    763: }
                    764: 
                    765: 
                    766: /* OleDoc_PasteFormatFromData
                    767: ** --------------------------
                    768: **
                    769: **    Paste a particular data format from a IDataObject*. The
                    770: **    IDataObject* may come from the clipboard (GetClipboard) or from a
                    771: **    drag/drop operation.
                    772: **
                    773: **    Returns TRUE if data was successfully pasted.
                    774: **            FALSE if data could not be pasted.
                    775: */
                    776: 
                    777: BOOL OleDoc_PasteFormatFromData(
                    778:         LPOLEDOC            lpOleDoc,
                    779:         CLIPFORMAT          cfFormat,
                    780:         LPDATAOBJECT        lpSrcDataObj,
                    781:         BOOL                fLocalDataObj,
                    782:         BOOL                fLink,
                    783:         BOOL                fDisplayAsIcon,
                    784:         HGLOBAL             hMetaPict
                    785: )
                    786: {
                    787: #if defined( OLE_SERVER )
                    788: 
                    789:     /* call server specific version of the function. */
                    790:     return ServerDoc_PasteFormatFromData(
                    791:             (LPSERVERDOC)lpOleDoc,
                    792:             cfFormat,
                    793:             lpSrcDataObj,
                    794:             fLocalDataObj,
                    795:             fLink
                    796:     );
                    797: 
                    798: #elif defined( OLE_CNTR )
                    799: 
                    800:     /* call container specific version of the function. */
                    801:     return ContainerDoc_PasteFormatFromData(
                    802:             (LPCONTAINERDOC)lpOleDoc,
                    803:             cfFormat,
                    804:             lpSrcDataObj,
                    805:             fLocalDataObj,
                    806:             fLink,
                    807:             fDisplayAsIcon,
                    808:             hMetaPict
                    809:     );
                    810: 
                    811: #endif
                    812: }
                    813: 
                    814: 
                    815: /* OleDoc_QueryPasteFromData
                    816: ** -------------------------
                    817: **
                    818: **    Check if the IDataObject* offers data in a format that we can
                    819: **    paste. The IDataObject* may come from the clipboard
                    820: **    (GetClipboard) or from a drag/drop operation.
                    821: **
                    822: **    Returns TRUE if paste can be performed
                    823: **            FALSE if paste is not possible.
                    824: */
                    825: 
                    826: BOOL OleDoc_QueryPasteFromData(
                    827:         LPOLEDOC            lpOleDoc,
                    828:         LPDATAOBJECT        lpSrcDataObj,
                    829:         BOOL                fLink
                    830: )
                    831: {
                    832: #if defined( OLE_SERVER )
                    833: 
                    834:     return ServerDoc_QueryPasteFromData(
                    835:             (LPSERVERDOC) lpOleDoc,
                    836:             lpSrcDataObj,
                    837:             fLink
                    838:     );
                    839: 
                    840: #elif defined( OLE_CNTR )
                    841: 
                    842:     return ContainerDoc_QueryPasteFromData(
                    843:             (LPCONTAINERDOC) lpOleDoc,
                    844:             lpSrcDataObj,
                    845:             fLink
                    846:     );
                    847: 
                    848: #endif
                    849: }
                    850: 
                    851: 
                    852: /* OleDoc_GetExtent
                    853:  * ----------------
                    854:  *
                    855:  *      Get the extent (width, height) of the entire document in Himetric.
                    856:  */
                    857: void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel)
                    858: {
                    859:     LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
                    860: 
                    861:     LineList_CalcSelExtentInHimetric(lpLL, NULL, lpsizel);
                    862: }
                    863: 
                    864: 
                    865: /* OleDoc_GetObjectDescriptorData
                    866:  * ------------------------------
                    867:  *
                    868:  * Return a handle to an object's data in CF_OBJECTDESCRIPTOR form
                    869:  *
                    870:  */
                    871: HGLOBAL OleDoc_GetObjectDescriptorData(LPOLEDOC lpOleDoc, LPLINERANGE lplrSel)
                    872: {
                    873:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
                    874:     
                    875:     /* Only our data transfer doc renders CF_OBJECTDESCRIPTOR */
                    876:     OleDbgAssert(lpOutlineDoc->m_fDataTransferDoc);
                    877: 
                    878: #if defined( OLE_SERVER )
                    879:     {
                    880:         LPSERVERDOC   lpServerDoc = (LPSERVERDOC)lpOleDoc;
                    881:         SIZEL         sizel;
                    882:         POINTL        pointl;
                    883:         LPSTR         lpszSrcOfCopy = NULL;
                    884:         IBindCtx  FAR *pbc = NULL;
                    885:         HGLOBAL       hObjDesc;
                    886:         DWORD         dwStatus = 0;
                    887:         LPOUTLINEDOC  lpSrcDocOfCopy=(LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy;
                    888:         LPMONIKER lpSrcMonikerOfCopy = ServerDoc_GetSelFullMoniker(
                    889:                 (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,
                    890:                 &lpServerDoc->m_lrSrcSelOfCopy,
                    891:                 GETMONIKER_TEMPFORUSER
                    892:         );
                    893: 
                    894:         SvrDoc_OleObj_GetMiscStatus(
                    895:                 (LPOLEOBJECT)&lpServerDoc->m_OleObject, 
                    896:                 DVASPECT_CONTENT, 
                    897:                 &dwStatus
                    898:         );
                    899: 
                    900:         OleDoc_GetExtent(lpOleDoc, &sizel);
                    901:         pointl.x = pointl.y = 0;
                    902: 
                    903:         if (lpSrcMonikerOfCopy) {
                    904:             CreateBindCtx(0, (LPBC FAR*)&pbc);
                    905:             lpSrcMonikerOfCopy->lpVtbl->GetDisplayName(
                    906:                 lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);
                    907:             pbc->lpVtbl->Release(pbc);
                    908:             lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy);
                    909:         } else {
                    910:             /* this document has no moniker; use our FullUserTypeName
                    911:             **    as the description of the source of copy.
                    912:             */
                    913:             lpszSrcOfCopy = FULLUSERTYPENAME;
                    914:         }
                    915: 
                    916:         hObjDesc =  OleStdGetObjectDescriptorData(
                    917:                 CLSID_APP,
                    918:                 DVASPECT_CONTENT,
                    919:                 sizel,
                    920:                 pointl,
                    921:                 dwStatus,
                    922:                 FULLUSERTYPENAME,
                    923:                 lpszSrcOfCopy
                    924:         );
                    925: 
                    926:         if (lpSrcMonikerOfCopy && lpszSrcOfCopy)
                    927:             OleStdFreeString(lpszSrcOfCopy, NULL);
                    928:         return hObjDesc;
                    929: 
                    930:     }
                    931: #elif defined( OLE_CNTR )
                    932:     {
                    933:         LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
                    934:         LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
                    935:         LPCONTAINERLINE lpContainerLine;
                    936:         HGLOBAL hObjDesc;
                    937:         BOOL fSelIsOleObject = FALSE;
                    938:         LPOLEOBJECT lpOleObj;
                    939:         SIZEL sizel;
                    940:         POINTL pointl;
                    941: 
                    942:         if ( lpLL->m_nNumLines == 1 ) {
                    943:             fSelIsOleObject = ContainerDoc_IsSelAnOleObject(
                    944:                     lpContainerDoc,
                    945:                     &IID_IOleObject,
                    946:                     (LPUNKNOWN FAR*)&lpOleObj,
                    947:                     NULL,    /* we don't need the line index */
                    948:                     (LPCONTAINERLINE FAR*)&lpContainerLine
                    949:             );
                    950:         }
                    951: 
                    952:         pointl.x = pointl.y = 0;
                    953: 
                    954:         if (fSelIsOleObject) {
                    955:             /* OLE2NOTE: a single OLE object is being transfered via
                    956:             **    this DataTransferDoc. we need to generate the
                    957:             **    CF_ObjectDescrioptor which describes the OLE object.
                    958:             */
                    959: 
                    960:             LPOUTLINEDOC lpSrcOutlineDoc = 
                    961:                     (LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy;
                    962:             LPSTR lpszSrcOfCopy = lpSrcOutlineDoc->m_szFileName;
                    963:             BOOL fFreeSrcOfCopy = FALSE;
                    964: 
                    965:             /* if the object copied can be linked to then get a
                    966:             **    TEMPFORUSER form of the moniker which identifies the
                    967:             **    source of copy. we do not want to force the
                    968:             **    assignment of the moniker until CF_LINKSOURCE is
                    969:             **    rendered. 
                    970:             **    if the object copied can not be a link source then use
                    971:             **    the source filename to identify the source of copy.
                    972:             **    there is no need to generate a moniker for the object
                    973:             **    copied.
                    974:             */
                    975:             if (lpOleDoc->m_fLinkSourceAvail && 
                    976:                     lpContainerDoc->m_lpSrcContainerLine) {
                    977:                 LPBINDCTX pbc = NULL;
                    978:                 LPMONIKER lpSrcMonikerOfCopy = ContainerLine_GetFullMoniker(
                    979:                         lpContainerDoc->m_lpSrcContainerLine,
                    980:                         GETMONIKER_TEMPFORUSER
                    981:                 );
                    982:                 if (lpSrcMonikerOfCopy) {
                    983:                     CreateBindCtx(0, (LPBC FAR*)&pbc);
                    984:                     if (pbc != NULL) {
                    985:                         lpSrcMonikerOfCopy->lpVtbl->GetDisplayName(
                    986:                                 lpSrcMonikerOfCopy, pbc, NULL,&lpszSrcOfCopy);
                    987:                         pbc->lpVtbl->Release(pbc);
                    988:                         fFreeSrcOfCopy = TRUE;
                    989:                     }
                    990:                     lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy);
                    991:                 }
                    992:             }
                    993: 
                    994:             hObjDesc = OleStdGetObjectDescriptorDataFromOleObject(
                    995:                     lpOleObj,
                    996:                     lpszSrcOfCopy,
                    997:                     lpContainerLine->m_dwDrawAspect,
                    998:                     pointl
                    999:             );
                   1000: 
                   1001:             if (fFreeSrcOfCopy && lpszSrcOfCopy) 
                   1002:                 OleStdFreeString(lpszSrcOfCopy, NULL);
                   1003:             OleStdRelease((LPUNKNOWN)lpOleObj);
                   1004:             return hObjDesc;
                   1005:         } else {
                   1006:             /* OLE2NOTE: the data being transfered via this
                   1007:             **    DataTransferDoc is NOT a single OLE object. thus in
                   1008:             **    this case the CF_ObjectDescriptor data should
                   1009:             **    describe our container app itself.
                   1010:             */
                   1011:             OleDoc_GetExtent(lpOleDoc, &sizel);
                   1012:             return OleStdGetObjectDescriptorData(
                   1013:                     CLSID_NULL, /* not used if no object formats */
                   1014:                     DVASPECT_CONTENT,
                   1015:                     sizel,
                   1016:                     pointl,
                   1017:                     0,
                   1018:                     NULL,       /* UserTypeName not used if no obj fmt's */
                   1019:                     FULLUSERTYPENAME   /* string to identify source of copy */
                   1020:             );
                   1021: 
                   1022:         }
                   1023:     }
                   1024: #endif
                   1025: }
                   1026: 
                   1027: 
                   1028: #if defined( OLE_SERVER )
                   1029: 
                   1030: /*************************************************************************
                   1031: ** ServerDoc Supprt Functions Used by Server versions
                   1032: *************************************************************************/
                   1033: 
                   1034: 
                   1035: /* ServerDoc_PasteFormatFromData
                   1036: ** -----------------------------
                   1037: **    
                   1038: **    Paste a particular data format from a IDataObject*. The
                   1039: **    IDataObject* may come from the clipboard (GetClipboard) or from a
                   1040: **    drag/drop operation. 
                   1041: **    
                   1042: **    NOTE: fLink is specified then FALSE if returned because the
                   1043: **    Server only version of the app can not support links.
                   1044: **    
                   1045: **    Returns TRUE if data was successfully pasted.
                   1046: **            FALSE if data could not be pasted.
                   1047: */
                   1048: BOOL ServerDoc_PasteFormatFromData(
                   1049:         LPSERVERDOC             lpServerDoc, 
                   1050:         CLIPFORMAT              cfFormat, 
                   1051:         LPDATAOBJECT            lpSrcDataObj, 
                   1052:         BOOL                    fLocalDataObj, 
                   1053:         BOOL                    fLink
                   1054: )
                   1055: {
                   1056:     LPLINELIST   lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpServerDoc)->m_LineList;
                   1057:     LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                   1058:     LPOLEAPP     lpOleApp = (LPOLEAPP)g_lpApp;
                   1059:     int          nIndex;
                   1060:     int          nCount = 0;
                   1061:     HGLOBAL      hData;
                   1062:     STGMEDIUM    medium;
                   1063:     LINERANGE    lrSel;
                   1064: 
                   1065:     if (LineList_GetCount(lpLL) == 0) 
                   1066:         nIndex = -1;    // pasting to empty list
                   1067:     else  
                   1068:         nIndex=LineList_GetFocusLineIndex(lpLL);
                   1069:     
                   1070:     if (fLink) {
                   1071:         /* We should paste a Link to the data, but we do not support links */
                   1072:         return FALSE;
                   1073: 
                   1074:     } else {
                   1075: 
                   1076:         if (cfFormat == lpOutlineApp->m_cfOutline) {
                   1077: 
                   1078:             hData = OleStdGetData(
                   1079:                     lpSrcDataObj, 
                   1080:                     lpOutlineApp->m_cfOutline, 
                   1081:                     NULL,
                   1082:                                        DVASPECT_CONTENT,
                   1083:                     (LPSTGMEDIUM)&medium
                   1084:             );
                   1085:                        if (hData == NULL) 
                   1086:                                return FALSE;
                   1087: 
                   1088:             nCount = OutlineDoc_PasteOutlineData(
                   1089:                     (LPOUTLINEDOC)lpServerDoc, 
                   1090:                     hData,
                   1091:                     nIndex
                   1092:             );
                   1093:             // OLE2NOTE: we must free data handle by releasing the medium
                   1094:             ReleaseStgMedium((LPSTGMEDIUM)&medium);  
                   1095: 
                   1096:         } else if(cfFormat == CF_TEXT) {
                   1097: 
                   1098:             hData = OleStdGetData(
                   1099:                     lpSrcDataObj, 
                   1100:                     CF_TEXT, 
                   1101:                     NULL,
                   1102:                                        DVASPECT_CONTENT,
                   1103:                     (LPSTGMEDIUM)&medium
                   1104:             );
                   1105:                        if (hData == NULL) 
                   1106:                                return FALSE;
                   1107: 
                   1108:             nCount = OutlineDoc_PasteTextData(
                   1109:                     (LPOUTLINEDOC)lpServerDoc, 
                   1110:                     hData, 
                   1111:                     nIndex
                   1112:             );
                   1113:             // OLE2NOTE: we must free data handle by releasing the medium
                   1114:             ReleaseStgMedium((LPSTGMEDIUM)&medium);  
                   1115:         }
                   1116:     }
                   1117: 
                   1118:     lrSel.m_nEndLine   = nIndex + 1;
                   1119:     lrSel.m_nStartLine = nIndex + nCount;
                   1120:     LineList_SetSel(lpLL, &lrSel);
                   1121:     return TRUE;
                   1122: }
                   1123: 
                   1124: 
                   1125: /* ServerDoc_QueryPasteFromData
                   1126: ** ----------------------------
                   1127: **    
                   1128: **    Check if the IDataObject* offers data in a format that we can
                   1129: **    paste. The IDataObject* may come from the clipboard
                   1130: **    (GetClipboard) or from a drag/drop operation. 
                   1131: **    In this function we look if one of the following formats is
                   1132: **    offered: 
                   1133: **              CF_OUTLINE
                   1134: **              CF_TEXT
                   1135: **    
                   1136: **    NOTE: fLink is specified then FALSE if returned because the
                   1137: **    Server only version of the app can not support links.
                   1138: **    
                   1139: **    Returns TRUE if paste can be performed
                   1140: **            FALSE if paste is not possible.
                   1141: */
                   1142: BOOL ServerDoc_QueryPasteFromData(
                   1143:         LPSERVERDOC             lpServerDoc, 
                   1144:         LPDATAOBJECT            lpSrcDataObj, 
                   1145:         BOOL                    fLink
                   1146: )
                   1147: {
                   1148:     LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
                   1149: 
                   1150:     if (fLink) {
                   1151:         /* we do not support links */
                   1152:         return FALSE;
                   1153: 
                   1154:     } else {
                   1155: 
                   1156:         int nFmtEtc;
                   1157: 
                   1158:         nFmtEtc = OleStdGetPriorityClipboardFormat(
                   1159:                 lpSrcDataObj,
                   1160:                 lpOleApp->m_arrPasteEntries,
                   1161:                 lpOleApp->m_nPasteEntries
                   1162:             );
                   1163:         
                   1164:         if (nFmtEtc < 0) 
                   1165:             return FALSE;   // there is no format we like
                   1166:     }
                   1167: 
                   1168:     return TRUE;
                   1169: }
                   1170: 
                   1171: 
                   1172: /* ServerDoc_GetData
                   1173:  * -----------------
                   1174:  *
                   1175:  * Render data from the document on a CALLEE allocated STGMEDIUM.
                   1176:  *      This routine is called via IDataObject::GetData.
                   1177:  */
                   1178: 
                   1179: HRESULT ServerDoc_GetData (
                   1180:         LPSERVERDOC             lpServerDoc, 
                   1181:         LPFORMATETC             lpformatetc, 
                   1182:         LPSTGMEDIUM             lpMedium
                   1183: )
                   1184: {
                   1185:     LPOLEDOC  lpOleDoc = (LPOLEDOC)lpServerDoc;
                   1186:     LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
                   1187:     LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;
                   1188:     LPOLEAPP  lpOleApp = (LPOLEAPP)lpServerApp;
                   1189:     LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
                   1190:     HRESULT hrErr;
                   1191:     SCODE sc;
                   1192: 
                   1193:     // OLE2NOTE: we must set out pointer parameters to NULL
                   1194:     lpMedium->pUnkForRelease = NULL;
                   1195: 
                   1196:     /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
                   1197:     lpMedium->tymed = TYMED_NULL;
                   1198:     lpMedium->pUnkForRelease = NULL;    // we transfer ownership to caller
                   1199:     lpMedium->u.hGlobal = NULL;
                   1200: 
                   1201:     if(lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {
                   1202:         // Verify caller asked for correct medium
                   1203:         if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
                   1204:             sc = DATA_E_FORMATETC;
                   1205:             goto error;
                   1206:         }
                   1207:         lpMedium->u.hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,NULL);
                   1208:         if (! lpMedium->u.hGlobal) {
                   1209:             sc = E_OUTOFMEMORY;
                   1210:             goto error;
                   1211:         }
                   1212: 
                   1213:         lpMedium->tymed = TYMED_HGLOBAL;
                   1214:         OleDbgOut3("ServerDoc_GetData: rendered CF_OUTLINE\r\n");
                   1215:                return NOERROR;
                   1216: 
                   1217:     } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
                   1218:                (lpformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_DOCPRINT)) ) {
                   1219:         // Verify caller asked for correct medium
                   1220:         if (!(lpformatetc->tymed & TYMED_MFPICT)) {
                   1221:             sc = DATA_E_FORMATETC;
                   1222:             goto error;
                   1223:         }
                   1224: 
                   1225:         lpMedium->u.hGlobal = ServerDoc_GetMetafilePictData(lpServerDoc,NULL);
                   1226:         if (! lpMedium->u.hGlobal) {
                   1227:             sc = E_OUTOFMEMORY;
                   1228:             goto error;
                   1229:         }
                   1230: 
                   1231:         lpMedium->tymed = TYMED_MFPICT;
                   1232:         OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT\r\n");
                   1233:                return NOERROR;
                   1234: 
                   1235:     } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
                   1236:                (lpformatetc->dwAspect & DVASPECT_ICON) ) {
                   1237:                CLSID clsid;
                   1238:         // Verify caller asked for correct medium
                   1239:         if (!(lpformatetc->tymed & TYMED_MFPICT)) {
                   1240:             sc = DATA_E_FORMATETC;
                   1241:             goto error;
                   1242:         }
                   1243: 
                   1244:                /* OLE2NOTE: we should return the default icon for our class.
                   1245:                **    we must be carefull to use the correct CLSID here.
                   1246:                **    if we are currently preforming a "TreatAs (aka. ActivateAs)"
                   1247:                **    operation then we need to use the class of the object
                   1248:                **    written in the storage of the object. otherwise we would
                   1249:                **    use our own class id. 
                   1250:                */
                   1251:                if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) {
                   1252:                        sc = DATA_E_FORMATETC;
                   1253:             goto error;
                   1254:                }                       
                   1255: 
                   1256:         lpMedium->u.hGlobal=GetIconOfClass(g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE);
                   1257:         if (! lpMedium->u.hGlobal) {
                   1258:             sc = E_OUTOFMEMORY;
                   1259:             goto error;
                   1260:         }
                   1261: 
                   1262:         lpMedium->tymed = TYMED_MFPICT;
                   1263:         OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT (icon)\r\n");
                   1264:                return NOERROR;
                   1265: 
                   1266:     } else if (lpformatetc->cfFormat == CF_TEXT) {
                   1267:         // Verify caller asked for correct medium
                   1268:         if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
                   1269:             sc = DATA_E_FORMATETC;
                   1270:             goto error;
                   1271:         }
                   1272: 
                   1273:         lpMedium->u.hGlobal = OutlineDoc_GetTextData (
                   1274:                 (LPOUTLINEDOC)lpServerDoc, 
                   1275:                 NULL
                   1276:         );
                   1277:         if (! lpMedium->u.hGlobal) {
                   1278:             sc = E_OUTOFMEMORY;
                   1279:             goto error;
                   1280:         }
                   1281: 
                   1282:         lpMedium->tymed = TYMED_HGLOBAL;
                   1283:         OleDbgOut3("ServerDoc_GetData: rendered CF_TEXT\r\n");
                   1284:                return NOERROR;
                   1285:     } 
                   1286:        
                   1287:        /* the above are the only formats supports by a user document (ie.
                   1288:        **    a non-data transfer doc). if the document is used for
                   1289:        **    purposes of data transfer, then additional formats are offered.
                   1290:        */
                   1291:        if (! lpOutlineDoc->m_fDataTransferDoc) {
                   1292:         sc = DATA_E_FORMATETC;
                   1293:                goto error;
                   1294:        }
                   1295: 
                   1296:        /* OLE2NOTE: ObjectDescriptor and LinkSrcDescriptor will
                   1297:        **    contain the same data for the pure container and pure server
                   1298:        **    type applications. only a container/server application may
                   1299:        **    have different content for ObjectDescriptor and
                   1300:        **    LinkSrcDescriptor. if a container/server copies a link for
                   1301:        **    example, then the ObjectDescriptor would give the class
                   1302:        **    of the link source but the LinkSrcDescriptor would give the
                   1303:        **    class of the container/server itself. in this situation if a
                   1304:        **    paste operation occurs, an equivalent link is pasted, but if
                   1305:        **    a pastelink operation occurs, then a link to a pseudo object
                   1306:        **    in the container/server is created.
                   1307:        */
                   1308:        if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor || 
                   1309:                (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
                   1310:                        lpOleDoc->m_fLinkSourceAvail)) {
                   1311:         // Verify caller asked for correct medium
                   1312:         if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
                   1313:             sc = DATA_E_FORMATETC;
                   1314:             goto error;
                   1315:         }
                   1316: 
                   1317:         lpMedium->u.hGlobal = OleDoc_GetObjectDescriptorData (
                   1318:                 (LPOLEDOC)lpServerDoc, 
                   1319:                 NULL
                   1320:         );
                   1321:         if (! lpMedium->u.hGlobal) {
                   1322:             sc = E_OUTOFMEMORY;
                   1323:             goto error;
                   1324:         }
                   1325: 
                   1326:         lpMedium->tymed = TYMED_HGLOBAL;
                   1327:         OleDbgOut3("ServerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n");
                   1328:                return NOERROR;
                   1329: 
                   1330:        } else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {
                   1331:         hrErr = OleStdGetOleObjectData(
                   1332:                 (LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage,
                   1333:                 lpformatetc,
                   1334:                 lpMedium,
                   1335:                 FALSE   /* fUseMemory -- (use file-base stg) */
                   1336: 
                   1337:         );
                   1338:         if (hrErr != NOERROR) {
                   1339:             sc = GetScode(hrErr);
                   1340:             goto error;
                   1341:         }
                   1342:         OleDbgOut3("ServerDoc_GetData: rendered CF_EMBEDSOURCE\r\n");
                   1343:                return NOERROR;
                   1344: 
                   1345:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {     
                   1346:         if (lpOleDoc->m_fLinkSourceAvail) {
                   1347:             LPMONIKER lpmk;
                   1348: 
                   1349:             lpmk = ServerDoc_GetSelFullMoniker(
                   1350:                     (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,
                   1351:                     &lpServerDoc->m_lrSrcSelOfCopy,
                   1352:                     GETMONIKER_FORCEASSIGN
                   1353:             );
                   1354:             if (lpmk) {
                   1355:                 hrErr = OleStdGetLinkSourceData(
                   1356:                         lpmk,
                   1357:                         (LPCLSID)&CLSID_APP,
                   1358:                         lpformatetc,
                   1359:                         lpMedium
                   1360:                 );
                   1361:                 OleStdRelease((LPUNKNOWN)lpmk);
                   1362:                 if (hrErr != NOERROR) {
                   1363:                     sc = GetScode(hrErr);
                   1364:                     goto error;
                   1365:                 }
                   1366:                 OleDbgOut3("ServerDoc_GetData: rendered CF_LINKSOURCE\r\n");
                   1367:                                return NOERROR;
                   1368: 
                   1369:             } else {
                   1370:                 sc = E_FAIL;
                   1371:                 goto error;
                   1372:             }
                   1373:         } else {
                   1374:             sc = DATA_E_FORMATETC;
                   1375:             goto error;
                   1376:         }
                   1377: 
                   1378:     } else {
                   1379:         sc = DATA_E_FORMATETC;
                   1380:                goto error;
                   1381:     }
                   1382: 
                   1383:     return NOERROR;
                   1384: 
                   1385: error:
                   1386:     return ResultFromScode(sc);
                   1387: }
                   1388: 
                   1389: 
                   1390: /* ServerDoc_GetDataHere
                   1391:  * ---------------------
                   1392:  *
                   1393:  * Render data from the document on a CALLER allocated STGMEDIUM.
                   1394:  *      This routine is called via IDataObject::GetDataHere.
                   1395:  */
                   1396: HRESULT ServerDoc_GetDataHere (
                   1397:         LPSERVERDOC             lpServerDoc, 
                   1398:         LPFORMATETC             lpformatetc, 
                   1399:         LPSTGMEDIUM             lpMedium
                   1400: )
                   1401: {
                   1402:     LPOLEDOC        lpOleDoc = (LPOLEDOC)lpServerDoc;
                   1403:     LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
                   1404:     LPSERVERAPP     lpServerApp = (LPSERVERAPP)g_lpApp;
                   1405:     LPOLEAPP        lpOleApp = (LPOLEAPP)lpServerApp;
                   1406:     LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
                   1407:     HRESULT         hrErr;
                   1408:     SCODE           sc;
                   1409: 
                   1410:     // OLE2NOTE: we must set out pointer parameters to NULL
                   1411:     lpMedium->pUnkForRelease = NULL;
                   1412:        
                   1413:        /* our user document does not support any formats for GetDataHere.
                   1414:        **    if the document is used for
                   1415:        **    purposes of data transfer, then additional formats are offered.
                   1416:        */
                   1417:        if (! lpOutlineDoc->m_fDataTransferDoc) {
                   1418:         sc = DATA_E_FORMATETC;
                   1419:                goto error;
                   1420:        }
                   1421: 
                   1422:     if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {
                   1423:         hrErr = OleStdGetOleObjectData(
                   1424:                 (LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage,
                   1425:                 lpformatetc,
                   1426:                 lpMedium,
                   1427:                 FALSE   /* fUseMemory -- (use file-base stg) */
                   1428:         );
                   1429:         if (hrErr != NOERROR) {
                   1430:             sc = GetScode(hrErr);
                   1431:             goto error;
                   1432:         }
                   1433:         OleDbgOut3("ServerDoc_GetDataHere: rendered CF_EMBEDSOURCE\r\n");
                   1434:                return NOERROR;
                   1435: 
                   1436:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {     
                   1437:         if (lpOleDoc->m_fLinkSourceAvail) {
                   1438:             LPMONIKER lpmk;
                   1439: 
                   1440:             lpmk = ServerDoc_GetSelFullMoniker(
                   1441:                     (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,
                   1442:                     &lpServerDoc->m_lrSrcSelOfCopy,
                   1443:                     GETMONIKER_FORCEASSIGN
                   1444:             );
                   1445:             if (lpmk) {
                   1446:                 hrErr = OleStdGetLinkSourceData(
                   1447:                         lpmk,
                   1448:                         (LPCLSID)&CLSID_APP,
                   1449:                         lpformatetc,
                   1450:                         lpMedium
                   1451:                 );
                   1452:                 OleStdRelease((LPUNKNOWN)lpmk);
                   1453:                 if (hrErr != NOERROR) {
                   1454:                     sc = GetScode(hrErr);
                   1455:                     goto error;
                   1456:                 }
                   1457: 
                   1458:                 OleDbgOut3(
                   1459:                         "ServerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n");
                   1460:                                return NOERROR;
                   1461: 
                   1462:             } else {
                   1463:                 sc = E_FAIL;
                   1464:                 goto error;
                   1465:             }
                   1466:         } else {
                   1467:             sc = DATA_E_FORMATETC;
                   1468:             goto error;
                   1469:         }
                   1470:     } else {
                   1471: 
                   1472:         /* Caller is requesting data to be returned in Caller allocated
                   1473:         **    medium, but we do NOT support this. we only support
                   1474:         **    global memory blocks that WE allocate for the caller.
                   1475:         */
                   1476:         sc = DATA_E_FORMATETC;
                   1477:         goto error;
                   1478:     }
                   1479: 
                   1480:     return NOERROR;
                   1481: 
                   1482: error:
                   1483:     return ResultFromScode(sc);
                   1484: }
                   1485: 
                   1486: 
                   1487: /* ServerDoc_QueryGetData
                   1488:  * ----------------------
                   1489:  *
                   1490:  * Answer if a particular data format is supported via GetData/GetDataHere.
                   1491:  *      This routine is called via IDataObject::QueryGetData.
                   1492:  */
                   1493: 
                   1494: HRESULT ServerDoc_QueryGetData (LPSERVERDOC lpServerDoc,LPFORMATETC lpformatetc)
                   1495: {
                   1496:     LPOLEDOC        lpOleDoc = (LPOLEDOC)lpServerDoc;
                   1497:     LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
                   1498:     LPSERVERAPP     lpServerApp = (LPSERVERAPP)g_lpApp;
                   1499:     LPOLEAPP        lpOleApp = (LPOLEAPP)lpServerApp;
                   1500:     LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)lpServerApp;
                   1501: 
                   1502:     /* Caller is querying if we support certain format but does not
                   1503:     **    want any data actually returned.
                   1504:     */
                   1505:     if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline ||
                   1506:             lpformatetc->cfFormat == CF_TEXT) {
                   1507:         // we only support HGLOBAL
                   1508:         return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL);
                   1509:        } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
                   1510:                (lpformatetc->dwAspect & 
                   1511:                        (DVASPECT_CONTENT | DVASPECT_CONTENT | DVASPECT_DOCPRINT)) ) {
                   1512:         return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT);
                   1513:     }
                   1514:        
                   1515:        /* the above are the only formats supports by a user document (ie.
                   1516:        **    a non-data transfer doc). if the document is used for
                   1517:        **    purposes of data transfer, then additional formats are offered.
                   1518:        */
                   1519:        if (! lpOutlineDoc->m_fDataTransferDoc) 
                   1520:                return ResultFromScode(DATA_E_FORMATETC);
                   1521:                
                   1522:     if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {
                   1523:         return OleStdQueryOleObjectData(lpformatetc);
                   1524: 
                   1525:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource &&
                   1526:         lpOleDoc->m_fLinkSourceAvail) {
                   1527:         return OleStdQueryLinkSourceData(lpformatetc);
                   1528: 
                   1529:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor) {
                   1530:         return OleStdQueryObjectDescriptorData(lpformatetc);
                   1531: 
                   1532:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
                   1533:                        lpOleDoc->m_fLinkSourceAvail) {
                   1534:         return OleStdQueryObjectDescriptorData(lpformatetc);
                   1535:     }
                   1536: 
                   1537:     return ResultFromScode(DATA_E_FORMATETC);
                   1538: }
                   1539: 
                   1540: 
                   1541: /* ServerDoc_EnumFormatEtc
                   1542:  * -----------------------
                   1543:  *
                   1544:  * Return an enumerator which enumerates the data accepted/offered by 
                   1545:  *      the document. 
                   1546:  *      This routine is called via IDataObject::EnumFormatEtc.
                   1547:  */
                   1548: HRESULT ServerDoc_EnumFormatEtc(
                   1549:         LPSERVERDOC             lpServerDoc, 
                   1550:         DWORD                   dwDirection, 
                   1551:         LPENUMFORMATETC FAR*    lplpenumFormatEtc
                   1552: )
                   1553: {
                   1554:     LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
                   1555:     LPOLEAPP  lpOleApp = (LPOLEAPP)g_lpApp;
                   1556:     int nActualFmts;
                   1557:     SCODE sc = S_OK;
                   1558: 
                   1559:     /* OLE2NOTE: the enumeration of formats for a data transfer
                   1560:     **    document is not a static list. the list of formats offered
                   1561:     **    may or may not include CF_LINKSOURCE depending on whether a
                   1562:     **    moniker is available for our document. thus we can NOT use
                   1563:     **    the default OLE enumerator which enumerates the formats that
                   1564:     **    are registered for our app in the registration database.
                   1565:     */
                   1566:     if (dwDirection == DATADIR_GET) {
                   1567:         nActualFmts = lpOleApp->m_nDocGetFmts;
                   1568:         
                   1569:         /* If the document does not have a Moniker, then exclude
                   1570:         **    CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR from the list of
                   1571:                **    formats available. these formats are deliberately listed
                   1572:                **    last in the array of possible "Get" formats.
                   1573:         */
                   1574:         if (! lpOleDoc->m_fLinkSourceAvail)
                   1575:             nActualFmts -= 2;
                   1576: 
                   1577:         *lplpenumFormatEtc = OleStdEnumFmtEtc_Create(
                   1578:                 nActualFmts, lpOleApp->m_arrDocGetFmts);
                   1579:         if (*lplpenumFormatEtc == NULL)
                   1580:             sc = E_OUTOFMEMORY;
                   1581: 
                   1582:     } else if (dwDirection == DATADIR_SET) {
                   1583:         /* OLE2NOTE: a document that is used to transfer data
                   1584:         **    (either via the clipboard or drag/drop does NOT
                   1585:         **    accept SetData on ANY format! 
                   1586:         */
                   1587:         sc = E_NOTIMPL;
                   1588:         goto error;
                   1589:     } else {
                   1590:         sc = E_INVALIDARG;
                   1591:         goto error;
                   1592:     }
                   1593:     
                   1594: error:
                   1595:     return ResultFromScode(sc);
                   1596: }
                   1597: 
                   1598: 
                   1599: /* ServerDoc_GetMetafilePictData
                   1600:  * -----------------------------
                   1601:  *
                   1602:  * Return a handle to an object's picture data in metafile format.
                   1603:  *
                   1604:  * 
                   1605:  * RETURNS: A handle to the object's data in metafile format.
                   1606:  *
                   1607:  */
                   1608: HGLOBAL ServerDoc_GetMetafilePictData(
                   1609:         LPSERVERDOC         lpServerDoc, 
                   1610:         LPLINERANGE         lplrSel
                   1611: )
                   1612: {
                   1613:     LPOUTLINEAPP       lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                   1614:     LPOUTLINEDOC    lpOutlineDoc=(LPOUTLINEDOC)lpServerDoc;
                   1615:     LPLINELIST      lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;
                   1616:     LPLINE          lpLine;
                   1617:     LPMETAFILEPICT  lppict = NULL;
                   1618:     HGLOBAL         hMFPict = NULL;
                   1619:     HMETAFILE       hMF = NULL;
                   1620:     RECT            rect;
                   1621:     HDC             hDC;
                   1622:     int             i;
                   1623:     int             nWidth;
                   1624:     int     nStart = (lplrSel ? lplrSel->m_nStartLine : 0);
                   1625:     int     nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1);
                   1626:     int     nLines = nEnd - nStart + 1;
                   1627:        UINT    fuAlign;
                   1628:     POINT point;
                   1629:     SIZE  size;
                   1630:      
                   1631:     hDC = CreateMetaFile(NULL);
                   1632: 
                   1633:     rect.left = 0;
                   1634:     rect.right = 0;
                   1635:     rect.bottom = 0;
                   1636: 
                   1637:        if (nLines > 0) {
                   1638:        // calculate the total height/width of LineList in HIMETRIC
                   1639:                for(i = nStart; i <= nEnd; i++) {
                   1640:                        lpLine = LineList_GetLine(lpLL,i);
                   1641:                        nWidth = Line_GetTotalWidthInHimetric(lpLine);
                   1642:                        rect.right = max(rect.right, nWidth);
                   1643:                        rect.bottom -= Line_GetHeightInHimetric(lpLine);
                   1644:                }
                   1645: 
                   1646: 
                   1647:                SetMapMode(hDC, MM_ANISOTROPIC);
                   1648: 
                   1649:                SetWindowOrgEx(hDC, 0, 0, &point);
                   1650:                SetWindowExtEx(hDC, rect.right, rect.bottom, &size);
                   1651: 
                   1652:                // Set the default font size, and font face name
                   1653:                SelectObject(hDC, OutlineApp_GetActiveFont(lpOutlineApp));
                   1654: 
                   1655:                FillRect(hDC, (LPRECT) &rect, GetStockObject(WHITE_BRUSH));
                   1656: 
                   1657:                rect.bottom = 0;
                   1658:                
                   1659:                fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);
                   1660:                
                   1661:                /* While more lines print out the text */
                   1662:                for(i = nStart; i <= nEnd; i++) {
                   1663:                        lpLine = LineList_GetLine(lpLL,i);
                   1664: 
                   1665:                        rect.top = rect.bottom;
                   1666:                        rect.bottom -= Line_GetHeightInHimetric(lpLine);
                   1667: 
                   1668:                        /* Draw the line */
                   1669:                        Line_Draw(lpLine, hDC, &rect);
                   1670:                }
                   1671:                
                   1672:                SetTextAlign(hDC, fuAlign);
                   1673:        }
                   1674:     
                   1675:     // Get handle to the metafile.
                   1676:     if (!(hMF = CloseMetaFile (hDC)))
                   1677:         return NULL;
                   1678: 
                   1679:     if (!(hMFPict = GlobalAlloc (GMEM_SHARE | GMEM_ZEROINIT, 
                   1680:                     sizeof (METAFILEPICT)))) {
                   1681:         DeleteMetaFile (hMF);
                   1682:         return NULL;
                   1683:     }
                   1684: 
                   1685:     if (!(lppict = (LPMETAFILEPICT)GlobalLock(hMFPict))) {
                   1686:         DeleteMetaFile (hMF);
                   1687:         GlobalFree (hMFPict);
                   1688:         return NULL;
                   1689:     }
                   1690: 
                   1691:     lppict->mm   =  MM_ANISOTROPIC;
                   1692:     lppict->hMF  =  hMF;
                   1693:     lppict->xExt =  rect.right;
                   1694:     lppict->yExt =  - rect.bottom;  // add minus sign to make it +ve
                   1695:     GlobalUnlock (hMFPict);
                   1696:     
                   1697:     return hMFPict;
                   1698: }
                   1699: 
                   1700: #endif  // OLE_SERVER
                   1701: 
                   1702: 
                   1703: 
                   1704: #if defined( OLE_CNTR )
                   1705: 
                   1706: /*************************************************************************
                   1707: ** ContainerDoc Supprt Functions Used by Container versions
                   1708: *************************************************************************/
                   1709: 
                   1710: 
                   1711: /* Paste OLE Link from clipboard */
                   1712: void ContainerDoc_PasteLinkCommand(LPCONTAINERDOC lpContainerDoc)
                   1713: {
                   1714:     LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                   1715:     LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;
                   1716:     LPDATAOBJECT    lpClipboardDataObj = NULL;
                   1717:     BOOL            fLink = TRUE;
                   1718:     BOOL            fLocalDataObj = FALSE;
                   1719:     BOOL            fDisplayAsIcon = FALSE;
                   1720:     HCURSOR         hPrevCursor;
                   1721:     HGLOBAL         hMem = NULL;
                   1722:     HGLOBAL         hMetaPict = NULL;
                   1723:     STGMEDIUM       medium;
                   1724:     BOOL            fStatus;
                   1725:     HRESULT         hrErr;
                   1726: 
                   1727:     hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);
                   1728:     if (hrErr != NOERROR)
                   1729:         return;     // Clipboard seems to be empty or can't be accessed
                   1730: 
                   1731:     // this may take a while, put up hourglass cursor
                   1732:     hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
                   1733: 
                   1734:     /* check if the data on the clipboard is local to our application
                   1735:     **    instance.
                   1736:     */
                   1737:     if (lpOutlineApp->m_lpClipboardDoc) {
                   1738:         LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
                   1739:         if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)
                   1740:             fLocalDataObj = TRUE;
                   1741:     }
                   1742: 
                   1743:     /* OLE2NOTE: we need to check what dwDrawAspect is being
                   1744:     **    transfered. if the data is an object that is displayed as an
                   1745:     **    icon in the source, then we want to keep it as an icon. the
                   1746:     **    aspect the object is displayed in at the source is transfered
                   1747:     **    via the CF_LINKSOURCEDESCRIPTOR format for a PasteLink
                   1748:     **    operation. 
                   1749:     */
                   1750:     if (hMem = OleStdGetData(
                   1751:             lpClipboardDataObj,
                   1752:             lpOleApp->m_cfLinkSrcDescriptor,
                   1753:             NULL,
                   1754:             DVASPECT_CONTENT,
                   1755:             (LPSTGMEDIUM)&medium)) {
                   1756:         LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem);
                   1757:         fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE);
                   1758:         GlobalUnlock(hMem);
                   1759:         ReleaseStgMedium((LPSTGMEDIUM)&medium);     // equiv to GlobalFree
                   1760: 
                   1761:         if (fDisplayAsIcon) {
                   1762:             hMetaPict = OleStdGetData(
                   1763:                     lpClipboardDataObj,
                   1764:                     CF_METAFILEPICT,
                   1765:                     NULL,
                   1766:                     DVASPECT_ICON,
                   1767:                     (LPSTGMEDIUM)&medium
                   1768:             );
                   1769:             if (hMetaPict == NULL) 
                   1770:                 fDisplayAsIcon = FALSE; // give up; failed to get icon MFP
                   1771:         }
                   1772:     }
                   1773: 
                   1774:     fStatus = ContainerDoc_PasteFormatFromData(
                   1775:             lpContainerDoc,
                   1776:             lpOleApp->m_cfLinkSource,
                   1777:             lpClipboardDataObj,
                   1778:             fLocalDataObj,
                   1779:             fLink,
                   1780:             fDisplayAsIcon,
                   1781:             hMetaPict
                   1782:     );
                   1783: 
                   1784:     if (!fStatus)
                   1785:         OutlineApp_ErrorMessage(g_lpApp, ErrMsgPasting);
                   1786: 
                   1787:     if (hMetaPict)
                   1788:         ReleaseStgMedium((LPSTGMEDIUM)&medium);  // properly free METAFILEPICT
                   1789: 
                   1790:     if (lpClipboardDataObj)
                   1791:         OleStdRelease((LPUNKNOWN)lpClipboardDataObj);
                   1792: 
                   1793:     SetCursor(hPrevCursor);     // restore original cursor
                   1794: }
                   1795: 
                   1796: 
                   1797: /* ContainerDoc_PasteFormatFromData
                   1798: ** --------------------------------
                   1799: **
                   1800: **    Paste a particular data format from a IDataObject*. The
                   1801: **    IDataObject* may come from the clipboard (GetClipboard) or from a
                   1802: **    drag/drop operation.
                   1803: **
                   1804: **    Returns TRUE if data was successfully pasted.
                   1805: **            FALSE if data could not be pasted.
                   1806: */
                   1807: BOOL ContainerDoc_PasteFormatFromData(
                   1808:         LPCONTAINERDOC          lpContainerDoc,
                   1809:         CLIPFORMAT              cfFormat,
                   1810:         LPDATAOBJECT            lpSrcDataObj,
                   1811:         BOOL                    fLocalDataObj,
                   1812:         BOOL                    fLink,
                   1813:         BOOL                    fDisplayAsIcon,
                   1814:         HGLOBAL                 hMetaPict
                   1815: )
                   1816: {
                   1817:     LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
                   1818:     LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                   1819:     LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;
                   1820:     LPCONTAINERAPP  lpContainerApp = (LPCONTAINERAPP)g_lpApp;
                   1821:     int             nIndex;
                   1822:     int             nCount = 0;
                   1823:     HGLOBAL         hData;
                   1824:     STGMEDIUM       medium;
                   1825:     FORMATETC       formatetc;
                   1826:     HRESULT         hrErr;
                   1827:     LINERANGE       lrSel;
                   1828: 
                   1829:     if (LineList_GetCount(lpLL) == 0)
                   1830:         nIndex = -1;    // pasting to empty list
                   1831:     else
                   1832:         nIndex=LineList_GetFocusLineIndex(lpLL);
                   1833: 
                   1834:     if (fLink) {
                   1835: 
                   1836:         /* We should paste a Link to the data */
                   1837: 
                   1838:         if (cfFormat != lpOleApp->m_cfLinkSource)
                   1839:             return FALSE;   // we only support OLE object type links
                   1840: 
                   1841:         nCount = ContainerDoc_PasteOleObject(
                   1842:                 lpContainerDoc,
                   1843:                 lpSrcDataObj,
                   1844:                 OLECREATEFROMDATA_LINK,
                   1845:                 cfFormat,
                   1846:                 nIndex,
                   1847:                 fDisplayAsIcon,
                   1848:                 hMetaPict
                   1849:             );
                   1850:         return (nCount > 0 ? TRUE : FALSE);
                   1851: 
                   1852:     } else {
                   1853: 
                   1854:         if (cfFormat == lpContainerApp->m_cfCntrOutl) {
                   1855:             if (fLocalDataObj) {
                   1856: 
                   1857:                 /* CASE I: IDataObject* is local to our app
                   1858:                 **
                   1859:                 **    if the source of the data is local to our
                   1860:                 **    application instance, then we can get direct
                   1861:                 **    access to the original OleDoc object that
                   1862:                 **    corresponds to the IDataObject* given.
                   1863:                 **    CF_CNTROUTL data is passed through a LPSTORAGE.
                   1864:                 **    if we call OleGetData asking for CF_CNTROUTL, we
                   1865:                 **    will be returned a copy of the existing open pStg
                   1866:                 **    of the original source document. we can NOT open
                   1867:                 **    streams and sub-storages again via this pStg
                   1868:                 **    since it is already open within our same
                   1869:                 **    application instance. we must copy the data from
                   1870:                 **    the original OleDoc source document.
                   1871:                 */
                   1872:                 LPLINELIST lpSrcLL;
                   1873:                 LPOLEDOC lpLocalSrcDoc =
                   1874:                     ((struct CDocDataObjectImpl FAR*)lpSrcDataObj)->lpOleDoc;
                   1875: 
                   1876:                 /* copy all lines from SrcDoc to DestDoc. */
                   1877:                 lpSrcLL = &((LPOUTLINEDOC)lpLocalSrcDoc)->m_LineList;
                   1878:                 nCount = LineList_CopySelToDoc(
                   1879:                         lpSrcLL,
                   1880:                         NULL,
                   1881:                         (LPOUTLINEDOC)lpContainerDoc
                   1882:                 );
                   1883: 
                   1884:             } else {
                   1885: 
                   1886:                 /* CASE II: IDataObject* is NOT local to our app
                   1887:                 **
                   1888:                 **    if the source of the data comes from another
                   1889:                 **    application instance. we can call GetDataHere to
                   1890:                 **    retrieve the CF_CNTROUTL data. CF_CNTROUTL data
                   1891:                 **    is passed through a LPSTORAGE. we MUST use
                   1892:                 **    IDataObject::GetDataHere. calling
                   1893:                 **    IDataObject::GetData does NOT work because OLE
                   1894:                 **    currently does NOT support remoting of a callee
                   1895:                 **    allocated root storage back to the caller. this
                   1896:                 **    hopefully will be supported in a future version.
                   1897:                 **    in order to call GetDataHere we must allocate an
                   1898:                 **    IStorage instance for the callee to write into.
                   1899:                 **    we will allocate an IStorage docfile that will
                   1900:                 **    delete-on-release. we could use either a
                   1901:                 **    memory-based storage or a file-based storage.
                   1902:                 */
                   1903:                 LPSTORAGE lpTmpStg = OleStdCreateTempStorage(
                   1904:                         FALSE /*fUseMemory*/, 
                   1905:                         STGM_READWRITE | STGM_TRANSACTED |STGM_SHARE_EXCLUSIVE
                   1906:                 );
                   1907:                 if (! lpTmpStg) 
                   1908:                     return FALSE;
                   1909: 
                   1910:                 formatetc.cfFormat = cfFormat;
                   1911:                 formatetc.ptd = NULL;
                   1912:                 formatetc.dwAspect = DVASPECT_CONTENT;
                   1913:                 formatetc.tymed = TYMED_ISTORAGE;
                   1914:                 formatetc.lindex = -1;
                   1915:                 
                   1916:                 medium.tymed = TYMED_ISTORAGE;
                   1917:                 medium.u.pstg = lpTmpStg;
                   1918:                 medium.pUnkForRelease = NULL;
                   1919: 
                   1920:                 OLEDBG_BEGIN2("IDataObject::GetDataHere called\r\n")
                   1921:                 hrErr = lpSrcDataObj->lpVtbl->GetDataHere(
                   1922:                         lpSrcDataObj,
                   1923:                         (LPFORMATETC)&formatetc,
                   1924:                         (LPSTGMEDIUM)&medium
                   1925:                 );
                   1926:                 OLEDBG_END2
                   1927: 
                   1928:                 if (hrErr == NOERROR) {
                   1929:                     nCount = ContainerDoc_PasteCntrOutlData(
                   1930:                             lpContainerDoc,
                   1931:                             lpTmpStg,
                   1932:                             nIndex
                   1933:                     );
                   1934:                 }
                   1935:                 OleStdVerifyRelease(
                   1936:                     (LPUNKNOWN)lpTmpStg, "Temp stg NOT released!\r\n");
                   1937:                 return ((hrErr == NOERROR) ? TRUE : FALSE);
                   1938:             }
                   1939: 
                   1940:         } else if (cfFormat == lpOutlineApp->m_cfOutline) {
                   1941: 
                   1942:             hData = OleStdGetData(
                   1943:                     lpSrcDataObj,
                   1944:                     lpOutlineApp->m_cfOutline,
                   1945:                     NULL,
                   1946:                     DVASPECT_CONTENT,
                   1947:                     (LPSTGMEDIUM)&medium
                   1948:             );
                   1949:             nCount = OutlineDoc_PasteOutlineData(
                   1950:                     (LPOUTLINEDOC)lpContainerDoc,
                   1951:                     hData,
                   1952:                     nIndex
                   1953:                 );
                   1954:             // OLE2NOTE: we must free data handle by releasing the medium
                   1955:             ReleaseStgMedium((LPSTGMEDIUM)&medium);
                   1956: 
                   1957:         } else if (cfFormat == lpOleApp->m_cfEmbedSource ||
                   1958:             cfFormat == lpOleApp->m_cfEmbeddedObject ||
                   1959:             cfFormat == lpOleApp->m_cfFileName) {
                   1960:             /* OLE2NOTE: OleCreateFromData API creates an OLE object if
                   1961:             **    CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are
                   1962:             **    available from the source data object. the
                   1963:             **    CF_FILENAME case arises when a file is copied to the
                   1964:             **    clipboard from the FileManager. if the file has an
                   1965:             **    associated class (see GetClassFile API), then an
                   1966:             **    object of that class is created. otherwise an OLE 1.0
                   1967:             **    Packaged object is created.
                   1968:             */
                   1969:             nCount = ContainerDoc_PasteOleObject(
                   1970:                     lpContainerDoc,
                   1971:                     lpSrcDataObj,
                   1972:                     OLECREATEFROMDATA_OBJECT,
                   1973:                     0,   /* N/A -- cfFormat */
                   1974:                     nIndex,
                   1975:                     fDisplayAsIcon,
                   1976:                     hMetaPict
                   1977:             );
                   1978:             return (nCount > 0 ? TRUE : FALSE);
                   1979: 
                   1980:         } else if (cfFormat == CF_METAFILEPICT 
                   1981:                     || cfFormat == CF_DIB
                   1982:                     || cfFormat == CF_BITMAP) {
                   1983: 
                   1984:             /* OLE2NOTE: OleCreateStaticFromData API creates an static
                   1985:             **    OLE object if CF_METAFILEPICT, CF_DIB, or CF_BITMAP is
                   1986:             **    CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are
                   1987:             **    available from the source data object. 
                   1988:             */
                   1989:             nCount = ContainerDoc_PasteOleObject(
                   1990:                     lpContainerDoc,
                   1991:                     lpSrcDataObj,
                   1992:                     OLECREATEFROMDATA_STATIC,
                   1993:                     cfFormat,
                   1994:                     nIndex,
                   1995:                     fDisplayAsIcon,
                   1996:                     hMetaPict
                   1997:             );
                   1998:             return (nCount > 0 ? TRUE : FALSE);
                   1999: 
                   2000:         } else if(cfFormat == CF_TEXT) {
                   2001: 
                   2002:             hData = OleStdGetData(
                   2003:                     lpSrcDataObj,
                   2004:                     CF_TEXT,
                   2005:                     NULL,
                   2006:                     DVASPECT_CONTENT,
                   2007:                     (LPSTGMEDIUM)&medium
                   2008:             );
                   2009:             nCount = OutlineDoc_PasteTextData(
                   2010:                     (LPOUTLINEDOC)lpContainerDoc,
                   2011:                     hData,
                   2012:                     nIndex
                   2013:                 );
                   2014:             // OLE2NOTE: we must free data handle by releasing the medium
                   2015:             ReleaseStgMedium((LPSTGMEDIUM)&medium);
                   2016: 
                   2017:         } else {
                   2018:             return FALSE;   // no acceptable format available to paste
                   2019:         }
                   2020:     }
                   2021: 
                   2022:     lrSel.m_nStartLine = nIndex + nCount;
                   2023:     lrSel.m_nEndLine = nIndex + 1;
                   2024:     LineList_SetSel(lpLL, &lrSel);
                   2025:     return TRUE;
                   2026: }
                   2027: 
                   2028: 
                   2029: /* ContainerDoc_PasteCntrOutlData
                   2030:  * -------------------------------
                   2031:  *
                   2032:  *      Load the lines stored in a lpSrcStg (stored in CF_CNTROUTL format)
                   2033:  *  into the document.
                   2034:  *
                   2035:  * Return the number of items added
                   2036:  */
                   2037: int ContainerDoc_PasteCntrOutlData(
                   2038:         LPCONTAINERDOC          lpDestContainerDoc,
                   2039:         LPSTORAGE               lpSrcStg,
                   2040:         int                     nStartIndex
                   2041: )
                   2042: {
                   2043:     int nCount;
                   2044:     LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                   2045:     LPOUTLINEDOC lpDestOutlineDoc = (LPOUTLINEDOC)lpDestContainerDoc;
                   2046:     LPOUTLINEDOC lpSrcOutlineDoc;
                   2047:     LPLINELIST   lpSrcLL;
                   2048: 
                   2049:     // create a temp document that will be used to load the lpSrcStg data.
                   2050:     lpSrcOutlineDoc = (LPOUTLINEDOC)OutlineApp_CreateDoc(lpOutlineApp, FALSE);
                   2051:     if ( ! lpSrcOutlineDoc )
                   2052:         return 0;
                   2053: 
                   2054:     if (! OutlineDoc_LoadFromStg(lpSrcOutlineDoc, lpSrcStg))
                   2055:         goto error;
                   2056: 
                   2057:     /* copy all lines from the SrcDoc to the DestDoc. */
                   2058:     lpSrcLL = &lpSrcOutlineDoc->m_LineList;
                   2059:     nCount = LineList_CopySelToDoc(lpSrcLL, NULL, lpDestOutlineDoc);
                   2060: 
                   2061:     if (lpSrcOutlineDoc)            // destroy temporary document.
                   2062:         OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE);      
                   2063: 
                   2064:     return nCount;
                   2065: 
                   2066: error:
                   2067:     if (lpSrcOutlineDoc)            // destroy temporary document.
                   2068:         OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE);
                   2069: 
                   2070:     return 0;
                   2071: }
                   2072: 
                   2073: 
                   2074: /* ContainerDoc_QueryPasteFromData
                   2075: ** -------------------------------
                   2076: **
                   2077: **    Check if the IDataObject* offers data in a format that we can
                   2078: **    paste. The IDataObject* may come from the clipboard
                   2079: **    (GetClipboard) or from a drag/drop operation.
                   2080: **    In this function we look if one of the following formats is
                   2081: **    offered:
                   2082: **              CF_OUTLINE
                   2083: **              <OLE object -- CF_EMBEDSOURCE or CF_EMBEDDEDOBJECT>
                   2084: **              CF_TEXT
                   2085: **
                   2086: **    NOTE: fLink is specified and CF_LINKSOURCE is available then TRUE
                   2087: **    is returned, else FALSE.
                   2088: **
                   2089: **    Returns TRUE if paste can be performed
                   2090: **            FALSE if paste is not possible.
                   2091: */
                   2092: BOOL ContainerDoc_QueryPasteFromData(
                   2093:         LPCONTAINERDOC          lpContainerDoc,
                   2094:         LPDATAOBJECT            lpSrcDataObj,
                   2095:         BOOL                    fLink
                   2096: )
                   2097: {
                   2098:     LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
                   2099: 
                   2100:     if (fLink) {
                   2101:         /* check if we can paste a Link to the data */
                   2102:         if (OleQueryLinkFromData(lpSrcDataObj) != NOERROR)
                   2103:             return FALSE;   // linking is NOT possible
                   2104:     } else {
                   2105: 
                   2106:         int nFmtEtc;
                   2107: 
                   2108:         nFmtEtc = OleStdGetPriorityClipboardFormat(
                   2109:                 lpSrcDataObj,
                   2110:                 lpOleApp->m_arrPasteEntries,
                   2111:                 lpOleApp->m_nPasteEntries
                   2112:             );
                   2113: 
                   2114:         if (nFmtEtc < 0)
                   2115:             return FALSE;   // there is no format we like
                   2116:     }
                   2117: 
                   2118:     return TRUE;
                   2119: }
                   2120: 
                   2121: 
                   2122: /* ContainerDoc_PasteOleObject
                   2123: ** ---------------------------
                   2124: **
                   2125: **    Embed or link an OLE object. the source of the data is a pointer
                   2126: **    to an IDataObject. normally this lpSrcDataObj comes from the
                   2127: **    clipboard after call OleGetClipboard.
                   2128: **
                   2129: **    dwCreateType controls what type of object will created:
                   2130: **    OLECREATEFROMDATA_LINK -- OleCreateLinkFromData will be called
                   2131: **    OLECREATEFROMDATA_OBJECT -- OleCreateFromData will be called
                   2132: **    OLECREATEFROMDATA_STATIC -- OleCreateStaticFromData will be called
                   2133: **                                  cfFormat controls the type of static
                   2134: **    a CONTAINERLINE object is created to manage the OLE object. this
                   2135: **    CONTAINERLINE is added to the ContainerDoc after line nIndex.
                   2136: **
                   2137: */
                   2138: int ContainerDoc_PasteOleObject(
                   2139:         LPCONTAINERDOC          lpContainerDoc,
                   2140:         LPDATAOBJECT            lpSrcDataObj,
                   2141:         DWORD                   dwCreateType,
                   2142:         CLIPFORMAT              cfFormat,
                   2143:         int                     nIndex,
                   2144:         BOOL                    fDisplayAsIcon,
                   2145:         HGLOBAL                 hMetaPict
                   2146: )
                   2147: {
                   2148:     LPLINELIST          lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
                   2149:     LPLINE              lpLine = NULL;
                   2150:     HDC                 hDC;
                   2151:     int                 nTab = 0;
                   2152:     char                szStgName[CWCSTORAGENAME];
                   2153:     LPCONTAINERLINE     lpContainerLine = NULL;
                   2154: 
                   2155:     ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName));
                   2156: 
                   2157:     /* default the new line to have the same indent as previous line */
                   2158:     lpLine = LineList_GetLine(lpLL, nIndex);
                   2159:     if (lpLine)
                   2160:         nTab = Line_GetTabLevel(lpLine);
                   2161: 
                   2162:     hDC = LineList_GetDC(lpLL);
                   2163: 
                   2164:     lpContainerLine = ContainerLine_CreateFromData(
                   2165:             hDC,
                   2166:             nTab,
                   2167:             lpContainerDoc,
                   2168:             lpSrcDataObj,
                   2169:             dwCreateType,
                   2170:             cfFormat,
                   2171:             fDisplayAsIcon,
                   2172:             hMetaPict,
                   2173:             szStgName
                   2174:         );
                   2175:     LineList_ReleaseDC(lpLL, hDC);
                   2176: 
                   2177:     if (! lpContainerLine)
                   2178:         goto error;
                   2179: 
                   2180:     /* add a ContainerLine object to the document's LineList. The
                   2181:     **    ContainerLine manages the rectangle on the screen occupied by
                   2182:     **    the OLE object. later when the app is updated to support
                   2183:     **    extended layout, there could be more than one Line associated
                   2184:     **    with the OLE object.
                   2185:     */
                   2186: 
                   2187:     LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex);
                   2188: 
                   2189:     // check to see if the object has any initial extents.
                   2190:     ContainerLine_UpdateExtent(lpContainerLine, NULL);
                   2191: 
                   2192:     OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE);
                   2193: 
                   2194:     return 1;   // one line added to LineList
                   2195: 
                   2196: error:
                   2197:     // NOTE: if ContainerLine_CreateFromClip failed
                   2198:     OutlineApp_ErrorMessage(g_lpApp, "Paste Object failed!");
                   2199:     return 0;       // no lines added to line list
                   2200: }
                   2201: 
                   2202: 
                   2203: /* ContainerDoc_GetData
                   2204:  * --------------------
                   2205:  *
                   2206:  * Render data from the document on a CALLEE allocated STGMEDIUM.
                   2207:  *      This routine is called via IDataObject::GetData.
                   2208:  */
                   2209: HRESULT ContainerDoc_GetData (
                   2210:         LPCONTAINERDOC          lpContainerDoc,
                   2211:         LPFORMATETC             lpformatetc,
                   2212:         LPSTGMEDIUM             lpMedium
                   2213: )
                   2214: {
                   2215:     LPOLEDOC  lpOleDoc = (LPOLEDOC)lpContainerDoc;
                   2216:     LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
                   2217:     LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
                   2218:     LPOLEAPP  lpOleApp = (LPOLEAPP)lpContainerApp;
                   2219:     LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
                   2220:     HRESULT hrErr;
                   2221:     SCODE sc;
                   2222: 
                   2223:     // OLE2NOTE: we must set out pointer parameters to NULL
                   2224:     lpMedium->pUnkForRelease = NULL;
                   2225: 
                   2226:     /* OLE2NOTE: we must set all out pointer parameters to NULL. */
                   2227:     lpMedium->tymed = TYMED_NULL;
                   2228:     lpMedium->pUnkForRelease = NULL;    // we transfer ownership to caller
                   2229:     lpMedium->u.hGlobal = NULL;
                   2230: 
                   2231:     if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {
                   2232:         
                   2233:         /* OLE2NOTE: currently OLE does NOT support remoting a root
                   2234:         **    level IStorage (either memory or file based) as an OUT
                   2235:         **    parameter. thus, we can NOT support GetData for this
                   2236:         **    TYMED_ISTORAGE based format. the caller MUST call GetDataHere.
                   2237:         */
                   2238:         sc = DATA_E_FORMATETC;
                   2239:         goto error;
                   2240: 
                   2241:     } else if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {
                   2242:         // Verify caller asked for correct medium
                   2243:         if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
                   2244:             sc = DATA_E_FORMATETC;
                   2245:             goto error;
                   2246:         }
                   2247: 
                   2248:         lpMedium->u.hGlobal = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL);
                   2249:         if (! lpMedium->u.hGlobal) {
                   2250:             sc = E_OUTOFMEMORY;
                   2251:             goto error;
                   2252:         }
                   2253: 
                   2254:         lpMedium->tymed = TYMED_HGLOBAL;
                   2255:         OleDbgOut3("ContainerDoc_GetData: rendered CF_OUTLINE\r\n");
                   2256:         return NOERROR;
                   2257: 
                   2258:     } else if (lpformatetc->cfFormat == CF_TEXT) {
                   2259:         // Verify caller asked for correct medium
                   2260:         if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
                   2261:             sc = DATA_E_FORMATETC;
                   2262:             goto error;
                   2263:         }
                   2264: 
                   2265:         lpMedium->u.hGlobal = OutlineDoc_GetTextData (
                   2266:                 (LPOUTLINEDOC)lpContainerDoc,
                   2267:                 NULL
                   2268:         );
                   2269:         if (! lpMedium->u.hGlobal) {
                   2270:             sc = E_OUTOFMEMORY;
                   2271:             goto error;
                   2272:         }
                   2273: 
                   2274:         lpMedium->tymed = TYMED_HGLOBAL;
                   2275:         OleDbgOut3("ContainerDoc_GetData: rendered CF_TEXT\r\n");
                   2276:         return NOERROR;
                   2277: 
                   2278:     } else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||
                   2279:         (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
                   2280:             lpOleDoc->m_fLinkSourceAvail) ) {
                   2281:         // Verify caller asked for correct medium
                   2282:         if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {
                   2283:             sc = DATA_E_FORMATETC;
                   2284:             goto error;
                   2285:         }
                   2286: 
                   2287:         lpMedium->u.hGlobal = OleDoc_GetObjectDescriptorData (
                   2288:                 (LPOLEDOC)lpContainerDoc,
                   2289:                 NULL
                   2290:         );
                   2291:         if (! lpMedium->u.hGlobal) {
                   2292:             sc = E_OUTOFMEMORY;
                   2293:             goto error;
                   2294:         }
                   2295: 
                   2296:         lpMedium->tymed = TYMED_HGLOBAL;
                   2297: #if defined( _DEBUG )
                   2298:         if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor)
                   2299:             OleDbgOut3(
                   2300:                 "ContainerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n");
                   2301:         else
                   2302:             OleDbgOut3(
                   2303:                 "ContainerDoc_GetData: rendered CF_LINKSRCDESCRIPTOR\r\n");
                   2304: #endif
                   2305:         return NOERROR;
                   2306: 
                   2307:     } else if (lpContainerDoc->m_fEmbeddedObjectAvail) {
                   2308: 
                   2309:         /* OLE2NOTE: if this document contains a single OLE object
                   2310:         **    (ie. cfEmbeddedObject data format is available), then
                   2311:         **    the formats offered via our IDataObject must include
                   2312:         **    the formats available from the OLE object itself.
                   2313:         **    thus, we delegate this call to the IDataObject* of the
                   2314:         **    OLE object.
                   2315:         */
                   2316: 
                   2317:         if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) {
                   2318:             LPPERSISTSTORAGE lpPersistStg =
                   2319:                     (LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject(
                   2320:                             lpContainerDoc,
                   2321:                             &IID_IPersistStorage,
                   2322:                             NULL
                   2323:             );
                   2324: 
                   2325:             if (! lpPersistStg)
                   2326:                 return ResultFromScode(DATA_E_FORMATETC);
                   2327: 
                   2328:             /* render CF_EMBEDDEDOBJECT by asking the storage to save
                   2329:             **    into the pStg of the caller.
                   2330:             */
                   2331: 
                   2332:             hrErr = OleStdGetOleObjectData(
                   2333:                     lpPersistStg,
                   2334:                     lpformatetc,
                   2335:                     lpMedium,
                   2336:                     FALSE   /* fUseMemory -- (use file-base stg) */
                   2337:             );
                   2338:             OleStdRelease((LPUNKNOWN)lpPersistStg);
                   2339:             if (hrErr != NOERROR) {
                   2340:                 sc = GetScode(hrErr);
                   2341:                 goto error;
                   2342:             }
                   2343:             OleDbgOut3(
                   2344:                     "ContainerDoc_GetData: rendered CF_EMBEDDEDOBJECT\r\n");
                   2345:             return hrErr;
                   2346: 
                   2347:         } else if (lpformatetc->cfFormat == CF_METAFILEPICT) {
                   2348: 
                   2349:             /* OLE2NOTE: as a container which draws objects, when a single
                   2350:             **    OLE object is copied, we can give the Metafile picture of
                   2351:             **    the object. we will offer this picture when asked either
                   2352:             **    for the actual drawing aspect that we are displaying for
                   2353:             **    the object or for DVASPECT_DOCPRINT (if asked to render
                   2354:             **    it to a printer)
                   2355:             */
                   2356:             LPCONTAINERLINE lpContainerLine;
                   2357:             LPOLEOBJECT lpOleObj;
                   2358: 
                   2359:             // Verify caller asked for correct medium
                   2360:             if (!(lpformatetc->tymed & TYMED_MFPICT)) {
                   2361:                 sc = DATA_E_FORMATETC;
                   2362:                 goto error;
                   2363:             }
                   2364: 
                   2365:             lpOleObj = (LPOLEOBJECT)ContainerDoc_GetSingleOleObject(
                   2366:                     lpContainerDoc,
                   2367:                     &IID_IOleObject,
                   2368:                     (LPCONTAINERLINE FAR*)&lpContainerLine
                   2369:             );
                   2370: 
                   2371:             if (! lpOleObj) {
                   2372:                 sc = E_OUTOFMEMORY;     // could not load object
                   2373:                 goto error;
                   2374:             }
                   2375:             if (lpformatetc->dwAspect &
                   2376:                     (lpContainerLine->m_dwDrawAspect | DVASPECT_DOCPRINT)) {
                   2377:                 /* render CF_METAFILEPICT by drawing the object into
                   2378:                 **    a metafile DC
                   2379:                 */
                   2380:                 lpMedium->u.hGlobal = OleStdGetMetafilePictFromOleObject(
                   2381:                         lpOleObj, lpContainerLine->m_dwDrawAspect);
                   2382:                 OleStdRelease((LPUNKNOWN)lpOleObj);
                   2383:                 if (! lpMedium->u.hGlobal) {
                   2384:                     sc = E_OUTOFMEMORY;
                   2385:                     goto error;
                   2386:                 }
                   2387: 
                   2388:                 lpMedium->tymed = TYMED_MFPICT;
                   2389:                 OleDbgOut3(
                   2390:                     "ContainerDoc_GetData: rendered CF_METAFILEPICT\r\n");
                   2391:                 return NOERROR;
                   2392:             } else {
                   2393:                 // improper aspect requested
                   2394:                 OleStdRelease((LPUNKNOWN)lpOleObj);
                   2395:                 return ResultFromScode(DATA_E_FORMATETC);
                   2396:             }
                   2397: 
                   2398:         } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {
                   2399:             if (lpOleDoc->m_fLinkSourceAvail) {
                   2400:                 LPMONIKER lpmk;
                   2401: 
                   2402:                 lpmk = ContainerLine_GetFullMoniker(
                   2403:                         lpContainerDoc->m_lpSrcContainerLine,
                   2404:                         GETMONIKER_FORCEASSIGN
                   2405:                 );
                   2406:                 if (lpmk) {
                   2407:                     hrErr = OleStdGetLinkSourceData(
                   2408:                             lpmk,
                   2409:                             &lpContainerDoc->m_clsidOleObjCopied,
                   2410:                             lpformatetc,
                   2411:                             lpMedium
                   2412:                     );
                   2413:                     OleStdRelease((LPUNKNOWN)lpmk);
                   2414:                     if (hrErr != NOERROR) {
                   2415:                         sc = GetScode(hrErr);
                   2416:                         goto error;
                   2417:                     }
                   2418:                     OleDbgOut3(
                   2419:                         "ContainerDoc_GetData: rendered CF_LINKSOURCE\r\n");
                   2420:                     return hrErr;
                   2421:                 } else {
                   2422:                     sc = DATA_E_FORMATETC;
                   2423:                     goto error;
                   2424:                 }
                   2425:             } else {
                   2426:                 sc = DATA_E_FORMATETC;
                   2427:                 goto error;
                   2428:             }
                   2429: 
                   2430:         } 
                   2431: #if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
                   2432:         /* OLE2NOTE: optionally, a container that wants to have a
                   2433:         **    potentially richer data transfer, can enumerate the data
                   2434:         **    formats from the OLE object's cache and offer them too. if
                   2435:         **    the object has a special handler, then it might be able to
                   2436:         **    render additional data formats. in this case, the
                   2437:         **    container must delegate the GetData call to the object if
                   2438:         **    it does not directly support the format.
                   2439:         **    
                   2440:         **    CNTROUTL does NOT enumerate the cache; it implements the
                   2441:         **    simpler strategy of offering a static list of formats.
                   2442:         **    thus the delegation is NOT required.
                   2443:         */
                   2444:       else {
                   2445: 
                   2446:             /* OLE2NOTE: we delegate this call to the IDataObject* of the
                   2447:             **    OLE object.
                   2448:             */
                   2449:             LPDATAOBJECT lpDataObj;
                   2450: 
                   2451:             lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(
                   2452:                     lpContainerDoc,
                   2453:                     &IID_IDataObject,
                   2454:                     NULL
                   2455:             );
                   2456: 
                   2457:             if (! lpDataObj) {
                   2458:                 sc = DATA_E_FORMATETC;
                   2459:                 goto error;
                   2460:             }
                   2461: 
                   2462:             OLEDBG_BEGIN2("ContainerDoc_GetData: delegate to OLE obj\r\n")
                   2463:             hrErr=lpDataObj->lpVtbl->GetData(lpDataObj,lpformatetc,lpMedium);
                   2464:             OLEDBG_END2
                   2465: 
                   2466:             OleStdRelease((LPUNKNOWN)lpDataObj);
                   2467:             return hrErr;
                   2468:         }
                   2469: #endif  // ! OPTIONAL_ADVANCED_DATA_TRANSFER
                   2470: 
                   2471:     }
                   2472: 
                   2473:     // if we get here then we do NOT support the requested format
                   2474:     sc = DATA_E_FORMATETC;
                   2475: 
                   2476: error:
                   2477:     return ResultFromScode(sc);
                   2478: }
                   2479: 
                   2480: 
                   2481: /* ContainerDoc_GetDataHere
                   2482:  * ------------------------
                   2483:  *
                   2484:  * Render data from the document on a CALLER allocated STGMEDIUM.
                   2485:  *      This routine is called via IDataObject::GetDataHere.
                   2486:  */
                   2487: HRESULT ContainerDoc_GetDataHere (
                   2488:         LPCONTAINERDOC          lpContainerDoc,
                   2489:         LPFORMATETC             lpformatetc,
                   2490:         LPSTGMEDIUM             lpMedium
                   2491: )
                   2492: {
                   2493:     LPOLEDOC  lpOleDoc = (LPOLEDOC)lpContainerDoc;
                   2494:     LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
                   2495:     LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
                   2496:     LPOLEAPP  lpOleApp = (LPOLEAPP)lpContainerApp;
                   2497:     LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
                   2498:     HRESULT hrErr;
                   2499: 
                   2500:     // OLE2NOTE: we must set out pointer parameters to NULL
                   2501:     lpMedium->pUnkForRelease = NULL;
                   2502: 
                   2503:     // we only support  IStorage medium
                   2504:     if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {
                   2505:         if (!(lpformatetc->tymed & TYMED_ISTORAGE))
                   2506:             return ResultFromScode(DATA_E_FORMATETC);
                   2507: 
                   2508:         if (lpMedium->tymed == TYMED_ISTORAGE) {
                   2509:             /* Caller has allocated the storage. we must copy all of our
                   2510:             **    data into his storage.
                   2511:             */
                   2512: 
                   2513:             /*  OLE2NOTE: we must be sure to write our class ID into our
                   2514:             **    storage. this information is used by OLE to determine the
                   2515:             **    class of the data stored in our storage. 
                   2516:             */
                   2517:             if((hrErr=WriteClassStg(lpMedium->u.pstg,&CLSID_APP)) != NOERROR) 
                   2518:                 return hrErr;
                   2519:             
                   2520:             OutlineDoc_SaveSelToStg(
                   2521:                     (LPOUTLINEDOC)lpContainerDoc,
                   2522:                     NULL,   /* entire doc */
                   2523:                     lpContainerApp->m_cfCntrOutl,
                   2524:                     lpMedium->u.pstg,
                   2525:                     FALSE
                   2526:             );
                   2527:             OleStdCommitStorage(lpMedium->u.pstg);
                   2528: 
                   2529:             OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_CNTROUTL\r\n");
                   2530:             return NOERROR;
                   2531:         } else {
                   2532:             // we only support IStorage medium
                   2533:             return ResultFromScode(DATA_E_FORMATETC);
                   2534:         }
                   2535: 
                   2536:     } else if (lpContainerDoc->m_fEmbeddedObjectAvail) {
                   2537: 
                   2538:         /* OLE2NOTE: if this document contains a single OLE object
                   2539:         **    (ie. cfEmbeddedObject data format is available), then
                   2540:         **    the formats offered via our IDataObject must include
                   2541:         **    CF_EMBEDDEDOBJECT and the formats available from the OLE
                   2542:         **    object itself.
                   2543:         */
                   2544: 
                   2545:         if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) {
                   2546:             LPPERSISTSTORAGE lpPersistStg =
                   2547:                     (LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject(
                   2548:                             lpContainerDoc,
                   2549:                             &IID_IPersistStorage,
                   2550:                             NULL
                   2551:             );
                   2552: 
                   2553:             if (! lpPersistStg) {
                   2554:                 return ResultFromScode(E_OUTOFMEMORY);
                   2555:             }
                   2556:             /* render CF_EMBEDDEDOBJECT by asking the storage to save
                   2557:             **    into the pStg of the caller.
                   2558:             */
                   2559: 
                   2560:             hrErr = OleStdGetOleObjectData(
                   2561:                     lpPersistStg,
                   2562:                     lpformatetc,
                   2563:                     lpMedium,
                   2564:                     FALSE   /* fUseMemory -- (use file-base stg) */
                   2565:             );
                   2566:             OleStdRelease((LPUNKNOWN)lpPersistStg);
                   2567:             if (hrErr != NOERROR) {
                   2568:                 return hrErr;
                   2569:             }
                   2570:             OleDbgOut3(
                   2571:                 "ContainerDoc_GetDataHere: rendered CF_EMBEDDEDOBJECT\r\n");
                   2572:             return hrErr;
                   2573: 
                   2574:         } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {
                   2575:             if (lpOleDoc->m_fLinkSourceAvail) {
                   2576:                 LPMONIKER lpmk;
                   2577: 
                   2578:                 lpmk = ContainerLine_GetFullMoniker(
                   2579:                         lpContainerDoc->m_lpSrcContainerLine,
                   2580:                         GETMONIKER_FORCEASSIGN
                   2581:                 );
                   2582:                 if (lpmk) {
                   2583:                     hrErr = OleStdGetLinkSourceData(
                   2584:                             lpmk,
                   2585:                             &lpContainerDoc->m_clsidOleObjCopied,
                   2586:                             lpformatetc,
                   2587:                             lpMedium
                   2588:                     );
                   2589:                     OleStdRelease((LPUNKNOWN)lpmk);
                   2590:                     OleDbgOut3(
                   2591:                       "ContainerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n");
                   2592:                     return hrErr;
                   2593:                 } else {
                   2594:                     return ResultFromScode(E_FAIL);
                   2595:                 }
                   2596:             } else {
                   2597:                 return ResultFromScode(DATA_E_FORMATETC);
                   2598:             }
                   2599: 
                   2600:         } 
                   2601: #if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
                   2602:         /* OLE2NOTE: optionally, a container that wants to have a
                   2603:         **    potentially richer data transfer, can enumerate the data
                   2604:         **    formats from the OLE object's cache and offer them too. if
                   2605:         **    the object has a special handler, then it might be able to
                   2606:         **    render additional data formats. in this case, the
                   2607:         **    container must delegate the GetData call to the object if
                   2608:         **    it does not directly support the format.
                   2609:         **    
                   2610:         **    CNTROUTL does NOT enumerate the cache; it implements the
                   2611:         **    simpler strategy of offering a static list of formats.
                   2612:         **    thus the delegation is NOT required.
                   2613:         */
                   2614:         else {
                   2615: 
                   2616:             /* OLE2NOTE: we delegate this call to the IDataObject* of the
                   2617:             **    OLE object.
                   2618:             */
                   2619:             LPDATAOBJECT lpDataObj;
                   2620: 
                   2621:             lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(
                   2622:                     lpContainerDoc,
                   2623:                     &IID_IDataObject,
                   2624:                     NULL
                   2625:             );
                   2626: 
                   2627:             if (! lpDataObj)
                   2628:                 return ResultFromScode(DATA_E_FORMATETC);
                   2629: 
                   2630:             OLEDBG_BEGIN2("ContainerDoc_GetDataHere: delegate to OLE obj\r\n")
                   2631:             hrErr = lpDataObj->lpVtbl->GetDataHere(
                   2632:                     lpDataObj,
                   2633:                     lpformatetc,
                   2634:                     lpMedium
                   2635:             );
                   2636:             OLEDBG_END2
                   2637: 
                   2638:             OleStdRelease((LPUNKNOWN)lpDataObj);
                   2639:             return hrErr;
                   2640:         }
                   2641: #endif  // OPTIONAL_ADVANCED_DATA_TRANSFER
                   2642:     } else {
                   2643:         return ResultFromScode(DATA_E_FORMATETC);
                   2644:     }
                   2645: }
                   2646: 
                   2647: 
                   2648: /* ContainerDoc_QueryGetData
                   2649:  * -------------------------
                   2650:  *
                   2651:  * Answer if a particular data format is supported via GetData/GetDataHere.
                   2652:  *      This routine is called via IDataObject::QueryGetData.
                   2653:  */
                   2654: HRESULT ContainerDoc_QueryGetData (
                   2655:         LPCONTAINERDOC          lpContainerDoc,
                   2656:         LPFORMATETC             lpformatetc
                   2657: )
                   2658: {
                   2659:     LPOLEDOC  lpOleDoc = (LPOLEDOC)lpContainerDoc;
                   2660:     LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
                   2661:     LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
                   2662:     LPOLEAPP  lpOleApp = (LPOLEAPP)lpContainerApp;
                   2663:     LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
                   2664:     LPDATAOBJECT  lpDataObj = NULL;
                   2665:     LPCONTAINERLINE lpContainerLine = NULL;
                   2666:     SCODE sc;
                   2667:     HRESULT hrErr;
                   2668: 
                   2669:     if (lpContainerDoc->m_fEmbeddedObjectAvail) {
                   2670:         lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(
                   2671:                     lpContainerDoc,
                   2672:                     &IID_IDataObject,
                   2673:                     (LPCONTAINERLINE FAR*)&lpContainerLine
                   2674:         );
                   2675:     }
                   2676: 
                   2677:     /* Caller is querying if we support certain format but does not
                   2678:     **    want any data actually returned.
                   2679:     */
                   2680:     if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {
                   2681:         // we only support ISTORAGE medium
                   2682:         sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_ISTORAGE) );
                   2683: 
                   2684:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject &&
                   2685:             lpContainerDoc->m_fEmbeddedObjectAvail ) {
                   2686:         sc = GetScode( OleStdQueryOleObjectData(lpformatetc) );
                   2687: 
                   2688:     } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource &&
                   2689:             lpOleDoc->m_fLinkSourceAvail) {
                   2690:         sc = GetScode( OleStdQueryLinkSourceData(lpformatetc) );
                   2691: 
                   2692:     } else if((lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline ||
                   2693:             lpformatetc->cfFormat == CF_TEXT) ) {
                   2694:         // we only support HGLOBAL medium
                   2695:         sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL) );
                   2696: 
                   2697:     } else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||
                   2698:         (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&
                   2699:             lpOleDoc->m_fLinkSourceAvail) ) {
                   2700:         sc = GetScode( OleStdQueryObjectDescriptorData(lpformatetc) );
                   2701: 
                   2702:     } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&
                   2703:             lpContainerDoc->m_fEmbeddedObjectAvail && lpContainerLine &&
                   2704:             (lpformatetc->dwAspect &
                   2705:                 (lpContainerLine->m_dwDrawAspect | DVASPECT_DOCPRINT))) {
                   2706: 
                   2707:         /* OLE2NOTE: as a container which draws objects, when a single
                   2708:         **    OLE object is copied, we can give the Metafile picture of
                   2709:         **    the object. we will offer this picture when asked either
                   2710:         **    for the actual drawing aspect that we are displaying for
                   2711:         **    the object or for DVASPECT_DOCPRINT (if asked to render
                   2712:         **    it to a printer)
                   2713:         */
                   2714:         // we only support MFPICT medium
                   2715:         sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT) );
                   2716: 
                   2717:     } else if (lpDataObj) {
                   2718: 
                   2719:         /* OLE2NOTE: if this document contains a single OLE object
                   2720:         **    (ie. cfEmbeddedObject data format is available), then
                   2721:         **    the formats offered via our IDataObject must include
                   2722:         **    the formats available from the OLE object itself.
                   2723:         **    thus we delegate this call to the IDataObject* of the
                   2724:         **    OLE object.
                   2725:         */
                   2726:         OLEDBG_BEGIN2("ContainerDoc_QueryGetData: delegate to OLE obj\r\n")
                   2727:         hrErr = lpDataObj->lpVtbl->QueryGetData(lpDataObj, lpformatetc);
                   2728:         OLEDBG_END2
                   2729: 
                   2730:         sc = GetScode(hrErr);
                   2731: 
                   2732:     } else {
                   2733:         sc = DATA_E_FORMATETC;
                   2734:     }
                   2735: 
                   2736:     if (lpDataObj)
                   2737:         OleStdRelease((LPUNKNOWN)lpDataObj);
                   2738:     return ResultFromScode(sc);
                   2739: }
                   2740: 
                   2741: 
                   2742: 
                   2743: /* ContainerDoc_SetData
                   2744:  * --------------------
                   2745:  *
                   2746:  * Set (modify) data of the document.
                   2747:  *      This routine is called via IDataObject::SetData.
                   2748:  */
                   2749: HRESULT ContainerDoc_SetData (
                   2750:         LPCONTAINERDOC          lpContainerDoc,
                   2751:         LPFORMATETC             lpformatetc,
                   2752:         LPSTGMEDIUM             lpmedium,
                   2753:         BOOL                    fRelease
                   2754: )
                   2755: {
                   2756:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
                   2757:     LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
                   2758: 
                   2759:     if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline)
                   2760:         OutlineDoc_PasteOutlineData(lpOutlineDoc,lpmedium->u.hGlobal,-1);
                   2761:     else if (lpformatetc->cfFormat == CF_TEXT)
                   2762:         OutlineDoc_PasteTextData(lpOutlineDoc,lpmedium->u.hGlobal,-1);
                   2763:     else
                   2764:         return ResultFromScode(DATA_E_FORMATETC);
                   2765: 
                   2766:     return NOERROR;
                   2767: }
                   2768: 
                   2769: 
                   2770: /* ContainerDoc_EnumFormatEtc
                   2771:  * --------------------------
                   2772:  *
                   2773:  * Return an enumerator which enumerates the data accepted/offered by
                   2774:  *      the document.
                   2775:  *      This routine is called via IDataObject::SetData.
                   2776:  */
                   2777: HRESULT ContainerDoc_EnumFormatEtc(
                   2778:         LPCONTAINERDOC          lpContainerDoc,
                   2779:         DWORD                   dwDirection,
                   2780:         LPENUMFORMATETC FAR*    lplpenumFormatEtc
                   2781: )
                   2782: {
                   2783:     LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
                   2784:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
                   2785:     LPOLEAPP  lpOleApp = (LPOLEAPP)g_lpApp;
                   2786:     LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp;
                   2787:     int nActualFmts;
                   2788:     int i;
                   2789:     SCODE sc = S_OK;
                   2790: 
                   2791:     /* the Container-Only version of Outline does NOT offer
                   2792:     **    IDataObject interface from its User documents.
                   2793:     */
                   2794:     if (! lpOutlineDoc->m_fDataTransferDoc)
                   2795:         return ResultFromScode(E_FAIL);
                   2796: 
                   2797:     if (dwDirection == DATADIR_GET) {
                   2798:         if (lpContainerDoc->m_fEmbeddedObjectAvail) {
                   2799: 
                   2800:             /* OLE2NOTE: if this document contains a single OLE object
                   2801:             **    (ie. cfEmbeddedObject data format is available), then
                   2802:             **    the formats offered via our enumerator must include
                   2803:             **    the formats available from the OLE object itself. we
                   2804:             **    have previously set up a special array of FORMATETC's
                   2805:             **    in OutlineDoc_CreateDataTransferDoc routine which includes
                   2806:             **    the combination of data we offer directly and data
                   2807:             **    offered by the OLE object.
                   2808:             */
                   2809: 
                   2810:             /* If the document does not have a Moniker, then exclude
                   2811:             **    CF_LINKSOURCE CF_LINKSRCDESCRIPTOR from the list of
                   2812:             **    formats available. these formats are deliberately
                   2813:             **    listed last in the array of possible "Get" formats.
                   2814:             */
                   2815:             nActualFmts = lpContainerApp->m_nSingleObjGetFmts;
                   2816:             if (! lpOleDoc->m_fLinkSourceAvail)
                   2817:                 nActualFmts -= 2;
                   2818: 
                   2819:             // set correct dwDrawAspect for METAFILEPICT of object copied
                   2820:             for (i = 0; i < nActualFmts; i++) {
                   2821:                 if (lpContainerApp->m_arrSingleObjGetFmts[i].cfFormat == 
                   2822:                                                             CF_METAFILEPICT) {
                   2823:                     lpContainerApp->m_arrSingleObjGetFmts[i].dwAspect = 
                   2824:                             lpContainerDoc->m_dwAspectOleObjCopied;
                   2825:                     break;  // DONE
                   2826:                 }
                   2827:             }
                   2828:             *lplpenumFormatEtc = OleStdEnumFmtEtc_Create(
                   2829:                     nActualFmts, lpContainerApp->m_arrSingleObjGetFmts);
                   2830:             if (*lplpenumFormatEtc == NULL)
                   2831:                 sc = E_OUTOFMEMORY;
                   2832: 
                   2833:         } else {
                   2834: 
                   2835:             /* This document does NOT offer cfEmbeddedObject,
                   2836:             **    therefore we can simply enumerate the
                   2837:             **    static list of formats that we handle directly.
                   2838:             */
                   2839:             *lplpenumFormatEtc = OleStdEnumFmtEtc_Create(
                   2840:                     lpOleApp->m_nDocGetFmts, lpOleApp->m_arrDocGetFmts);
                   2841:             if (*lplpenumFormatEtc == NULL)
                   2842:                 sc = E_OUTOFMEMORY;
                   2843:         }
                   2844:     } else if (dwDirection == DATADIR_SET) {
                   2845:         /* OLE2NOTE: a document that is used to transfer data
                   2846:         **    (either via the clipboard or drag/drop does NOT
                   2847:         **    accept SetData on ANY format!
                   2848:         */
                   2849:         sc = E_NOTIMPL;
                   2850: 
                   2851:     } else {
                   2852:         sc = E_NOTIMPL;
                   2853:     }
                   2854: 
                   2855:     return ResultFromScode(sc);
                   2856: }
                   2857: 
                   2858: 
                   2859: #if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )
                   2860: /* OLE2NOTE: optionally, a container that wants to have a
                   2861: **    potentially richer data transfer, can enumerate the data
                   2862: **    formats from the OLE object's cache and offer them too. if
                   2863: **    the object has a special handler, then it might be able to
                   2864: **    render additional data formats.
                   2865: **    
                   2866: **    CNTROUTL does NOT enumerate the cache; it implements the simpler
                   2867: **    strategy of offering a static list of formats. the following
                   2868: **    function is included in order to illustrates how enumerating the
                   2869: **    cache could be done. CNTROUTL does NOT call this function.
                   2870: **    
                   2871: */
                   2872: 
                   2873: /* ContainerDoc_SetupDocGetFmts
                   2874: ** ----------------------------
                   2875: **    Setup the combined list of formats that this data transfer
                   2876: **    ContainerDoc which contains a single OLE object should offer.
                   2877: **
                   2878: **    OLE2NOTE: The list of formats that should be offered when a
                   2879: **    single OLE object is being transfered include the following:
                   2880: **          * any formats the container app wants to give
                   2881: **          * CF_EMBEDDEDOBJECT
                   2882: **          * CF_METAFILEPICT
                   2883: **          * any formats that the OLE object's cache can offer directly
                   2884: **
                   2885: **    We will offer the following formats in the order given:
                   2886: **                  1. CF_CNTROUTL
                   2887: **                  2. CF_EMBEDDEDOBJECT
                   2888: **                  3. CF_OBJECTDESCRIPTOR
                   2889: **                  4. CF_METAFILEPICT
                   2890: **                  5. <data formats from OLE object's cache>
                   2891: **                  6. CF_OUTLINE
                   2892: **                  7. CF_TEXT
                   2893: **                  8. CF_LINKSOURCE
                   2894: **                  9. CF_LINKSRCDESCRIPTOR
                   2895: */
                   2896: BOOL ContainerDoc_SetupDocGetFmts(
                   2897:         LPCONTAINERDOC          lpContainerDoc,
                   2898:         LPCONTAINERLINE         lpContainerLine
                   2899: )
                   2900: {
                   2901:     LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
                   2902:     LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
                   2903:     LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
                   2904:     LPOLECACHE lpOleCache;
                   2905:     HRESULT hrErr;
                   2906:     STATDATA        StatData;
                   2907:     LPENUMSTATDATA  lpEnumStatData = NULL;
                   2908:     LPFORMATETC lparrDocGetFmts = NULL;
                   2909:     UINT nOleObjFmts = 0;
                   2910:     UINT nTotalFmts;
                   2911:     UINT i;
                   2912:     UINT iFmt;
                   2913: 
                   2914:     lpOleCache = (LPOLECACHE)OleStdQueryInterface(
                   2915:             (LPUNKNOWN)lpContainerLine->m_lpOleObj,
                   2916:             &IID_IOleCache
                   2917:     );
                   2918:     if (lpOleCache) {
                   2919:         OLEDBG_BEGIN2("IOleCache::EnumCache called\r\n")
                   2920:         hrErr = lpOleCache->lpVtbl->EnumCache(
                   2921:                 lpOleCache,
                   2922:                 (LPENUMSTATDATA FAR*)&lpEnumStatData
                   2923:         );
                   2924:         OLEDBG_END2
                   2925:     }
                   2926: 
                   2927:     if (lpEnumStatData) {
                   2928:         /* Cache enumerator is available. count the number of
                   2929:         **    formats that the OLE object's cache offers.
                   2930:         */
                   2931:         while(lpEnumStatData->lpVtbl->Next(
                   2932:                     lpEnumStatData,
                   2933:                     1,
                   2934:                     (LPSTATDATA)&StatData,
                   2935:                     NULL) == NOERROR) {
                   2936:             nOleObjFmts++;
                   2937:             // OLE2NOTE: we MUST free the TargetDevice
                   2938:             OleStdFree(StatData.formatetc.ptd);
                   2939:         }
                   2940:         lpEnumStatData->lpVtbl->Reset(lpEnumStatData);  // reset for next loop
                   2941:     }
                   2942: 
                   2943:     /* OLE2NOTE: the maximum total number of formats that our IDataObject
                   2944:     **    could offer equals the sum of the following:
                   2945:     **          n offered by the OLE object's cache
                   2946:     **       +  n normally offered by our app
                   2947:     **       +  1 CF_EMBEDDEDOBJECT
                   2948:     **       +  1 CF_METAFILEPICT
                   2949:     **       +  1 CF_LINKSOURCE
                   2950:     **       +  1 CF_LINKSRCDESCRIPTOR
                   2951:     **    the actual number of formats that we can offer could be less
                   2952:     **    than this total if there is any clash between the formats
                   2953:     **    that we offer directly and those offered by the cache. if
                   2954:     **    there is a clash, the container's rendering overrides that of
                   2955:     **    the object. eg.: as a container transfering an OLE object we
                   2956:     **    should directly offer CF_METAFILEPICT to guarantee that this
                   2957:     **    format is always available. thus, if the cache offers
                   2958:     **    CF_METAFILEPICT then it is skipped.
                   2959:     */
                   2960:     nTotalFmts = nOleObjFmts + lpOleApp->m_nDocGetFmts + 4;
                   2961:     lparrDocGetFmts = (LPFORMATETC)New (nTotalFmts * sizeof(FORMATETC));
                   2962: 
                   2963:     if (! OleDbgVerifySz(lparrDocGetFmts != NULL,
                   2964:                                             "Error allocating arrDocGetFmts"))
                   2965:             return FALSE;
                   2966: 
                   2967:     for (i = 0, iFmt = 0; i < lpOleApp->m_nDocGetFmts; i++) {
                   2968:         _fmemcpy((LPFORMATETC)&lparrDocGetFmts[iFmt++],
                   2969:                 (LPFORMATETC)&lpOleApp->m_arrDocGetFmts[i],
                   2970:                 sizeof(FORMATETC)
                   2971:         );
                   2972:         if (lpOleApp->m_arrDocGetFmts[i].cfFormat ==
                   2973:             lpContainerApp->m_cfCntrOutl) {
                   2974:             /* insert CF_EMBEDDEDOBJECT, CF_METAFILEPICT, and formats
                   2975:             **    available from the OLE object's cache following
                   2976:             **    CF_CNTROUTL.
                   2977:             */
                   2978:             lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfEmbeddedObject;
                   2979:             lparrDocGetFmts[iFmt].ptd      = NULL;
                   2980:             lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;
                   2981:             lparrDocGetFmts[iFmt].tymed    = TYMED_ISTORAGE;
                   2982:             lparrDocGetFmts[iFmt].lindex   = -1;
                   2983:             iFmt++;
                   2984:             lparrDocGetFmts[iFmt].cfFormat = CF_METAFILEPICT;
                   2985:             lparrDocGetFmts[iFmt].ptd      = NULL;
                   2986:             lparrDocGetFmts[iFmt].dwAspect = lpContainerLine->m_dwDrawAspect;
                   2987:             lparrDocGetFmts[iFmt].tymed    = TYMED_MFPICT;
                   2988:             lparrDocGetFmts[iFmt].lindex   = -1;
                   2989:             iFmt++;
                   2990: 
                   2991:             if (lpEnumStatData) {
                   2992:                 /* Cache enumerator is available. enumerate all of
                   2993:                 **    the formats that the OLE object's cache offers.
                   2994:                 */
                   2995:                 while(lpEnumStatData->lpVtbl->Next(
                   2996:                         lpEnumStatData,
                   2997:                         1,
                   2998:                         (LPSTATDATA)&StatData,
                   2999:                         NULL) == NOERROR) {
                   3000:                     /* check if the format clashes with one of our fmts */
                   3001:                     if (StatData.formatetc.cfFormat != CF_METAFILEPICT
                   3002:                         && ! OleStdIsDuplicateFormat(
                   3003:                                 (LPFORMATETC)&StatData.formatetc,
                   3004:                                 lpOleApp->m_arrDocGetFmts,
                   3005:                                 lpOleApp->m_nDocGetFmts)) {
                   3006:                         OleStdCopyFormatEtc(
                   3007:                                 &(lparrDocGetFmts[iFmt]),&StatData.formatetc);
                   3008:                         iFmt++;
                   3009:                     }
                   3010:                     // OLE2NOTE: we MUST free the TargetDevice
                   3011:                     OleStdFree(StatData.formatetc.ptd);
                   3012:                 }
                   3013:             }
                   3014:         }
                   3015:     }
                   3016: 
                   3017:     if (lpOleCache)
                   3018:         OleStdRelease((LPUNKNOWN)lpOleCache);
                   3019: 
                   3020:     /* append CF_LINKSOURCE format */
                   3021:     lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSource;
                   3022:     lparrDocGetFmts[iFmt].ptd      = NULL;
                   3023:     lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;
                   3024:     lparrDocGetFmts[iFmt].tymed    = TYMED_ISTREAM;
                   3025:     lparrDocGetFmts[iFmt].lindex   = -1;
                   3026:     iFmt++;
                   3027: 
                   3028:     /* append CF_LINKSRCDESCRIPTOR format */
                   3029:     lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSrcDescriptor;
                   3030:     lparrDocGetFmts[iFmt].ptd      = NULL;
                   3031:     lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;
                   3032:     lparrDocGetFmts[iFmt].tymed    = TYMED_HGLOBAL;
                   3033:     lparrDocGetFmts[iFmt].lindex   = -1;
                   3034:     iFmt++;
                   3035: 
                   3036:     lpContainerDoc->m_lparrDocGetFmts = lparrDocGetFmts;
                   3037:     lpContainerDoc->m_nDocGetFmts = iFmt;
                   3038: 
                   3039:     if (lpEnumStatData)
                   3040:         OleStdVerifyRelease(
                   3041:                 (LPUNKNOWN)lpEnumStatData,
                   3042:                 "Cache enumerator not released properly"
                   3043:         );
                   3044: 
                   3045:     return TRUE;
                   3046: }
                   3047: #endif  // OPTIONAL_ADVANCED_DATA_TRANSFER
                   3048: 
                   3049: #endif  // OLE_CNTR

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.