Annotation of mstools/ole20/samples/ole2ui/olestd.c, revision 1.1.1.1

1.1       root        1: /*************************************************************************
                      2: **
                      3: **    OLE 2 Standard Utilities
                      4: **
                      5: **    olestd.c
                      6: **
                      7: **    This file contains utilities that are useful for most standard
                      8: **        OLE 2.0 compound document type applications.
                      9: **
                     10: **    (c) Copyright Microsoft Corp. 1992 All Rights Reserved
                     11: **
                     12: *************************************************************************/
                     13: 
                     14: #define NONAMELESSUNION     // use strict ANSI standard (for DVOBJ.H)
                     15: 
                     16: #define STRICT  1
                     17: #include "ole2ui.h"
                     18: #include <stdlib.h>
                     19: #include <ctype.h>
                     20: #include <shellapi.h>
                     21: #include "regdb.h"
                     22: #include "geticon.h"
                     23: #include "common.h"
                     24: 
                     25: OLEDBGDATA
                     26: 
                     27: static char szAssertMemAlloc[] = "CoGetMalloc failed";
                     28: 
                     29: 
                     30: /* OleStdSetupAdvises
                     31: ** ------------------
                     32: **    Setup the standard View and Ole advises required by a standard,
                     33: **    compound document-oriented container. Such a container relies on
                     34: **    Ole to manage the presentation of the Ole object. The container
                     35: **    call IViewObject::Draw to render (display) the object.
                     36: **
                     37: **    This helper routine performs the following tasks:
                     38: **                      setup View advise
                     39: **                      setup Ole advise
                     40: **                      Call IOleObject::SetHostNames
                     41: **                      Call OleSetContainedObject
                     42: */
                     43: STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,
                     44:                     LPSTR lpszContainerApp, LPSTR lpszContainerObj,
                     45:                     LPADVISESINK lpAdviseSink)
                     46: {
                     47:     LPVIEWOBJECT lpViewObject;
                     48:     HRESULT hrErr;
                     49:     DWORD dwTemp;
                     50:     BOOL fStatus = TRUE;
                     51: 
                     52:     hrErr = lpOleObject->lpVtbl->QueryInterface(
                     53:             lpOleObject,
                     54:             &IID_IViewObject,
                     55:             (LPVOID FAR*)&lpViewObject
                     56:     );
                     57: 
                     58:     /* Setup View advise */
                     59:     if (hrErr == NOERROR) {
                     60: 
                     61:         OLEDBG_BEGIN2("IViewObject::SetAdvise called\r\n")
                     62:         lpViewObject->lpVtbl->SetAdvise(
                     63:                 lpViewObject,
                     64:                 dwDrawAspect,
                     65:                 0,
                     66:                 lpAdviseSink
                     67:         );
                     68:         OLEDBG_END2
                     69: 
                     70:         OleStdRelease((LPUNKNOWN)lpViewObject);
                     71:     } else {
                     72:         fStatus = FALSE;
                     73:     }
                     74: 
                     75:     /* Setup OLE advise.
                     76:     **    OLE2NOTE: normally containers do NOT need to setup an OLE
                     77:     **    advise. this advise connection is only useful for the OLE's
                     78:     **    DefHandler and the OleLink object implementation. some
                     79:     **    special container's might need to setup this advise for
                     80:     **    programatic reasons.
                     81:     **    
                     82:     **    NOTE: this advise will be torn down automatically by the
                     83:     **    server when we release the object, therefore we do not need
                     84:     **    to store the connection id.
                     85:     */
                     86:     OLEDBG_BEGIN2("IOleObject::Advise called\r\n")
                     87:     hrErr = lpOleObject->lpVtbl->Advise(
                     88:             lpOleObject,
                     89:             lpAdviseSink,
                     90:             (DWORD FAR*)&dwTemp
                     91:     );
                     92:     OLEDBG_END2
                     93:     if (hrErr != NOERROR) fStatus = FALSE;
                     94: 
                     95:     /* Setup the host names for the OLE object. */
                     96:     OLEDBG_BEGIN2("IOleObject::SetHostNames called\r\n")
                     97:     hrErr = lpOleObject->lpVtbl->SetHostNames(
                     98:             lpOleObject,
                     99:             lpszContainerApp,
                    100:             lpszContainerObj
                    101:     );
                    102:     OLEDBG_END2
                    103:     if (hrErr != NOERROR) fStatus = FALSE;
                    104: 
                    105:     /* Inform the loadded object's handler/inproc-server that it is in
                    106:     **    its embedding container's process.
                    107:     */
                    108:     OLEDBG_BEGIN2("OleSetContainedObject(TRUE) called\r\n")
                    109:     OleSetContainedObject((LPUNKNOWN)lpOleObject, TRUE);
                    110:     OLEDBG_END2
                    111: 
                    112:     return fStatus;
                    113: }
                    114: 
                    115: 
                    116: /* OleStdSwitchDisplayAspect
                    117: ** -------------------------
                    118: **    Switch the currently cached display aspect between DVASPECT_ICON
                    119: **    and DVASPECT_CONTENT.
                    120: **
                    121: **    NOTE: when setting up icon aspect, any currently cached content
                    122: **    cache is discarded and any advise connections for content aspect
                    123: **    are broken.
                    124: **
                    125: **    RETURNS:
                    126: **      S_OK -- new display aspect setup successfully
                    127: **      E_INVALIDARG -- IOleCache interface is NOT supported (this is
                    128: **                  required).
                    129: **      <other SCODE> -- any SCODE that can be returned by
                    130: **                  IOleCache::Cache method.
                    131: **      NOTE: if an error occurs then the current display aspect and
                    132: **            cache contents unchanged. 
                    133: */
                    134: STDAPI OleStdSwitchDisplayAspect(
                    135:         LPOLEOBJECT             lpOleObj,
                    136:         LPDWORD                 lpdwCurAspect,
                    137:         DWORD                   dwNewAspect,
                    138:         HGLOBAL                 hMetaPict,
                    139:         BOOL                    fDeleteOldAspect,
                    140:         BOOL                    fSetupViewAdvise,
                    141:         LPADVISESINK            lpAdviseSink,
                    142:         BOOL FAR*               lpfMustUpdate
                    143: )
                    144: {
                    145:     LPOLECACHE      lpOleCache = NULL;
                    146:     LPVIEWOBJECT    lpViewObj = NULL;
                    147:     LPENUMSTATDATA  lpEnumStatData = NULL;
                    148:     STATDATA        StatData;
                    149:     FORMATETC       FmtEtc;
                    150:     STGMEDIUM       Medium;
                    151:     DWORD           dwAdvf;
                    152:     DWORD           dwNewConnection;
                    153:     DWORD           dwOldAspect = *lpdwCurAspect;
                    154:     HRESULT         hrErr;
                    155: 
                    156:     *lpfMustUpdate = FALSE;
                    157: 
                    158:     lpOleCache = (LPOLECACHE)OleStdQueryInterface(
                    159:                                         (LPUNKNOWN)lpOleObj,&IID_IOleCache);
                    160: 
                    161:     // if IOleCache* is NOT available, do nothing
                    162:     if (! lpOleCache)
                    163:         return ResultFromScode(E_INVALIDARG);
                    164: 
                    165:     // Setup new cache with the new aspect
                    166:     FmtEtc.cfFormat = CF_METAFILEPICT;
                    167:     FmtEtc.ptd      = NULL;
                    168:     FmtEtc.dwAspect = dwNewAspect;
                    169:     FmtEtc.lindex   = -1;
                    170:     FmtEtc.tymed    = TYMED_MFPICT;
                    171: 
                    172:     /* OLE2NOTE: if we are setting up Icon aspect with a custom icon
                    173:     **    then we do not want DataAdvise notifications to ever change
                    174:     **    the contents of the data cache. thus we set up a NODATA
                    175:     **    advise connection. otherwise we set up a standard DataAdvise
                    176:     **    connection.
                    177:     */
                    178:     if (dwNewAspect == DVASPECT_ICON && hMetaPict)
                    179:         dwAdvf = ADVF_NODATA;
                    180:     else
                    181:         dwAdvf = ADVF_PRIMEFIRST;
                    182: 
                    183:     OLEDBG_BEGIN2("IOleCache::Cache called\r\n")
                    184:     hrErr = lpOleCache->lpVtbl->Cache(
                    185:             lpOleCache,
                    186:             (LPFORMATETC)&FmtEtc,
                    187:             dwAdvf,
                    188:             (LPDWORD)&dwNewConnection
                    189:     );
                    190:     OLEDBG_END2
                    191: 
                    192:     if (! SUCCEEDED(hrErr)) {
                    193:         OleDbgOutHResult("IOleCache::Cache returned", hrErr);
                    194:         OleStdRelease((LPUNKNOWN)lpOleCache);
                    195:         return hrErr;
                    196:     }
                    197: 
                    198:     *lpdwCurAspect = dwNewAspect;
                    199: 
                    200:     /* OLE2NOTE: if we are setting up Icon aspect with a custom icon,
                    201:     **    then stuff the icon into the cache. otherwise force the cache
                    202:     **    to be updated. this will run the object if necessary.
                    203:     */
                    204:     if (dwNewAspect == DVASPECT_ICON && hMetaPict) {
                    205: 
                    206:         Medium.tymed            = TYMED_MFPICT;
                    207:         Medium.u.hGlobal        = hMetaPict;
                    208:         Medium.pUnkForRelease   = NULL;
                    209: 
                    210:         OLEDBG_BEGIN2("IOleCache::SetData called\r\n")
                    211:         hrErr = lpOleCache->lpVtbl->SetData(
                    212:                 lpOleCache,
                    213:                 (LPFORMATETC)&FmtEtc,
                    214:                 (LPSTGMEDIUM)&Medium,
                    215:                 FALSE   /* fRelease */
                    216:         );
                    217:         OLEDBG_END2
                    218:     } else {
                    219:         *lpfMustUpdate = TRUE;
                    220:     }
                    221: 
                    222:     if (fSetupViewAdvise && lpAdviseSink) {
                    223:         /* OLE2NOTE: re-establish the ViewAdvise connection */
                    224:         lpViewObj = (LPVIEWOBJECT)OleStdQueryInterface(
                    225:                                         (LPUNKNOWN)lpOleObj,&IID_IViewObject);
                    226: 
                    227:         if (lpViewObj) {
                    228: 
                    229:             OLEDBG_BEGIN2("IViewObject::SetAdvise called\r\n")
                    230:             lpViewObj->lpVtbl->SetAdvise(
                    231:                     lpViewObj,
                    232:                     dwNewAspect,
                    233:                     0,
                    234:                     lpAdviseSink
                    235:             );
                    236:             OLEDBG_END2
                    237: 
                    238:             OleStdRelease((LPUNKNOWN)lpViewObj);
                    239:         }
                    240:     }
                    241: 
                    242:     /* OLE2NOTE: remove any existing caches that are set up for the old
                    243:     **    display aspect. It WOULD be possible to retain the caches set
                    244:     **    up for the old aspect, but this would increase the storage
                    245:     **    space required for the object and possibly require additional
                    246:     **    overhead to maintain the unused cachaes. For these reasons the
                    247:     **    strategy to delete the previous caches is prefered. if it is a
                    248:     **    requirement to quickly switch between Icon and Content
                    249:     **    display, then it would be better to keep both aspect caches.
                    250:     */
                    251: 
                    252:     if (fDeleteOldAspect) {
                    253:         OLEDBG_BEGIN2("IOleCache::EnumCache called\r\n")
                    254:         hrErr = lpOleCache->lpVtbl->EnumCache(
                    255:                 lpOleCache,
                    256:                 (LPENUMSTATDATA FAR*)&lpEnumStatData
                    257:         );
                    258:         OLEDBG_END2
                    259: 
                    260:         while(hrErr == NOERROR) {
                    261:             hrErr = lpEnumStatData->lpVtbl->Next(
                    262:                     lpEnumStatData,
                    263:                     1,
                    264:                     (LPSTATDATA)&StatData,
                    265:                     NULL
                    266:             );
                    267:             if (hrErr != NOERROR)
                    268:                 break;              // DONE! no more caches.
                    269: 
                    270:             if (StatData.formatetc.dwAspect == dwOldAspect) {
                    271: 
                    272:                 // Remove previous cache with old aspect
                    273:                 OLEDBG_BEGIN2("IOleCache::Uncache called\r\n")
                    274:                 lpOleCache->lpVtbl->Uncache(lpOleCache,StatData.dwConnection);
                    275:                 OLEDBG_END2
                    276:             }
                    277:         }
                    278: 
                    279:         if (lpEnumStatData) {
                    280:             OleStdVerifyRelease(
                    281:                     (LPUNKNOWN)lpEnumStatData,
                    282:                     "OleStdSwitchDisplayAspect: Cache enumerator NOT released"
                    283:             );
                    284:         }
                    285:     }
                    286: 
                    287:     if (lpOleCache)
                    288:         OleStdRelease((LPUNKNOWN)lpOleCache);
                    289: 
                    290:     return NOERROR;
                    291: }
                    292: 
                    293: 
                    294: /* OleStdSetIconInCache
                    295: ** --------------------
                    296: **    SetData a new icon into the existing DVASPECT_ICON cache.
                    297: **
                    298: **    RETURNS:
                    299: **      HRESULT returned from IOleCache::SetData
                    300: */
                    301: STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict)
                    302: {
                    303:     LPOLECACHE      lpOleCache = NULL;
                    304:     FORMATETC       FmtEtc;
                    305:     STGMEDIUM       Medium;
                    306:     HRESULT         hrErr;
                    307: 
                    308:     if (! hMetaPict)
                    309:         return FALSE;   // invalid icon
                    310: 
                    311:     lpOleCache = (LPOLECACHE)OleStdQueryInterface(
                    312:                                         (LPUNKNOWN)lpOleObj,&IID_IOleCache);
                    313:     if (! lpOleCache)
                    314:         return FALSE;   // if IOleCache* is NOT available, do nothing
                    315: 
                    316:     FmtEtc.cfFormat = CF_METAFILEPICT;
                    317:     FmtEtc.ptd      = NULL;
                    318:     FmtEtc.dwAspect = DVASPECT_ICON;
                    319:     FmtEtc.lindex   = -1;
                    320:     FmtEtc.tymed    = TYMED_MFPICT;
                    321: 
                    322:     // stuff the icon into the cache.
                    323:     Medium.tymed            = TYMED_MFPICT;
                    324:     Medium.u.hGlobal        = hMetaPict;
                    325:     Medium.pUnkForRelease   = NULL;
                    326: 
                    327:     OLEDBG_BEGIN2("IOleCache::SetData called\r\n")
                    328:     hrErr = lpOleCache->lpVtbl->SetData(
                    329:             lpOleCache,
                    330:             (LPFORMATETC)&FmtEtc,
                    331:             (LPSTGMEDIUM)&Medium,
                    332:             FALSE   /* fRelease */
                    333:     );
                    334:     OLEDBG_END2
                    335: 
                    336:     OleStdRelease((LPUNKNOWN)lpOleCache);
                    337: 
                    338:     return hrErr;
                    339: }
                    340: 
                    341: 
                    342: 
                    343: /* OleStdDoConvert
                    344: ** ---------------
                    345: ** Do the container-side responsibilities for converting an object. 
                    346: **    This function would be used in conjunction with the OleUIConvert
                    347: **    dialog. If the user selects to convert an object then the
                    348: **    container must do the following:
                    349: **          1. unload the object.
                    350: **          2. write the NEW CLSID and NEW user type name
                    351: **              string into the storage of the object,
                    352: **              BUT write the OLD format tag.
                    353: **          3. force an update of the object to force the actual
                    354: **              conversion of the data bits.
                    355: **    
                    356: **    This function takes care of step 2.
                    357: */
                    358: STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew)
                    359: {
                    360:     HRESULT error;
                    361:     CLSID clsidOld;
                    362:     CLIPFORMAT cfOld;
                    363:     LPSTR lpszOld = NULL;
                    364:     char szNew[OLEUI_CCHKEYMAX];
                    365: 
                    366:     if ((error = ReadClassStg(lpStg, &clsidOld)) != NOERROR) {
                    367:         clsidOld = CLSID_NULL;
                    368:         goto errRtn;
                    369:     }
                    370: 
                    371:     // read old fmt/old user type; sets out params to NULL on error
                    372:     error = ReadFmtUserTypeStg(lpStg, &cfOld, &lpszOld);
                    373:     OleDbgAssert(error == NOERROR || (cfOld == 0 && lpszOld == NULL));
                    374: 
                    375:     // get new user type name; if error, set to NULL string
                    376:     if (OleStdGetUserTypeOfClass(
                    377:             (LPCLSID)rClsidNew, szNew,sizeof(szNew),NULL /* hKey */) == 0)
                    378:         szNew[0] = '\0';
                    379: 
                    380:     // write class stg
                    381:     if ((error = WriteClassStg(lpStg, rClsidNew)) != NOERROR)
                    382:         goto errRtn;
                    383: 
                    384:     // write old fmt/new user type;
                    385:     if ((error = WriteFmtUserTypeStg(lpStg, cfOld, szNew)) != NOERROR)
                    386:         goto errRewriteInfo;
                    387: 
                    388:     // set convert bit
                    389:     if ((error = SetConvertStg(lpStg, TRUE)) != NOERROR)
                    390:         goto errRewriteInfo;
                    391: 
                    392:     // Commit the changes to make them permanent in the storage
                    393:     OleStdCommitStorage(lpStg);
                    394:     goto okRtn;
                    395: 
                    396: errRewriteInfo:
                    397:     (void)WriteClassStg(lpStg, &clsidOld);
                    398:     (void)WriteFmtUserTypeStg(lpStg, cfOld, lpszOld);
                    399: 
                    400: errRtn:
                    401: 
                    402: okRtn:
                    403:     OleStdFreeString(lpszOld, NULL);
                    404:     return error;
                    405: }
                    406: 
                    407: 
                    408: /* OleStdGetTreatAsFmtUserType
                    409: ** ---------------------------
                    410: **    Determine if the application should perform a TreatAs (ActivateAs
                    411: **    object or emulation) operation for the object that is stored in
                    412: **    the storage.
                    413: **
                    414: **    if the CLSID written in the storage is not the same as the
                    415: **    application's own CLSID (clsidApp), then a TreatAs operation
                    416: **    should take place. if so determine the format the data should be
                    417: **    written and the user type name of the object the app should
                    418: **    emulate (ie. pretend to be). if this information is not written
                    419: **    in the storage then it is looked up in the REGDB. if it can not
                    420: **    be found in the REGDB, then the TreatAs operation can NOT be
                    421: **    executed.
                    422: **
                    423: **    RETURNS: TRUE -- if TreatAs should be performed.
                    424: **               valid lpclsid, lplpszType, lpcfFmt to TreatAs are returned
                    425: **                      (NOTE: lplpszType must be freed by caller)
                    426: **             FALSE -- NO TreatAs. lpszType will be NULL.
                    427: **               lpclsid = CLSID_NULL; lplpszType = lpcfFmt = NULL;
                    428: */
                    429: STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(
                    430:         REFCLSID        rclsidApp,
                    431:         LPSTORAGE       lpStg,
                    432:         CLSID FAR*      lpclsid,
                    433:         CLIPFORMAT FAR* lpcfFmt,
                    434:         LPSTR FAR*      lplpszType
                    435: )
                    436: {
                    437:     HRESULT hrErr;
                    438:     HKEY    hKey;
                    439:     LONG    lRet;
                    440:     UINT    lSize;
                    441:     char    szBuf[OLEUI_CCHKEYMAX];
                    442: 
                    443:     *lpclsid    = CLSID_NULL;
                    444:     *lpcfFmt    = 0;
                    445:     *lplpszType = NULL;
                    446: 
                    447:     hrErr = ReadClassStg(lpStg, lpclsid);
                    448:     if (hrErr == NOERROR &&
                    449:         ! IsEqualCLSID(lpclsid, &CLSID_NULL) &&
                    450:         ! IsEqualCLSID(lpclsid, rclsidApp)) {
                    451: 
                    452:         hrErr = ReadFmtUserTypeStg(lpStg,(CLIPFORMAT FAR*)lpcfFmt,lplpszType);
                    453:         if (hrErr == NOERROR && lplpszType && *lpcfFmt != 0)
                    454:             return TRUE;    // Do TreatAs. info was in lpStg.
                    455: 
                    456:         /* read info from REGDB
                    457:         **    *lpcfFmt = value of field: CLSID\{...}\DataFormats\DefaultFile
                    458:         **    *lplpszType = value of field: CLSID\{...}
                    459:         */
                    460:         //Open up the root key.
                    461:         lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
                    462:         if (lRet != (LONG)ERROR_SUCCESS)
                    463:             return FALSE;
                    464:         *lpcfFmt = OleStdGetDefaultFileFormatOfClass(lpclsid, hKey);
                    465:         if (*lpcfFmt == 0)
                    466:             return FALSE;
                    467:         lSize = OleStdGetUserTypeOfClass(lpclsid,szBuf,sizeof(szBuf),hKey);
                    468:         if (lSize == 0)
                    469:             return FALSE;
                    470:         *lplpszType = OleStdCopyString(szBuf, NULL);
                    471:     } else {
                    472:         return FALSE;       // NO TreatAs
                    473:     }
                    474: }
                    475: 
                    476: 
                    477: 
                    478: /* OleStdDoConvert
                    479: ** ---------------
                    480: ** Do the container-side responsibilities for "ActivateAs" (aka.
                    481: **    TreatAs) for an object. 
                    482: **    This function would be used in conjunction with the OleUIConvert
                    483: **    dialog. If the user selects to ActivateAs an object then the
                    484: **    container must do the following:
                    485: **          1. unload ALL objects of the OLD class that app knows about
                    486: **          2. add the TreatAs tag in the registration database
                    487: **              by calling CoTreatAsClass().
                    488: **          3. lazily it can reload the objects; when the objects
                    489: **              are reloaded the TreatAs will take effect.
                    490: **    
                    491: **    This function takes care of step 2.
                    492: */
                    493: STDAPI OleStdDoTreatAsClass(LPSTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew)
                    494: {
                    495:     HRESULT hrErr;
                    496:     LPSTR   lpszCLSID = NULL;
                    497:     LONG    lRet;
                    498:     HKEY    hKey;
                    499:     
                    500:     OLEDBG_BEGIN2("CoTreatAsClass called\r\n")
                    501:     hrErr = CoTreatAsClass(rclsid, rclsidNew);
                    502:     OLEDBG_END2
                    503: 
                    504:     if ((hrErr != NOERROR) && lpszUserType) {
                    505:         lRet = RegOpenKey(HKEY_CLASSES_ROOT, (LPCSTR)"CLSID", 
                    506:                 (HKEY FAR *)&hKey);
                    507:         StringFromCLSID(rclsid, (LPSTR FAR*)&lpszCLSID);
                    508:         RegSetValue(hKey, lpszCLSID, REG_SZ, lpszUserType, 
                    509:                 lstrlen(lpszUserType));
                    510:                 
                    511:         if (lpszCLSID)
                    512:             OleStdFreeString(lpszCLSID, NULL);
                    513:         
                    514:         hrErr = CoTreatAsClass(rclsid, rclsidNew);
                    515:         RegCloseKey(hKey);
                    516:     }
                    517:     
                    518:     return hrErr;
                    519: }
                    520:     
                    521: 
                    522: 
                    523: /* OleStdIsOleLink
                    524: ** ---------------
                    525: **    Returns TRUE if the OleObject is infact an OLE link object. this
                    526: **    checks if IOleLink interface is supported. if so, the object is a
                    527: **    link, otherwise not.
                    528: */
                    529: STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk)
                    530: {
                    531:     LPOLELINK lpOleLink;
                    532: 
                    533:     lpOleLink = (LPOLELINK)OleStdQueryInterface(lpUnk, &IID_IOleLink);
                    534: 
                    535:     if (lpOleLink) {
                    536:         OleStdRelease((LPUNKNOWN)lpOleLink);
                    537:         return TRUE;
                    538:     } else
                    539:         return FALSE;
                    540: }
                    541: 
                    542: 
                    543: /* OleStdQueryInterface
                    544: ** --------------------
                    545: **    Returns the desired interface pointer if exposed by the given object.
                    546: **    Returns NULL if the interface is not available.
                    547: **    eg.:
                    548: **      lpDataObj = OleStdQueryInterface(lpOleObj, &IID_DataObject);
                    549: */
                    550: STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid)
                    551: {
                    552:     LPUNKNOWN lpInterface;
                    553:     HRESULT hrErr;
                    554: 
                    555:     hrErr = lpUnk->lpVtbl->QueryInterface(
                    556:             lpUnk,
                    557:             riid,
                    558:             (LPVOID FAR*)&lpInterface
                    559:     );
                    560: 
                    561:     if (hrErr == NOERROR)
                    562:         return lpInterface;
                    563:     else
                    564:         return NULL;
                    565: }
                    566: 
                    567: 
                    568: /* OleStdGetData
                    569: ** -------------
                    570: **    Retrieve data from an IDataObject in a specified format on a
                    571: **    global memory block. This function ALWAYS returns a private copy
                    572: **    of the data to the caller. if necessary a copy is made of the
                    573: **    data (ie. if lpMedium->pUnkForRelease != NULL). The caller assumes
                    574: **    ownership of the data block in all cases and must free the data
                    575: **    when done with it. The caller may directly free the data handle
                    576: **    returned (taking care whether it is a simple HGLOBAL or a HANDLE
                    577: **    to a MetafilePict) or the caller may call
                    578: **    ReleaseStgMedium(lpMedium). this OLE helper function will do the
                    579: **    right thing.
                    580: **
                    581: **    PARAMETERS:
                    582: **        LPDATAOBJECT lpDataObj  -- object on which GetData should be
                    583: **                                                         called.
                    584: **        CLIPFORMAT cfFormat     -- desired clipboard format (eg. CF_TEXT)
                    585: **        DVTARGETDEVICE FAR* lpTargetDevice -- target device for which
                    586: **                                  the data should be composed. This may
                    587: **                                  be NULL. NULL can be used whenever the
                    588: **                                  data format is insensitive to target
                    589: **                                  device or when the caller does not care
                    590: **                                  what device is used.
                    591: **        LPSTGMEDIUM lpMedium    -- ptr to STGMEDIUM struct. the
                    592: **                                  resultant medium from the
                    593: **                                  IDataObject::GetData call is
                    594: **                                  returned.
                    595: **
                    596: **    RETURNS:
                    597: **       HGLOBAL -- global memory handle of retrieved data block.
                    598: **       NULL    -- if error.
                    599: */
                    600: STDAPI_(HGLOBAL) OleStdGetData(
                    601:         LPDATAOBJECT        lpDataObj,
                    602:         CLIPFORMAT          cfFormat,
                    603:         DVTARGETDEVICE FAR* lpTargetDevice,
                    604:         DWORD               dwAspect,
                    605:         LPSTGMEDIUM         lpMedium
                    606: )
                    607: {
                    608:     HRESULT hrErr;
                    609:     FORMATETC formatetc;
                    610:     HGLOBAL hGlobal = NULL;
                    611:     HGLOBAL hCopy;
                    612:     LPVOID  lp;
                    613: 
                    614:     formatetc.cfFormat = cfFormat;
                    615:     formatetc.ptd = lpTargetDevice;
                    616:     formatetc.dwAspect = dwAspect;
                    617:     formatetc.lindex = -1;
                    618: 
                    619:     switch (cfFormat) {
                    620:         case CF_METAFILEPICT:
                    621:             formatetc.tymed = TYMED_MFPICT;
                    622:             break;
                    623: 
                    624:         case CF_BITMAP:
                    625:             formatetc.tymed = TYMED_GDI;
                    626:             break;
                    627: 
                    628:         default:
                    629:             formatetc.tymed = TYMED_HGLOBAL;
                    630:             break;
                    631:     }
                    632: 
                    633:     OLEDBG_BEGIN2("IDataObject::GetData called\r\n")
                    634:     hrErr = lpDataObj->lpVtbl->GetData(
                    635:             lpDataObj,
                    636:             (LPFORMATETC)&formatetc,
                    637:             lpMedium
                    638:     );
                    639:     OLEDBG_END2
                    640: 
                    641:     if (hrErr != NOERROR)
                    642:         return NULL;
                    643: 
                    644:     if ((hGlobal = lpMedium->u.hGlobal) == NULL) 
                    645:         return NULL;
                    646:     
                    647:     // Check if hGlobal really points to valid memory
                    648:     if ((lp = GlobalLock(hGlobal)) != NULL) {
                    649:         if (IsBadReadPtr(lp, 1)) {
                    650:             GlobalUnlock(hGlobal);
                    651:             return NULL;    // ERROR: memory is NOT valid
                    652:         }
                    653:         GlobalUnlock(hGlobal);
                    654:     }
                    655: 
                    656:     if (hGlobal != NULL && lpMedium->pUnkForRelease != NULL) {
                    657:         /* OLE2NOTE: the callee wants to retain ownership of the data.
                    658:         **    this is indicated by passing a non-NULL pUnkForRelease.
                    659:         **    thus, we will make a copy of the data and release the
                    660:         **    callee's copy.
                    661:         */
                    662: 
                    663:         hCopy = OleDuplicateData(hGlobal, cfFormat, GHND|GMEM_SHARE);
                    664:         ReleaseStgMedium(lpMedium); // release callee's copy of data
                    665: 
                    666:         hGlobal = hCopy;
                    667:         lpMedium->u.hGlobal = hCopy;
                    668:         lpMedium->pUnkForRelease = NULL;
                    669:     }
                    670:     return hGlobal;
                    671: }
                    672: 
                    673: 
                    674: /* OleStdMalloc
                    675: ** ------------
                    676: **    allocate memory using the currently active IMalloc* allocator
                    677: */
                    678: STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize)
                    679: {
                    680:     LPVOID pout;
                    681:     LPMALLOC pmalloc;
                    682: 
                    683:     if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != S_OK) {
                    684:         OleDbgAssertSz(0, szAssertMemAlloc);
                    685:         return NULL;
                    686:     }
                    687: 
                    688:     pout = (LPVOID)pmalloc->lpVtbl->Alloc(pmalloc, ulSize);
                    689: 
                    690:     if (pmalloc != NULL) {
                    691:         ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
                    692:     }
                    693: 
                    694:     return pout;
                    695: }
                    696: 
                    697: 
                    698: /* OleStdRealloc
                    699: ** -------------
                    700: **    re-allocate memory using the currently active IMalloc* allocator
                    701: */
                    702: STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize)
                    703: {
                    704:     LPVOID pout;
                    705:     LPMALLOC pmalloc;
                    706: 
                    707:     if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != S_OK) {
                    708:         OleDbgAssertSz(0, szAssertMemAlloc);
                    709:         return NULL;
                    710:     }
                    711: 
                    712:     pout = (LPVOID)pmalloc->lpVtbl->Realloc(pmalloc, pmem, ulSize);
                    713: 
                    714:     if (pmalloc != NULL) {
                    715:         ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
                    716:     }
                    717: 
                    718:     return pout;
                    719: }
                    720: 
                    721: 
                    722: /* OleStdFree
                    723: ** ----------
                    724: **    free memory using the currently active IMalloc* allocator
                    725: */
                    726: STDAPI_(void) OleStdFree(LPVOID pmem)
                    727: {
                    728:     LPMALLOC pmalloc;
                    729: 
                    730:     if (pmem == NULL) 
                    731:         return;
                    732: 
                    733:     if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != S_OK) {
                    734:         OleDbgAssertSz(0, szAssertMemAlloc);
                    735:         return;
                    736:     }
                    737: 
                    738:     pmalloc->lpVtbl->Free(pmalloc, pmem);
                    739: 
                    740:     if (pmalloc != NULL) {
                    741:         ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
                    742:     }
                    743: 
                    744: }
                    745: 
                    746: 
                    747: /* OleStdGetSize
                    748: ** -------------
                    749: **    Get the size of a memory block that was allocated using the
                    750: **    currently active IMalloc* allocator.
                    751: */
                    752: STDAPI_(ULONG) OleStdGetSize(LPVOID pmem)
                    753: {
                    754:     ULONG ulSize;
                    755:     LPMALLOC pmalloc;
                    756: 
                    757:     if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != S_OK) {
                    758:         OleDbgAssertSz(0, szAssertMemAlloc);
                    759:         return (ULONG)-1;
                    760:     }
                    761: 
                    762:     ulSize = pmalloc->lpVtbl->GetSize(pmalloc, pmem);
                    763: 
                    764:     if (pmalloc != NULL) {
                    765:         ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
                    766:     }
                    767: 
                    768:     return ulSize;
                    769: }
                    770: 
                    771: 
                    772: /* OleStdFreeString
                    773: ** ----------------
                    774: **    Free a string that was allocated with the currently active
                    775: **    IMalloc* allocator.
                    776: **
                    777: **    if the caller has the current IMalloc* handy, then it can be
                    778: **    passed as a argument, otherwise this function will retrieve the
                    779: **    active allocator and use it.
                    780: */
                    781: STDAPI_(void) OleStdFreeString(LPSTR lpsz, LPMALLOC lpMalloc)
                    782: {
                    783:     BOOL fMustRelease = FALSE;
                    784: 
                    785:     if (! lpMalloc) {
                    786:         if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)
                    787:             return;
                    788:         fMustRelease = TRUE;
                    789:     }
                    790: 
                    791:     lpMalloc->lpVtbl->Free(lpMalloc, lpsz);
                    792: 
                    793:     if (fMustRelease)
                    794:         OleStdRelease((LPUNKNOWN)lpMalloc);
                    795: }
                    796: 
                    797: 
                    798: /* OleStdCopyString
                    799: ** ----------------
                    800: **    Copy a string into memory allocated with the currently active
                    801: **    IMalloc* allocator.
                    802: **
                    803: **    if the caller has the current IMalloc* handy, then it can be
                    804: **    passed as a argument, otherwise this function will retrieve the
                    805: **    active allocator and use it.
                    806: */
                    807: STDAPI_(LPSTR) OleStdCopyString(LPSTR lpszSrc, LPMALLOC lpMalloc)
                    808: {
                    809:     LPSTR lpszDest = NULL;
                    810:     BOOL fMustRelease = FALSE;
                    811:     UINT lSize = lstrlen(lpszSrc);
                    812: 
                    813:     if (! lpMalloc) {
                    814:         if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)
                    815:             return NULL;
                    816:         fMustRelease = TRUE;
                    817:     }
                    818: 
                    819:     lpszDest = lpMalloc->lpVtbl->Alloc(lpMalloc, lSize+1);
                    820: 
                    821:     if (lpszDest)
                    822:         lstrcpy(lpszDest, lpszSrc);
                    823: 
                    824:     if (fMustRelease)
                    825:         OleStdRelease((LPUNKNOWN)lpMalloc);
                    826:     return lpszDest;
                    827: }
                    828: 
                    829: 
                    830: /*
                    831:  * OleStdCreateStorageOnHGlobal()
                    832:  *
                    833:  * Purpose:
                    834:  *  Create a memory based IStorage*.
                    835:  *
                    836:  *  OLE2NOTE: if fDeleteOnRelease==TRUE, then the ILockBytes is created
                    837:  *            such that it will delete them memory on its last release.
                    838:  *            the IStorage on created on top of the ILockBytes in NOT
                    839:  *            created with STGM_DELETEONRELEASE. when the IStorage receives
                    840:  *            its last release, it will release the ILockBytes which will
                    841:  *            in turn free the memory. it is in fact an error to specify
                    842:  *            STGM_DELETEONRELEASE in this situation.
                    843:  *
                    844:  * Parameters:
                    845:  *  hGlobal --  handle to MEM_SHARE allocated memory. may be NULL and
                    846:  *              memory will be automatically allocated.
                    847:  *  fDeleteOnRelease -- controls if the memory is freed on the last release.
                    848:  *  grfMode --  flags passed to StgCreateDocfileOnILockBytes
                    849:  *
                    850:  *  NOTE: if hGlobal is NULL, then a new IStorage is created and
                    851:  *              STGM_CREATE flag is passed to StgCreateDocfileOnILockBytes.
                    852:  *        if hGlobal is non-NULL, then it is assumed that the hGlobal already
                    853:  *              has an IStorage inside it and STGM_CONVERT flag is passed
                    854:  *              to StgCreateDocfileOnILockBytes.
                    855:  *
                    856:  * Return Value:
                    857:  *    SCODE  -  S_OK if successful
                    858:  */
                    859: STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(
                    860:         HANDLE hGlobal,
                    861:         BOOL fDeleteOnRelease,
                    862:         DWORD grfMode
                    863: )
                    864: {
                    865:     DWORD grfCreateMode=grfMode | (hGlobal==NULL ? STGM_CREATE:STGM_CONVERT);
                    866:     HRESULT hrErr;
                    867:     LPLOCKBYTES lpLockBytes = NULL;
                    868:     DWORD reserved = 0;
                    869:     LPSTORAGE lpStg = NULL;
                    870: 
                    871:     hrErr = CreateILockBytesOnHGlobal(
                    872:             hGlobal,
                    873:             fDeleteOnRelease,
                    874:             (LPLOCKBYTES FAR*)&lpLockBytes
                    875:     );
                    876:     if (hrErr != NOERROR)
                    877:         return NULL;
                    878: 
                    879:     hrErr = StgCreateDocfileOnILockBytes(
                    880:             lpLockBytes,
                    881:             grfCreateMode,
                    882:             reserved,
                    883:             (LPSTORAGE FAR*)&lpStg
                    884:     );
                    885:     if (hrErr != NOERROR) {
                    886:         OleStdRelease((LPUNKNOWN)lpLockBytes);
                    887:         return NULL;
                    888:     }
                    889:     return lpStg;
                    890: }
                    891: 
                    892: 
                    893: 
                    894: /*
                    895:  * OleStdCreateTempStorage()
                    896:  *
                    897:  * Purpose:
                    898:  *  Create a temporay IStorage* that will DeleteOnRelease.
                    899:  *  this can be either memory based or file based.
                    900:  *
                    901:  * Parameters:
                    902:  *  fUseMemory -- controls if memory-based or file-based stg is created
                    903:  *  grfMode --  storage mode flags
                    904:  *
                    905:  * Return Value:
                    906:  *    LPSTORAGE  -  if successful, NULL otherwise
                    907:  */
                    908: STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode)
                    909: {
                    910:     LPSTORAGE   lpstg;
                    911:     HRESULT     hrErr;
                    912:     DWORD       reserved = 0;
                    913: 
                    914:     if (fUseMemory) {
                    915:         lpstg = OleStdCreateStorageOnHGlobal(
                    916:                 NULL,  /* auto allocate */
                    917:                 TRUE,  /* delete on release */
                    918:                 grfMode
                    919:         );
                    920:     } else {
                    921:         /* allocate a temp docfile that will delete on last release */
                    922:         hrErr = StgCreateDocfile(
                    923:                 NULL,
                    924:                 grfMode | STGM_DELETEONRELEASE | STGM_CREATE,
                    925:                 reserved,
                    926:                 &lpstg
                    927:         );
                    928:         if (hrErr != NOERROR)
                    929:             return NULL;
                    930:     }
                    931:     return lpstg;
                    932: }
                    933: 
                    934: 
                    935: /* OleStdGetOleObjectData
                    936: ** ----------------------
                    937: **    Render CF_EMBEDSOURCE/CF_EMBEDDEDOBJECT data on an TYMED_ISTORAGE
                    938: **    medium by asking the object to save into the storage.
                    939: **    the object must support IPersistStorage.
                    940: **
                    941: **    if lpMedium->tymed == TYMED_NULL, then a delete-on-release
                    942: **    storage is allocated (either file-based or memory-base depending
                    943: **    the value of fUseMemory). this is useful to support an
                    944: **    IDataObject::GetData call where the callee must allocate the
                    945: **    medium.
                    946: **
                    947: **    if lpMedium->tymed == TYMED_ISTORAGE, then the data is writen
                    948: **    into the passed in IStorage. this is useful to support an
                    949: **    IDataObject::GetDataHere call where the caller has allocated his
                    950: **    own IStorage.
                    951: */
                    952: STDAPI OleStdGetOleObjectData(
                    953:         LPPERSISTSTORAGE        lpPStg,
                    954:         LPFORMATETC             lpformatetc,
                    955:         LPSTGMEDIUM             lpMedium,
                    956:         BOOL                    fUseMemory
                    957: )
                    958: {
                    959:     LPSTORAGE   lpstg = NULL;
                    960:     DWORD       reserved = 0;
                    961:     SCODE       sc = S_OK;
                    962:     HRESULT     hrErr;
                    963: 
                    964:     lpMedium->pUnkForRelease = NULL;
                    965: 
                    966:     if (lpMedium->tymed == TYMED_NULL) {
                    967: 
                    968:         if (lpformatetc->tymed & TYMED_ISTORAGE) {
                    969: 
                    970:             /* allocate a temp docfile that will delete on last release */
                    971:             lpstg = OleStdCreateTempStorage(
                    972:                     TRUE /*fUseMemory*/,
                    973:                     STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE
                    974:             );
                    975:             if (!lpstg)
                    976:                 return ResultFromScode(E_OUTOFMEMORY);
                    977: 
                    978:             lpMedium->u.pstg = lpstg;
                    979:             lpMedium->tymed = TYMED_ISTORAGE;
                    980:             lpMedium->pUnkForRelease = NULL;
                    981:         } else {
                    982:             return ResultFromScode(DATA_E_FORMATETC);
                    983:         }
                    984:     } else if (lpMedium->tymed == TYMED_ISTORAGE) {
                    985:         lpMedium->tymed = TYMED_ISTORAGE;
                    986:     } else {
                    987:         return ResultFromScode(DATA_E_FORMATETC);
                    988:     }
                    989: 
                    990:     // OLE2NOTE: even if OleSave returns an error you should still call 
                    991:     // SaveCompleted.
                    992: 
                    993:     OLEDBG_BEGIN2("OleSave called\r\n")
                    994:     hrErr = OleSave(lpPStg, lpMedium->u.pstg, FALSE /* fSameAsLoad */);
                    995:     OLEDBG_END2
                    996: 
                    997:     if (hrErr != NOERROR) {
                    998:         OleDbgOutHResult("WARNING: OleSave returned", hrErr);
                    999:         sc = GetScode(hrErr);
                   1000:     }
                   1001:     OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")
                   1002:     hrErr = lpPStg->lpVtbl->SaveCompleted(lpPStg, NULL);
                   1003:     OLEDBG_END2
                   1004: 
                   1005:     if (hrErr != NOERROR) {
                   1006:         OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);
                   1007:         if (sc == S_OK)
                   1008:             sc = GetScode(hrErr);
                   1009:     }
                   1010: 
                   1011:     return ResultFromScode(sc);
                   1012: }
                   1013: 
                   1014: 
                   1015: STDAPI OleStdGetLinkSourceData(
                   1016:         LPMONIKER           lpmk,
                   1017:         LPCLSID             lpClsID,
                   1018:         LPFORMATETC         lpformatetc,
                   1019:         LPSTGMEDIUM         lpMedium
                   1020: )
                   1021: {
                   1022:     LPSTREAM    lpstm = NULL;
                   1023:     DWORD       reserved = 0;
                   1024:     HRESULT     hrErr;
                   1025: 
                   1026:     if (lpMedium->tymed == TYMED_NULL) {
                   1027:         if (lpformatetc->tymed & TYMED_ISTREAM) {
                   1028:             hrErr = CreateStreamOnHGlobal(
                   1029:                     NULL, /* auto allocate */
                   1030:                     TRUE, /* delete on release */
                   1031:                     (LPSTREAM FAR*)&lpstm
                   1032:             );
                   1033:             if (hrErr != NOERROR) {
                   1034:                 lpMedium->pUnkForRelease = NULL;
                   1035:                 return ResultFromScode(E_OUTOFMEMORY);
                   1036:             }
                   1037:             lpMedium->u.pstm = lpstm;
                   1038:             lpMedium->tymed = TYMED_ISTREAM;
                   1039:             lpMedium->pUnkForRelease = NULL;
                   1040:         } else {
                   1041:             lpMedium->pUnkForRelease = NULL;
                   1042:             return ResultFromScode(DATA_E_FORMATETC);
                   1043:         }
                   1044:     } else {
                   1045:         if (lpMedium->tymed == TYMED_ISTREAM) {
                   1046:             lpMedium->tymed = TYMED_ISTREAM;
                   1047:             lpMedium->u.pstm = lpMedium->u.pstm;
                   1048:             lpMedium->pUnkForRelease = NULL;
                   1049:         } else {
                   1050:             lpMedium->pUnkForRelease = NULL;
                   1051:             return ResultFromScode(DATA_E_FORMATETC);
                   1052:         }
                   1053:     }
                   1054: 
                   1055:     hrErr = OleSaveToStream((LPPERSISTSTREAM)lpmk, lpMedium->u.pstm);
                   1056:     if (hrErr != NOERROR) return hrErr;
                   1057:     return WriteClassStm(lpMedium->u.pstm, lpClsID);
                   1058: }
                   1059: 
                   1060: /*
                   1061:  * OleStdGetObjectDescriptorData
                   1062:  *
                   1063:  * Purpose:
                   1064:  *  Fills and returns a OBJECTDESCRIPTOR structure.
                   1065:  *  See OBJECTDESCRIPTOR for more information.
                   1066:  *
                   1067:  * Parameters:
                   1068:  *  clsid           CLSID   CLSID of object being transferred
                   1069:  *  dwAspect        DWORD   Display Aspect of object
                   1070:  *  sizel           SIZEL   Size of object in HIMETRIC
                   1071:  *  pointl          POINTL  Offset from upper-left corner of object where mouse went
                   1072:  *                          down for drag. Meaningful only when drag-drop is used.
                   1073:  *  dwStatus        DWORD   OLEMISC flags
                   1074:  *  lpszFullUserTypeName  LPSTR Full User Type Name
                   1075:  *  lpszSrcOfCopy   LPSTR   Source of Copy
                   1076:  *
                   1077:  * Return Value:
                   1078:  *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.
                   1079:  */
                   1080: STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(
                   1081:     CLSID     clsid,
                   1082:     DWORD     dwAspect,
                   1083:     SIZEL     sizel,
                   1084:     POINTL    pointl,
                   1085:     DWORD     dwStatus,
                   1086:     LPSTR     lpszFullUserTypeName,
                   1087:     LPSTR     lpszSrcOfCopy
                   1088: )
                   1089: {
                   1090:     HGLOBAL            hMem = NULL;
                   1091:     IBindCtx   FAR    *pbc = NULL;
                   1092:     LPOBJECTDESCRIPTOR lpOD;
                   1093:     DWORD              dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen;
                   1094: 
                   1095:     // Get the length of Full User Type Name; Add 1 for the null terminator
                   1096:     dwFullUserTypeNameLen = lpszFullUserTypeName ? lstrlen(lpszFullUserTypeName)+1 : 0;
                   1097: 
                   1098:     // Get the Source of Copy string and it's length; Add 1 for the null terminator
                   1099:     if (lpszSrcOfCopy)
                   1100:        dwSrcOfCopyLen = lstrlen(lpszSrcOfCopy)+1;
                   1101:     else {
                   1102:        // No src moniker so use user type name as source string.
                   1103:        lpszSrcOfCopy =  lpszFullUserTypeName;
                   1104:        dwSrcOfCopyLen = dwFullUserTypeNameLen;
                   1105:     }
                   1106: 
                   1107:     // Allocate space for OBJECTDESCRIPTOR and the additional string data
                   1108:     dwObjectDescSize = sizeof(OBJECTDESCRIPTOR);
                   1109:     hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
                   1110:                dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen);
                   1111:     if (NULL == hMem)
                   1112:         goto error;
                   1113: 
                   1114:     lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);
                   1115: 
                   1116:     // Set the FullUserTypeName offset and copy the string
                   1117:     if (lpszFullUserTypeName)
                   1118:     {
                   1119:         lpOD->dwFullUserTypeName = dwObjectDescSize;
                   1120:         lstrcpy((LPSTR)lpOD+lpOD->dwFullUserTypeName , lpszFullUserTypeName);
                   1121:     }
                   1122:     else lpOD->dwFullUserTypeName = 0;  // zero offset indicates that string is not present
                   1123: 
                   1124:     // Set the SrcOfCopy offset and copy the string
                   1125:     if (lpszSrcOfCopy)
                   1126:     {
                   1127:         lpOD->dwSrcOfCopy = dwObjectDescSize + dwFullUserTypeNameLen;
                   1128:         lstrcpy((LPSTR)lpOD+lpOD->dwSrcOfCopy , lpszSrcOfCopy);
                   1129:     }
                   1130:     else lpOD->dwSrcOfCopy = 0;  // zero offset indicates that string is not present
                   1131: 
                   1132:     // Initialize the rest of the OBJECTDESCRIPTOR
                   1133:     lpOD->cbSize       = dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen;
                   1134:     lpOD->clsid        = clsid;
                   1135:     lpOD->dwDrawAspect = dwAspect;
                   1136:     lpOD->sizel        = sizel;
                   1137:     lpOD->pointl       = pointl;
                   1138:     lpOD->dwStatus     = dwStatus;
                   1139: 
                   1140:     GlobalUnlock(hMem);
                   1141:     return hMem;
                   1142: 
                   1143: error:
                   1144:    if (hMem)
                   1145:    {
                   1146:        GlobalUnlock(hMem);
                   1147:        GlobalFree(hMem);
                   1148:    }
                   1149:    return NULL;
                   1150: }
                   1151: 
                   1152: /*
                   1153:  * OleStdGetObjectDescriptorDataFromOleObject
                   1154:  *
                   1155:  * Purpose:
                   1156:  *  Fills and returns a OBJECTDESCRIPTOR structure. Information for the structure is
                   1157:  *  obtained from an OLEOBJECT.
                   1158:  *  See OBJECTDESCRIPTOR for more information.
                   1159:  *
                   1160:  * Parameters:
                   1161:  *  lpOleObj        LPOLEOBJECT OleObject from which ONJECTDESCRIPTOR info 
                   1162:  *                  is obtained.
                   1163:  *  lpszSrcOfCopy   LPSTR string to identify source of copy.
                   1164:  *                  May be NULL in which case IOleObject::GetMoniker is called
                   1165:  *                  to get the moniker of the object. if the object is loaded
                   1166:  *                  as part of a data transfer document, then usually 
                   1167:  *                  lpOleClientSite==NULL is passed to OleLoad when loading
                   1168:  *                  the object. in this case the IOleObject:GetMoniker call
                   1169:  *                  will always fail (it tries to call back to the object's 
                   1170:  *                  client site). in this situation a non-NULL lpszSrcOfCopy
                   1171:  *                  parameter should be passed.
                   1172:  *  dwAspect        DWORD   Display Aspect of object
                   1173:  *  pointl          POINTL  Offset from upper-left corner of object where mouse went
                   1174:  *                          down for drag. Meaningful only when drag-drop is used.
                   1175:  *
                   1176:  * Return Value:
                   1177:  *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.
                   1178:  */
                   1179: 
                   1180: STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(
                   1181:         LPOLEOBJECT lpOleObj,
                   1182:         LPSTR       lpszSrcOfCopy,
                   1183:         DWORD       dwAspect,
                   1184:         POINTL      pointl
                   1185: )
                   1186: {
                   1187:     CLSID clsid;
                   1188:     LPSTR lpszFullUserTypeName = NULL;
                   1189:     LPMONIKER lpSrcMonikerOfCopy = NULL;
                   1190:     HGLOBAL hObjDesc;
                   1191:     IBindCtx  FAR  *pbc = NULL;
                   1192:     HRESULT hrErr;
                   1193:     SIZEL sizel;
                   1194:     BOOL  fFreeSrcOfCopy = FALSE;
                   1195:     LPOLELINK lpOleLink = 
                   1196:            (LPOLELINK)OleStdQueryInterface((LPUNKNOWN)lpOleObj,&IID_IOleLink);
                   1197:     BOOL  fIsLink = (lpOleLink ? TRUE : FALSE);
                   1198:     char  szLinkedTypeFmt[80];
                   1199:     LPSTR lpszBuf = NULL;
                   1200:     DWORD dwStatus = 0;
                   1201: 
                   1202:     // Get CLSID
                   1203:     OLEDBG_BEGIN2("IOleObject::GetUserClassID called\r\n")
                   1204:     hrErr = lpOleObj->lpVtbl->GetUserClassID(lpOleObj, &clsid);
                   1205:     OLEDBG_END2
                   1206:     if (hrErr != NOERROR)
                   1207:         clsid = CLSID_NULL;
                   1208: 
                   1209:     // Get FullUserTypeName
                   1210:     OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")
                   1211:     hrErr = lpOleObj->lpVtbl->GetUserType(
                   1212:             lpOleObj,
                   1213:             USERCLASSTYPE_FULL,
                   1214:             (LPSTR FAR*)&lpszFullUserTypeName
                   1215:     );
                   1216:     OLEDBG_END2
                   1217: 
                   1218: // REVIEW: added IDS_OLE2UILINKEDTYPE to strings.rc
                   1219:     /* if object is a link, then expand usertypename to be "Linked %s" */
                   1220:     if (fIsLink && lpszFullUserTypeName) {
                   1221:         lpszBuf = OleStdMalloc(
                   1222:                 lstrlen(lpszFullUserTypeName)+lstrlen(szLinkedTypeFmt)+1);
                   1223:         if (lpszBuf) {
                   1224: #if defined( LATER )
                   1225:             if (0 == LoadString(ghInst, IDS_OLE2UILINKEDTYPE, 
                   1226:                             (LPSTR)szLinkedTypeFmt, sizeof(szLinkedTypeFmt))) 
                   1227: #endif
                   1228:                 lstrcpy(szLinkedTypeFmt, (LPSTR)"Linked %s");
                   1229:             
                   1230:             wsprintf(lpszBuf, szLinkedTypeFmt, lpszFullUserTypeName);
                   1231:             OleStdFreeString(lpszFullUserTypeName, NULL);
                   1232:             lpszFullUserTypeName = lpszBuf;
                   1233:         }
                   1234:     }
                   1235: 
                   1236:     /* Get Source Of Copy
                   1237:     **    if the object is an embedding, then get the object's moniker
                   1238:     **    if the object is a link, then get the link source moniker
                   1239:     */
                   1240:     if (fIsLink) {
                   1241:         
                   1242:         OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n")
                   1243:         hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(
                   1244:                 lpOleLink, &lpszSrcOfCopy );
                   1245:         OLEDBG_END2
                   1246:         fFreeSrcOfCopy = TRUE;
                   1247:         
                   1248:     } else {
                   1249: 
                   1250:         if (lpszSrcOfCopy == NULL) {
                   1251:             OLEDBG_BEGIN2("IOleObject::GetMoniker called\r\n")
                   1252:             hrErr = lpOleObj->lpVtbl->GetMoniker(
                   1253:                     lpOleObj,
                   1254:                     OLEGETMONIKER_TEMPFORUSER,
                   1255:                     OLEWHICHMK_OBJFULL,
                   1256:                     (LPMONIKER FAR*)&lpSrcMonikerOfCopy
                   1257:             );
                   1258:             OLEDBG_END2
                   1259:             if (hrErr == NOERROR)
                   1260:             {
                   1261:                 CreateBindCtx(0, (LPBC FAR*)&pbc);
                   1262:                 lpSrcMonikerOfCopy->lpVtbl->GetDisplayName(
                   1263:                         lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);
                   1264:                 pbc->lpVtbl->Release(pbc);
                   1265:                 fFreeSrcOfCopy = TRUE;
                   1266:             }
                   1267:         }
                   1268:     }
                   1269: 
                   1270:     // Get SIZEL
                   1271:     OLEDBG_BEGIN2("IOleObject::GetExtent called\r\n")
                   1272:     hrErr = lpOleObj->lpVtbl->GetExtent(
                   1273:                 lpOleObj,
                   1274:                 dwAspect,
                   1275:                 &sizel
                   1276:     );
                   1277:     OLEDBG_END2
                   1278:     if (hrErr != NOERROR)
                   1279:         sizel.cx = sizel.cy = 0;
                   1280: 
                   1281:     // Get DWSTATUS
                   1282:     OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")
                   1283:     hrErr = lpOleObj->lpVtbl->GetMiscStatus(
                   1284:                 lpOleObj,
                   1285:                 dwAspect,
                   1286:                 &dwStatus
                   1287:     );
                   1288:     OLEDBG_END2
                   1289:     if (hrErr != NOERROR)
                   1290:         dwStatus = 0;
                   1291: 
                   1292:     // Get OBJECTDESCRIPTOR
                   1293:     hObjDesc = OleStdGetObjectDescriptorData(
                   1294:             clsid,
                   1295:             dwAspect,
                   1296:             sizel,
                   1297:             pointl,
                   1298:             dwStatus,
                   1299:             lpszFullUserTypeName,
                   1300:             lpszSrcOfCopy
                   1301:     );
                   1302:     if (! hObjDesc)
                   1303:         goto error;
                   1304: 
                   1305:     // Clean up
                   1306:     if (lpszFullUserTypeName)
                   1307:         OleStdFreeString(lpszFullUserTypeName, NULL);
                   1308:     if (fFreeSrcOfCopy && lpszSrcOfCopy)
                   1309:         OleStdFreeString(lpszSrcOfCopy, NULL);
                   1310:     if (lpSrcMonikerOfCopy)
                   1311:         OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);
                   1312:     if (lpOleLink)
                   1313:         OleStdRelease((LPUNKNOWN)lpOleLink);
                   1314: 
                   1315:     return hObjDesc;
                   1316: 
                   1317: error:
                   1318:     if (lpszFullUserTypeName)
                   1319:         OleStdFreeString(lpszFullUserTypeName, NULL);
                   1320:     if (fFreeSrcOfCopy && lpszSrcOfCopy)
                   1321:         OleStdFreeString(lpszSrcOfCopy, NULL);
                   1322:     if (lpSrcMonikerOfCopy)
                   1323:         OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);
                   1324:     if (lpOleLink)
                   1325:         OleStdRelease((LPUNKNOWN)lpOleLink);
                   1326: 
                   1327:     return NULL;
                   1328: }
                   1329: 
                   1330: /*
                   1331:  * OleStdFillObjectDescriptorFromData
                   1332:  *
                   1333:  * Purpose:
                   1334:  *  Fills and returns a OBJECTDESCRIPTOR structure. The source object will offer CF_OBJECTDESCRIPTOR
                   1335:  *  if it is an OLE2 object, CF_OWNERLINK if it is an OLE1 object, or CF_FILENAME if it has been
                   1336:  *  copied to the clipboard by FileManager.
                   1337:  *
                   1338:  * Parameters:
                   1339:  *  lpDataObject    LPDATAOBJECT Source object
                   1340:  *  lpmedium        LPSTGMEDIUM  Storage medium
                   1341:  *  lpcfFmt         CLIPFORMAT FAR * Format offered by lpDataObject (OUT parameter)
                   1342:  *
                   1343:  * Return Value:
                   1344:  *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.
                   1345:  */
                   1346: 
                   1347: STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(
                   1348:         LPDATAOBJECT     lpDataObject,
                   1349:         LPSTGMEDIUM      lpmedium,
                   1350:         CLIPFORMAT FAR* lpcfFmt
                   1351: )
                   1352: {
                   1353:     CLSID              clsid;
                   1354:     SIZEL              sizel;
                   1355:     POINTL             pointl;
                   1356:     LPSTR              lpsz, szFullUserTypeName, szSrcOfCopy, szClassName, szDocName, szItemName;
                   1357:     int                nClassName, nDocName, nItemName, nFullUserTypeName;
                   1358:     LPSTR              szBuf = NULL;
                   1359:     HGLOBAL            hMem = NULL;
                   1360:     HKEY               hKey = NULL;
                   1361:     LPMALLOC           pIMalloc = NULL;
                   1362:     DWORD              dw = OLEUI_CCHKEYMAX;
                   1363:     HGLOBAL            hObjDesc;
                   1364:     HRESULT            hrErr;
                   1365: 
                   1366: 
                   1367:     // GetData CF_OBJECTDESCRIPTOR format from the object on the clipboard.
                   1368:     // Only OLE 2 objects on the clipboard will offer CF_OBJECTDESCRIPTOR
                   1369:     if (hMem = OleStdGetData(
                   1370:             lpDataObject,
                   1371:             cfObjectDescriptor,
                   1372:             NULL,
                   1373:             DVASPECT_CONTENT,
                   1374:             lpmedium))
                   1375:     {
                   1376:         *lpcfFmt = cfObjectDescriptor;
                   1377:         return hMem;  // Don't drop to clean up at the end of this function
                   1378:     }
                   1379:     // If CF_OBJECTDESCRIPTOR is not available, i.e. if this is not an OLE2 object,
                   1380:     //     check if this is an OLE 1 object. OLE 1 objects will offer CF_OWNERLINK
                   1381:     else if (hMem = OleStdGetData(
                   1382:                 lpDataObject,
                   1383:                 cfOwnerLink,
                   1384:                 NULL,
                   1385:                 DVASPECT_CONTENT,
                   1386:                 lpmedium))
                   1387:     {
                   1388:         *lpcfFmt = cfOwnerLink;
                   1389:         // CF_OWNERLINK contains null-terminated strings for class name, document name
                   1390:         // and item name with two null terminating characters at the end
                   1391:         szClassName = (LPSTR)GlobalLock(hMem);
                   1392:         nClassName = lstrlen(szClassName);
                   1393:         szDocName   = szClassName + nClassName + 1;
                   1394:         nDocName   = lstrlen(szDocName);
                   1395:         szItemName  = szDocName + nDocName + 1;
                   1396:         nItemName  =  lstrlen(szItemName);
                   1397: 
                   1398:         hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
                   1399:         if (hrErr != NOERROR)
                   1400:             goto error;
                   1401: 
                   1402:         // Find FullUserTypeName from Registration database using class name
                   1403:         if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS)
                   1404:            goto error;
                   1405: 
                   1406:         // Allocate space for szFullUserTypeName & szSrcOfCopy. Maximum length of FullUserTypeName
                   1407:         // is OLEUI_CCHKEYMAX. SrcOfCopy is constructed by concatenating FullUserTypeName, Document
                   1408:         // Name and ItemName separated by spaces.
                   1409:         szBuf = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc,
                   1410:                             (DWORD)2*OLEUI_CCHKEYMAX+nDocName+nItemName+4);
                   1411:         if (NULL == szBuf)
                   1412:             goto error;
                   1413:         szFullUserTypeName = szBuf;
                   1414:         szSrcOfCopy = szFullUserTypeName+OLEUI_CCHKEYMAX+1;
                   1415: 
                   1416:         // Get FullUserTypeName
                   1417:         if (RegQueryValue(hKey, NULL, szFullUserTypeName, &dw) != ERROR_SUCCESS)
                   1418:            goto error;
                   1419: 
                   1420:         // Build up SrcOfCopy string from FullUserTypeName, DocumentName & ItemName
                   1421:         lpsz = szSrcOfCopy;
                   1422:         lstrcpy(lpsz, szFullUserTypeName);
                   1423:         nFullUserTypeName = lstrlen(szFullUserTypeName);
                   1424:         lpsz[nFullUserTypeName]=' ';
                   1425:         lpsz += nFullUserTypeName+1;
                   1426:         lstrcpy(lpsz, szDocName);
                   1427:         lpsz[nDocName] = ' ';
                   1428:         lpsz += nDocName+1;
                   1429:         lstrcpy(lpsz, szItemName);
                   1430: 
                   1431:         sizel.cx = sizel.cy = 0;
                   1432:         pointl.x = pointl.y = 0;
                   1433: 
                   1434:         CLSIDFromProgID(szClassName, &clsid);
                   1435: 
                   1436:         hObjDesc = OleStdGetObjectDescriptorData(
                   1437:                 clsid,
                   1438:                 DVASPECT_CONTENT,
                   1439:                 sizel,
                   1440:                 pointl,
                   1441:                 0,
                   1442:                 szFullUserTypeName,
                   1443:                 szSrcOfCopy
                   1444:         );
                   1445:         if (!hObjDesc)
                   1446:            goto error;
                   1447:      }
                   1448:      // Check if object is CF_FILENAME
                   1449:      else if (hMem = OleStdGetData(
                   1450:                 lpDataObject,
                   1451:                 cfFileName,
                   1452:                 NULL,
                   1453:                 DVASPECT_CONTENT,
                   1454:                 lpmedium))
                   1455:      {
                   1456:          *lpcfFmt = cfFileName;
                   1457:          lpsz = (LPSTR)GlobalLock(hMem);
                   1458:          hrErr = GetClassFile(lpsz, &clsid);
                   1459: 
                   1460:          /* OLE2NOTE: if the file does not have an OLE class
                   1461:          **    associated, then use the OLE 1 Packager as the class of
                   1462:          **    the object to be created. this is the behavior of
                   1463:          **    OleCreateFromData API
                   1464:          */
                   1465:          if (hrErr != NOERROR)
                   1466:             CLSIDFromProgID("Package", &clsid);
                   1467:          sizel.cx = sizel.cy = 0;
                   1468:          pointl.x = pointl.y = 0;
                   1469: 
                   1470:          hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
                   1471:          if (hrErr != NOERROR)
                   1472:             goto error;
                   1473:          szBuf = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)OLEUI_CCHKEYMAX);
                   1474:          if (NULL == szBuf)
                   1475:             goto error;
                   1476: 
                   1477:          OleStdGetUserTypeOfClass(&clsid, szBuf, OLEUI_CCHKEYMAX, NULL);
                   1478: 
                   1479:          hObjDesc = OleStdGetObjectDescriptorData(
                   1480:                 clsid,
                   1481:                 DVASPECT_CONTENT,
                   1482:                 sizel,
                   1483:                 pointl,
                   1484:                 0,
                   1485:                 szBuf,
                   1486:                 lpsz
                   1487:         );
                   1488:         if (!hObjDesc)
                   1489:            goto error;
                   1490:      }
                   1491:      else goto error;
                   1492: 
                   1493:      // Clean up
                   1494:      if (szBuf)
                   1495:          pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);
                   1496:      if (pIMalloc)
                   1497:          OleStdRelease((LPUNKNOWN)pIMalloc);
                   1498:      if (hMem)
                   1499:      {
                   1500:          GlobalUnlock(hMem);
                   1501:          GlobalFree(hMem);
                   1502:      }
                   1503:      if (hKey)
                   1504:          RegCloseKey(hKey);
                   1505:      return hObjDesc;
                   1506: 
                   1507: error:
                   1508:    if (szBuf)
                   1509:        pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);
                   1510:    if (pIMalloc)
                   1511:        OleStdRelease((LPUNKNOWN)pIMalloc);
                   1512:      if (hMem)
                   1513:      {
                   1514:          GlobalUnlock(hMem);
                   1515:          GlobalFree(hMem);
                   1516:      }
                   1517:      if (hKey)
                   1518:          RegCloseKey(hKey);
                   1519:      return NULL;
                   1520: }
                   1521: 
                   1522: 
                   1523: STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc)
                   1524: {
                   1525:     if (lpformatetc->tymed & TYMED_ISTORAGE) {
                   1526:         return NOERROR;
                   1527:     } else {
                   1528:         return ResultFromScode(DATA_E_FORMATETC);
                   1529:     }
                   1530: }
                   1531: 
                   1532: 
                   1533: STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc)
                   1534: {
                   1535:     if (lpformatetc->tymed & TYMED_ISTREAM)
                   1536:         return NOERROR;
                   1537:     else
                   1538:         return ResultFromScode(DATA_E_FORMATETC);
                   1539: }
                   1540: 
                   1541: 
                   1542: STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc)
                   1543: {
                   1544:     if (lpformatetc->tymed & TYMED_HGLOBAL) {
                   1545:         return NOERROR;
                   1546:     } else {
                   1547:         return ResultFromScode(DATA_E_FORMATETC);
                   1548:     }
                   1549: }
                   1550: 
                   1551: 
                   1552: STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed)
                   1553: {
                   1554:     if (lpformatetc->tymed & tymed) {
                   1555:         return NOERROR;
                   1556:     } else {
                   1557:         return ResultFromScode(DATA_E_FORMATETC);
                   1558:     }
                   1559: }
                   1560: 
                   1561: 
                   1562: 
                   1563: /*
                   1564:  * OleStdCopyMetafilePict()
                   1565:  *
                   1566:  * Purpose:
                   1567:  *    Make an independent copy of a MetafilePict
                   1568:  * Parameters:
                   1569:  *
                   1570:  * Return Value:
                   1571:  *    TRUE if successful, else FALSE.
                   1572:  */
                   1573: STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout)
                   1574: {
                   1575:     HANDLE hpictout;
                   1576:     LPMETAFILEPICT ppictin, ppictout;
                   1577: 
                   1578:     if (hpictin == NULL || phpictout == NULL) {
                   1579:         OleDbgAssert(hpictin == NULL || phpictout == NULL);
                   1580:         return FALSE;
                   1581:     }
                   1582: 
                   1583:     *phpictout = NULL;
                   1584: 
                   1585:     if ((ppictin = (LPMETAFILEPICT)GlobalLock(hpictin)) == NULL) {
                   1586:         return FALSE;
                   1587:     }
                   1588: 
                   1589:     hpictout = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
                   1590: 
                   1591:     if (hpictout && (ppictout = (LPMETAFILEPICT)GlobalLock(hpictout))){
                   1592:         ppictout->hMF  = CopyMetaFile(ppictin->hMF, NULL);
                   1593:         ppictout->xExt = ppictin->xExt;
                   1594:         ppictout->yExt = ppictin->yExt;
                   1595:         ppictout->mm   = ppictin->mm;
                   1596:         GlobalUnlock(hpictout);
                   1597:     }
                   1598: 
                   1599:     *phpictout = hpictout;
                   1600: 
                   1601:     return TRUE;
                   1602: 
                   1603: }
                   1604: 
                   1605: 
                   1606: /*
                   1607:  * OleStdGetMetafilePictFromOleObject()
                   1608:  *
                   1609:  * Purpose:
                   1610:  *      Generate a MetafilePict by drawing the OLE object.
                   1611:  * Parameters:
                   1612:  *
                   1613:  * Return Value:
                   1614:  *    HANDLE    -- handle of allocated METAFILEPICT
                   1615:  */
                   1616: STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(
                   1617:         LPOLEOBJECT         lpOleObj,
                   1618:         DWORD               dwDrawAspect
                   1619: )
                   1620: {
                   1621:     LPVIEWOBJECT lpViewObj = NULL;
                   1622:     HDC hDC;
                   1623:     HMETAFILE hmf;
                   1624:     HANDLE hMetaPict;
                   1625:     LPMETAFILEPICT lpPict;
                   1626:     RECT rcHim;
                   1627:     RECTL rclHim;
                   1628:     SIZEL sizelHim;
                   1629:     HRESULT hrErr;
                   1630:     SIZE size;
                   1631:     POINT point;
                   1632: 
                   1633:     lpViewObj = (LPVIEWOBJECT)OleStdQueryInterface(
                   1634:             (LPUNKNOWN)lpOleObj, &IID_IViewObject);
                   1635:     if (! lpViewObj)
                   1636:         return NULL;
                   1637: 
                   1638:     OLEDBG_BEGIN2("IOleObject::GetExtent called\r\n")
                   1639:     lpOleObj->lpVtbl->GetExtent(
                   1640:                 lpOleObj,
                   1641:                 dwDrawAspect,
                   1642:                 (LPSIZEL)&sizelHim
                   1643:     );
                   1644:     OLEDBG_END2
                   1645: 
                   1646:     hDC = CreateMetaFile(NULL);
                   1647: 
                   1648:     rclHim.left     = 0;
                   1649:     rclHim.top      = 0;
                   1650:     rclHim.right    = sizelHim.cx;
                   1651:     rclHim.bottom   = sizelHim.cy;
                   1652: 
                   1653:     rcHim.left      = (int)rclHim.left;
                   1654:     rcHim.top       = (int)rclHim.top;
                   1655:     rcHim.right     = (int)rclHim.right;
                   1656:     rcHim.bottom    = (int)rclHim.bottom;
                   1657: 
                   1658:     SetWindowOrgEx(hDC, rcHim.left, rcHim.top, &point);
                   1659:     SetWindowExtEx(hDC, rcHim.right-rcHim.left, rcHim.bottom-rcHim.top,&size);
                   1660: 
                   1661:     OLEDBG_BEGIN2("IViewObject::Draw called\r\n")
                   1662:     hrErr = lpViewObj->lpVtbl->Draw(
                   1663:             lpViewObj,
                   1664:             dwDrawAspect,
                   1665:             -1,
                   1666:             NULL,
                   1667:             NULL,
                   1668:             NULL,
                   1669:             hDC,
                   1670:             (LPRECTL)&rclHim,
                   1671:             (LPRECTL)&rclHim,
                   1672:             NULL,
                   1673:             0
                   1674:     );
                   1675:     OLEDBG_END2
                   1676: 
                   1677:     OleStdRelease((LPUNKNOWN)lpViewObj);
                   1678:     if (hrErr != NOERROR) {
                   1679:         OleDbgOutHResult("IViewObject::Draw returned", hrErr);
                   1680:     }
                   1681: 
                   1682:     hmf = CloseMetaFile(hDC);
                   1683: 
                   1684:     hMetaPict = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
                   1685: 
                   1686:     if (hMetaPict && (lpPict = (LPMETAFILEPICT)GlobalLock(hMetaPict))){
                   1687:         lpPict->hMF  = hmf;
                   1688:         lpPict->xExt = (int)sizelHim.cx ;
                   1689:         lpPict->yExt = (int)sizelHim.cy ;
                   1690:         lpPict->mm   = MM_ANISOTROPIC;
                   1691:         GlobalUnlock(hMetaPict);
                   1692:     }
                   1693: 
                   1694:     return hMetaPict;
                   1695: }
                   1696: 
                   1697: 
                   1698: /* Call Release on the object that is expected to go away.
                   1699: **      if the refcnt of the object did no go to 0 then give a debug message.
                   1700: */
                   1701: STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPSTR lpszMsg)
                   1702: {
                   1703:     ULONG cRef;
                   1704: 
                   1705:     cRef = lpUnk->lpVtbl->Release(lpUnk);
                   1706: 
                   1707: #if defined( _DEBUG )
                   1708:     if (cRef != 0) {
                   1709:         char szBuf[80];
                   1710:         if (lpszMsg)
                   1711:             MessageBox(NULL, lpszMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
                   1712:         wsprintf(
                   1713:                 (LPSTR)szBuf,
                   1714:                 "refcnt (%ld) != 0 after object (0x%lx) release\n",
                   1715:                 cRef,
                   1716:                 lpUnk
                   1717:         );
                   1718:         if (lpszMsg)
                   1719:             OleDbgOut1(lpszMsg);
                   1720:         OleDbgOut1((LPSTR)szBuf);
                   1721:         OleDbgAssertSz(cRef == 0, (LPSTR)szBuf);
                   1722:     } else {
                   1723:         char szBuf[80];
                   1724:         wsprintf(
                   1725:                 (LPSTR)szBuf,
                   1726:                 "refcnt = 0 after object (0x%lx) release\n", lpUnk
                   1727:         );
                   1728:         OleDbgOut4((LPSTR)szBuf);
                   1729:     }
                   1730: #endif
                   1731:     return cRef;
                   1732: }
                   1733: 
                   1734: 
                   1735: /* Call Release on the object that is NOT necessarily expected to go away.
                   1736: */
                   1737: STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk)
                   1738: {
                   1739:     ULONG cRef;
                   1740: 
                   1741:     cRef = lpUnk->lpVtbl->Release(lpUnk);
                   1742: 
                   1743: #if defined( _DEBUG )
                   1744:     {
                   1745:         char szBuf[80];
                   1746:         wsprintf(
                   1747:                 (LPSTR)szBuf,
                   1748:                 "refcnt = %ld after object (0x%lx) release\n",
                   1749:                 cRef,
                   1750:                 lpUnk
                   1751:         );
                   1752:         OleDbgOut4((LPSTR)szBuf);
                   1753:     }
                   1754: #endif
                   1755:     return cRef;
                   1756: }
                   1757: 
                   1758: 
                   1759: /* OleStdInitVtbl
                   1760: ** --------------
                   1761: **
                   1762: **    Initialize an interface Vtbl to ensure that there are no NULL
                   1763: **    function pointers in the Vtbl. All entries in the Vtbl are
                   1764: **    set to a valid funtion pointer (OleStdNullMethod) that issues
                   1765: **        debug assert message (message box) and returns E_NOTIMPL if called.
                   1766: **
                   1767: **    NOTE: this funtion does not initialize the Vtbl with usefull
                   1768: **    function pointers, only valid function pointers to avoid the
                   1769: **    horrible run-time crash when a call is made through the Vtbl with
                   1770: **    a NULL function pointer. this API is only necessary when
                   1771: **    initializing the Vtbl's in C. C++ guarantees that all interface
                   1772: **    functions (in C++ terms -- pure virtual functions) are implemented.
                   1773: */
                   1774: 
                   1775: STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl)
                   1776: {
                   1777:     LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;
                   1778:     UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);
                   1779:     UINT i;
                   1780: 
                   1781:     for (i = 0; i < nMethods; i++) {
                   1782:         lpFuncPtrArr[i] = OleStdNullMethod;
                   1783:     }
                   1784: }
                   1785: 
                   1786: 
                   1787: /* OleStdCheckVtbl
                   1788: ** ---------------
                   1789: **
                   1790: **    Check if all entries in the Vtbl are properly initialized with
                   1791: **    valid function pointers. If any entries are either NULL or
                   1792: **    OleStdNullMethod, then this function returns FALSE. If compiled
                   1793: **    for _DEBUG this function reports which function pointers are
                   1794: **    invalid.
                   1795: **
                   1796: **    RETURNS:  TRUE if all entries in Vtbl are valid
                   1797: **                              FALSE otherwise.
                   1798: */
                   1799: 
                   1800: STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPSTR lpszIface)
                   1801: {
                   1802:     LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;
                   1803:     UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);
                   1804:     UINT i;
                   1805:     BOOL fStatus = TRUE;
                   1806:     int nChar = 0;
                   1807: 
                   1808:     for (i = 0; i < nMethods; i++) {
                   1809:         if (lpFuncPtrArr[i] == NULL || lpFuncPtrArr[i] == OleStdNullMethod) {
                   1810: #if defined( _DEBUG )
                   1811:             char szBuf[256];
                   1812:             wsprintf(szBuf, "%s::method# %d NOT valid!", lpszIface, i);
                   1813:             OleDbgOut1((LPSTR)szBuf);
                   1814: #endif
                   1815:             fStatus = FALSE;
                   1816:         }
                   1817:     }
                   1818:     return fStatus;
                   1819: }
                   1820: 
                   1821: 
                   1822: /* OleStdNullMethod
                   1823: ** ----------------
                   1824: **    Dummy method used by OleStdInitVtbl to initialize an interface
                   1825: **    Vtbl to ensure that there are no NULL function pointers in the
                   1826: **    Vtbl. All entries in the Vtbl are set to this function. this
                   1827: **    function issues a debug assert message (message box) and returns
                   1828: **    E_NOTIMPL if called. If all is done properly, this function will
                   1829: **    NEVER be called!
                   1830: */
                   1831: STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis)
                   1832: {
                   1833:     MessageBox(
                   1834:             NULL,
                   1835:             "ERROR: INTERFACE METHOD NOT IMPLEMENTED!\r\n",
                   1836:             NULL,
                   1837:             MB_SYSTEMMODAL | MB_ICONHAND | MB_OK
                   1838:     );
                   1839: 
                   1840:     return ResultFromScode(E_NOTIMPL);
                   1841: }
                   1842: 
                   1843: 
                   1844: 
                   1845: static BOOL  GetFileTimes(LPSTR lpszFileName, FILETIME FAR* pfiletime)
                   1846: {
                   1847: #ifdef WIN32
                   1848:     WIN32_FIND_DATA fd;
                   1849:     HANDLE hFind;
                   1850:     hFind = FindFirstFile(lpszFileName,&fd);
                   1851:     if (hFind == NULL || hFind == INVALID_HANDLE_VALUE) {
                   1852:         return FALSE;
                   1853:     }
                   1854:     FindClose(hFind);
                   1855:     *pfiletime = fd.ftLastWriteTime;
                   1856:     return TRUE;
                   1857: #else
                   1858:     static char sz[256];
                   1859:     static struct _find_t fileinfo;
                   1860: 
                   1861:     lstrcpyn((LPSTR)sz, lpszFileName, sizeof(sz)-1);
                   1862:     sz[sizeof(sz)-1]= '\0';
                   1863:     AnsiToOem(sz, sz);
                   1864:     return (_dos_findfirst(sz,_A_NORMAL|_A_HIDDEN|_A_SUBDIR|_A_SYSTEM,
                   1865:                      (struct _find_t *)&fileinfo) == 0 &&
                   1866:         CoDosDateTimeToFileTime(fileinfo.wr_date,fileinfo.wr_time,pfiletime));
                   1867: #endif 
                   1868: }
                   1869: 
                   1870: 
                   1871: 
                   1872: /* OleStdRegisterAsRunning
                   1873: ** -----------------------
                   1874: **    Register a moniker in the RunningObjectTable.
                   1875: **    if there is an existing registration (*lpdwRegister!=NULL), then
                   1876: **    first revoke that registration.
                   1877: **    
                   1878: **    new dwRegister key is returned via *lpdwRegister parameter.
                   1879: */
                   1880: STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister)
                   1881: {
                   1882:     LPRUNNINGOBJECTTABLE lpROT;
                   1883:     HRESULT hrErr;
                   1884:     DWORD dwOldRegister = *lpdwRegister;
                   1885: 
                   1886:     OLEDBG_BEGIN2("OleStdRegisterAsRunning\r\n")
                   1887: 
                   1888:     OLEDBG_BEGIN2("GetRunningObjectTable called\r\n")
                   1889:     hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
                   1890:     OLEDBG_END2
                   1891: 
                   1892:     if (hrErr == NOERROR) {
                   1893: 
                   1894:         /* register as running if a valid moniker is passed
                   1895:         **
                   1896:         ** OLE2NOTE: we deliberately register the new moniker BEFORE
                   1897:         **    revoking the old moniker just in case the object
                   1898:         **    currently has no external locks. if the object has no
                   1899:         **    locks then revoking it from the running object table will
                   1900:         **    cause the object's StubManager to initiate shutdown of
                   1901:         **    the object.
                   1902:         */
                   1903:         if (lpmkFull) {
                   1904: 
                   1905:             OLEDBG_BEGIN2("IRunningObjectTable::Register called\r\n")
                   1906:             lpROT->lpVtbl->Register(lpROT, 0, lpUnk,lpmkFull,lpdwRegister);
                   1907:             OLEDBG_END2
                   1908: 
                   1909: #if _DEBUG
                   1910:             {
                   1911:                 char szBuf[512];
                   1912:                 LPSTR lpszDisplay;
                   1913:                 LPBC lpbc;
                   1914: 
                   1915:                 CreateBindCtx(0, (LPBC FAR*)&lpbc);
                   1916:                 lpmkFull->lpVtbl->GetDisplayName(
                   1917:                         lpmkFull,
                   1918:                         lpbc,
                   1919:                         NULL,
                   1920:                         (LPSTR FAR*)&lpszDisplay
                   1921:                 );
                   1922:                 OleStdRelease((LPUNKNOWN)lpbc);
                   1923:                 wsprintf(
                   1924:                         szBuf,
                   1925:                         "Moniker '%s' REGISTERED as [0x%lx] in ROT\r\n",
                   1926:                         lpszDisplay,
                   1927:                         *lpdwRegister
                   1928:                 );
                   1929:                 OleDbgOut2(szBuf);
                   1930:                 OleStdFreeString(lpszDisplay, NULL);
                   1931:             }
                   1932: #endif  // _DEBUG
                   1933: 
                   1934:         }
                   1935: 
                   1936:         // if already registered, revoke
                   1937:         if (dwOldRegister != 0) {
                   1938: 
                   1939: #if _DEBUG
                   1940:             {
                   1941:                 char szBuf[512];
                   1942: 
                   1943:                 wsprintf(
                   1944:                         szBuf,
                   1945:                         "Moniker [0x%lx] REVOKED from ROT\r\n",
                   1946:                         dwOldRegister
                   1947:                 );
                   1948:                 OleDbgOut2(szBuf);
                   1949:             }
                   1950: #endif  // _DEBUG
                   1951: 
                   1952:             OLEDBG_BEGIN2("IRunningObjectTable::Revoke called\r\n")
                   1953:             lpROT->lpVtbl->Revoke(lpROT, dwOldRegister);
                   1954:             OLEDBG_END2
                   1955: 
                   1956:             *lpdwRegister = 0;
                   1957:         }
                   1958: 
                   1959:         OleStdRelease((LPUNKNOWN)lpROT);
                   1960:     } else {
                   1961:         OleDbgAssertSz(
                   1962:                 lpROT != NULL,
                   1963:                 "OleStdRegisterAsRunning: GetRunningObjectTable FAILED\r\n"
                   1964:         );
                   1965:     }
                   1966: 
                   1967:     OLEDBG_END2
                   1968: }
                   1969: 
                   1970: 
                   1971: 
                   1972: /* OleStdRevokeAsRunning
                   1973: ** ---------------------
                   1974: **    Revoke a moniker from the RunningObjectTable if there is an
                   1975: **    existing registration (*lpdwRegister!=NULL).
                   1976: **    
                   1977: **    *lpdwRegister parameter will be set to NULL.
                   1978: */
                   1979: STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister)
                   1980: {
                   1981:     LPRUNNINGOBJECTTABLE lpROT;
                   1982:     HRESULT hrErr;
                   1983: 
                   1984:     OLEDBG_BEGIN2("OleStdRevokeAsRunning\r\n")
                   1985: 
                   1986:     // if still registered, then revoke
                   1987:     if (*lpdwRegister != 0) {
                   1988: 
                   1989:         OLEDBG_BEGIN2("GetRunningObjectTable called\r\n")
                   1990:         hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
                   1991:         OLEDBG_END2
                   1992: 
                   1993:         if (hrErr == NOERROR) {
                   1994: 
                   1995: #if _DEBUG
                   1996:             {
                   1997:                 char szBuf[512];
                   1998: 
                   1999:                 wsprintf(
                   2000:                         szBuf,
                   2001:                         "Moniker [0x%lx] REVOKED from ROT\r\n",
                   2002:                         *lpdwRegister
                   2003:                 );
                   2004:                 OleDbgOut2(szBuf);
                   2005:             }
                   2006: #endif  // _DEBUG
                   2007: 
                   2008:             OLEDBG_BEGIN2("IRunningObjectTable::Revoke called\r\n")
                   2009:             lpROT->lpVtbl->Revoke(lpROT, *lpdwRegister);
                   2010:             OLEDBG_END2
                   2011: 
                   2012:             *lpdwRegister = 0;
                   2013: 
                   2014:             OleStdRelease((LPUNKNOWN)lpROT);
                   2015:         } else {
                   2016:             OleDbgAssertSz(
                   2017:                     lpROT != NULL,
                   2018:                     "OleStdRevokeAsRunning: GetRunningObjectTable FAILED\r\n"
                   2019:             );
                   2020:         }
                   2021:     }
                   2022:     OLEDBG_END2
                   2023: }
                   2024: 
                   2025: 
                   2026: /* OleStdNoteFileChangeTime
                   2027: ** ------------------------
                   2028: **    Note the time a File-Based object has been saved in the
                   2029: **    RunningObjectTable. These change times are used as the basis for
                   2030: **    IOleObject::IsUpToDate. 
                   2031: **    It is important to set the time of the file-based object
                   2032: **    following a save operation to exactly the time of the saved file.
                   2033: **    this helps IOleObject::IsUpToDate to give the correct answer
                   2034: **    after a file has been saved.
                   2035: */
                   2036: STDAPI_(void) OleStdNoteFileChangeTime(LPSTR lpszFileName, DWORD dwRegister)
                   2037: {
                   2038:     if (dwRegister != 0) {
                   2039: 
                   2040:         LPRUNNINGOBJECTTABLE lprot;
                   2041:         FILETIME filetime;
                   2042: 
                   2043:         if (GetFileTimes(lpszFileName, &filetime) &&
                   2044:             GetRunningObjectTable(0,&lprot) == NOERROR)
                   2045:         {
                   2046:             lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );
                   2047:             lprot->lpVtbl->Release(lprot);
                   2048:             
                   2049:             OleDbgOut2("IRunningObjectTable::NoteChangeTime called\r\n");
                   2050:         }
                   2051:     }
                   2052: }
                   2053: 
                   2054: 
                   2055: /* OleStdNoteObjectChangeTime
                   2056: ** --------------------------
                   2057: **    Set the last change time of an object that is registered in the
                   2058: **    RunningObjectTable. These change times are used as the basis for
                   2059: **    IOleObject::IsUpToDate. 
                   2060: **    
                   2061: **    every time the object sends out a OnDataChange notification, it
                   2062: **    should update the Time of last change in the ROT.
                   2063: **    
                   2064: **    NOTE: this function set the change time to the current time.
                   2065: */
                   2066: STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister)
                   2067: {
                   2068:     if (dwRegister != 0) {
                   2069: 
                   2070:         LPRUNNINGOBJECTTABLE lprot;
                   2071:         FILETIME filetime;
                   2072: 
                   2073:         if (GetRunningObjectTable(0,&lprot) == NOERROR)
                   2074:         {
                   2075:             CoFileTimeNow( &filetime );
                   2076:             lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );
                   2077:             lprot->lpVtbl->Release(lprot);
                   2078:             
                   2079:             OleDbgOut2("IRunningObjectTable::NoteChangeTime called\r\n");
                   2080:         }
                   2081:     }
                   2082: }
                   2083: 
                   2084: 
                   2085: 
                   2086: STDAPI_(void) OleStdCreateTempFileMoniker(LPSTR lpszPrefixString, UINT FAR* lpuUnique, LPSTR lpszName, LPMONIKER FAR* lplpmk)
                   2087: {
                   2088:     LPRUNNINGOBJECTTABLE lpROT = NULL;
                   2089:     UINT i = (lpuUnique != NULL ? *lpuUnique : 1);
                   2090:     HRESULT hrErr;
                   2091: 
                   2092:     wsprintf(lpszName, "%s%d", lpszPrefixString, i++);
                   2093:     CreateFileMoniker(lpszName, lplpmk);
                   2094: 
                   2095:     OLEDBG_BEGIN2("GetRunningObjectTable called\r\n")
                   2096:     hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
                   2097:     OLEDBG_END2
                   2098: 
                   2099:     if (hrErr == NOERROR) {
                   2100: 
                   2101:         while (1) {
                   2102:             if (! *lplpmk)
                   2103:                 break;  // failed to create FileMoniker
                   2104: 
                   2105:             OLEDBG_BEGIN2("IRunningObjectTable::IsRunning called\r\n")
                   2106:             hrErr = lpROT->lpVtbl->IsRunning(lpROT,*lplpmk);
                   2107:             OLEDBG_END2
                   2108: 
                   2109:             if (hrErr != NOERROR)
                   2110:                 break;  // the Moniker is NOT running; found unused one!
                   2111: 
                   2112:             OleStdVerifyRelease(
                   2113:                     (LPUNKNOWN)*lplpmk,
                   2114:                     "OleStdCreateTempFileMoniker: Moniker NOT released"
                   2115:                 );
                   2116: 
                   2117:             wsprintf(lpszName, "%s%d", lpszPrefixString, i++);
                   2118:             CreateFileMoniker(lpszName, lplpmk);
                   2119:         }
                   2120: 
                   2121:         OleStdRelease((LPUNKNOWN)lpROT);
                   2122:     }
                   2123: 
                   2124:     if (lpuUnique != NULL)
                   2125:         *lpuUnique = i;
                   2126: }
                   2127: 
                   2128: 
                   2129: /* OleStdGetFirstMoniker
                   2130: ** ---------------------
                   2131: **    return the first piece of a moniker.
                   2132: **
                   2133: **    NOTE: if the given moniker is not a generic composite moniker,
                   2134: **    then an AddRef'ed pointer to the given moniker is returned.
                   2135: */
                   2136: STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk)
                   2137: {
                   2138:     LPMONIKER       lpmkFirst = NULL;
                   2139:     LPENUMMONIKER   lpenumMoniker;
                   2140:     DWORD           dwMksys;
                   2141:     HRESULT         hrErr;
                   2142: 
                   2143:     if (! lpmk)
                   2144:         return NULL;
                   2145: 
                   2146:     if (lpmk->lpVtbl->IsSystemMoniker(lpmk, (LPDWORD)&dwMksys) == NOERROR
                   2147:         && dwMksys == MKSYS_GENERICCOMPOSITE) {
                   2148: 
                   2149:         /* OLE2NOTE: the moniker is a GenericCompositeMoniker.
                   2150:         **    enumerate the moniker to pull off the first piece.
                   2151:         */
                   2152: 
                   2153:         hrErr = lpmk->lpVtbl->Enum(
                   2154:                 lpmk,
                   2155:                 TRUE /* fForward */,
                   2156:                 (LPENUMMONIKER FAR*)&lpenumMoniker
                   2157:         );
                   2158:         if (hrErr != NOERROR)
                   2159:             return NULL;    // ERROR: give up!
                   2160: 
                   2161:         hrErr = lpenumMoniker->lpVtbl->Next(
                   2162:                 lpenumMoniker,
                   2163:                 1,
                   2164:                 (LPMONIKER FAR*)&lpmkFirst,
                   2165:                 NULL
                   2166:         );
                   2167:         lpenumMoniker->lpVtbl->Release(lpenumMoniker);
                   2168:         return lpmkFirst;
                   2169: 
                   2170:     } else {
                   2171:         /* OLE2NOTE: the moniker is NOT a GenericCompositeMoniker.
                   2172:         **    return an AddRef'ed pointer to the input moniker.
                   2173:         */
                   2174:         lpmk->lpVtbl->AddRef(lpmk);
                   2175:         return lpmk;
                   2176:     }
                   2177: }
                   2178: 
                   2179: 
                   2180: /* OleStdGetLenFilePrefixOfMoniker
                   2181: ** -------------------------------
                   2182: **    if the first piece of the Moniker is a FileMoniker, then return
                   2183: **    the length of the filename string. 
                   2184: **    
                   2185: **    lpmk      pointer to moniker
                   2186: **    
                   2187: **    Returns
                   2188: **      0       if moniker does NOT start with a FileMoniker
                   2189: **      uLen    string length of filename prefix of the display name
                   2190: **              retrieved from the given (lpmk) moniker.
                   2191: */
                   2192: STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk)
                   2193: {
                   2194:     LPMONIKER       lpmkFirst = NULL;
                   2195:     DWORD           dwMksys;
                   2196:     LPSTR           lpsz = NULL;
                   2197:     LPBC            lpbc = NULL;
                   2198:     ULONG           uLen = 0;
                   2199:     HRESULT         hrErr;
                   2200: 
                   2201:     if (! lpmk)
                   2202:         return 0;
                   2203: 
                   2204:     lpmkFirst = OleStdGetFirstMoniker(lpmk);
                   2205:     if (lpmkFirst) {
                   2206:         if ( (lpmkFirst->lpVtbl->IsSystemMoniker(
                   2207:                             lpmkFirst, (LPDWORD)&dwMksys) == NOERROR)
                   2208:                 && dwMksys == MKSYS_FILEMONIKER) {
                   2209: 
                   2210:             hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);
                   2211:             if (hrErr == NOERROR) {
                   2212:                 hrErr = lpmkFirst->lpVtbl->GetDisplayName(
                   2213:                         lpmkFirst,
                   2214:                         lpbc,
                   2215:                         NULL,   /* pmkToLeft */
                   2216:                         (LPSTR FAR*)&lpsz
                   2217:                 );
                   2218:                 if (hrErr == NOERROR && lpsz != NULL) {
                   2219:                     uLen = lstrlen(lpsz);
                   2220:                     OleStdFreeString(lpsz, NULL);
                   2221:                 }
                   2222:                 OleStdRelease((LPUNKNOWN)lpbc);
                   2223:             }
                   2224:         }
                   2225:         lpmkFirst->lpVtbl->Release(lpmkFirst);
                   2226:     }
                   2227:     return uLen;
                   2228: }
                   2229: 
                   2230: 
                   2231: /*
                   2232:  * OleStdMarkPasteEntryList
                   2233:  *
                   2234:  * Purpose:
                   2235:  *  Mark each entry in the PasteEntryList if its format is available from 
                   2236:  *  the source IDataObject*. the dwScratchSpace field of each PasteEntry
                   2237:  *  is set to TRUE if available, else FALSE.
                   2238:  *
                   2239:  * Parameters:
                   2240:  *  LPOLEUIPASTEENTRY   array of PasteEntry structures
                   2241:  *  int                 count of elements in PasteEntry array
                   2242:  *  LPDATAOBJECT        source IDataObject* pointer
                   2243:  *
                   2244:  * Return Value:
                   2245:  *   none
                   2246:  */
                   2247: STDAPI_(void) OleStdMarkPasteEntryList(
                   2248:         LPDATAOBJECT        lpSrcDataObj,
                   2249:         LPOLEUIPASTEENTRY   lpPriorityList, 
                   2250:         int                 cEntries
                   2251: )
                   2252: {
                   2253:     LPENUMFORMATETC     lpEnumFmtEtc = NULL;
                   2254:     FORMATETC           fmtetc;
                   2255:     int                 i;
                   2256:     HRESULT             hrErr;
                   2257: 
                   2258:     // Clear all marks
                   2259:     for (i = 0; i < cEntries; i++) {
                   2260:         lpPriorityList[i].dwScratchSpace = FALSE;
                   2261:         
                   2262:         if (! lpPriorityList[i].fmtetc.cfFormat) {
                   2263:             // caller wants this item always considered available
                   2264:             // (by specifying a NULL format)
                   2265:             lpPriorityList[i].dwScratchSpace = TRUE;
                   2266:         } else if (lpPriorityList[i].fmtetc.cfFormat == cfEmbeddedObject
                   2267:                 || lpPriorityList[i].fmtetc.cfFormat == cfEmbedSource
                   2268:                 || lpPriorityList[i].fmtetc.cfFormat == cfFileName) {
                   2269: 
                   2270:             // if there is an OLE object format, then handle it 
                   2271:             // specially by calling OleQueryCreateFromData. the caller 
                   2272:             // need only specify one object type format.
                   2273:             OLEDBG_BEGIN2("OleQueryCreateFromData called\r\n")
                   2274:             hrErr = OleQueryCreateFromData(lpSrcDataObj);
                   2275:             OLEDBG_END2
                   2276:             if(NOERROR == hrErr) {
                   2277:                 lpPriorityList[i].dwScratchSpace = TRUE;
                   2278:             } 
                   2279:         } else if (lpPriorityList[i].fmtetc.cfFormat == cfLinkSource) {
                   2280: 
                   2281:             // if there is OLE 2.0 LinkSource format, then handle it 
                   2282:             // specially by calling OleQueryLinkFromData.
                   2283:             OLEDBG_BEGIN2("OleQueryLinkFromData called\r\n")
                   2284:             hrErr = OleQueryLinkFromData(lpSrcDataObj);
                   2285:             OLEDBG_END2
                   2286:             if(NOERROR == hrErr) {
                   2287:                 lpPriorityList[i].dwScratchSpace = TRUE;
                   2288:             } 
                   2289:         }
                   2290:     }
                   2291: 
                   2292:     OLEDBG_BEGIN2("IDataObject::EnumFormatEtc called\r\n")
                   2293:     hrErr = lpSrcDataObj->lpVtbl->EnumFormatEtc(
                   2294:             lpSrcDataObj,
                   2295:             DATADIR_GET,
                   2296:             (LPENUMFORMATETC FAR*)&lpEnumFmtEtc
                   2297:     );
                   2298:     OLEDBG_END2
                   2299: 
                   2300:     if (hrErr != NOERROR)
                   2301:         return;    // unable to get format enumerator
                   2302: 
                   2303:     // Enumerate the formats offered by the source
                   2304:     // Loop over all formats offered by the source
                   2305:     while (lpEnumFmtEtc->lpVtbl->Next(
                   2306:             lpEnumFmtEtc, 1, (LPFORMATETC)&fmtetc, NULL) == S_OK)
                   2307:     {
                   2308:         for (i = 0; i < cEntries; i++)
                   2309:         {
                   2310:             if (! lpPriorityList[i].dwScratchSpace &&
                   2311:                 IsEqualFORMATETC(fmtetc, lpPriorityList[i].fmtetc))
                   2312:             {
                   2313:                 lpPriorityList[i].dwScratchSpace = TRUE;
                   2314:             }
                   2315:         }
                   2316:     }
                   2317: 
                   2318:     // Clean up
                   2319:     if (lpEnumFmtEtc)
                   2320:         OleStdRelease((LPUNKNOWN)lpEnumFmtEtc);
                   2321: }
                   2322: 
                   2323: 
                   2324: /* OleStdGetPriorityClipboardFormat
                   2325: ** --------------------------------
                   2326: **
                   2327: **    Retrieve the first clipboard format in a list for which data
                   2328: **    exists in the source IDataObject*.
                   2329: **
                   2330: **    Returns -1 if no acceptable match is found.
                   2331: **                        index of first acceptable match in the priority list.
                   2332: **
                   2333: */
                   2334: STDAPI_(int) OleStdGetPriorityClipboardFormat(LPDATAOBJECT lpSrcDataObj, LPOLEUIPASTEENTRY lpPriorityList, int cEntries)
                   2335: {
                   2336:     int i;
                   2337:     int nFmtEtc = -1;
                   2338: 
                   2339:     // Mark all entries that the Source provides
                   2340:     OleStdMarkPasteEntryList(lpSrcDataObj, lpPriorityList, cEntries);
                   2341: 
                   2342:     // Loop over the target's priority list of formats
                   2343:     for (i = 0; i < cEntries; i++)
                   2344:     {
                   2345:         if (lpPriorityList[i].dwFlags != OLEUIPASTE_PASTEONLY &&
                   2346:                 !(lpPriorityList[i].dwFlags & OLEUIPASTE_PASTE)) 
                   2347:             continue;
                   2348:              
                   2349:         // get first marked entry
                   2350:         if (lpPriorityList[i].dwScratchSpace) {
                   2351:             nFmtEtc = i;
                   2352:             break;          // Found priority format; DONE
                   2353:         }
                   2354:     }
                   2355:     
                   2356:     return nFmtEtc;
                   2357: }
                   2358: 
                   2359: 
                   2360: /* OleStdIsDuplicateFormat
                   2361: ** -----------------------
                   2362: **    Returns TRUE if the lpFmtEtc->cfFormat is found in the array of
                   2363: **    FormatEtc structures.
                   2364: */
                   2365: STDAPI_(BOOL) OleStdIsDuplicateFormat(
                   2366:         LPFORMATETC         lpFmtEtc,
                   2367:         LPFORMATETC         arrFmtEtc,
                   2368:         int                 nFmtEtc
                   2369: )
                   2370: {
                   2371:     int i;
                   2372: 
                   2373:     for (i = 0; i < nFmtEtc; i++) {
                   2374:         if (lpFmtEtc->cfFormat == arrFmtEtc[i].cfFormat)
                   2375:             return TRUE;
                   2376:     }
                   2377: 
                   2378:     return FALSE;
                   2379: }
                   2380: 
                   2381: 
                   2382: /* OleStdGetDropEffect
                   2383: ** -------------------
                   2384: **
                   2385: ** Convert a keyboard state into a DROPEFFECT.
                   2386: **
                   2387: ** returns the DROPEFFECT value derived from the key state.
                   2388: **    the following is the standard interpretation:
                   2389: **          no modifier -- Default Drop     (NULL is returned)
                   2390: **          CTRL        -- DROPEFFECT_COPY
                   2391: **          SHIFT       -- DROPEFFECT_MOVE
                   2392: **          CTRL-SHIFT  -- DROPEFFECT_LINK
                   2393: **
                   2394: **    Default Drop: this depends on the type of the target application.
                   2395: **    this is re-interpretable by each target application. a typical
                   2396: **    interpretation is if the drag is local to the same document
                   2397: **    (which is source of the drag) then a MOVE operation is
                   2398: **    performed. if the drag is not local, then a COPY operation is
                   2399: **    performed.
                   2400: */
                   2401: STDAPI_(DWORD) OleStdGetDropEffect( DWORD grfKeyState )
                   2402: {
                   2403: 
                   2404:     if (grfKeyState & MK_CONTROL) {
                   2405: 
                   2406:         if (grfKeyState & MK_SHIFT)
                   2407:             return DROPEFFECT_LINK;
                   2408:         else
                   2409:             return DROPEFFECT_COPY;
                   2410: 
                   2411:     } else if (grfKeyState & MK_SHIFT)
                   2412:         return DROPEFFECT_MOVE;
                   2413: 
                   2414:     return 0;    // no modifier -- do default operation
                   2415: }
                   2416: 
                   2417: 
                   2418: /* OleStdGetItemToken
                   2419:  * ------------------
                   2420:  *
                   2421:  * LPSTR lpszSrc - Pointer to a source string
                   2422:  * LPSTR lpszDst - Pointer to destination buffer
                   2423:  *
                   2424:  * Will copy one token from the lpszSrc buffer to the lpszItem buffer.
                   2425:  * It considers all alpha-numeric and white space characters as valid
                   2426:  * characters for a token. the first non-valid character delimates the
                   2427:  * token.
                   2428:  *
                   2429:  * returns the number of charaters eaten.
                   2430:  */
                   2431: STDAPI_(ULONG) OleStdGetItemToken(LPSTR lpszSrc, LPSTR lpszDst, int nMaxChars)
                   2432: {
                   2433:     ULONG chEaten = 0L;
                   2434: 
                   2435:     // skip leading delimeter characters
                   2436:     while (*lpszSrc && --nMaxChars > 0
                   2437:                                && ((*lpszSrc=='/') || (*lpszSrc=='\\') || 
                   2438:                                                                   (*lpszSrc=='!') || (*lpszSrc==':'))) {
                   2439:         *lpszSrc++;
                   2440:         chEaten++;
                   2441:        }
                   2442: 
                   2443:     // Extract token string (up to first delimeter char or EOS)
                   2444:     while (*lpszSrc && --nMaxChars > 0
                   2445:                                && !((*lpszSrc=='/') || (*lpszSrc=='\\') || 
                   2446:                                                                   (*lpszSrc=='!') || (*lpszSrc==':'))) {
                   2447:         *lpszDst++ = *lpszSrc++;
                   2448:         chEaten++;
                   2449:     }
                   2450:     *lpszDst = '\0';
                   2451:     return chEaten;
                   2452: }
                   2453: 
                   2454: 
                   2455: /*************************************************************************
                   2456: ** OleStdCreateRootStorage
                   2457: **    create a root level Storage given a filename that is compatible
                   2458: **    to be used by a top-level OLE container. if the filename
                   2459: **    specifies an existing file, then an error is returned.
                   2460: **    the root storage (Docfile) that is created by this function
                   2461: **    is suitable to be used to create child storages for embedings.
                   2462: **    (CreateChildStorage can be used to create child storages.)
                   2463: **    NOTE: the root-level storage is opened in transacted mode.
                   2464: *************************************************************************/
                   2465: 
                   2466: STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPSTR lpszStgName, DWORD grfMode)
                   2467: {
                   2468:     HRESULT hr;
                   2469:     DWORD grfCreateMode = STGM_READWRITE | STGM_TRANSACTED;
                   2470:     DWORD reserved = 0;
                   2471:     LPSTORAGE lpRootStg;
                   2472:     char szMsg[64];
                   2473: 
                   2474:     // if temp file is being created, enable delete-on-release
                   2475:     if (! lpszStgName)
                   2476:         grfCreateMode |= STGM_DELETEONRELEASE;
                   2477: 
                   2478:     hr = StgCreateDocfile(
                   2479:             lpszStgName,
                   2480:             grfMode | grfCreateMode,
                   2481:             reserved,
                   2482:             (LPSTORAGE FAR*)&lpRootStg
                   2483:         );
                   2484: 
                   2485:     if (hr == NOERROR)
                   2486:         return lpRootStg;               // existing file successfully opened
                   2487: 
                   2488:     OleDbgOutHResult("StgCreateDocfile returned", hr);
                   2489: 
                   2490:     if (0 == LoadString(ghInst, IDS_OLESTDNOCREATEFILE, (LPSTR)szMsg, 64))
                   2491:       return NULL;
                   2492: 
                   2493:     MessageBox(NULL, (LPSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);
                   2494:     return NULL;
                   2495: }
                   2496: 
                   2497: 
                   2498: /*************************************************************************
                   2499: ** OleStdOpenRootStorage
                   2500: **    open a root level Storage given a filename that is compatible
                   2501: **    to be used by a top-level OLE container. if the file does not
                   2502: **    exist then an error is returned.
                   2503: **    the root storage (Docfile) that is opened by this function
                   2504: **    is suitable to be used to create child storages for embedings.
                   2505: **    (CreateChildStorage can be used to create child storages.)
                   2506: **    NOTE: the root-level storage is opened in transacted mode.
                   2507: *************************************************************************/
                   2508: 
                   2509: STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPSTR lpszStgName, DWORD grfMode)
                   2510: {
                   2511:     HRESULT hr;
                   2512:     DWORD reserved = 0;
                   2513:     LPSTORAGE lpRootStg;
                   2514:     char  szMsg[64];
                   2515: 
                   2516:     if (lpszStgName) {
                   2517: 
                   2518:         hr = StgOpenStorage(
                   2519:                 lpszStgName,
                   2520:                 NULL,
                   2521:                 grfMode | STGM_TRANSACTED,
                   2522:                 NULL,
                   2523:                 reserved,
                   2524:                 (LPSTORAGE FAR*)&lpRootStg
                   2525:             );
                   2526: 
                   2527:         if (hr == NOERROR)
                   2528:             return lpRootStg;     // existing file successfully opened
                   2529: 
                   2530:         OleDbgOutHResult("StgOpenStorage returned", hr);
                   2531:     }
                   2532: 
                   2533:     if (0 == LoadString(ghInst, IDS_OLESTDNOOPENFILE, szMsg, 64))
                   2534:       return NULL;
                   2535: 
                   2536:     MessageBox(NULL, (LPSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);
                   2537:     return NULL;
                   2538: }
                   2539: 
                   2540: 
                   2541: /*************************************************************************
                   2542: ** OpenOrCreateRootStorage
                   2543: **    open a root level Storage given a filename that is compatible
                   2544: **    to be used by a top-level OLE container. if the filename
                   2545: **    specifies an existing file, then it is open, otherwise a new file
                   2546: **    with the given name is created.
                   2547: **    the root storage (Docfile) that is created by this function
                   2548: **    is suitable to be used to create child storages for embedings.
                   2549: **    (CreateChildStorage can be used to create child storages.)
                   2550: **    NOTE: the root-level storage is opened in transacted mode.
                   2551: *************************************************************************/
                   2552: 
                   2553: STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPSTR lpszStgName, DWORD grfMode)
                   2554: {
                   2555:     HRESULT hrErr;
                   2556:     SCODE sc;
                   2557:     DWORD reserved = 0;
                   2558:     LPSTORAGE lpRootStg;
                   2559:     char      szMsg[64];
                   2560: 
                   2561:     if (lpszStgName) {
                   2562: 
                   2563:         hrErr = StgOpenStorage(
                   2564:                 lpszStgName,
                   2565:                 NULL,
                   2566:                 grfMode | STGM_READWRITE | STGM_TRANSACTED,
                   2567:                 NULL,
                   2568:                 reserved,
                   2569:                 (LPSTORAGE FAR*)&lpRootStg
                   2570:         );
                   2571: 
                   2572:         if (hrErr == NOERROR)
                   2573:             return lpRootStg;      // existing file successfully opened
                   2574: 
                   2575:         OleDbgOutHResult("StgOpenStorage returned", hrErr);
                   2576:         sc = GetScode(hrErr);
                   2577: 
                   2578:         if (sc!=STG_E_FILENOTFOUND && sc!=STG_E_FILEALREADYEXISTS) {
                   2579:             return NULL;
                   2580:         }
                   2581:     }
                   2582: 
                   2583:     /* if file did not already exist, try to create a new one */
                   2584:     hrErr = StgCreateDocfile(
                   2585:             lpszStgName,
                   2586:             grfMode | STGM_READWRITE | STGM_TRANSACTED,
                   2587:             reserved,
                   2588:             (LPSTORAGE FAR*)&lpRootStg
                   2589:     );
                   2590: 
                   2591:     if (hrErr == NOERROR)
                   2592:         return lpRootStg;               // existing file successfully opened
                   2593: 
                   2594:     OleDbgOutHResult("StgCreateDocfile returned", hrErr);
                   2595: 
                   2596:     if (0 == LoadString(ghInst, IDS_OLESTDNOCREATEFILE, (LPSTR)szMsg, 64))
                   2597:       return NULL;
                   2598: 
                   2599:     MessageBox(NULL, (LPSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
                   2600:     return NULL;
                   2601: }
                   2602: 
                   2603: 
                   2604: /*
                   2605: ** OleStdCreateChildStorage
                   2606: **    create a child Storage inside the given lpStg that is compatible
                   2607: **    to be used by an embedded OLE object. the return value from this
                   2608: **    function can be passed to OleCreateXXX functions.
                   2609: **    NOTE: the child storage is opened in transacted mode.
                   2610: */
                   2611: STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPSTR lpszStgName)
                   2612: {
                   2613:     if (lpStg != NULL) {
                   2614:         LPSTORAGE lpChildStg;
                   2615:         DWORD grfMode = (STGM_READWRITE | STGM_TRANSACTED |
                   2616:                 STGM_SHARE_EXCLUSIVE);
                   2617:         DWORD reserved = 0;
                   2618: 
                   2619:         HRESULT hrErr = lpStg->lpVtbl->CreateStorage(
                   2620:                 lpStg,
                   2621:                 lpszStgName,
                   2622:                 grfMode,
                   2623:                 reserved,
                   2624:                 reserved,
                   2625:                 (LPSTORAGE FAR*)&lpChildStg
                   2626:             );
                   2627: 
                   2628:         if (hrErr == NOERROR)
                   2629:             return lpChildStg;
                   2630: 
                   2631:         OleDbgOutHResult("lpStg->lpVtbl->CreateStorage returned", hrErr);
                   2632:     }
                   2633:     return NULL;
                   2634: }
                   2635: 
                   2636: 
                   2637: /*
                   2638: ** OleStdOpenChildStorage
                   2639: **    open a child Storage inside the given lpStg that is compatible
                   2640: **    to be used by an embedded OLE object. the return value from this
                   2641: **    function can be passed to OleLoad function.
                   2642: **    NOTE: the child storage is opened in transacted mode.
                   2643: */
                   2644: STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPSTR lpszStgName, DWORD grfMode)
                   2645: {
                   2646:     LPSTORAGE lpChildStg;
                   2647:     LPSTORAGE lpstgPriority = NULL;
                   2648:     DWORD reserved = 0;
                   2649:     HRESULT hrErr;
                   2650: 
                   2651:     if (lpStg  != NULL) {
                   2652: 
                   2653:         hrErr = lpStg->lpVtbl->OpenStorage(
                   2654:                 lpStg,
                   2655:                 lpszStgName,
                   2656:                 lpstgPriority,
                   2657:                 grfMode | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
                   2658:                 NULL,
                   2659:                 reserved,
                   2660:                 (LPSTORAGE FAR*)&lpChildStg
                   2661:             );
                   2662: 
                   2663:         if (hrErr == NOERROR)
                   2664:             return lpChildStg;
                   2665: 
                   2666:         OleDbgOutHResult("lpStg->lpVtbl->OpenStorage returned", hrErr);
                   2667:     }
                   2668:     return NULL;
                   2669: }
                   2670: 
                   2671: /* OleStdCommitStorage
                   2672: ** -------------------
                   2673: **    Commit the changes to the given IStorage*. This routine can be
                   2674: **    called on either a root-level storage as used by an OLE-Container
                   2675: **    or by a child storage as used by an embedded object.
                   2676: **
                   2677: **    This routine first attempts to perform this commit in a safe
                   2678: **    manner. if this fails it then attempts to do the commit in a less
                   2679: **    robust manner (STGC_OVERWRITE).
                   2680: */
                   2681: STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg)
                   2682: {
                   2683:     HRESULT hrErr;
                   2684: 
                   2685:     // make the changes permanent
                   2686:     hrErr = lpStg->lpVtbl->Commit(lpStg, 0);
                   2687: 
                   2688:     if (GetScode(hrErr) == STG_E_MEDIUMFULL) {
                   2689:         // try to commit changes in less robust manner.
                   2690:         OleDbgOut("Warning: commiting with STGC_OVERWRITE specified\n");
                   2691:         hrErr = lpStg->lpVtbl->Commit(lpStg, STGC_OVERWRITE);
                   2692:     }
                   2693: 
                   2694:     if (hrErr != NOERROR)
                   2695:     {
                   2696:         char szMsg[64];
                   2697: 
                   2698:         if (0 == LoadString(ghInst, IDS_OLESTDDISKFULL, (LPSTR)szMsg, 64))
                   2699:            return FALSE;
                   2700: 
                   2701:         MessageBox(NULL, (LPSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
                   2702:         return FALSE;
                   2703:     }
                   2704:     else {
                   2705:         return TRUE;
                   2706:     }
                   2707: }

unix.superglobalmegacorp.com

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