//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: oddataxfer
//
//   CLASSES: none
//
//   ORIGINS: 82,27,94
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//
// @(#) 1.18 nt/src/storage/WLink.cpp, oddataxfer, od96nt, odnt9712d 10/14/96 18:34:26 [ 3/21/97 17:14:07 ]
/*
	File:		Link.cpp

	Contains:	Implementation of ODLink class

	Owned by:	Craig Carper

	Copyright:	© 1993 - 1995 by Apple Computer, Inc., all rights reserved.

	Change History (most recent first):

		<43>	 10/8/95	TJ		Fixes Recomended by Refball
		<42>	 10/4/95	jpa		Added missing ODVolatiles [1285799]
		<41>	  9/8/95	T‚		1281096 FB2:Many constants in ODTypesB
									without kOD prefix!
		<40>	 8/12/95	T‚		1276807 Opt./Bug: use StdTypIO routines for
									portable streaming & smaller footprint
		<39>	  8/3/95	RR		#1257260: Collapse B classes. Remove
									somInit methods. Don't call IsInitialized
									or SubclassResponsibility
		<38>	 7/28/95	CC		1183569: Externalize only when dirty.
		<37>	 7/27/95	CC		1259986: WriteLinkEdition: Close edition
									file on failure.
									CreateLinkEdition: Delete edition file on
									error writing file.
		<36>	 7/24/95	CC		1154714: Removed ODUpdateID parameter from
									UpdateDependents.
		<35>	 7/21/95	CC		1153788: Write 'TEXT' & 'PICT' formats to
									Edition file.
		<34>	 6/30/95	CC		1242642: DeleteLinkEdition: Release after
									unregistering.
		<33>	 5/26/95	VL		1251403: Multithreading naming support.
		<32>	 5/22/95	CC		1248361: CloneToMemoryContainer:
									Externalize content SU to  resolve promises
									before cloning to memory container.
		<31>	 5/18/95	CC		1238898: Add destFrame argument to
									BeginClone call.
		<30>	 5/16/95	CC		1248090: CloneToMemoryContainer: Clone
									content frame if present.
		<29>	 4/25/95	CC		1242555:  Removed obsolete $5 comment.
		<28>	 4/14/95	T‚		#1235279 BB: InfoUtil & StdTypIO functions
									should take Environment* and SU* when
									possible
		<27>	 4/11/95	CC		1236452:  Replaced SOM_CATCH with SOM_TRY
									in WriteLinkEdition.
									Added parenthesis to TopDraft (probably not
									necessary).
		<26>	  4/3/95	CC		1229068: IsTopDraft: Use ODDocument::Exists
									to test for top draft.
		<25>	  3/9/95	CC		1221471: Added changesAllowed parameter to
									ShowLinkDestinationInfo().
		<24>	  3/3/95	CC		1223861, 1153949 Override
									ShowLinkDestinationInfo().
		<23>	  2/7/95	CC		1185113 Externalize: Lock handles during
									writing.
									1193560 InitLinkFromStorage: Use ptr
									returned by ODLockHandle;
									WASSERTS --> ifÉTHROW
		<22>	  2/1/95	CC		1153347 Added static function IsTopDraft().
									Register sections if draft is topmost.
									Use IsRegisteredSection for robustness.
		<21>	 1/19/95	CC		1212831, 1193556, 1194158 Use creator of
									document file when creating edition file.
		<20>	12/22/94	CC		1153926 UpdateDependents() - Update
									cross-document links immediately if source
									is manual.
		<19>	12/22/94	CC		1153759 CreateLinkEdition - call ODDRaft::
									SetChangedFromPrev().
									1207987 Added DeleteLinkEdition().
		<18>	12/20/94	VL		1195012: Make Storage calls be
									marshallable.
		<17>	12/16/94	CC		1203516 Removed ODLinkSource parameter from
									InitLink().
		<16>	 12/8/94	CC		1154711 InitLinkFromStorage(),
									ReleaseAll(): Only register & unregister
									with the Edition manager if draft has write
									permission.
		<15>	11/30/94	RR		1188078 Use ODTime, not time_t
		<14>	 10/7/94	CC		1191089 - Use change time for mod date of
									edition file.
		<13>	 10/4/94	CC		1190862 - Added Release().
		<12>	 9/29/94	RA		1189812: Mods for 68K build.
		<11>	 9/23/94	VL		1184272: ContainerID is now a sequence of
									octets.
		<10>	 9/15/94	CC		1186669 - Implemented CloneInto();
									CloneToMemoryContainer use draftKey for
									Clone() call.
		 <9>	  9/7/94	CC		#1185114 - Catch throws from KeyValid().
		 <8>	 8/26/94	VL		1183174: Use updated cloning APIs.
		 <7>	 8/15/94	T‚		#1180922 Removed most obsolete types from
									StdTypes.idl
		 <6>	 8/10/94	CC		1179943 - Moved platform-independent
									implementation into LinkB.cpp.
		 <5>	  8/3/94	VL		1153123: Storage to ODStor.
		 <4>	 6/24/94	CC		Clean up some easy $5 comments.
		 <3>	 6/24/94	CC		Added call to ShowLinkDestinationInfo().
		 <2>	 6/24/94	CC		Changed parameters to InitBaseLink().
		 <1>	 6/21/94	CC		first checked in

		------------------- CC ---- Converted to SOM

		 <5>	  5/9/94	MB		#1162181: Changes necessary to install MMM.
		 <4>	 4/12/94	CC		Clients may call UnregisterDependent()
									after this object's ReleaseAll() method has
									run. (1155973)
		 <3>	 3/28/94	CG		1153547: ODSessn.h renamed to ODSessM.h
		 <2>	 3/27/94	T‚		#1153523.  Adjust name of
									kODPropRootPartSU to more clearly indicate
									what it is supposed to be used for.
		 <1>	 3/25/94	CC		first checked in

		------------------- CC ---- Moved from Core to Storage subsystem

		 <7>	 3/24/94	CC		Implemented CloneTo() (1153038) and
									GetChangeTime() (115340).
		 <6>	 3/15/94	MB		Changes to support SCpp/ASLM builds,
									#1150864.
		 <5>	  3/2/94	CC		ReleaseAll: Check fLinkSource for NIL
									before releasing it! (1144936)
		 <4>	  3/1/94	JA		Include ODMemory.h. (1147588)
		 <3>	  3/1/94	CC		Replaced calls to HLock, HUnlock, and
									GetHandleSize with OD equivalents.
		 <2>	 2/17/94	CC		CloneToMemoryContainer: Re-instate fix lost
									after 2/2/94	checkin.
		<12>	  2/8/94	T‚		Throw -> THROW & some code clean up
		<11>	  2/7/94	T‚		more fixes to compile with PPC Headers
		<10>	  2/4/94	T‚		fixes to compile with PPC Universal headers
		 <9>	  2/3/94	CG		System Session break out.
		 <8>	  2/2/94	CC		CloneToMemoryContainer:  Moved code to set
									kODPropRootSU property after the rootSU
									has been determined.
		 <7>	  2/1/94	CC		Pass ODCloneKind argument to BeginClone.
		 <6>	 1/28/94	CC		Added ReleaseAll(); increment and decrement
									ref count of part in ODPartList::AddPart
									and ::RemovePart; release parts and delete
									list entries in ODPartList destructor.
		 <5>	 1/27/94	VL		Used ODStorageUnit::CloneInto.
		 <4>	 1/25/94	CC		CloneToMemoryContainer: use distinct
									identifiers for clipboard and draft keys;
									RegisterDependent: call LinkUpdated only if
									change id is different; GetTextValue: add
									Volatile stmt.; UpdateDependents: remove
									ODUnused().
		 <3>	 1/24/94	CC		Added ODUpdateID parameter to call to
									LinkUpdated().
		 <2>	 1/22/94	CC		Don't call release() in destructor.
		 <1>	 1/21/94	CC		first checked in
		<17>	 1/18/94	CG		Added include for StorgDef.h
		<16>	 1/18/94	CC		Use kODScrapTypePart; release draft
									properties on failure in
									CloneToMemoryContainer and
									CloneFromMemoryContainer
		<15>	 1/14/94	CC		Added Lock(), Unlock(), GetTimeStamp(),
									GetStatus(), SetAutoExport(),
									IsAutoExport(), Export(),
									ShowSourceContent(), type ODLinkKey; added
									key parameter to various routines; renamed
									Edition Manager support routines.
		<14>	 1/11/94	T‚		Init... changes
		<13>	12/22/93	CC		Maintain persistent fields fContentSU and
									fChangedDate.  Read/write link content
									from/to edition file by cloning fContentSU
									into a memory container.  Increment link
									ref count for registered sections.  Write
									edition files only on Externalize().
		<12>	12/21/93	VL		Changed ODStorageUnit::GetValueSize to
									StorageUnit::GetSize.
		<11>	12/16/93	CC		Added methods to create, write, and read
									Edition files.  Save Edition Manager
									section records and aliases persistently.
		<10>	12/14/93	T‚		InitLink changes.  Internalize, Initialize
									went away.
		 <9>	 12/8/93	CC		ODValueLink -> ODPartListLink to avoid
									name conflict.  Removed multiple
									constructors.  Added InitPartListLink
		 <8>	11/18/93	T‚		call inherited::InitializePersistent()
									::Externalize()
		 <7>	11/17/93	CC		RegisterDependent calls the LinkUpdated
									method of its part argument.
		 <6>	 9/29/93	VL		Added InitializePersistent.
		 <5>	  7/1/93	NP		Abstract/Concrete breakout.
		 <4>	 6/10/93	NP		Added comments.
		 <3>	 4/28/93	NP		File name changes.
		 <2>	 4/27/93	NP		Now compilable.
		 <1>	 4/21/93	NP		first checked in

	To Do:
	In Progress:
*/

#define VARIABLE_MACROS

#define ODLink_Class_Source
#include <Link.xih>

#ifndef _LINKDLGS_
#include <LinkDlgs.h>
#endif

#ifndef _EXCEPT_
#include <Except.h>
#endif

#ifndef _ODMEMORY_
#include <ODMemory.h>
#endif

#ifndef _CONSTDEF_
#include <ConstDf.h>
#endif

#ifndef SOM_ODLinkSource_xh
#include <LinkSrc.xh>
#endif

#ifndef SOM_ODLinkManager_xh
#include <LinkMgr.xh>
#endif

#ifndef SOM_ODPart_xh
#include <Part.xh>
#endif

#ifndef SOM_ODSession_xh
#include <ODSessn.xh>
#endif

#ifndef SOM_ODContainer_xh
#include <ODCtr.xh>
#endif

#ifndef SOM_ODDocument_xh
#include <Document.xh>
#endif

#ifndef SOM_ODDraft_xh
#include <Draft.xh>
#endif

#ifndef SOM_ODStorageSystem_xh
#include <ODStor.xh>
#endif

#ifndef _PLFMFILE_
#include <PlfmFile.h>
#endif

#ifndef SOM_ODStorageUnit_xh
#include <StorageU.xh>
#endif

#ifndef SOM_Module_OpenDoc_StdProps_defined
#include <StdProps.xh>
#endif

#ifndef SOM_Module_OpenDoc_StdTypes_defined
#include <StdTypes.xh>
#endif

#ifndef __ERRORS__
#include <Errors.h>
#endif

#ifndef _ODDEBUG_
#include <ODDebug.h>
#endif

#ifndef _BARRAY_
#include <BArray.h>
#endif

#ifndef _STDTYPIO_
#include <StdTypIO.h>
#endif

#ifndef _STORUTIL_
#include <StorUtil.h>
#endif

#ifndef SOM_ODTranslation_xh
#include <Translt.xh>
#endif

#ifndef SOM_Module_OpenDoc_StdDefs_defined
#include <StdDefs.xh>
#endif

#ifdef OD_PAGETUNE_H_
#include <ODPagtun.h>
#endif

#ifndef _ODUTILW_
#include "ODUtilW.h"
#endif

#ifndef _OLEDATA_H_
#include "OleData.h"
#endif

#ifndef _OLEXFER_H_
#include "OleXfer.h"
#endif

#ifndef _OLEMGRW_
#include "OLEMgrW.h"
#endif

#if ODDebug
#define ODDebugLink 1
#else
#define ODDebugLink 0
#endif

#pragma segment ODLink

//==============================================================================
// Local Functions
//==============================================================================
//==============================================================================
// ODLink
//==============================================================================

//------------------------------------------------------------------------------
// ODLink: somUninit
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinksomUninit(ODLink *somSelf)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","somUninit");

    if (_fpszItemName)
    	ODDisposePtr(_fpszItemName);
    if (_fpDataObject)
    	((IUnknown*)_fpDataObject)->Release();

    parent_somUninit(somSelf);
}

//------------------------------------------------------------------------------
// ODLink: InitLink
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkInitLink(ODLink *somSelf, Environment *ev,
		ODStorageUnit* storageUnit)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","InitLink");

	SOM_TRY


	/* Moved from somInit. SOM itself sets fields to zero
	_fSection = (SectionHandle) kODNULL;
	_fDirty = kODFalse;
	*/
	somSelf->InitBaseLink(ev, storageUnit);
	somSelf->SetLinkDirty(ev);  // added 23 may 96 rrk - where else do we need to set this?

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLink: InitLinkFromStorage
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkInitLinkFromStorage(ODLink *somSelf, Environment *ev,
		ODStorageUnit* storageUnit)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","InitLinkFromStorage");

	SOM_TRY


	
	/* Moved from somInit. SOM itself sets fields to zero
	_fSection = (SectionHandle) kODNULL;
	_fDirty = kODFalse;
	*/
	somSelf->InitBaseLinkFromStorage(ev, storageUnit);



	/* Read the item name - if it was used
	 */
	if (storageUnit->Exists(ev,kODPropLinkItem, kODAppleITEM, 0))
	{
		storageUnit->Focus(ev,kODPropLinkItem, kODPosUndefined,
						   kODAppleITEM, (ODValueIndex)0,kODPosUndefined);
		ODULong size	 		= storageUnit->GetSize(ev);
		_fpszItemName	= (char*)ODNewPtrClear(size); // rrk 3 sep 96 added clear
		if(_fpszItemName)
			StorageUnitGetValue(storageUnit, ev,size,_fpszItemName);
		
		somSelf->Acquire(ev);	// Link must not be deleted until its item
									// name is unregistered...
	}

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLink: Release (OVERRIDE)
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkRelease(ODLink *somSelf, Environment *ev)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","Release");

	SOM_TRY

	parent_Release(somSelf, ev);

#if ODDebugLink
	somPrintf("ODLink %d::Release: Ref count is %d\n", somSelf->GetID(ev), somSelf->GetRefCount(ev));
#endif

	if (somSelf->GetRefCount(ev) == 0)
		somSelf->GetStorageUnit(ev)->GetDraft(ev)->ReleaseLink(ev, somSelf);

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLink: Externalize (OVERRIDE)
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkExternalize(ODLink *somSelf, Environment *ev)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","Externalize");

	SOM_TRY

    parent_Externalize(somSelf,ev);

	ODStorageUnit* su = somSelf->GetStorageUnit(ev);

	if ( _fDirty )
	{

	/* Save the link item moniker name if we have been given it...
	 */
	if (_fpszItemName)
	{
		if (su->Exists(ev,kODPropLinkItem, 0, 0))
		{

			su->Focus(ev,kODPropLinkItem, kODPosUndefined,
					  (ODValueType) 0, (ODValueIndex) 0, kODPosUndefined);
			su->Remove(ev);
		}

  		//if (!su->Exists(ev,kODPropLinkItem, kODAppleITEM, 0))
  			su->AddProperty(ev,kODPropLinkItem)->AddValue(ev,kODAppleITEM);
  		su->Focus(ev,kODPropLinkItem, kODPosUndefined,
				  kODAppleITEM, (ODValueIndex)0, kODPosUndefined);
		StorageUnitSetValue(su, ev,strlen(_fpszItemName), (ODValue)_fpszItemName);
	}
	else
	{
		if (su->Exists(ev,kODPropLinkItem, 0, 0))
		{
			su->Focus(ev,kODPropLinkItem, kODPosUndefined,
					  (ODValueType) 0, (ODValueIndex) 0, kODPosUndefined);
			su->Remove(ev);
		}
	}

	_fDirty = kODFalse;
	}

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLink: CloneInto (OVERRIDE)
//------------------------------------------------------------------------------
// We don't clone the cross-document link info, so a second publisher can't be created.
// This depends on this method being called rather than ODStorageUnit::CloneInto().
// Currently, all link objects are internalized when a draft is opened, so this is true.

SOM_Scope void  SOMLINK ODLinkCloneInto(ODLink *somSelf, Environment *ev,
		ODDraftKey key,
		ODStorageUnit* toSU,
		ODFrame* scopeFrame)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","CloneInto");

	SOM_TRY
#	
	// If one of our properties already exists, this object has been cloned already

	if ( toSU->Exists(ev, kODPropLinkItem, kODAppleITEM, 0 ) )  
		return;

	parent_CloneInto(somSelf, ev, key, toSU, scopeFrame);

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLink: ReleaseAll (OVERRIDE)
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkReleaseAll(ODLink *somSelf, Environment *ev)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","ReleaseAll");

	SOM_TRY


    parent_ReleaseAll(somSelf,ev);



	/* If we are linked to from the outside, release the item name and the
	 * data object we created (if applicable)
	 */
	if (_fpszItemName)
	{
		ODDisposePtr(_fpszItemName);
		_fpszItemName		= NULL;
		if (_fpDataObject)
		{
			((IUnknown*)_fpDataObject)->Release();
			_fpDataObject	= NULL;
		}

		//		somSelf->Release(ev);   /* RefCount incremented when item was registered */
	}

	somSelf->Release(ev);   /* RefCount incremented when item was registered */

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODBaseLink: UpdateDependents (OVERRIDE)
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkUpdateDependents(ODLink *somSelf, Environment *ev)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","UpdateDependents");

	HRESULT				hr;
	IUnknown			*pOleData;
	ODBoolean			bLocked;

	SOM_TRY

    parent_UpdateDependents(somSelf, ev);


        /* Update the IDataObject if necessary and send an OnDataChange
       	 * notification back to anyone who registered for advice notifications
       	 * on this object.
       	 */

	ODLinkKey key;
	if (somSelf->GetLinkSource(ev)->Lock(ev, 0, &key)) {
	  somSelf->RefreshDataObject(ev,key);
	  somSelf->GetLinkSource(ev)->Unlock(ev, key);
	}

       	if (_fpszItemName && _fpDataObject)
       	{
       		hr = ((IDataObject*)_fpDataObject)->QueryInterface(IID_IUnknown,
       																		  (void**)&pOleData);
       		if(SUCCEEDED(hr))
       		{
       			((OleData*)pOleData)->OnDataChange();
       			pOleData->Release();
       		}
       	}

        if (_fpszItemName && somSelf->GetLinkSource(ev)->IsAutoUpdate(ev))
	{
		ODLinkManager*	linkManager = somSelf->GetStorageUnit(ev)->GetSession(ev)->GetLinkManager(ev);
		linkManager->ExportOnSave(ev,somSelf, kODTrue);
	}


	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLink::ShowLinkDestinationInfo (OVERRIDE)
//------------------------------------------------------------------------------

SOM_Scope ODBoolean  SOMLINK ODLinkShowLinkDestinationInfo(ODLink *somSelf, Environment *ev,
		ODFacet* facet,
		ODLinkInfo* info,
		ODBoolean changesAllowed,
		ODLinkInfoResult* infoResult)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","ShowLinkDestinationInfo");

	SOM_TRY

	
	ODLinkSource* linkSource = somSelf->GetLinkSource(ev);

#ifdef _PLATFORM_MACINTOSH_	
	// RRK 30 Apr 96 - I'm leaving this ifdef in to remind us that this is where the Mac code
	//                 calls interrogates the link status and puts up a status alert if
	//                 applicable.  GetStatus() is mac-specific and does not apply to our
	//                 implementation.
	ODError error = linkSource->GetStatus(ev);

	if ( error )
		ShowLinkStatusAlert(error);
#endif // _PLATFORM_MACINTOSH_

	return parent_ShowLinkDestinationInfo(somSelf, ev, facet, info, changesAllowed, infoResult);

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return kODFalse;
}

//------------------------------------------------------------------------------
// ODLink: SetLinkDirty
//         note: rrk 23 may 96; the design says we don't need this, but I think now that we do.
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkSetLinkDirty(ODLink *somSelf, Environment *ev)
{
    ODLinkData *somThis = ODLinkGetData(somSelf);
    ODLinkMethodDebug("ODLink","SetLinkDirty");

	SOM_TRY	
		_fDirty = kODTrue;

		ODDraft* draft = somSelf->GetStorageUnit(ev)->GetDraft(ev);
		if ( draft->GetPermissions(ev) != kODDPReadOnly )
			draft->SetChangedFromPrev(ev);
	SOM_CATCH_ALL
	SOM_ENDTRY
}


/* METHOD: CloneIntoMemoryContainer
 *
 * DESCRIPTION:
 *   Clone the link to a memory container
 */
SOM_Scope ODHandle SOMLINK ODLinkCloneIntoMemoryContainer(
	ODLink		*somSelf,
	Environment	*ev,
	ODLinkKey 	linkKey)
{
	ODLinkData			*somThis		= ODLinkGetData(somSelf);
	ODContainer*		container 		= (ODContainer*) kODNULL;;
	ODDocument*			document 		= (ODDocument*) kODNULL;
	ODDraft*			draft 			= (ODDraft*) kODNULL;
	ODStorageUnitID		rootSUID                        = 0;
	ODStorageUnit*		draftProperties = (ODStorageUnit*) kODNULL;
	ODDraft*			myDraft 		= somSelf->GetStorageUnit(ev)->GetDraft(ev);
	ODStorageSystem*	myStorageSystem = myDraft->GetDocument(ev)->GetContainer(ev)->GetStorageSystem(ev);
	time_t				changeTime 		= somSelf->GetLinkSource(ev)->GetChangeTime(ev);
	ODHandle			containerHandle;
	ODStorageUnitRef	suRef;


	ODVolatile(draft);
	ODVolatile(document);
	ODVolatile(container);
	ODVolatile(containerHandle);
	ODVolatile(myDraft);
	
	ODStorageUnit*	contentSU = somSelf->GetContentStorageUnit(ev,linkKey); // rrk 22jul
	contentSU->Externalize(ev); // rrk 22 jul
	containerHandle = ODNewHandle(0);
	TRY
		container = CreateMemoryContainer(ev,
						  somSelf->GetStorageUnit(ev)->GetSession( ev ),
						  containerHandle, kODBentoMemoryContainer);
		document  = container->AcquireDocument(ev,kODDefaultDocument);
		draft 	  = document->AcquireBaseDraft(ev,kODDPExclusiveWrite);
		// rrk 2 apr 96 - Begin Clone has changed; need ptr to a frame; we'll use kODNULL			
//		ODDraftKey draftKey = myDraft->BeginClone(ev,draft,kODCloneAll);
		ODDraftKey draftKey = myDraft->BeginClone(ev,draft,kODNULL,kODCloneAll);
		ODVolatile(draftKey);
		TRY
		  //ODStorageUnit*	contentSU = somSelf->GetContentStorageUnit(ev,linkKey);
		  //rootSU 		  			  = draft->CreateStorageUnit(ev);
		  rootSUID = myDraft->Clone(ev, draftKey, contentSU->GetID(ev), kODNULLID, 0);
		  if (ODSUExistsThenFocus(ev, contentSU, kODPropContentFrame, kODWeakStorageUnitRef)) {
		    ODID contentFrameID = ODGetWeakSURefProp(ev, contentSU, kODPropContentFrame, kODWeakStorageUnitRef);
		    myDraft->Clone(ev, draftKey, contentFrameID, kODNULLID, 0);
		  }
		  //contentSU->CloneInto(ev,draftKey,rootSU,kODNULL);
		CATCH_ALL
			myDraft->AbortClone(ev,draftKey);
			RERAISE;
		ENDTRY
		myDraft->EndClone(ev,draftKey);

		draftProperties = draft->AcquireDraftProperties(ev);
		ODSetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef, rootSUID);
		//		draftProperties->AddProperty(ev,kODPropRootPartSU)->AddValue(ev,kODStrongStorageUnitRef);
		//draftProperties->GetStrongStorageUnitRef(ev,rootSU->GetID(ev), suRef);
		//StorageUnitSetValue(draftProperties,ev,sizeof(suRef), (ODValue) &suRef);
		draftProperties->AddProperty(ev,kODPropChangeTime)->AddValue(ev,kODTime_T);
		StorageUnitSetValue(draftProperties, ev,sizeof(time_t), (ODValue) &changeTime);
		draftProperties->Release(ev);

		//	rootSU->Release(ev);		
		draft->Externalize(ev);
		draft->Release(ev);
		document->Release(ev);
		container->Release(ev);

	CATCH_ALL
		if (draftProperties)
			draftProperties->Release(ev);
	//		if (rootSU)
	//		rootSU->Release(ev);
		if (draft)
			draft->Release(ev);
		if (document)
			document->Release(ev);
		if (container)
			container->Release(ev);
		// rrk 2 apr 96 - replaced "Handle" with "ODHandle"
		ODDisposeHandle((ODHandle)containerHandle);
		RERAISE;
	ENDTRY

	return containerHandle;
}

/* METHOD: UseItemName
 *
 * DESCRIPTION:
 *   Use the given item name to describe this link, it is being used remotely.
 *   Note that the item name is saved persistently... and should never be
 *   changed.
 */
SOM_Scope void SOMLINK ODLinkUseItemName(
	ODLink		*somSelf,
	Environment	*ev,
	char		*pszItemName)
{
	ODLinkData		*somThis	= ODLinkGetData(somSelf);
	int		cbItemName;

	if (pszItemName)
	{
		if(_fpszItemName)
			ODDisposePtr((char*)_fpszItemName);
		cbItemName		= strlen(pszItemName)+1;
		_fpszItemName	= (char *)ODNewPtr(cbItemName);
		if(_fpszItemName)
			strcpy(_fpszItemName,pszItemName);
	}
}

/* METHOD: GetItemName
 *
 * DESCRIPTION:
 *   Return the item name that describes this link.
 */
SOM_Scope char * SOMLINK ODLinkGetItemName(
	ODLink		*somSelf,
	Environment	*ev)
{
	ODLinkData		*somThis	= ODLinkGetData(somSelf);

	return	_fpszItemName;
}

/* METHOD: GetDataObject
 *
 * DESCRIPTION:
 *   Return an IDataObject that wraps the storage unit of this link
 */
SOM_Scope LPVOID SOMLINK ODLinkGetDataObject(
	ODLink		*somSelf,
	Environment	*ev,
	ODLinkKey 	linkKey)
{
	ODLinkData		*somThis		= ODLinkGetData(somSelf);
	IDataObject		*pDataObject	= (IDataObject*)_fpDataObject;
	ODOLEManager*		OleManager = somSelf->GetStorageUnit(ev)->GetSession(ev)->GetOleManager(ev);

	/* Create an IDataObject that encapsulates the linkspec
	 * storage unit reference indicated by lpszItem
	 */
	if(!pDataObject)
	{			
#ifdef LATER // rrk  30 Apr 96 We are not yet certain whether we'll need or want a factory for OleData.
	     //                We are leaning toward "not."  Anyway, this CreateInstance call is copied 
	     //                from Novell - it would need to be changed if we were to use it.  
	     //
	     //                For now we will use "new" to get an OleData, and initialize it via
	     //                OleData::Initialize, which is what the factory would do.
		((IClassFactory*)gpProcessData->gDataFactory)->CreateInstance(
														NULL,
														IID_IDataObject,
														(void**)&pDataObject);
#else
	OleData *tempOleData = new OleData();
	tempOleData->Initialize(OleManager->fCFEmbeddedObject,
				OleManager->fCFEmbedSource,
				OleManager->fCFObjectDescriptor,
				OleManager->fCFOleWrapper);
	tempOleData->QueryInterface(IID_IDataObject, (void**)&pDataObject);
#endif
		if (pDataObject)							
			((DataIDataObject*)pDataObject)->fpData->SetLink(ev,somSelf);

		/* AddRef the object one additional time because we are both returning
		 * it as a parameter (AddRef'ed thru CreateInstance) and keeping a
		 * pointer to it ourselves...
		 */
		_fpDataObject	= (LPVOID)pDataObject;		
		pDataObject->AddRef();						
	}
	else
		pDataObject->AddRef();

	/* Read link source information into the data object
	 */
	if (pDataObject)
		somSelf->RefreshDataObject(ev,linkKey);
	
	return	_fpDataObject;
}

/* METHOD: RefreshDataObject
 *
 * DESCRIPTION:
 *   Read the link source and package it up into the current IDataObject
 *   that we have exported to the processes that are linked to us.
 */
SOM_Scope void SOMLINK ODLinkRefreshDataObject(
	ODLink		*somSelf,
	Environment	*ev,
	ODLinkKey 	linkKey)
{
	ODLinkData			*somThis		= ODLinkGetData(somSelf);
	IDataObject			*pDataObject	= (IDataObject*)_fpDataObject;
	ODPlatformType		platformType;
	ODHandle			hdata;
	STGMEDIUM			stm;
    FORMATETC			fe;
	HRESULT				hr;
		
	if (pDataObject)
	{
		/* Clone the link source storage unit to a global memory segment
		 */
		hdata		= somSelf->CloneIntoMemoryContainer(ev,linkKey);
		if (hdata)
		{
	//---------------------------------------------------------------------------
	// The following code differs somewhat from Novell's implementation.  See the comments
	// in WClipbd.cpp for a discussion. 14 jun 96
	//---------------------------------------------------------------------------
                ODULong                  dataSize = ODGetHandleSize(hdata);
                HGLOBAL                  hGlobaldata;
	        ODPtr                    data;
	        hGlobaldata = GlobalAlloc(GMEM_SHARE,dataSize);
	        if (hGlobaldata) {
		      data	= GlobalLock(hGlobaldata);
		      if (data) {
			LPSTR lpstrFrom = (LPSTR) ODLockHandle(hdata);
			memcpy(data, lpstrFrom, dataSize);
			ODUnlockHandle((ODHandle) lpstrFrom);
		      }
		      else
			 THROW(kODErrOutOfMemory);
		    }
	         else
	             THROW(kODErrOutOfMemory);


			/* Translate the type into a Windows clipboard format
			 */
			platformType = somSelf->GetStorageUnit(ev)->GetSession( ev )->GetTranslation(ev)->GetPlatformTypeFromISOType(ev,kODApplePart);
	
			/* Flush out any data already existing in the data object
			 */
			pDataObject->SetData(NULL,NULL,TRUE);


			// provide a CF_METAFILEPICT if we are ever asked for it. When DataIDataObject::GetData
			// sees the HGLOB_GOBUS it does the necessary work to conjur up a metafile to 
			// fulfill the promise. dwj

			SETDEFAULTFORMATETC(fe,CF_METAFILEPICT,TYMED_MFPICT);
			if ( FAILED(pDataObject->QueryGetData(&fe)) )
			{
				memset(&stm,0,sizeof(stm));
				stm.hGlobal                     = HGLOB_BOGUS;
				stm.tymed                       = TYMED_MFPICT;
				pDataObject->SetData(&fe, &stm, TRUE);
			}

	
			/* Add the clipboard format to our IDataObject
			 */
			memset(&stm,0,sizeof(stm));
			stm.hGlobal			= hGlobaldata;
			stm.tymed			= TYMED_HGLOBAL;
// rrk - 2 apr 96 -  vacpp will not convert 32-bit ptr to 16-bit int, but will convert 32-bit int to 16-bit.
//			SETDEFAULTFORMATETC(fe,(CLIPFORMAT)platformType,TYMED_HGLOBAL);
  			SETDEFAULTFORMATETC(fe,(unsigned long)platformType,TYMED_HGLOBAL);
			hr 					= pDataObject->SetData(&fe, &stm, TRUE);
	                GlobalUnlock(hGlobaldata);
			WASSERTMSG_DEBUG(SUCCEEDED(hr),
					 "WrapIOleItemContainer: failure on IDataObject::SetData");
			if (FAILED(hr))
				ODDisposeHandle(hdata);
		}
	}
}
