Annotation of mstools/ole20/samples/outline/cntrbase.c, revision 1.1

1.1     ! root        1: /*************************************************************************
        !             2: **
        !             3: **    OLE 2 Container Sample Code
        !             4: **
        !             5: **    cntrbase.c
        !             6: **    
        !             7: **    This file contains all interfaces, methods and related support
        !             8: **    functions for the basic OLE Container application. The
        !             9: **    basic OLE Container application supports being a container for
        !            10: **    embedded and linked objects.
        !            11: **    The basic Container application includes the following
        !            12: **    implementation objects: 
        !            13: **    
        !            14: **    ContainerDoc Object
        !            15: **      no required interfaces for basic functionality
        !            16: **      (see linking.c for linking related support)
        !            17: **      (see clipbrd.c for clipboard related support)
        !            18: **      (see dragdrop.c for drag/drop related support)
        !            19: **    
        !            20: **    ContainerLine Object
        !            21: **    (see cntrline.c for all ContainerLine functions and interfaces)
        !            22: **      exposed interfaces:
        !            23: **          IOleClientSite
        !            24: **          IAdviseSink
        !            25: **
        !            26: **    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
        !            27: **
        !            28: *************************************************************************/
        !            29: 
        !            30: #include "outline.h"
        !            31: #include <geticon.h>    // for OleStdGetUserTypeOfClass
        !            32: 
        !            33: 
        !            34: OLEDBGDATA
        !            35: 
        !            36: 
        !            37: extern LPOUTLINEAPP             g_lpApp;
        !            38: extern IOleUILinkContainerVtbl  g_CntrDoc_OleUILinkContainerVtbl;
        !            39: 
        !            40: 
        !            41: // REVIEW: should use string resource for messages
        !            42: char ErrMsgShowObj[] = "Could not show object server!";
        !            43: char ErrMsgInsertObj[] = "Insert Object failed!";
        !            44: char ErrMsgConvertObj[] = "Convert Object failed!";
        !            45: char ErrMsgCantConvert[] = "Unable to convert the selection!";
        !            46: char ErrMsgActivateAsObj[] = "Activate As Object failed!";
        !            47: 
        !            48: extern char ErrMsgSaving[];
        !            49: extern char ErrMsgOpening[];
        !            50: 
        !            51: 
        !            52: /* ContainerDoc_Init
        !            53:  * -----------------
        !            54:  *
        !            55:  *  Initialize the fields of a new ContainerDoc object. The doc is initially
        !            56:  *  not associated with a file or an (Untitled) document. This function sets
        !            57:  *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the
        !            58:  *  caller should call:
        !            59:  *      1.) Doc_InitNewFile to set the ContainerDoc to (Untitled)
        !            60:  *      2.) Doc_LoadFromFile to associate the ContainerDoc with a file.
        !            61:  *  This function creates a new window for the document.
        !            62:  *
        !            63:  *  NOTE: the window is initially created with a NIL size. it must be
        !            64:  *        sized and positioned by the caller. also the document is initially
        !            65:  *        created invisible. the caller must call Doc_ShowWindow
        !            66:  *        after sizing it to make the document window visible.
        !            67:  */
        !            68: BOOL ContainerDoc_Init(LPCONTAINERDOC lpContainerDoc, BOOL fDataTransferDoc)
        !            69: {
        !            70:     LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
        !            71:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
        !            72: 
        !            73:     lpOutlineDoc->m_cfSaveFormat             = lpContainerApp->m_cfCntrOutl;
        !            74:     lpContainerDoc->m_nNextObjNo            = 0L;
        !            75:     lpContainerDoc->m_lpStg                 = NULL;
        !            76:     lpContainerDoc->m_lpNewStg              = NULL;
        !            77:     lpContainerDoc->m_fEmbeddedObjectAvail  = FALSE;
        !            78:     lpContainerDoc->m_clsidOleObjCopied     = CLSID_NULL;
        !            79:     lpContainerDoc->m_dwAspectOleObjCopied  = DVASPECT_CONTENT;
        !            80:     lpContainerDoc->m_lpSrcContainerLine    = NULL;
        !            81:     lpContainerDoc->m_fShowObject           = TRUE;
        !            82: 
        !            83: #if defined( INPLACE_CNTR )
        !            84:     lpContainerDoc->m_lpLastIpActiveLine    = NULL;
        !            85:     lpContainerDoc->m_lpLastUIActiveLine    = NULL;
        !            86:     lpContainerDoc->m_hwndUIActiveObj       = NULL;
        !            87:     lpContainerDoc->m_fAddMyUI              = TRUE; // UI needs to be added
        !            88:     lpContainerDoc->m_cIPActiveObjects         = 0;    
        !            89:        
        !            90: #if defined( INPLACE_CNTRSVR )
        !            91:     lpContainerDoc->m_lpTopIPFrame          =
        !            92:                     (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceFrame;
        !            93:     lpContainerDoc->m_lpTopIPDoc            =
        !            94:                     (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc;
        !            95:     lpContainerDoc->m_hSharedMenu           = NULL;
        !            96:     lpContainerDoc->m_hOleMenu              = NULL;
        !            97: 
        !            98: #endif  // INPLACE_CNTRSVR
        !            99: #endif  // INPLACE_CNTR
        !           100: 
        !           101:     INIT_INTERFACEIMPL(
        !           102:             &lpContainerDoc->m_OleUILinkContainer,
        !           103:             &g_CntrDoc_OleUILinkContainerVtbl,
        !           104:             lpContainerDoc
        !           105:     );
        !           106: 
        !           107:     return TRUE;
        !           108: }
        !           109: 
        !           110: 
        !           111: /* ContainerDoc_GetNextLink
        !           112:  * ------------------------
        !           113:  *
        !           114:  *  Update all links in the document. A dialog box will be popped up showing
        !           115:  *     the progress of the update and allow the user to quit by pushing the
        !           116:  *  stop button
        !           117:  */
        !           118: LPCONTAINERLINE ContainerDoc_GetNextLink(
        !           119:                LPCONTAINERDOC lpContainerDoc, 
        !           120:                LPCONTAINERLINE lpContainerLine
        !           121: )
        !           122: {
        !           123:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           124:     DWORD dwNextLink = 0;
        !           125:     LPLINE lpLine;
        !           126:     static int nIndex = 0;
        !           127:        
        !           128:        if (lpContainerLine==NULL)
        !           129:                nIndex = 0;
        !           130: 
        !           131:     for ( ; nIndex < lpLL->m_nNumLines; nIndex++) {
        !           132:         lpLine = LineList_GetLine(lpLL, nIndex);
        !           133: 
        !           134:         if (lpLine
        !           135:             && (Line_GetLineType(lpLine) == CONTAINERLINETYPE)
        !           136:             && ContainerLine_IsOleLink((LPCONTAINERLINE)lpLine)) {
        !           137:                        
        !           138:                        nIndex++;
        !           139:                        return (LPCONTAINERLINE)lpLine;
        !           140:                }
        !           141:        }
        !           142: 
        !           143:     return NULL;
        !           144: }
        !           145: 
        !           146: 
        !           147: 
        !           148: /* ContainerDoc_UpdateLinks
        !           149:  * ------------------------
        !           150:  *
        !           151:  *  Update all links in the document. A dialog box will be popped up showing
        !           152:  *     the progress of the update and allow the user to quit by pushing the
        !           153:  *  stop button
        !           154:  */
        !           155: void ContainerDoc_UpdateLinks(LPCONTAINERDOC lpContainerDoc)
        !           156: {
        !           157:        int                             cLinks;
        !           158:        HWND                    hwndDoc = ((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;
        !           159:        HCURSOR                 hCursor;
        !           160:        LPCONTAINERLINE lpContainerLine = NULL;
        !           161:        HRESULT                 hrErr;
        !           162:        DWORD                   dwUpdateOpt;
        !           163:        
        !           164:        hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
        !           165:        
        !           166:        /* get total number of automatic links */
        !           167:        cLinks = 0;
        !           168:        while (lpContainerLine = ContainerDoc_GetNextLink(
        !           169:                                                                        lpContainerDoc, 
        !           170:                                                                        lpContainerLine)) {
        !           171:                hrErr = CntrDoc_LinkCont_GetLinkUpdateOptions(
        !           172:                                (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer,
        !           173:                                (DWORD)lpContainerLine,
        !           174:                                (LPDWORD)&dwUpdateOpt
        !           175:                );
        !           176:                if (hrErr == NOERROR) {
        !           177:                        if (dwUpdateOpt==OLEUPDATE_ALWAYS)
        !           178:                                cLinks++;
        !           179:                }
        !           180:                else
        !           181:                        OleDbgOutHResult("IOleUILinkContainer::GetLinkUpdateOptions returned",hrErr);
        !           182:                
        !           183:        }
        !           184:        
        !           185:     SetCursor(hCursor);
        !           186:        
        !           187:        if ((cLinks > 0) && !OleUIUpdateLinks(
        !           188:                        (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer, 
        !           189:                        hwndDoc, 
        !           190:                        (LPSTR)APPNAME, 
        !           191:                        cLinks)) {
        !           192:                if (ID_PU_LINKS == OleUIPromptUser(
        !           193:                                IDD_CANNOTUPDATELINK, 
        !           194:                                hwndDoc,
        !           195:                                (LPSTR)APPNAME)) {
        !           196:                        ContainerDoc_EditLinksCommand(lpContainerDoc);
        !           197:                }
        !           198:        }
        !           199: }
        !           200: 
        !           201:        
        !           202: 
        !           203: /* ContainerDoc_SetShowObjectFlag
        !           204:  * ------------------------------
        !           205:  *
        !           206:  *  Set/Clear the ShowObject flag of ContainerDoc
        !           207:  */
        !           208: void ContainerDoc_SetShowObjectFlag(LPCONTAINERDOC lpContainerDoc, BOOL fShow)
        !           209: {
        !           210:     if (!lpContainerDoc)
        !           211:         return;
        !           212: 
        !           213:     lpContainerDoc->m_fShowObject = fShow;
        !           214: }
        !           215: 
        !           216: 
        !           217: /* ContainerDoc_GetShowObjectFlag
        !           218:  * ------------------------------
        !           219:  *
        !           220:  *  Get the ShowObject flag of ContainerDoc
        !           221:  */
        !           222: BOOL ContainerDoc_GetShowObjectFlag(LPCONTAINERDOC lpContainerDoc)
        !           223: {
        !           224:     if (!lpContainerDoc)
        !           225:         return FALSE;
        !           226: 
        !           227:     return lpContainerDoc->m_fShowObject;
        !           228: }
        !           229: 
        !           230: 
        !           231: /* ContainerDoc_InsertOleObjectCommand
        !           232:  * -----------------------------------
        !           233:  *
        !           234:  * Insert a new OLE object in the ContainerDoc.
        !           235:  */
        !           236: void ContainerDoc_InsertOleObjectCommand(LPCONTAINERDOC lpContainerDoc)
        !           237: {
        !           238:     LPLINELIST              lpLL =&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           239:     LPLINE                  lpLine = NULL;
        !           240:     HDC                     hDC;
        !           241:     int                     nTab = 0;
        !           242:     int                     nIndex = LineList_GetFocusLineIndex(lpLL);
        !           243:     LPCONTAINERLINE         lpContainerLine=NULL;
        !           244:     char                    szStgName[CWCSTORAGENAME];
        !           245:     UINT                    uRet;
        !           246:     OLEUIINSERTOBJECT       io;
        !           247:     char                    szFile[OLEUI_CCHPATHMAX];
        !           248:     DWORD                   dwOleCreateType;
        !           249:     BOOL                    fDisplayAsIcon;
        !           250:     HCURSOR                 hPrevCursor;
        !           251: 
        !           252:     //String initially NULL.
        !           253:     _fmemset((LPSTR)szFile, 0, OLEUI_CCHPATHMAX);
        !           254: 
        !           255:     _fmemset((LPOLEUIINSERTOBJECT)&io, 0, sizeof(io));
        !           256:     io.cbStruct=sizeof(io);
        !           257:     io.dwFlags=IOF_SELECTCREATENEW | IOF_SHOWHELP;
        !           258:     io.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;
        !           259: 
        !           260:     io.lpszFile=(LPSTR)szFile;
        !           261:     io.cchFile=sizeof(szFile);
        !           262: 
        !           263:     OLEDBG_BEGIN3("OleUIInsertObject called\r\n")
        !           264:     uRet=OleUIInsertObject((LPOLEUIINSERTOBJECT)&io);
        !           265:     OLEDBG_END3
        !           266: 
        !           267:     if (OLEUI_OK != uRet)
        !           268:         return;     // user canceled dialog
        !           269: 
        !           270:     // this may take a while, put up hourglass cursor
        !           271:     hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
        !           272: 
        !           273:     fDisplayAsIcon = (io.dwFlags & IOF_CHECKDISPLAYASICON ? TRUE : FALSE);
        !           274: 
        !           275:     // make up a storage name for the OLE object
        !           276:     ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName));
        !           277: 
        !           278:     /* default the new line to have the same indent as previous line */
        !           279:     lpLine = LineList_GetLine(lpLL, nIndex);
        !           280:     if (lpLine)
        !           281:         nTab = Line_GetTabLevel(lpLine);
        !           282: 
        !           283:     hDC = LineList_GetDC(lpLL);
        !           284: 
        !           285:     //Only try to create new objects IF Create New was selected
        !           286:     if ((io.dwFlags & IOF_SELECTCREATENEW))
        !           287:         dwOleCreateType = IOF_SELECTCREATENEW;
        !           288:     else
        !           289:         {
        !           290:         if ((io.dwFlags & IOF_SELECTCREATEFROMFILE))
        !           291:             dwOleCreateType = IOF_SELECTCREATEFROMFILE;
        !           292: 
        !           293:         if ((io.dwFlags & IOF_CHECKLINK))
        !           294:             dwOleCreateType = IOF_CHECKLINK;
        !           295:         }
        !           296: 
        !           297:     lpContainerLine = ContainerLine_Create(
        !           298:             dwOleCreateType,
        !           299:             hDC,
        !           300:             nTab,
        !           301:             lpContainerDoc,
        !           302:             &io.clsid,
        !           303:             (LPSTR)szFile,
        !           304:             fDisplayAsIcon,
        !           305:             io.hMetaPict,
        !           306:             szStgName
        !           307:     );
        !           308: 
        !           309:     if (!lpContainerLine)
        !           310:         goto error;         // creation of OLE object FAILED
        !           311: 
        !           312:     if (io.hMetaPict) {
        !           313:         OleUIMetafilePictIconFree(io.hMetaPict);    // clean up metafile
        !           314:     }
        !           315: 
        !           316:     /* add a ContainerLine object to the document's LineList. The
        !           317:     **    ContainerLine manages the rectangle on the screen occupied by
        !           318:     **    the OLE object. later when the app is updated to support
        !           319:     **    extended layout, there could be more than one Line associated
        !           320:     **    with the OLE object.
        !           321:     */
        !           322: 
        !           323:     LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex);
        !           324: 
        !           325:     /* before calling DoVerb(OLEIVERB_SHOW), check to see if the object
        !           326:     **    has any initial extents.
        !           327:     */
        !           328:     ContainerLine_UpdateExtent(lpContainerLine, NULL);
        !           329: 
        !           330:     /* If a new embedded object was created, tell the object server to
        !           331:     **    make itself visible (show itself).
        !           332:     */
        !           333:     if (dwOleCreateType == IOF_SELECTCREATENEW) {
        !           334:         if (! ContainerLine_DoVerb(lpContainerLine, OLEIVERB_SHOW, TRUE, 
        !           335:                                TRUE)) {
        !           336:             OutlineApp_ErrorMessage(g_lpApp, ErrMsgShowObj);
        !           337:         }
        !           338: 
        !           339:         /* OLE2NOTE: we will immediately force a save of the object
        !           340:         **    to guarantee that a valid initial object is saved
        !           341:         **    with our document. if the object is a OLE 1.0 object,
        !           342:         **    then it may exit without update. by forcing this
        !           343:         **    initial save we consistently always have a valid
        !           344:         **    object even if it is a OLE 1.0 object that exited
        !           345:         **    without saving. if we did NOT do this save here, then
        !           346:         **    we would have to worry about deleting the object if
        !           347:         **    it was a OLE 1.0 object that closed without saving.
        !           348:         **    the OLE 2.0 User Model dictates that the object
        !           349:         **    should always be valid after CreateNew performed. the
        !           350:         **    user must explicitly delete it.
        !           351:         */
        !           352:         ContainerLine_SaveOleObject(
        !           353:                 lpContainerLine, 
        !           354:                 lpContainerLine->m_lpStg, 
        !           355:                 TRUE,  /* fSameAsLoad */
        !           356:                 TRUE,  /* fRemember */
        !           357:                 TRUE   /* fForceUpdate */
        !           358:                );
        !           359:     }
        !           360: 
        !           361:     OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE);
        !           362: 
        !           363:     LineList_ReleaseDC(lpLL, hDC);
        !           364: 
        !           365:     SetCursor(hPrevCursor);     // restore original cursor
        !           366: 
        !           367:     return;
        !           368: 
        !           369: error:
        !           370:     // NOTE: if ContainerLine_Create failed
        !           371:     LineList_ReleaseDC(lpLL, hDC);
        !           372: 
        !           373:     if (OLEUI_OK == uRet && io.hMetaPict)
        !           374:         OleUIMetafilePictIconFree(io.hMetaPict);    // clean up metafile
        !           375: 
        !           376:     SetCursor(hPrevCursor);     // restore original cursor
        !           377:     OutlineApp_ErrorMessage(g_lpApp, ErrMsgInsertObj);
        !           378: }
        !           379: 
        !           380: 
        !           381: 
        !           382: void ContainerDoc_EditLinksCommand(LPCONTAINERDOC lpContainerDoc)
        !           383: {
        !           384:     UINT        uRet;
        !           385:     OLEUIEDITLINKS      el;
        !           386:     LPCONTAINERLINE lpContainerLine = NULL;
        !           387:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           388: 
        !           389:     _fmemset((LPOLEUIEDITLINKS)&el,0,sizeof(el));
        !           390:     el.cbStruct=sizeof(el);
        !           391:     el.dwFlags=ELF_SHOWHELP;  //what else?
        !           392:     el.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;
        !           393:     el.lpOleUILinkContainer =
        !           394:             (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer;
        !           395: 
        !           396:     OLEDBG_BEGIN3("OleUIEditLinks called\r\n")
        !           397:     uRet=OleUIEditLinks((LPOLEUIEDITLINKS)&el);
        !           398:     OLEDBG_END3
        !           399: 
        !           400:     OleDbgAssert((uRet==1) || (uRet==OLEUI_CANCEL));
        !           401: 
        !           402: }
        !           403: 
        !           404: 
        !           405: /* Convert command - brings up the "Convert" dialog
        !           406:  */
        !           407: void ContainerDoc_ConvertCommand(
        !           408:         LPCONTAINERDOC      lpContainerDoc, 
        !           409:         BOOL                fServerNotRegistered
        !           410: )
        !           411: {
        !           412:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
        !           413:     OLEUICONVERT ct;
        !           414:     UINT         uRet;
        !           415:     LPDATAOBJECT  lpDataObj;
        !           416:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           417:     LPCONTAINERLINE lpContainerLine = NULL;
        !           418:     BOOL         fSelIsOleObject;
        !           419:     int          nIndex;
        !           420:     STGMEDIUM    medium;
        !           421:     LPSTR        lpErrMsg = NULL;
        !           422:     HRESULT      hrErr;
        !           423:     HCURSOR      hPrevCursor;
        !           424:        BOOL             fRunServer=FALSE;
        !           425:     BOOL         fMustRun = FALSE;
        !           426:     BOOL         fObjConverted = FALSE;
        !           427:     BOOL         fDisplayChanged = FALSE;
        !           428:     BOOL         fHaveCLSID = FALSE;
        !           429:     BOOL         fHaveFmtUserType = FALSE;
        !           430:     char         szUserType[128];
        !           431:     BOOL         fMustActivate;
        !           432: 
        !           433:     /* OLE2NOTE: if we came to the Convert dialog because the user
        !           434:     **    activated a non-registered object, then we should activate
        !           435:     **    the object after the user has converted it or setup an
        !           436:     **    ActivateAs server.
        !           437:     */
        !           438:     fMustActivate = fServerNotRegistered;
        !           439: 
        !           440:     _fmemset((LPOLEUICONVERT)&ct,0,sizeof(ct));
        !           441: 
        !           442:     fSelIsOleObject = ContainerDoc_IsSelAnOleObject(
        !           443:             (LPCONTAINERDOC)lpContainerDoc,
        !           444:             &IID_IDataObject,
        !           445:             (LPUNKNOWN FAR*)&lpDataObj,
        !           446:             &nIndex,
        !           447:             (LPCONTAINERLINE FAR*)&lpContainerLine
        !           448:     );
        !           449: 
        !           450:     lpErrMsg = ErrMsgCantConvert;
        !           451: 
        !           452:     if (! fSelIsOleObject) 
        !           453:         goto error;     // can NOT do Convert.
        !           454: 
        !           455:     if (! lpContainerLine) {
        !           456:         OleStdRelease((LPUNKNOWN)lpDataObj);
        !           457:         goto error;     // can NOT do Convert.
        !           458:     }
        !           459: 
        !           460:     ct.cbStruct  = sizeof(OLEUICONVERT);
        !           461:     ct.dwFlags   = CF_SHOWHELPBUTTON;
        !           462:     ct.hWndOwner = lpContainerDoc->m_OleDoc.m_OutlineDoc.m_hWndDoc;
        !           463:     ct.lpszCaption = (LPSTR)NULL;
        !           464:     ct.lpfnHook  = NULL;
        !           465:     ct.lCustData = 0;
        !           466:     ct.hInstance = NULL;
        !           467:     ct.lpszTemplate = NULL;
        !           468:     ct.hResource = 0;
        !           469:     ct.fIsLinkedObject = ContainerLine_IsOleLink(lpContainerLine);
        !           470:     ct.dvAspect = lpContainerLine->m_dwDrawAspect;
        !           471: 
        !           472:     if (! ct.fIsLinkedObject) {
        !           473:         /* OLE2NOTE: the object is an embedded object. we should first
        !           474:         **    attempt to read the actual object CLSID, file data
        !           475:         **    format, and full user type name that is written inside of
        !           476:         **    the object's storage as this should be the most
        !           477:         **    definitive information. if this fails we will ask the
        !           478:         **    object what its class is and attempt to get the rest of
        !           479:         **    the information out of the REGDB.
        !           480:         */
        !           481:         hrErr=ReadClassStg(lpContainerLine->m_lpStg,(CLSID FAR*)&(ct.clsid));
        !           482:         if (hrErr == NOERROR) 
        !           483:             fHaveCLSID = TRUE;
        !           484:         else {
        !           485:             OleDbgOutHResult("ReadClassStg returned", hrErr);
        !           486:         }
        !           487:         hrErr = ReadFmtUserTypeStg(
        !           488:                 lpContainerLine->m_lpStg, 
        !           489:                 (CLIPFORMAT FAR*)&ct.wFormat, 
        !           490:                 (LPSTR FAR*)&ct.lpszUserType);
        !           491:         if (hrErr == NOERROR) 
        !           492:             fHaveFmtUserType = TRUE;
        !           493:         else {
        !           494:             OleDbgOutHResult("ReadFmtUserTypeStg returned", hrErr);
        !           495:         }
        !           496:     }
        !           497: 
        !           498:     if (! fHaveCLSID) {
        !           499:         hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(
        !           500:                 lpContainerLine->m_lpOleObj,
        !           501:                 (CLSID FAR*)&ct.clsid
        !           502:         );
        !           503:         if (hrErr != NOERROR) 
        !           504:             ct.clsid = CLSID_NULL;
        !           505:     }
        !           506:     if (! fHaveFmtUserType) {
        !           507:         ct.wFormat = 0;
        !           508:         if (OleStdGetUserTypeOfClass(
        !           509:                 (CLSID FAR*)&ct.clsid,szUserType,sizeof(szUserType),NULL)) {
        !           510:             ct.lpszUserType = OleStdCopyString(szUserType, NULL);
        !           511:         } else {
        !           512:             ct.lpszUserType = NULL;
        !           513:         }
        !           514:     }
        !           515: 
        !           516:     if (lpContainerLine->m_dwDrawAspect == DVASPECT_ICON) {
        !           517:         ct.hMetaPict = OleStdGetData(
        !           518:                 lpDataObj,
        !           519:                 CF_METAFILEPICT,
        !           520:                 NULL,
        !           521:                 DVASPECT_ICON,
        !           522:                 (LPSTGMEDIUM)&medium
        !           523:         );
        !           524:     } else {
        !           525:         ct.hMetaPict = NULL;
        !           526:     }
        !           527:     OleStdRelease((LPUNKNOWN)lpDataObj);
        !           528: 
        !           529:     OLEDBG_BEGIN3("OleUIConvert called\r\n")
        !           530:     uRet = OleUIConvert(&ct);
        !           531:     OLEDBG_END3
        !           532: 
        !           533:     // this may take a while, put up hourglass cursor
        !           534:     hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
        !           535: 
        !           536:     if (uRet == OLEUI_OK) {
        !           537: 
        !           538:         /*****************************************************************
        !           539:         **  OLE2NOTE: the convert dialog actually allows the user to
        !           540:         **    change two orthogonal properties of the object: the
        !           541:         **    object's type/server and the object's display aspect.
        !           542:         **    first we will execute the ConvertTo/ActivateAs action and
        !           543:         **    then we will deal with any display aspect change. we want
        !           544:         **    to be careful to only call IOleObject::Update once
        !           545:         **    because this is an expensive operation; it results in
        !           546:         **    launching the object's server.
        !           547:         *****************************************************************/
        !           548: 
        !           549:         if (ct.dwFlags & CF_SELECTCONVERTTO &&
        !           550:                 ! IsEqualCLSID(&ct.clsid, &ct.clsidNew)) {
        !           551: 
        !           552:             /* user selected CONVERT.
        !           553:             **
        !           554:             ** OLE2NOTE: to achieve the "Convert To" at this point we
        !           555:             **    need to take the following steps:
        !           556:             **    1. unload the object.
        !           557:             **    2. write the NEW CLSID and NEW user type name
        !           558:             **       string into the storage of the object,
        !           559:             **       BUT write the OLD format tag.
        !           560:             **    3. force an update to force the actual conversion of
        !           561:             **       the data bits.
        !           562:             */
        !           563:             lpErrMsg = ErrMsgConvertObj; // setup correct msg in case of error
        !           564: 
        !           565:             ContainerLine_UnloadOleObject(lpContainerLine);
        !           566: 
        !           567:             OLEDBG_BEGIN2("OleStdDoConvert called \r\n")
        !           568:             hrErr = OleStdDoConvert(
        !           569:                     lpContainerLine->m_lpStg, (REFCLSID)&ct.clsidNew);
        !           570:             OLEDBG_END2
        !           571:             if (hrErr != NOERROR) 
        !           572:                 goto error;
        !           573: 
        !           574:             // Reload the object
        !           575:             ContainerLine_LoadOleObject(lpContainerLine);
        !           576:             
        !           577:             /* we need to force the object to run to complete the
        !           578:             **    conversion. set flag to force OleRun to be called at 
        !           579:             **    end of function. 
        !           580:             */
        !           581:             fMustRun = TRUE;
        !           582:             fObjConverted = TRUE;
        !           583: 
        !           584:         } else if (ct.dwFlags & CF_SELECTACTIVATEAS) {
        !           585:             /* user selected ACTIVATE AS.
        !           586:             **
        !           587:             ** OLE2NOTE: to achieve the "Activate As" at this point we
        !           588:             **    need to take the following steps:
        !           589:             **    1. unload ALL objects of the OLD class that app knows about
        !           590:             **    2. add the TreatAs tag in the registration database
        !           591:             **    by calling CoTreatAsClass().
        !           592:             **    3. lazily it can reload the objects; when the objects
        !           593:             **    are reloaded the TreatAs will take effect.
        !           594:             */
        !           595:             lpErrMsg = ErrMsgActivateAsObj; // setup msg in case of error
        !           596: 
        !           597:             ContainerDoc_UnloadAllOleObjectsOfClass(
        !           598:                     lpContainerDoc, (REFCLSID)&ct.clsid);
        !           599: 
        !           600:             OLEDBG_BEGIN2("OleStdDoTreatAsClass called \r\n")
        !           601:                        hrErr = OleStdDoTreatAsClass(ct.lpszUserType, (REFCLSID)&ct.clsid,
        !           602:                                        (REFCLSID)&ct.clsidNew);
        !           603:             OLEDBG_END2
        !           604: 
        !           605:             // Reload the object
        !           606:             ContainerLine_LoadOleObject(lpContainerLine);
        !           607: 
        !           608:             fMustActivate = TRUE;   // we should activate this object
        !           609:         }
        !           610:         
        !           611:         /*****************************************************************
        !           612:         **  OLE2NOTE: now we will try to change the display if
        !           613:         **    necessary. 
        !           614:         *****************************************************************/
        !           615: 
        !           616:         if (lpContainerLine->m_lpOleObj && 
        !           617:                 ct.dvAspect != lpContainerLine->m_dwDrawAspect) {
        !           618:             /* user has selected to change display aspect between icon
        !           619:             **    aspect and content aspect.
        !           620:             **    
        !           621:             ** OLE2NOTE: if we got here because the server was not
        !           622:             **    registered, then we will NOT delete the object's
        !           623:             **    original display aspect. because we do not have the
        !           624:             **    original server, we can NEVER get it back. this is a
        !           625:             **    safety precaution.
        !           626:             */
        !           627:             
        !           628:             hrErr = OleStdSwitchDisplayAspect(
        !           629:                     lpContainerLine->m_lpOleObj,
        !           630:                     &lpContainerLine->m_dwDrawAspect,
        !           631:                     ct.dvAspect,
        !           632:                     ct.hMetaPict,
        !           633:                     !fServerNotRegistered,   /* fDeleteOldAspect */
        !           634:                     TRUE,                    /* fSetupViewAdvise */
        !           635:                     (LPADVISESINK)&lpContainerLine->m_AdviseSink,
        !           636:                     (BOOL FAR*)&fMustRun
        !           637:             );
        !           638: 
        !           639:             if (hrErr == NOERROR) 
        !           640:                 fDisplayChanged = TRUE;
        !           641: 
        !           642: #if defined( INPLACE_CNTR )
        !           643:                 ContainerDoc_UpdateInPlaceObjectRects(
        !           644:                         lpContainerLine->m_lpDoc, nIndex);
        !           645: #endif
        !           646:             
        !           647:         } else if (ct.dvAspect == DVASPECT_ICON && ct.fObjectsIconChanged) {
        !           648:             hrErr = OleStdSetIconInCache(
        !           649:                     lpContainerLine->m_lpOleObj,
        !           650:                     ct.hMetaPict
        !           651:             );
        !           652: 
        !           653:             if (hrErr == NOERROR) 
        !           654:                 fDisplayChanged = TRUE;
        !           655:         }
        !           656: 
        !           657:                /* we deliberately run the object so that the update won't shut
        !           658:                ** the server down. 
        !           659:                */
        !           660:                if ((fMustActivate || fMustRun) 
        !           661:                 && !OleIsRunning(lpContainerLine->m_lpOleObj)) {
        !           662:                        ContainerLine_RunOleObject(lpContainerLine);
        !           663:                        fRunServer = TRUE;
        !           664:                }
        !           665: 
        !           666:         if (fDisplayChanged) {
        !           667:             /* the Object's display was changed, force a repaint of
        !           668:             **    the line. note the extents of the object may have
        !           669:             **    changed.
        !           670:             */
        !           671:             ContainerLine_UpdateExtent(lpContainerLine, NULL);
        !           672:             LineList_ForceLineRedraw(lpLL, nIndex, TRUE);
        !           673:         }
        !           674:         
        !           675:         if (fDisplayChanged || fObjConverted) {
        !           676:             /* mark ContainerDoc as now dirty. if display changed, then
        !           677:             **    the extents of the object may have changed.
        !           678:             */
        !           679:             OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fDisplayChanged);
        !           680:         }
        !           681:                
        !           682:                if (fMustActivate)
        !           683:                        ContainerLine_DoVerb(lpContainerLine, OLEIVERB_SHOW, FALSE,FALSE);
        !           684:         else if (fRunServer) {
        !           685:             /* if we launched the server in order to get an update of
        !           686:             **    the presentation, then we must shut the server down
        !           687:             */
        !           688:             ContainerLine_CloseOleObject(lpContainerLine);
        !           689:         }
        !           690:     }
        !           691: 
        !           692: 
        !           693:     if (ct.hMetaPict)
        !           694:         OleUIMetafilePictIconFree(ct.hMetaPict);    // clean up metafile
        !           695: 
        !           696:     SetCursor(hPrevCursor);     // restore original cursor
        !           697: 
        !           698:     return;
        !           699: 
        !           700: error:
        !           701:        if (fRunServer)
        !           702:                ContainerLine_CloseOleObject(lpContainerLine);
        !           703: 
        !           704:     if (ct.lpszUserType)
        !           705:         OleStdFreeString(ct.lpszUserType, NULL);
        !           706: 
        !           707:     if (ct.hMetaPict)
        !           708:         OleUIMetafilePictIconFree(ct.hMetaPict);    // clean up metafile
        !           709: 
        !           710:     SetCursor(hPrevCursor);     // restore original cursor
        !           711:     if (lpErrMsg) 
        !           712:         OutlineApp_ErrorMessage(g_lpApp, lpErrMsg);
        !           713:        
        !           714: }
        !           715: 
        !           716: 
        !           717: /* ContainerDoc_CloseAllOleObjects
        !           718: ** -------------------------------
        !           719: **    Close all OLE objects. This forces all OLE objects to transition
        !           720: **    from the running state to the loaded state.
        !           721: **
        !           722: **    Returns TRUE if all objects closed successfully  
        !           723: **            FALSE if any object could not be closed.
        !           724: */
        !           725: BOOL ContainerDoc_CloseAllOleObjects(LPCONTAINERDOC lpContainerDoc)
        !           726: {
        !           727:     LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           728:     int         i;
        !           729:     LPLINE      lpLine;
        !           730:     BOOL        fStatus = TRUE;
        !           731: 
        !           732:     for (i = 0; i < lpLL->m_nNumLines; i++) {
        !           733:         lpLine=LineList_GetLine(lpLL, i);
        !           734: 
        !           735:         if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE))
        !           736:             if (! ContainerLine_CloseOleObject((LPCONTAINERLINE)lpLine))
        !           737:                 fStatus = FALSE;
        !           738:     }
        !           739:     
        !           740:     return fStatus;
        !           741: }
        !           742: 
        !           743: 
        !           744: /* ContainerDoc_UnloadAllOleObjectsOfClass
        !           745: ** ---------------------------------------
        !           746: **    Unload all OLE objects of a particular class. this is necessary
        !           747: **    when a class level "ActivateAs" (aka. TreatAs) is setup. the user
        !           748: **    can do this with the Convert dialog. for the TreatAs to take
        !           749: **    effect, all objects of the class have to loaded and reloaded.
        !           750: */
        !           751: void ContainerDoc_UnloadAllOleObjectsOfClass(
        !           752:         LPCONTAINERDOC      lpContainerDoc,
        !           753:         REFCLSID            rClsid
        !           754: )
        !           755: {
        !           756:     LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           757:     int         i;
        !           758:     LPLINE      lpLine;
        !           759:     CLSID       clsid;
        !           760:     HRESULT     hrErr;
        !           761: 
        !           762:     for (i = 0; i < lpLL->m_nNumLines; i++) {
        !           763:         lpLine=LineList_GetLine(lpLL, i);
        !           764: 
        !           765:         if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
        !           766:             LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
        !           767:             
        !           768:             if (! lpContainerLine->m_lpOleObj) 
        !           769:                 continue;       // this object is NOT loaded
        !           770: 
        !           771:             hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(
        !           772:                     lpContainerLine->m_lpOleObj,
        !           773:                     (CLSID FAR*)&clsid
        !           774:             );
        !           775:             if (hrErr == NOERROR && 
        !           776:                     ( IsEqualCLSID((CLSID FAR*)&clsid,rClsid) 
        !           777:                       || IsEqualCLSID(rClsid,&CLSID_NULL) ) ) {
        !           778:                 ContainerLine_UnloadOleObject(lpContainerLine);
        !           779:             }
        !           780:         }
        !           781:     }
        !           782: }
        !           783: 
        !           784: 
        !           785: /* ContainerDoc_UpdateExtentOfAllOleObjects
        !           786: ** ----------------------------------------
        !           787: **    Update the extents of any OLE object that is marked that its size
        !           788: **    may  have changed. when an IAdviseSink::OnViewChange notification
        !           789: **    is received, the corresponding ContainerLine is marked
        !           790: **    (m_fDoGetExtent==TRUE) and a message (WM_U_UPDATEOBJECTEXTENT) is
        !           791: **    posted to the document indicating that there are dirty objects.
        !           792: **    when this message is received, this function is called.
        !           793: */
        !           794: void ContainerDoc_UpdateExtentOfAllOleObjects(LPCONTAINERDOC lpContainerDoc)
        !           795: {
        !           796:     LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           797:     int         i;
        !           798:     LPLINE      lpLine;
        !           799:     BOOL        fStatus = TRUE;
        !           800: 
        !           801:     for (i = 0; i < lpLL->m_nNumLines; i++) {
        !           802:         lpLine=LineList_GetLine(lpLL, i);
        !           803: 
        !           804:         if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
        !           805:             LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
        !           806:             
        !           807:             if (lpContainerLine->m_fDoGetExtent)
        !           808:                                ContainerLine_UpdateExtent(lpContainerLine, NULL);
        !           809:         }
        !           810:     }
        !           811: }
        !           812: 
        !           813: 
        !           814: BOOL ContainerDoc_SaveToFile(
        !           815:         LPCONTAINERDOC          lpContainerDoc,
        !           816:         LPCSTR                  lpszFileName,
        !           817:         UINT                    uFormat,
        !           818:         BOOL                    fRemember
        !           819: )
        !           820: {
        !           821:     LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
        !           822:     LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
        !           823:     LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
        !           824:     LPSTORAGE lpDestStg;
        !           825:     BOOL fStatus;
        !           826:     BOOL fMustRelDestStg = FALSE;
        !           827:     HRESULT hrErr;
        !           828: 
        !           829:     if (fRemember) {
        !           830:         if (lpszFileName) {
        !           831:             fStatus = OutlineDoc_SetFileName(
        !           832:                     lpOutlineDoc, (LPSTR)lpszFileName, NULL);
        !           833:             if (! fStatus) goto error;
        !           834:         }
        !           835: 
        !           836:         /* The ContainerDoc keeps its storage open at all times. it is not
        !           837:         **    necessary to reopen the file.
        !           838:         ** if SaveAs is pending, then lpNewStg is the new destination for
        !           839:         **    the save operation, else the existing storage is the dest.
        !           840:         */
        !           841:         lpDestStg = (lpContainerDoc->m_lpNewStg ?
        !           842:                         lpContainerDoc->m_lpNewStg : lpContainerDoc->m_lpStg);
        !           843:     } else {
        !           844:         if (! lpszFileName)
        !           845:             goto error;
        !           846: 
        !           847:         /* OLE2NOTE: since we are preforming a SaveCopyAs operation, we
        !           848:         **    do not need to have the DocFile open in STGM_TRANSACTED mode.
        !           849:         **    there is less overhead to use STGM_DIRECT mode.
        !           850:         */
        !           851:         hrErr = StgCreateDocfile(
        !           852:                 lpszFileName,
        !           853:                 STGM_READWRITE|STGM_DIRECT|STGM_SHARE_DENY_WRITE|STGM_CREATE,
        !           854:                 0,
        !           855:                 &lpDestStg
        !           856:         );
        !           857:         if (! OleDbgVerifySz(hrErr == NOERROR, "Could not create Docfile"))
        !           858:             goto error;
        !           859:         fMustRelDestStg = TRUE;
        !           860:     }
        !           861: 
        !           862:     /*  OLE2NOTE: we must be sure to write our class ID into our
        !           863:     **    storage. this information is used by OLE to determine the
        !           864:     **    class of the data stored in our storage. Even for top
        !           865:     **    "file-level" objects this information should be written to
        !           866:     **    the file.
        !           867:     */
        !           868:     hrErr = WriteClassStg(lpDestStg, &CLSID_APP);
        !           869:     if(hrErr != NOERROR) goto error;
        !           870: 
        !           871:     fStatus = OutlineDoc_SaveSelToStg(
        !           872:             lpOutlineDoc,
        !           873:             NULL,           // save all lines
        !           874:             uFormat,
        !           875:             lpDestStg,
        !           876:             TRUE            // remember this stg
        !           877:         );
        !           878: 
        !           879:     if (fStatus)
        !           880:         fStatus = OleStdCommitStorage(lpDestStg);
        !           881: 
        !           882:     if (fRemember) {
        !           883:         /* if SaveAs was pending, then release the old storage and remember
        !           884:         **    the new storage as the active current storage. all data from
        !           885:         **    the old storage has been copied into the new storage.
        !           886:         */
        !           887:         if (lpContainerDoc->m_lpNewStg) {
        !           888:             OleStdRelease((LPUNKNOWN)lpContainerDoc->m_lpStg);  // free old stg
        !           889:             lpContainerDoc->m_lpStg = lpContainerDoc->m_lpNewStg;   // save new stg
        !           890:             lpContainerDoc->m_lpNewStg = NULL;
        !           891:         }
        !           892:         if (! fStatus) goto error;
        !           893: 
        !           894:         OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);
        !           895: 
        !           896:         /* OLE2NOTE: we must note the time this File-Based object has
        !           897:         **    been saved in the RunningObjectTable. this is necessary
        !           898:         **    for Container applications which support linking to
        !           899:         **    embedded objects. These change times are used as the
        !           900:         **    basis for IOleObject::IsUpToDate.  It is important to set
        !           901:         **    the time of the file-based object following a save
        !           902:         **    operation to exactly the time of the saved file. this
        !           903:         **    helps IOleObject::IsUpToDate to give the correct answer
        !           904:         **    after a file has been saved. 
        !           905:         */
        !           906:         OleStdNoteFileChangeTime(
        !           907:                 lpOutlineDoc->m_szFileName, lpOleDoc->m_dwRegROT);
        !           908:     }
        !           909: 
        !           910:     if (fMustRelDestStg)
        !           911:         OleStdRelease((LPUNKNOWN)lpDestStg);
        !           912:     return TRUE;
        !           913: 
        !           914: error:
        !           915:     if (fMustRelDestStg)
        !           916:         OleStdRelease((LPUNKNOWN)lpDestStg);
        !           917:     OutlineApp_ErrorMessage(g_lpApp, ErrMsgSaving);
        !           918:     return FALSE;
        !           919: }
        !           920: 
        !           921: 
        !           922: /* ContainerDoc_ContainerLineDoVerbCommand
        !           923: ** ---------------------------------------
        !           924: **    Execute a verb of the OLE object in the current focus line.
        !           925: */
        !           926: void ContainerDoc_ContainerLineDoVerbCommand(
        !           927:         LPCONTAINERDOC          lpContainerDoc,
        !           928:         LONG                    iVerb
        !           929: )
        !           930: {
        !           931:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           932:     int nIndex = LineList_GetFocusLineIndex(lpLL);
        !           933:     LPLINE lpLine = LineList_GetLine(lpLL, nIndex);
        !           934:     HCURSOR                 hPrevCursor;
        !           935: 
        !           936:     if (! lpLine || (Line_GetLineType(lpLine) != CONTAINERLINETYPE) ) return;
        !           937: 
        !           938:     // this may take a while, put up hourglass cursor
        !           939:     hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
        !           940: 
        !           941:     ContainerLine_DoVerb((LPCONTAINERLINE) lpLine, iVerb, TRUE, TRUE);
        !           942: 
        !           943:     SetCursor(hPrevCursor);     // restore original cursor
        !           944: }
        !           945: 
        !           946: 
        !           947: /* ContainerDoc_GetNextStgName
        !           948: ** ---------------------------
        !           949: **    Generate the next unused name for a sub-storage to be used by an
        !           950: **    OLE object. The ContainerDoc keeps a counter. The storages for
        !           951: **    OLE objects are simply numbered (eg. Obj 0, Obj 1). A "long"
        !           952: **    integer worth of storage names should be more than enough than we
        !           953: **    will ever need.
        !           954: **
        !           955: **    NOTE: when an OLE object is transfered via drag/drop or the
        !           956: **    clipboard, we attempt to keep the currently assigned name for the
        !           957: **    object (if not currently in use). thus it is possible that an
        !           958: **    object with a the next default name (eg. "Obj 5") already exists
        !           959: **    in the current document if an object with this name was privously
        !           960: **    transfered (pasted or dropped). we therefore loop until we find
        !           961: **    the next lowest unused name.
        !           962: */
        !           963: void ContainerDoc_GetNextStgName(
        !           964:         LPCONTAINERDOC          lpContainerDoc,
        !           965:         LPSTR                   lpszStgName,
        !           966:         int                     nLen
        !           967: )
        !           968: {
        !           969:     wsprintf(lpszStgName, "%s %ld",
        !           970:             (LPSTR)DEFOBJNAMEPREFIX,
        !           971:             ++(lpContainerDoc->m_nNextObjNo)
        !           972:     );
        !           973: 
        !           974:     while (ContainerDoc_IsStgNameUsed(lpContainerDoc, lpszStgName) == TRUE) {
        !           975:         wsprintf(lpszStgName, "%s %ld",
        !           976:                 (LPSTR)DEFOBJNAMEPREFIX,
        !           977:                 ++(lpContainerDoc->m_nNextObjNo)
        !           978:         );
        !           979:     }
        !           980: }
        !           981: 
        !           982: 
        !           983: /* ContainerDoc_IsStgNameUsed
        !           984: ** --------------------------
        !           985: **    Check if a given StgName is already in use.
        !           986: */
        !           987: BOOL ContainerDoc_IsStgNameUsed(
        !           988:         LPCONTAINERDOC          lpContainerDoc,
        !           989:         LPSTR                   lpszStgName
        !           990: )
        !           991: {
        !           992:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !           993:     int i;
        !           994:     LPLINE lpLine;
        !           995: 
        !           996:     for (i = 0; i < lpLL->m_nNumLines; i++) {
        !           997:         lpLine=LineList_GetLine(lpLL, i);
        !           998: 
        !           999:         if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
        !          1000:             if (lstrcmp(lpszStgName,
        !          1001:                     ((LPCONTAINERLINE)lpLine)->m_szStgName) == 0) {
        !          1002:                 return TRUE;    // Match FOUND!
        !          1003:             }
        !          1004:         }
        !          1005:     }
        !          1006:     return FALSE;   // if we get here, then NO match was found.
        !          1007: }
        !          1008: 
        !          1009: 
        !          1010: LPSTORAGE ContainerDoc_GetStg(LPCONTAINERDOC lpContainerDoc)
        !          1011: {
        !          1012:     return lpContainerDoc->m_lpStg;
        !          1013: }
        !          1014: 
        !          1015: 
        !          1016: /* ContainerDoc_GetSingleOleObject
        !          1017: ** -------------------------------
        !          1018: **    If the entire document contains a single OLE object, then
        !          1019: **    return the desired interface of the object.
        !          1020: **
        !          1021: **    Returns NULL if there is are multiple lines in the document or
        !          1022: **    the single line is not a ContainerLine.
        !          1023: */
        !          1024: LPUNKNOWN ContainerDoc_GetSingleOleObject(
        !          1025:         LPCONTAINERDOC          lpContainerDoc,
        !          1026:         REFIID                  riid,
        !          1027:         LPCONTAINERLINE FAR*    lplpContainerLine
        !          1028: )
        !          1029: {
        !          1030:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !          1031:     LPLINE lpLine;
        !          1032:     LPUNKNOWN lpObj = NULL;
        !          1033: 
        !          1034:     if (lplpContainerLine)
        !          1035:         *lplpContainerLine = NULL;
        !          1036: 
        !          1037:     if (lpLL->m_nNumLines != 1)
        !          1038:         return NULL;    // doc does NOT contain a single line
        !          1039: 
        !          1040:     lpLine=LineList_GetLine(lpLL, 0);
        !          1041: 
        !          1042:     if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE))
        !          1043:         lpObj = ContainerLine_GetOleObject((LPCONTAINERLINE)lpLine, riid);
        !          1044: 
        !          1045:     if (lplpContainerLine)
        !          1046:         *lplpContainerLine = (LPCONTAINERLINE)lpLine;
        !          1047: 
        !          1048:     return lpObj;
        !          1049: }
        !          1050: 
        !          1051: 
        !          1052: /* ContainerDoc_IsSelAnOleObject
        !          1053: ** -----------------------------
        !          1054: **    Check if the selection is a single selection of an OLE object.
        !          1055: **    if so, then optionally return the desired interface of the object
        !          1056: **    and/or index of the ContainerLine containing the OLE object.
        !          1057: **
        !          1058: **    Returns FALSE if there is a multiple selection or the single
        !          1059: **    selection is not a ContainerLine.
        !          1060: */
        !          1061: BOOL ContainerDoc_IsSelAnOleObject(
        !          1062:         LPCONTAINERDOC          lpContainerDoc,
        !          1063:         REFIID                  riid,
        !          1064:         LPUNKNOWN FAR*          lplpvObj,
        !          1065:         int FAR*                lpnIndex,
        !          1066:         LPCONTAINERLINE FAR*    lplpContainerLine
        !          1067: )
        !          1068: {
        !          1069:     LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !          1070:     LINERANGE lrSel;
        !          1071:     int nNumSel;
        !          1072:     LPLINE lpLine;
        !          1073: 
        !          1074:     if (lplpvObj) *lplpvObj = NULL;
        !          1075:     if (lpnIndex) *lpnIndex = -1;
        !          1076:     if (lplpContainerLine) *lplpContainerLine = NULL;
        !          1077: 
        !          1078:     nNumSel = LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);
        !          1079:     if (nNumSel != 1)
        !          1080:         return FALSE;   // selection is not a single line
        !          1081: 
        !          1082:     lpLine = LineList_GetLine(lpLL, lrSel.m_nStartLine);
        !          1083: 
        !          1084:     if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
        !          1085:         if (lpnIndex)
        !          1086:             *lpnIndex = lrSel.m_nStartLine;
        !          1087:         if (lplpContainerLine) 
        !          1088:             *lplpContainerLine = (LPCONTAINERLINE)lpLine;
        !          1089:         if (riid) {
        !          1090:             *lplpvObj = ContainerLine_GetOleObject(
        !          1091:                     (LPCONTAINERLINE)lpLine,
        !          1092:                     riid
        !          1093:             );
        !          1094:         }
        !          1095: 
        !          1096:         return (*lplpvObj ? TRUE : FALSE);
        !          1097:     }
        !          1098: 
        !          1099:     return FALSE;
        !          1100: }
        !          1101: 
        !          1102: 
        !          1103: /*************************************************************************
        !          1104: ** ContainerDoc::IOleUILinkContainer interface implementation
        !          1105: *************************************************************************/
        !          1106: 
        !          1107: STDMETHODIMP CntrDoc_LinkCont_QueryInterface(
        !          1108:         LPOLEUILINKCONTAINER    lpThis,
        !          1109:         REFIID                  riid,
        !          1110:         LPVOID FAR*             lplpvObj
        !          1111: )
        !          1112: {
        !          1113:     LPOLEDOC lpOleDoc = (LPOLEDOC)
        !          1114:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1115: 
        !          1116:     return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
        !          1117: }
        !          1118: 
        !          1119: 
        !          1120: STDMETHODIMP_(ULONG) CntrDoc_LinkCont_AddRef(LPOLEUILINKCONTAINER lpThis)
        !          1121: {
        !          1122:     LPOLEDOC lpOleDoc = (LPOLEDOC)
        !          1123:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1124: 
        !          1125:     OleDbgAddRefMethod(lpThis, "IOleUILinkContainer");
        !          1126: 
        !          1127:     return OleDoc_AddRef(lpOleDoc);
        !          1128: }
        !          1129: 
        !          1130: 
        !          1131: STDMETHODIMP_(ULONG) CntrDoc_LinkCont_Release(LPOLEUILINKCONTAINER lpThis)
        !          1132: {
        !          1133:     LPOLEDOC lpOleDoc = (LPOLEDOC)
        !          1134:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1135: 
        !          1136:     OleDbgReleaseMethod(lpThis, "IOleUILinkContainer");
        !          1137: 
        !          1138:     return OleDoc_Release(lpOleDoc);
        !          1139: }
        !          1140: 
        !          1141: 
        !          1142: STDMETHODIMP_(DWORD) CntrDoc_LinkCont_GetNextLink(
        !          1143:         LPOLEUILINKCONTAINER    lpThis,
        !          1144:         DWORD                   dwLink
        !          1145: )
        !          1146: {
        !          1147:     LPCONTAINERDOC lpContainerDoc =
        !          1148:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1149:        LPCONTAINERLINE lpContainerLine = NULL;
        !          1150: 
        !          1151:     OLEDBG_BEGIN2("CntrDoc_LinkCont_GetNextLink\r\n")
        !          1152: 
        !          1153:        lpContainerLine = ContainerDoc_GetNextLink(
        !          1154:                        lpContainerDoc, 
        !          1155:                        (LPCONTAINERLINE)dwLink
        !          1156:        );
        !          1157: 
        !          1158:     OLEDBG_END2
        !          1159:     return (DWORD)lpContainerLine;
        !          1160: }
        !          1161: 
        !          1162: 
        !          1163: STDMETHODIMP CntrDoc_LinkCont_SetLinkUpdateOptions(
        !          1164:         LPOLEUILINKCONTAINER    lpThis,
        !          1165:         DWORD                   dwLink,
        !          1166:         DWORD                   dwUpdateOpt
        !          1167: )
        !          1168: {
        !          1169:     LPCONTAINERDOC lpContainerDoc =
        !          1170:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1171:     LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1172:     LPOLELINK lpOleLink;
        !          1173:     SCODE sc = S_OK;
        !          1174:     HRESULT hrErr;
        !          1175: 
        !          1176:     OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkUpdateOptions\r\n")
        !          1177: 
        !          1178:     OleDbgAssert(lpContainerLine);
        !          1179: 
        !          1180:     lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
        !          1181:             lpContainerLine,
        !          1182:             &IID_IOleLink
        !          1183:     );
        !          1184: 
        !          1185:     if (! lpOleLink) {
        !          1186:         sc = E_FAIL;
        !          1187:         goto error;
        !          1188:     }
        !          1189: 
        !          1190:     OLEDBG_BEGIN2("IOleLink::SetUpdateOptions called\r\n")
        !          1191:     hrErr = lpOleLink->lpVtbl->SetUpdateOptions(
        !          1192:             lpOleLink,
        !          1193:             dwUpdateOpt
        !          1194:     );
        !          1195:     OLEDBG_END2
        !          1196: 
        !          1197:     OleStdRelease((LPUNKNOWN)lpOleLink);
        !          1198: 
        !          1199:     if (hrErr != NOERROR) {
        !          1200:         OleDbgOutHResult("IOleLink::SetUpdateOptions returned", hrErr);
        !          1201:         sc = GetScode(hrErr);
        !          1202:         goto error;
        !          1203:     }
        !          1204: 
        !          1205:     OLEDBG_END2
        !          1206:     return ResultFromScode(sc);
        !          1207: 
        !          1208: error:
        !          1209:     OLEDBG_END2
        !          1210:     return ResultFromScode(sc);
        !          1211: }
        !          1212: 
        !          1213: 
        !          1214: STDMETHODIMP CntrDoc_LinkCont_GetLinkUpdateOptions(
        !          1215:         LPOLEUILINKCONTAINER    lpThis,
        !          1216:         DWORD                   dwLink,
        !          1217:         DWORD FAR*              lpdwUpdateOpt
        !          1218: )
        !          1219: {
        !          1220:     LPCONTAINERDOC lpContainerDoc =
        !          1221:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1222:     LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1223:     LPOLELINK lpOleLink;
        !          1224:     SCODE sc = S_OK;
        !          1225:     HRESULT hrErr;
        !          1226: 
        !          1227:     OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkUpdateOptions\r\n")
        !          1228: 
        !          1229:     OleDbgAssert(lpContainerLine);
        !          1230: 
        !          1231:     lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
        !          1232:             lpContainerLine,
        !          1233:             &IID_IOleLink
        !          1234:     );
        !          1235: 
        !          1236:     if (! lpOleLink) {
        !          1237:         sc = E_FAIL;
        !          1238:         goto error;
        !          1239:     }
        !          1240: 
        !          1241:     OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n")
        !          1242:     hrErr = lpOleLink->lpVtbl->GetUpdateOptions(
        !          1243:             lpOleLink,
        !          1244:             lpdwUpdateOpt
        !          1245:     );
        !          1246:     OLEDBG_END2
        !          1247: 
        !          1248:     OleStdRelease((LPUNKNOWN)lpOleLink);
        !          1249: 
        !          1250:     if (hrErr != NOERROR) {
        !          1251:         OleDbgOutHResult("IOleLink::GetUpdateOptions returned", hrErr);
        !          1252:         sc = GetScode(hrErr);
        !          1253:         goto error;
        !          1254:     }
        !          1255: 
        !          1256:     OLEDBG_END2
        !          1257:     return ResultFromScode(sc);
        !          1258: 
        !          1259: error:
        !          1260:     OLEDBG_END2
        !          1261:     return ResultFromScode(sc);
        !          1262: }
        !          1263: 
        !          1264: 
        !          1265: STDMETHODIMP CntrDoc_LinkCont_SetLinkSource(
        !          1266:         LPOLEUILINKCONTAINER   lpThis,
        !          1267:                DWORD                                   dwLink,
        !          1268:         LPSTR                                  lpszDisplayName,
        !          1269:                ULONG                                   lenFileName,            
        !          1270:         ULONG FAR*                             lpchEaten,
        !          1271:                BOOL                                    fValidateSource
        !          1272: )
        !          1273: {
        !          1274:     LPCONTAINERDOC lpContainerDoc =
        !          1275:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1276:     LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1277:     SCODE       sc = S_OK;
        !          1278:     HRESULT     hrErr;
        !          1279:     LPOLELINK   lpOleLink = NULL;
        !          1280:     LPBC        lpbc = NULL;
        !          1281:     LPMONIKER   lpmk = NULL;
        !          1282:        LPOLEOBJECT lpLinkSrcOleObj = NULL;
        !          1283:        CLSID       clsid = CLSID_NULL;
        !          1284: 
        !          1285: 
        !          1286:     OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkSource\r\n")
        !          1287: 
        !          1288:     OleDbgAssert(lpContainerLine);
        !          1289: 
        !          1290:        lpContainerLine->m_fLinkUnavailable = TRUE;
        !          1291:        
        !          1292:        if (fValidateSource) {
        !          1293: 
        !          1294:         /* OLE2NOTE: validate the link source by parsing the string
        !          1295:         **    into a Moniker. if this is successful, then the string is
        !          1296:         **    valid.
        !          1297:         */
        !          1298:         hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);
        !          1299:         if (hrErr != NOERROR) {
        !          1300:             sc = GetScode(hrErr);   // ERROR: OOM
        !          1301:             goto cleanup;
        !          1302:         }
        !          1303: 
        !          1304:                OLEDBG_BEGIN2("MkParseDisplayName called\r\n")
        !          1305:                hrErr = MkParseDisplayName(
        !          1306:                                lpbc, lpszDisplayName, lpchEaten, (LPMONIKER FAR*)&lpmk);
        !          1307:                OLEDBG_END2
        !          1308: 
        !          1309:                if (hrErr != NOERROR) {
        !          1310:                        sc = GetScode(hrErr);   // ERROR in parsing moniker!
        !          1311:                        goto cleanup;
        !          1312:                }
        !          1313:         /* OLE2NOTE: the link source was validated; it successfully
        !          1314:         **    parsed into a Moniker. we can set the source of the link
        !          1315:         **    directly with this Moniker. if we want the link to be
        !          1316:         **    able to know the correct class for the new link source,
        !          1317:         **    we must bind to the moniker and get the CLSID. if we do
        !          1318:         **    not do this then methods like IOleObject::GetUserType
        !          1319:         **    will return nothing (NULL strings).
        !          1320:         */
        !          1321:         
        !          1322:         hrErr = lpmk->lpVtbl->BindToObject(
        !          1323:                 lpmk,lpbc,NULL,&IID_IOleObject,(LPVOID FAR*)&lpLinkSrcOleObj);
        !          1324:                if (hrErr == NOERROR) {
        !          1325:                        hrErr = lpLinkSrcOleObj->lpVtbl->GetUserClassID(
        !          1326:                                                        lpLinkSrcOleObj,
        !          1327:                                                        (CLSID FAR*)&clsid);
        !          1328:                        lpContainerLine->m_fLinkUnavailable = FALSE;                    
        !          1329:                }
        !          1330:                else
        !          1331:                        lpContainerLine->m_fLinkUnavailable = TRUE;
        !          1332:        }
        !          1333:        else {
        !          1334:                LPMONIKER       lpmkFile = NULL;
        !          1335:                LPMONIKER       lpmkItem = NULL;
        !          1336:                char            szName[OLEUI_CCHPATHMAX];
        !          1337:                
        !          1338:                lstrcpyn((LPSTR)szName, lpszDisplayName, (int)lenFileName + 1);
        !          1339:                
        !          1340:                OLEDBG_BEGIN2("CreateFileMoniker called\r\n")           
        !          1341:                CreateFileMoniker((LPSTR)szName, (LPMONIKER FAR*)&lpmkFile);
        !          1342:                OLEDBG_END2
        !          1343:                        
        !          1344:                if (!lpmkFile)
        !          1345:                        goto cleanup;
        !          1346: 
        !          1347:         if (lstrlen(lpszDisplayName) > (int)lenFileName) {     // have item name
        !          1348:             lstrcpy((LPSTR)szName, lpszDisplayName + lenFileName + 1);
        !          1349:                
        !          1350:             OLEDBG_BEGIN2("CreateItemMoniker called\r\n")
        !          1351:             CreateItemMoniker(
        !          1352:                                        OLESTDDELIM, (LPSTR)szName, (LPMONIKER FAR*)&lpmkItem);
        !          1353:             OLEDBG_END2
        !          1354:                        
        !          1355:             if (!lpmkItem) {
        !          1356:                 OleStdRelease((LPUNKNOWN)lpmkFile);
        !          1357:                 goto cleanup;
        !          1358:             }
        !          1359:                        
        !          1360:                        OLEDBG_BEGIN2("CreateGenericComposite called\r\n")
        !          1361:                        CreateGenericComposite(lpmkFile, lpmkItem, (LPMONIKER FAR*)&lpmk);
        !          1362:                        OLEDBG_END2
        !          1363:        
        !          1364:                        if (lpmkFile)
        !          1365:                                OleStdRelease((LPUNKNOWN)lpmkFile);
        !          1366:                        if (lpmkItem)
        !          1367:                                OleStdRelease((LPUNKNOWN)lpmkItem);
        !          1368:                
        !          1369:                        if (!lpmk)
        !          1370:                                goto cleanup;
        !          1371:                }
        !          1372:                else
        !          1373:                        lpmk = lpmkFile;
        !          1374:        }
        !          1375:        
        !          1376:     lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
        !          1377:             lpContainerLine,
        !          1378:             &IID_IOleLink
        !          1379:     );
        !          1380: 
        !          1381:     if (! lpOleLink) {
        !          1382:         OleDbgAssert(lpOleLink != NULL);
        !          1383:         sc = E_FAIL;
        !          1384:         goto cleanup;
        !          1385:     }
        !          1386:     
        !          1387:     if (lpmk) {
        !          1388:         
        !          1389:         OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n")
        !          1390:         hrErr = lpOleLink->lpVtbl->SetSourceMoniker(
        !          1391:                 lpOleLink, lpmk, (REFCLSID)&clsid);
        !          1392:         OLEDBG_END2
        !          1393: 
        !          1394:         if (FAILED(GetScode(hrErr))) {
        !          1395:             OleDbgOutHResult("IOleLink::SetSourceMoniker returned",hrErr);
        !          1396:             sc = GetScode(hrErr);
        !          1397:             goto cleanup;
        !          1398:         }
        !          1399: 
        !          1400:         /* OLE2NOTE: above we forced the link source moniker to bind.
        !          1401:         **    because we deliberately hold on to the bind context
        !          1402:         **    (lpbc) the link source object will not shut down. during
        !          1403:         **    the call to IOleLink::SetSourceMoniker, the link will
        !          1404:         **    connect to the running link source (the link internally
        !          1405:         **    calls BindIfRunning). it is important to initially allow
        !          1406:         **    the link to bind to the running object so that it can get
        !          1407:         **    an update of the presentation for its cache. we do not
        !          1408:         **    want the connection from our link to the link source be
        !          1409:         **    the only reason the link source stays running. thus we
        !          1410:         **    deliberately for the link to release (unbind) the source
        !          1411:         **    object, we then release the bind context, and then we
        !          1412:         **    allow the link to rebind to the link source if it is
        !          1413:         **    running anyway.
        !          1414:         */
        !          1415:         if (lpbc && lpmk->lpVtbl->IsRunning(lpmk,lpbc,NULL,NULL) == NOERROR) {
        !          1416: 
        !          1417:             OLEDBG_BEGIN2("IOleLink::Update called\r\n")
        !          1418:             hrErr = lpOleLink->lpVtbl->Update(lpOleLink, NULL);
        !          1419:             OLEDBG_END2
        !          1420: 
        !          1421: #if defined( _DEBUG )
        !          1422:             if (FAILED(GetScode(hrErr))) 
        !          1423:                 OleDbgOutHResult("IOleLink::Update returned",hrErr);
        !          1424: #endif
        !          1425: 
        !          1426:             OLEDBG_BEGIN2("IOleLink::UnbindSource called\r\n")
        !          1427:             hrErr = lpOleLink->lpVtbl->UnbindSource(lpOleLink);
        !          1428:             OLEDBG_END2
        !          1429: 
        !          1430: #if defined( _DEBUG )
        !          1431:             if (FAILED(GetScode(hrErr))) 
        !          1432:                 OleDbgOutHResult("IOleLink::UnbindSource returned",hrErr);
        !          1433: #endif
        !          1434: 
        !          1435:             if (lpLinkSrcOleObj) {
        !          1436:                 OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj);
        !          1437:                 lpLinkSrcOleObj = NULL;
        !          1438:             }
        !          1439: 
        !          1440:             if (lpbc) {
        !          1441:                 OleStdRelease((LPUNKNOWN)lpbc);
        !          1442:                 lpbc = NULL;
        !          1443:             }
        !          1444: 
        !          1445:             OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n")
        !          1446:             hrErr = lpOleLink->lpVtbl->BindIfRunning(lpOleLink);
        !          1447:             OLEDBG_END2
        !          1448: 
        !          1449: #if defined( _DEBUG )
        !          1450:             if (FAILED(GetScode(hrErr))) 
        !          1451:                 OleDbgOutHResult("IOleLink::BindIfRunning returned",hrErr);
        !          1452: #endif
        !          1453:         }        
        !          1454:     } else {
        !          1455:         /* OLE2NOTE: the link source was NOT validated; it was NOT
        !          1456:         **    successfully parsed into a Moniker. we can only set the
        !          1457:         **    display name string as the source of the link. this link
        !          1458:         **    is not able to bind.
        !          1459:         */
        !          1460:         OLEDBG_BEGIN2("IOleLink::SetSourceDisplayName called\r\n")
        !          1461:         hrErr = lpOleLink->lpVtbl->SetSourceDisplayName(
        !          1462:                 lpOleLink, (LPCSTR)lpszDisplayName);
        !          1463:         OLEDBG_END2
        !          1464: 
        !          1465:         if (hrErr != NOERROR) {
        !          1466:             OleDbgOutHResult("IOleLink::SetSourceDisplayName returned",hrErr);
        !          1467:             sc = GetScode(hrErr);
        !          1468:             goto cleanup;
        !          1469:         }
        !          1470:     }
        !          1471: 
        !          1472: cleanup:
        !          1473:     if (lpOleLink)
        !          1474:         OleStdRelease((LPUNKNOWN)lpOleLink);
        !          1475:     if (lpLinkSrcOleObj) 
        !          1476:         OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj);
        !          1477:     if (lpmk)
        !          1478:         OleStdRelease((LPUNKNOWN)lpmk);
        !          1479:     if (lpbc)
        !          1480:         OleStdRelease((LPUNKNOWN)lpbc);
        !          1481: 
        !          1482:     OLEDBG_END2
        !          1483:     return ResultFromScode(sc);
        !          1484: }
        !          1485: 
        !          1486: 
        !          1487: STDMETHODIMP CntrDoc_LinkCont_GetLinkSource(
        !          1488:         LPOLEUILINKCONTAINER    lpThis,
        !          1489:         DWORD                   dwLink,
        !          1490:         LPSTR FAR*              lplpszDisplayName,
        !          1491:         ULONG FAR*              lplenFileName,
        !          1492:         LPSTR FAR*              lplpszFullLinkType,
        !          1493:         LPSTR FAR*              lplpszShortLinkType,
        !          1494:         BOOL FAR*               lpfSourceAvailable,
        !          1495:         BOOL FAR*               lpfIsSelected
        !          1496: )
        !          1497: {
        !          1498:     LPCONTAINERDOC lpContainerDoc =
        !          1499:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1500:     LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1501:     LPOLELINK       lpOleLink = NULL;
        !          1502:     LPOLEOBJECT     lpOleObj = NULL;
        !          1503:     LPMONIKER       lpmk = NULL;
        !          1504:     LPMONIKER       lpmkFirst = NULL;
        !          1505:     LPBC            lpbc = NULL;
        !          1506:     SCODE           sc = S_OK;
        !          1507:     HRESULT         hrErr;
        !          1508: 
        !          1509:     OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkSource\r\n")
        !          1510: 
        !          1511:     /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
        !          1512:     *lplpszDisplayName  = NULL;
        !          1513:     *lplpszFullLinkType = NULL;
        !          1514:     *lplpszShortLinkType= NULL;
        !          1515:     *lplenFileName      = 0;
        !          1516:     *lpfSourceAvailable = !lpContainerLine->m_fLinkUnavailable;
        !          1517: 
        !          1518:     OleDbgAssert(lpContainerLine);
        !          1519: 
        !          1520:     lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
        !          1521:             lpContainerLine,
        !          1522:             &IID_IOleLink
        !          1523:     );
        !          1524: 
        !          1525:     if (! lpOleLink) {
        !          1526:         OLEDBG_END2
        !          1527:         return ResultFromScode(E_FAIL);
        !          1528:     }
        !          1529: 
        !          1530:     OLEDBG_BEGIN2("IOleLink::GetSourceMoniker called\r\n")
        !          1531:     hrErr = lpOleLink->lpVtbl->GetSourceMoniker(
        !          1532:             lpOleLink,
        !          1533:             (LPMONIKER FAR*)&lpmk
        !          1534:     );
        !          1535:     OLEDBG_END2
        !          1536: 
        !          1537:     if (hrErr == NOERROR) {
        !          1538:         /* OLE2NOTE: the link has the Moniker form of the link source;
        !          1539:         **    this is therefore a validated link source. if the first
        !          1540:         **    part of the Moniker is a FileMoniker, then we need to
        !          1541:         **    return the length of the filename string. we need to
        !          1542:         **    return the ProgID associated with the link source as the
        !          1543:         **    "lpszShortLinkType". we need to return the
        !          1544:         **    FullUserTypeName associated with the link source as the
        !          1545:         **    "lpszFullLinkType".
        !          1546:         */
        !          1547:                
        !          1548:         lpOleObj = (LPOLEOBJECT)OleStdQueryInterface(
        !          1549:                 (LPUNKNOWN)lpOleLink, &IID_IOleObject);
        !          1550:         if (lpOleObj) {
        !          1551:             lpOleObj->lpVtbl->GetUserType(
        !          1552:                     lpOleObj,
        !          1553:                     USERCLASSTYPE_FULL,
        !          1554:                     lplpszFullLinkType
        !          1555:             );
        !          1556:             lpOleObj->lpVtbl->GetUserType(
        !          1557:                     lpOleObj,
        !          1558:                     USERCLASSTYPE_SHORT,
        !          1559:                     lplpszShortLinkType
        !          1560:             );
        !          1561:             OleStdRelease((LPUNKNOWN)lpOleObj);
        !          1562:         }
        !          1563:         *lplenFileName = OleStdGetLenFilePrefixOfMoniker(lpmk);
        !          1564:         lpmk->lpVtbl->Release(lpmk);
        !          1565:     }
        !          1566: 
        !          1567:     OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n")
        !          1568:     hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(
        !          1569:             lpOleLink,
        !          1570:             lplpszDisplayName
        !          1571:     );
        !          1572:     OLEDBG_END2
        !          1573: 
        !          1574:     OleStdRelease((LPUNKNOWN)lpOleLink);
        !          1575: 
        !          1576:     if (hrErr != NOERROR) {
        !          1577:         OleDbgOutHResult("IOleLink::GetSourceDisplayName returned", hrErr);
        !          1578:         OLEDBG_END2
        !          1579:         return hrErr;
        !          1580:     }
        !          1581: 
        !          1582:     OLEDBG_END2
        !          1583:         
        !          1584:     if (lpfIsSelected)
        !          1585:         *lpfIsSelected = Line_IsSelected((LPLINE)lpContainerLine);
        !          1586: 
        !          1587:     return NOERROR;
        !          1588: }
        !          1589: 
        !          1590: 
        !          1591: STDMETHODIMP CntrDoc_LinkCont_OpenLinkSource(
        !          1592:         LPOLEUILINKCONTAINER    lpThis,
        !          1593:         DWORD                   dwLink
        !          1594: )
        !          1595: {
        !          1596:     LPCONTAINERDOC lpContainerDoc =
        !          1597:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1598:     LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1599:     SCODE sc = S_OK;
        !          1600: 
        !          1601:     OLEDBG_BEGIN2("CntrDoc_LinkCont_OpenLinkSource\r\n")
        !          1602: 
        !          1603:     OleDbgAssert(lpContainerLine);
        !          1604: 
        !          1605:     if (! ContainerLine_DoVerb(lpContainerLine, OLEIVERB_SHOW, TRUE, FALSE)) {
        !          1606:         OutlineApp_ErrorMessage(g_lpApp, ErrMsgShowObj);
        !          1607:         sc = E_FAIL;
        !          1608:     }
        !          1609:        
        !          1610:        lpContainerLine->m_fLinkUnavailable = (sc != S_OK);
        !          1611: 
        !          1612:     OLEDBG_END2
        !          1613:     return ResultFromScode(sc);
        !          1614: }
        !          1615: 
        !          1616: 
        !          1617: STDMETHODIMP CntrDoc_LinkCont_UpdateLink(
        !          1618:         LPOLEUILINKCONTAINER    lpThis,
        !          1619:         DWORD                   dwLink,
        !          1620:                BOOL                                    fErrorMessage,
        !          1621:                BOOL                                    fErrorAction            // ignore if fErrorMessage
        !          1622:                                                                                                        //              is FALSE
        !          1623: )
        !          1624: {
        !          1625:     LPCONTAINERDOC lpContainerDoc =
        !          1626:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1627:     LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1628:     SCODE sc = S_OK;
        !          1629:     HRESULT hrErr;
        !          1630: 
        !          1631:     OLEDBG_BEGIN2("CntrDoc_LinkCont_UpdateLink\r\n")
        !          1632: 
        !          1633:     OleDbgAssert(lpContainerLine);
        !          1634: 
        !          1635:     if (! lpContainerLine->m_lpOleObj)
        !          1636:         ContainerLine_LoadOleObject(lpContainerLine);
        !          1637: 
        !          1638:        if (!fErrorMessage) {
        !          1639:                OLEDBG_BEGIN2("IOleObject::IsUpToDate called\r\n")
        !          1640:                hrErr = lpContainerLine->m_lpOleObj->lpVtbl->IsUpToDate(
        !          1641:                                lpContainerLine->m_lpOleObj
        !          1642:                );
        !          1643:                OLEDBG_END2
        !          1644:        }       
        !          1645:        
        !          1646:        if (hrErr != NOERROR) {
        !          1647:                OLEDBG_BEGIN2("IOleObject::Update called\r\n")
        !          1648:                hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Update(
        !          1649:                                lpContainerLine->m_lpOleObj
        !          1650:                );
        !          1651:                OLEDBG_END2
        !          1652:        }
        !          1653: 
        !          1654:        lpContainerLine->m_fLinkUnavailable = (hrErr != NOERROR);
        !          1655:                
        !          1656:     if (hrErr != NOERROR) {
        !          1657:         OleDbgOutHResult("IOleObject::Update returned", hrErr);
        !          1658:         sc = GetScode(hrErr);
        !          1659:                if (fErrorMessage)
        !          1660:                        ProcessError(hrErr, lpContainerLine, fErrorAction);
        !          1661:     }
        !          1662:     /* OLE2NOTE: if the update of the object requires us to update our
        !          1663:     **    display, then we will automatically be sent a OnViewChange
        !          1664:     **    advise. thus we do not need to take any action here to force
        !          1665:     **    a repaint.
        !          1666:     */
        !          1667: 
        !          1668:     OLEDBG_END2
        !          1669:     return ResultFromScode(sc);
        !          1670: }
        !          1671: 
        !          1672: 
        !          1673: /* CntrDoc_LinkCont_CancelLink
        !          1674: ** ---------------------------
        !          1675: **    Convert the link to a static picture.
        !          1676: **    
        !          1677: **    OLE2NOTE: OleCreateStaticFromData can be used to create a static
        !          1678: **    picture object.
        !          1679: */
        !          1680: STDMETHODIMP CntrDoc_LinkCont_CancelLink(
        !          1681:         LPOLEUILINKCONTAINER    lpThis,
        !          1682:         DWORD                   dwLink
        !          1683: )
        !          1684: {
        !          1685:     LPCONTAINERDOC lpContainerDoc =
        !          1686:             ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;
        !          1687:        LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;
        !          1688:     LPLINELIST          lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
        !          1689:     LPLINE              lpLine = NULL;
        !          1690:     HDC                 hDC;
        !          1691:     int                 nTab = 0;
        !          1692:     char                szStgName[CWCSTORAGENAME];
        !          1693:     LPCONTAINERLINE     lpNewContainerLine = NULL;
        !          1694:     LPDATAOBJECT        lpSrcDataObj;
        !          1695:     LPOLELINK           lpOleLink;
        !          1696:     int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);
        !          1697: 
        !          1698:     OLEDBG_BEGIN2("CntrDoc_LinkCont_CancelLink\r\n")
        !          1699: 
        !          1700:     /* we will first break the connection of the link to its source. */
        !          1701:     lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
        !          1702:             lpContainerLine,
        !          1703:             &IID_IOleLink
        !          1704:     );
        !          1705:     if (lpOleLink) {
        !          1706:         OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n")
        !          1707:         lpOleLink->lpVtbl->SetSourceMoniker(
        !          1708:                 lpOleLink, NULL, (REFCLSID)&CLSID_NULL);
        !          1709:         OLEDBG_END2
        !          1710:         OleStdRelease((LPUNKNOWN)lpOleLink);
        !          1711:     }
        !          1712:         
        !          1713:     lpSrcDataObj = (LPDATAOBJECT)ContainerLine_GetOleObject(
        !          1714:             lpContainerLine,&IID_IDataObject);
        !          1715:     if (! lpSrcDataObj) 
        !          1716:         goto error;
        !          1717: 
        !          1718:     ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName));
        !          1719:     nTab = Line_GetTabLevel((LPLINE)lpContainerLine);
        !          1720:     hDC = LineList_GetDC(lpLL);
        !          1721: 
        !          1722:     lpNewContainerLine = ContainerLine_CreateFromData(
        !          1723:             hDC,
        !          1724:             nTab,
        !          1725:             lpContainerDoc,
        !          1726:             lpSrcDataObj,
        !          1727:             OLECREATEFROMDATA_STATIC,
        !          1728:             0,   /* no special cfFormat required */
        !          1729:             FALSE,  /* fDisplayAsIcon */
        !          1730:             NULL,   /* hMetaPict */
        !          1731:             szStgName
        !          1732:     );
        !          1733:     LineList_ReleaseDC(lpLL, hDC);
        !          1734: 
        !          1735:     OleStdRelease((LPUNKNOWN)lpSrcDataObj);
        !          1736: 
        !          1737:     if (! lpNewContainerLine)
        !          1738:         goto error;
        !          1739:        
        !          1740:     OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, FALSE);
        !          1741: 
        !          1742:     LineList_ReplaceLine(lpLL, (LPLINE)lpNewContainerLine, nIndex);
        !          1743: 
        !          1744:     OLEDBG_END2
        !          1745:        return ResultFromScode(NOERROR);
        !          1746: 
        !          1747: error:
        !          1748:     OutlineApp_ErrorMessage(g_lpApp, "Could not break the link.");
        !          1749:     OLEDBG_END2
        !          1750:     return ResultFromScode(E_FAIL);
        !          1751: }

unix.superglobalmegacorp.com

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