diff options
Diffstat (limited to 'private/oleutest/letest/outline')
83 files changed, 46374 insertions, 0 deletions
diff --git a/private/oleutest/letest/outline/classfac.c b/private/oleutest/letest/outline/classfac.c new file mode 100644 index 000000000..cf3070227 --- /dev/null +++ b/private/oleutest/letest/outline/classfac.c @@ -0,0 +1,219 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** classfac.c +** +** This file contains the implementation for IClassFactory for both the +** server and the client version of the OUTLINE app. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + +/* OLE2NOTE: this object illustrates the manner in which to statically +** (compile-time) initialize an interface VTBL. +*/ +static IClassFactoryVtbl g_AppClassFactoryVtbl = { + AppClassFactory_QueryInterface, + AppClassFactory_AddRef, + AppClassFactory_Release, + AppClassFactory_CreateInstance, + AppClassFactory_LockServer +}; + + +/* AppClassFactory_Create +** ---------------------- +** create an instance of APPCLASSFACTORY. +** NOTE: type of pointer returned is an IClassFactory* interface ptr. +** the returned pointer can be directly passed to +** CoRegisterClassObject and released later by calling the +** Release method of the interface. +*/ +LPCLASSFACTORY WINAPI AppClassFactory_Create(void) +{ + LPAPPCLASSFACTORY lpAppClassFactory; + LPMALLOC lpMalloc; + + if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR) + return NULL; + + lpAppClassFactory = (LPAPPCLASSFACTORY)lpMalloc->lpVtbl->Alloc( + lpMalloc, (sizeof(APPCLASSFACTORY))); + lpMalloc->lpVtbl->Release(lpMalloc); + if (! lpAppClassFactory) return NULL; + + lpAppClassFactory->m_lpVtbl = &g_AppClassFactoryVtbl; + lpAppClassFactory->m_cRef = 1; +#if defined( _DEBUG ) + lpAppClassFactory->m_cSvrLock = 0; +#endif + return (LPCLASSFACTORY)lpAppClassFactory; +} + + +/************************************************************************* +** OleApp::IClassFactory interface implementation +*************************************************************************/ + +STDMETHODIMP AppClassFactory_QueryInterface( + LPCLASSFACTORY lpThis, REFIID riid, LPVOID FAR* ppvObj) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + SCODE scode; + + // Two interfaces supported: IUnknown, IClassFactory + + if (IsEqualIID(riid, &IID_IClassFactory) || + IsEqualIID(riid, &IID_IUnknown)) { + lpAppClassFactory->m_cRef++; // A pointer to this object is returned + *ppvObj = lpThis; + scode = S_OK; + } + else { // unsupported interface + *ppvObj = NULL; + scode = E_NOINTERFACE; + } + + return ResultFromScode(scode); +} + + +STDMETHODIMP_(ULONG) AppClassFactory_AddRef(LPCLASSFACTORY lpThis) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + return ++lpAppClassFactory->m_cRef; +} + +STDMETHODIMP_(ULONG) AppClassFactory_Release(LPCLASSFACTORY lpThis) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + LPMALLOC lpMalloc; + + if (--lpAppClassFactory->m_cRef != 0) // Still used by others + return lpAppClassFactory->m_cRef; + + // Free storage + if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR) + return 0; + + lpMalloc->lpVtbl->Free(lpMalloc, lpAppClassFactory); + lpMalloc->lpVtbl->Release(lpMalloc); + return 0; +} + + +STDMETHODIMP AppClassFactory_CreateInstance ( + LPCLASSFACTORY lpThis, + LPUNKNOWN lpUnkOuter, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEDOC lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("AppClassFactory_CreateInstance\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpvObj = NULL; + + /********************************************************************* + ** OLE2NOTE: this is an SDI app; it can only create and support one + ** instance. After the instance is created, the OLE libraries + ** should not call CreateInstance again. it is a good practise + ** to specifically guard against this. + *********************************************************************/ + + if (lpOutlineApp->m_lpDoc != NULL) + return ResultFromScode(E_UNEXPECTED); + + /* OLE2NOTE: create a new document instance. by the time we return + ** from this method the document's refcnt must be 1. + */ + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpDoc; + if (! lpOleDoc) { + OLEDBG_END2 + return ResultFromScode(E_OUTOFMEMORY); + } + + /* OLE2NOTE: retrieve pointer to requested interface. the ref cnt + ** of the object after OutlineApp_CreateDoc is 0. this call to + ** QueryInterface will increment the refcnt to 1. the object + ** returned from IClassFactory::CreateInstance should have a + ** refcnt of 1 and be controlled by the caller. If the caller + ** releases the document, the document should be destroyed. + */ + hrErr = OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); + + OLEDBG_END2 + return hrErr; +} + + +STDMETHODIMP AppClassFactory_LockServer ( + LPCLASSFACTORY lpThis, + BOOL fLock +) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + HRESULT hrErr; + OLEDBG_BEGIN2("AppClassFactory_LockServer\r\n") + +#if defined( _DEBUG ) + if (fLock) { + ++lpAppClassFactory->m_cSvrLock; + OleDbgOutRefCnt3( + "AppClassFactory_LockServer: cLock++\r\n", + lpAppClassFactory, lpAppClassFactory->m_cSvrLock); + } else { + + /* OLE2NOTE: when there are no open documents and the app is not + ** under the control of the user and there are no outstanding + ** locks on the app, then revoke our ClassFactory to enable the + ** app to shut down. + */ + --lpAppClassFactory->m_cSvrLock; + OleDbgAssertSz (lpAppClassFactory->m_cSvrLock >= 0, + "AppClassFactory_LockServer(FALSE) called with cLock == 0" + ); + + if (lpAppClassFactory->m_cSvrLock == 0) { + OleDbgOutRefCnt2( + "AppClassFactory_LockServer: UNLOCKED\r\n", + lpAppClassFactory, lpAppClassFactory->m_cSvrLock); + } else { + OleDbgOutRefCnt3( + "AppClassFactory_LockServer: cLock--\r\n", + lpAppClassFactory, lpAppClassFactory->m_cSvrLock); + } + } +#endif // _DEBUG + /* OLE2NOTE: in order to hold the application alive we call + ** CoLockObjectExternal to add a strong reference to our app + ** object. this will keep the app alive when all other external + ** references release us. if the user issues File.Exit the + ** application will shut down in any case ignoring any + ** outstanding LockServer locks because CoDisconnectObject is + ** called in OleApp_CloseAllDocsAndExitCommand. this will + ** forceably break any existing strong reference counts + ** including counts that we add ourselves by calling + ** CoLockObjectExternal and guarantee that the App object gets + ** its final release (ie. cRefs goes to 0). + */ + hrErr = OleApp_Lock(lpOleApp, fLock, TRUE /* fLastUnlockReleases */); + + OLEDBG_END2 + return hrErr; +} diff --git a/private/oleutest/letest/outline/classfac.h b/private/oleutest/letest/outline/classfac.h new file mode 100644 index 000000000..cf3070227 --- /dev/null +++ b/private/oleutest/letest/outline/classfac.h @@ -0,0 +1,219 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** classfac.c +** +** This file contains the implementation for IClassFactory for both the +** server and the client version of the OUTLINE app. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + +/* OLE2NOTE: this object illustrates the manner in which to statically +** (compile-time) initialize an interface VTBL. +*/ +static IClassFactoryVtbl g_AppClassFactoryVtbl = { + AppClassFactory_QueryInterface, + AppClassFactory_AddRef, + AppClassFactory_Release, + AppClassFactory_CreateInstance, + AppClassFactory_LockServer +}; + + +/* AppClassFactory_Create +** ---------------------- +** create an instance of APPCLASSFACTORY. +** NOTE: type of pointer returned is an IClassFactory* interface ptr. +** the returned pointer can be directly passed to +** CoRegisterClassObject and released later by calling the +** Release method of the interface. +*/ +LPCLASSFACTORY WINAPI AppClassFactory_Create(void) +{ + LPAPPCLASSFACTORY lpAppClassFactory; + LPMALLOC lpMalloc; + + if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR) + return NULL; + + lpAppClassFactory = (LPAPPCLASSFACTORY)lpMalloc->lpVtbl->Alloc( + lpMalloc, (sizeof(APPCLASSFACTORY))); + lpMalloc->lpVtbl->Release(lpMalloc); + if (! lpAppClassFactory) return NULL; + + lpAppClassFactory->m_lpVtbl = &g_AppClassFactoryVtbl; + lpAppClassFactory->m_cRef = 1; +#if defined( _DEBUG ) + lpAppClassFactory->m_cSvrLock = 0; +#endif + return (LPCLASSFACTORY)lpAppClassFactory; +} + + +/************************************************************************* +** OleApp::IClassFactory interface implementation +*************************************************************************/ + +STDMETHODIMP AppClassFactory_QueryInterface( + LPCLASSFACTORY lpThis, REFIID riid, LPVOID FAR* ppvObj) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + SCODE scode; + + // Two interfaces supported: IUnknown, IClassFactory + + if (IsEqualIID(riid, &IID_IClassFactory) || + IsEqualIID(riid, &IID_IUnknown)) { + lpAppClassFactory->m_cRef++; // A pointer to this object is returned + *ppvObj = lpThis; + scode = S_OK; + } + else { // unsupported interface + *ppvObj = NULL; + scode = E_NOINTERFACE; + } + + return ResultFromScode(scode); +} + + +STDMETHODIMP_(ULONG) AppClassFactory_AddRef(LPCLASSFACTORY lpThis) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + return ++lpAppClassFactory->m_cRef; +} + +STDMETHODIMP_(ULONG) AppClassFactory_Release(LPCLASSFACTORY lpThis) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + LPMALLOC lpMalloc; + + if (--lpAppClassFactory->m_cRef != 0) // Still used by others + return lpAppClassFactory->m_cRef; + + // Free storage + if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR) + return 0; + + lpMalloc->lpVtbl->Free(lpMalloc, lpAppClassFactory); + lpMalloc->lpVtbl->Release(lpMalloc); + return 0; +} + + +STDMETHODIMP AppClassFactory_CreateInstance ( + LPCLASSFACTORY lpThis, + LPUNKNOWN lpUnkOuter, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEDOC lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("AppClassFactory_CreateInstance\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpvObj = NULL; + + /********************************************************************* + ** OLE2NOTE: this is an SDI app; it can only create and support one + ** instance. After the instance is created, the OLE libraries + ** should not call CreateInstance again. it is a good practise + ** to specifically guard against this. + *********************************************************************/ + + if (lpOutlineApp->m_lpDoc != NULL) + return ResultFromScode(E_UNEXPECTED); + + /* OLE2NOTE: create a new document instance. by the time we return + ** from this method the document's refcnt must be 1. + */ + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpDoc; + if (! lpOleDoc) { + OLEDBG_END2 + return ResultFromScode(E_OUTOFMEMORY); + } + + /* OLE2NOTE: retrieve pointer to requested interface. the ref cnt + ** of the object after OutlineApp_CreateDoc is 0. this call to + ** QueryInterface will increment the refcnt to 1. the object + ** returned from IClassFactory::CreateInstance should have a + ** refcnt of 1 and be controlled by the caller. If the caller + ** releases the document, the document should be destroyed. + */ + hrErr = OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); + + OLEDBG_END2 + return hrErr; +} + + +STDMETHODIMP AppClassFactory_LockServer ( + LPCLASSFACTORY lpThis, + BOOL fLock +) +{ + LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + HRESULT hrErr; + OLEDBG_BEGIN2("AppClassFactory_LockServer\r\n") + +#if defined( _DEBUG ) + if (fLock) { + ++lpAppClassFactory->m_cSvrLock; + OleDbgOutRefCnt3( + "AppClassFactory_LockServer: cLock++\r\n", + lpAppClassFactory, lpAppClassFactory->m_cSvrLock); + } else { + + /* OLE2NOTE: when there are no open documents and the app is not + ** under the control of the user and there are no outstanding + ** locks on the app, then revoke our ClassFactory to enable the + ** app to shut down. + */ + --lpAppClassFactory->m_cSvrLock; + OleDbgAssertSz (lpAppClassFactory->m_cSvrLock >= 0, + "AppClassFactory_LockServer(FALSE) called with cLock == 0" + ); + + if (lpAppClassFactory->m_cSvrLock == 0) { + OleDbgOutRefCnt2( + "AppClassFactory_LockServer: UNLOCKED\r\n", + lpAppClassFactory, lpAppClassFactory->m_cSvrLock); + } else { + OleDbgOutRefCnt3( + "AppClassFactory_LockServer: cLock--\r\n", + lpAppClassFactory, lpAppClassFactory->m_cSvrLock); + } + } +#endif // _DEBUG + /* OLE2NOTE: in order to hold the application alive we call + ** CoLockObjectExternal to add a strong reference to our app + ** object. this will keep the app alive when all other external + ** references release us. if the user issues File.Exit the + ** application will shut down in any case ignoring any + ** outstanding LockServer locks because CoDisconnectObject is + ** called in OleApp_CloseAllDocsAndExitCommand. this will + ** forceably break any existing strong reference counts + ** including counts that we add ourselves by calling + ** CoLockObjectExternal and guarantee that the App object gets + ** its final release (ie. cRefs goes to 0). + */ + hrErr = OleApp_Lock(lpOleApp, fLock, TRUE /* fLastUnlockReleases */); + + OLEDBG_END2 + return hrErr; +} diff --git a/private/oleutest/letest/outline/clipbrd.c b/private/oleutest/letest/outline/clipbrd.c new file mode 100644 index 000000000..a6e7effa3 --- /dev/null +++ b/private/oleutest/letest/outline/clipbrd.c @@ -0,0 +1,3401 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** clipbrd.c +** +** This file contains the major interfaces, methods and related support +** functions for implementing clipboard data transfer. The code +** contained in this file is used by BOTH the Container and Server +** (Object) versions of the Outline sample code. +** (see file dragdrop.c for Drag/Drop support implementation) +** +** OleDoc Object +** exposed interfaces: +** IDataObject +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +// REVIEW: should use string resource for messages +char ErrMsgPasting[] = "Could not paste data from clipboard!"; +char ErrMsgBadFmt[] = "Invalid format selected!"; +char ErrMsgPasteFailed[] = "Could not paste data from clipboard!"; +char ErrMsgClipboardChanged[] = "Contents of clipboard have changed!\r\nNo paste performed."; + + + +/************************************************************************* +** OleDoc::IDataObject interface implementation +*************************************************************************/ + +// IDataObject::QueryInterface +STDMETHODIMP OleDoc_DataObj_QueryInterface ( + LPDATAOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface((LPOLEDOC)lpOleDoc, riid, lplpvObj); +} + + +// IDataObject::AddRef +STDMETHODIMP_(ULONG) OleDoc_DataObj_AddRef(LPDATAOBJECT lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IDataObject"); + + return OleDoc_AddRef((LPOLEDOC)lpOleDoc); +} + + +// IDataObject::Release +STDMETHODIMP_(ULONG) OleDoc_DataObj_Release (LPDATAOBJECT lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IDataObject"); + + return OleDoc_Release((LPOLEDOC)lpOleDoc); +} + + +// IDataObject::GetData +STDMETHODIMP OleDoc_DataObj_GetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc, + LPSTGMEDIUM lpMedium +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_DataObj_GetData\r\n") + +#if defined( OLE_SERVER ) + // Call OLE Server specific version of this function + hrErr = ServerDoc_GetData((LPSERVERDOC)lpOleDoc, lpFormatetc, lpMedium); +#endif +#if defined( OLE_CNTR ) + // Call OLE Container specific version of this function + hrErr = ContainerDoc_GetData( + (LPCONTAINERDOC)lpOleDoc, + lpFormatetc, + lpMedium + ); +#endif + + OLEDBG_END2 + return hrErr; +} + + +// IDataObject::GetDataHere +STDMETHODIMP OleDoc_DataObj_GetDataHere ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc, + LPSTGMEDIUM lpMedium +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_DataObj_GetDataHere\r\n") + +#if defined( OLE_SERVER ) + // Call OLE Server specific version of this function + hrErr = ServerDoc_GetDataHere( + (LPSERVERDOC)lpOleDoc, + lpFormatetc, + lpMedium + ); +#endif +#if defined( OLE_CNTR ) + // Call OLE Container specific version of this function + hrErr = ContainerDoc_GetDataHere( + (LPCONTAINERDOC)lpOleDoc, + lpFormatetc, + lpMedium + ); +#endif + + OLEDBG_END2 + return hrErr; +} + + +// IDataObject::QueryGetData +STDMETHODIMP OleDoc_DataObj_QueryGetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + OLEDBG_BEGIN2("OleDoc_DataObj_QueryGetData\r\n"); + +#if defined( OLE_SERVER ) + // Call OLE Server specific version of this function + hrErr = ServerDoc_QueryGetData((LPSERVERDOC)lpOleDoc, lpFormatetc); +#endif +#if defined( OLE_CNTR ) + // Call OLE Container specific version of this function + hrErr = ContainerDoc_QueryGetData((LPCONTAINERDOC)lpOleDoc, lpFormatetc); +#endif + + OLEDBG_END2 + return hrErr; +} + + +// IDataObject::GetCanonicalFormatEtc +STDMETHODIMP OleDoc_DataObj_GetCanonicalFormatEtc( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPFORMATETC lpformatetcOut +) +{ + HRESULT hrErr; + OleDbgOut2("OleDoc_DataObj_GetCanonicalFormatEtc\r\n"); + + if (!lpformatetcOut) + return ResultFromScode(E_INVALIDARG); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + lpformatetcOut->ptd = NULL; + + if (!lpformatetc) + return ResultFromScode(E_INVALIDARG); + + // OLE2NOTE: we must validate that the format requested is supported + if ((hrErr=lpThis->lpVtbl->QueryGetData(lpThis,lpformatetc)) != NOERROR) + return hrErr; + + /* OLE2NOTE: an app that is insensitive to target device (as the + ** Outline Sample is) should fill in the lpformatOut parameter + ** but NULL out the "ptd" field; it should return NOERROR if the + ** input formatetc->ptd what non-NULL. this tells the caller + ** that it is NOT necessary to maintain a separate screen + ** rendering and printer rendering. if should return + ** DATA_S_SAMEFORMATETC if the input and output formatetc's are + ** identical. + */ + + *lpformatetcOut = *lpformatetc; + if (lpformatetc->ptd == NULL) + return ResultFromScode(DATA_S_SAMEFORMATETC); + else { + lpformatetcOut->ptd = NULL; + return NOERROR; + } +} + + +// IDataObject::SetData +STDMETHODIMP OleDoc_DataObj_SetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc, + LPSTGMEDIUM lpMedium, + BOOL fRelease +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + SCODE sc = S_OK; + OLEDBG_BEGIN2("OleDoc_DataObj_SetData\r\n") + + /* OLE2NOTE: a document that is used to transfer data (either via + ** the clipboard or drag/drop) does NOT accept SetData on ANY + ** format! + */ + if (lpOutlineDoc->m_fDataTransferDoc) { + sc = E_FAIL; + goto error; + } + +#if defined( OLE_SERVER ) + if (lpFormatetc->cfFormat == lpOutlineApp->m_cfOutline) { + OLEDBG_BEGIN2("ServerDoc_SetData: CF_OUTLINE\r\n") + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + OutlineDoc_ClearAllLines(lpOutlineDoc); + OutlineDoc_PasteOutlineData(lpOutlineDoc,lpMedium->hGlobal,-1); + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + OLEDBG_END3 + } else if (lpFormatetc->cfFormat == CF_TEXT) { + OLEDBG_BEGIN2("ServerDoc_SetData: CF_TEXT\r\n") + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + OutlineDoc_ClearAllLines(lpOutlineDoc); + OutlineDoc_PasteTextData(lpOutlineDoc,lpMedium->hGlobal,-1); + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + OLEDBG_END3 + } else { + sc = DV_E_FORMATETC; + } +#endif // OLE_SERVER +#if defined( OLE_CNTR ) + /* the Container-Only version of Outline does NOT offer + ** IDataObject interface from its User documents. this is + ** required by objects which can be embedded or linked. the + ** Container-only app only allows linking to its contained + ** objects, NOT the data of the container itself. + */ + OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n"); + sc = E_NOTIMPL; +#endif // OLE_CNTR + +error: + + /* OLE2NOTE: if fRelease==TRUE, then we must take + ** responsibility to release the lpMedium. we should only do + ** this if we are going to return NOERROR. if we do NOT + ** accept the data, then we should NOT release the lpMedium. + ** if fRelease==FALSE, then the caller retains ownership of + ** the data. + */ + if (sc == S_OK && fRelease) + ReleaseStgMedium(lpMedium); + + OLEDBG_END2 + return ResultFromScode(sc); + +} + + +// IDataObject::EnumFormatEtc +STDMETHODIMP OleDoc_DataObj_EnumFormatEtc( + LPDATAOBJECT lpThis, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +) +{ + LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_DataObj_EnumFormatEtc\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumFormatEtc = NULL; + +#if defined( OLE_SERVER ) + /* OLE2NOTE: a user document only needs to enumerate the static list + ** of formats that are registered for our app in the + ** registration database. OLE provides a default enumerator + ** which enumerates from the registration database. this default + ** enumerator is requested by returning OLE_S_USEREG. it is NOT + ** required that a user document (ie. non-DataTransferDoc) + ** enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or + ** CF_EMBEDDEDOBJECT. + ** + ** An object implemented as a server EXE (as this sample + ** is) may simply return OLE_S_USEREG to instruct the OLE + ** DefHandler to call the OleReg* helper API which uses info in + ** the registration database. Alternatively, the OleRegEnumFormatEtc + ** API may be called directly. Objects implemented as a server + ** DLL may NOT return OLE_S_USEREG; they must call the OleReg* + ** API or provide their own implementation. For EXE based + ** objects it is more efficient to return OLE_S_USEREG, because + ** in then the enumerator is instantiated in the callers + ** process space and no LRPC remoting is required. + */ + if (! ((LPOUTLINEDOC)lpOleDoc)->m_fDataTransferDoc) + return ResultFromScode(OLE_S_USEREG); + + // Call OLE Server specific version of this function + hrErr = ServerDoc_EnumFormatEtc( + (LPSERVERDOC)lpOleDoc, + dwDirection, + lplpenumFormatEtc + ); +#endif +#if defined( OLE_CNTR ) + // Call OLE Container specific version of this function + hrErr = ContainerDoc_EnumFormatEtc( + (LPCONTAINERDOC)lpOleDoc, + dwDirection, + lplpenumFormatEtc + ); +#endif + + OLEDBG_END2 + return hrErr; +} + + +// IDataObject::DAdvise +STDMETHODIMP OleDoc_DataObj_DAdvise( + LPDATAOBJECT lpThis, + FORMATETC FAR* lpFormatetc, + DWORD advf, + LPADVISESINK lpAdvSink, + DWORD FAR* lpdwConnection +) +{ + LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_DataObj_DAdvise\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lpdwConnection = 0; + + /* OLE2NOTE: a document that is used to transfer data (either via + ** the clipboard or drag/drop) does NOT support Advise notifications. + */ + if (lpOutlineDoc->m_fDataTransferDoc) { + sc = OLE_E_ADVISENOTSUPPORTED; + goto error; + } + +#if defined( OLE_SERVER ) + { + HRESULT hrErr; + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + + /* OLE2NOTE: we should validate if the caller is setting up an + ** Advise for a data type that we support. we must + ** explicitly allow an advise for the "wildcard" advise. + */ + if ( !( lpFormatetc->cfFormat == 0 && + lpFormatetc->ptd == NULL && + lpFormatetc->dwAspect == -1L && + lpFormatetc->lindex == -1L && + lpFormatetc->tymed == -1L) && + (hrErr = OleDoc_DataObj_QueryGetData(lpThis, lpFormatetc)) + != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + + if (lpServerDoc->m_OleDoc.m_fObjIsClosing) + { + // We don't accept any more Advise's once we're closing + sc = OLE_E_ADVISENOTSUPPORTED; + goto error; + } + + if (lpServerDoc->m_lpDataAdviseHldr == NULL && + CreateDataAdviseHolder(&lpServerDoc->m_lpDataAdviseHldr) + != NOERROR) { + sc = E_OUTOFMEMORY; + goto error; + } + + OLEDBG_BEGIN2("IDataAdviseHolder::Advise called\r\n"); + hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Advise( + lpServerDoc->m_lpDataAdviseHldr, + (LPDATAOBJECT)&lpOleDoc->m_DataObject, + lpFormatetc, + advf, + lpAdvSink, + lpdwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + } +#endif // OLE_SVR +#if defined( OLE_CNTR ) + { + /* the Container-Only version of Outline does NOT offer + ** IDataObject interface from its User documents. this is + ** required by objects which can be embedded or linked. the + ** Container-only app only allows linking to its contained + ** objects, NOT the data of the container itself. + */ + OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n"); + sc = E_NOTIMPL; + goto error; + } +#endif // OLE_CNTR + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +// IDataObject::DUnadvise +STDMETHODIMP OleDoc_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection) +{ + LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_DataObj_DUnadvise\r\n") + + /* OLE2NOTE: a document that is used to transfer data (either via + ** the clipboard or drag/drop) does NOT support Advise notifications. + */ + if (lpOutlineDoc->m_fDataTransferDoc) { + sc = OLE_E_ADVISENOTSUPPORTED; + goto error; + } + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + HRESULT hrErr; + + if (lpServerDoc->m_lpDataAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IDataAdviseHolder::Unadvise called\r\n"); + hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Unadvise( + lpServerDoc->m_lpDataAdviseHldr, + dwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + } +#endif +#if defined( OLE_CNTR ) + { + /* the Container-Only version of Outline does NOT offer + ** IDataObject interface from its User documents. this is + ** required by objects which can be embedded or linked. the + ** Container-only app only allows linking to its contained + ** objects, NOT the data of the container itself. + */ + OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n"); + sc = E_NOTIMPL; + goto error; + } +#endif + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IDataObject::EnumDAdvise +STDMETHODIMP OleDoc_DataObj_EnumDAdvise( + LPDATAOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +) +{ + LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_DataObj_EnumDAdvise\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumAdvise = NULL; + + /* OLE2NOTE: a document that is used to transfer data (either via + ** the clipboard or drag/drop) does NOT support Advise notifications. + */ + if (lpOutlineDoc->m_fDataTransferDoc) { + sc = OLE_E_ADVISENOTSUPPORTED; + goto error; + } + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + HRESULT hrErr; + + if (lpServerDoc->m_lpDataAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IDataAdviseHolder::EnumAdvise called\r\n"); + hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->EnumAdvise( + lpServerDoc->m_lpDataAdviseHldr, + lplpenumAdvise + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + } +#endif +#if defined( OLE_CNTR ) + { + /* the Container-Only version of Outline does NOT offer + ** IDataObject interface from its User documents. this is + ** required by objects which can be embedded or linked. the + ** Container-only app only allows linking to its contained + ** objects, NOT the data of the container itself. + */ + OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n"); + sc = E_NOTIMPL; + goto error; + } +#endif + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +/************************************************************************* +** OleDoc Supprt Functions common to both Container and Server versions +*************************************************************************/ + + +/* OleDoc_CopyCommand + * ------------------ + * Copy selection to clipboard. + * Post to the clipboard the formats that the app can render. + * the actual data is not rendered at this time. using the + * delayed rendering technique, Windows will send the clipboard + * owner window either a WM_RENDERALLFORMATS or a WM_RENDERFORMAT + * message when the actual data is requested. + * + * OLE2NOTE: the normal delayed rendering technique where Windows + * sends the clipboard owner window either a WM_RENDERALLFORMATS or + * a WM_RENDERFORMAT message when the actual data is requested is + * NOT exposed to the app calling OleSetClipboard. OLE internally + * creates its own window as the clipboard owner and thus our app + * will NOT get these WM_RENDER messages. + */ +void OleDoc_CopyCommand(LPOLEDOC lpSrcOleDoc) +{ + LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpClipboardDoc; + + /* squirrel away a copy of the current selection to the ClipboardDoc */ + lpClipboardDoc = OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc); + + if (! lpClipboardDoc) + return; // Error: could not create DataTransferDoc + + lpOutlineApp->m_lpClipboardDoc = (LPOUTLINEDOC)lpClipboardDoc; + + /* OLE2NOTE: initially the Doc object is created with a 0 ref + ** count. in order to have a stable Doc object during the + ** process of initializing the Doc instance and transfering it + ** to the clipboard, we intially AddRef the Doc ref cnt and later + ** Release it. This initial AddRef is artificial; it is simply + ** done to guarantee that a harmless QueryInterface followed by + ** a Release does not inadvertantly force our object to destroy + ** itself prematurely. + */ + OleDoc_AddRef((LPOLEDOC)lpClipboardDoc); + + /* OLE2NOTE: the OLE 2.0 style to put data onto the clipboard is to + ** give the clipboard a pointer to an IDataObject interface that + ** is able to statisfy IDataObject::GetData calls to render + ** data. in our case we give the pointer to the ClipboardDoc + ** which holds a cloned copy of the current user's selection. + */ + OLEDBG_BEGIN2("OleSetClipboard called\r\n") + OleSetClipboard((LPDATAOBJECT)&((LPOLEDOC)lpClipboardDoc)->m_DataObject); + OLEDBG_END2 + + OleDoc_Release((LPOLEDOC)lpClipboardDoc); // rel artificial AddRef above +} + + +/* OleDoc_PasteCommand +** ------------------- +** Paste default format data from the clipboard. +** In this function we choose the highest fidelity format that the +** source clipboard IDataObject* offers that we understand. +** +** OLE2NOTE: clipboard handling in an OLE 2.0 application is +** different than normal Windows clipboard handling. Data from the +** clipboard is retieved by getting the IDataObject* pointer +** returned by calling OleGetClipboard. +*/ +void OleDoc_PasteCommand(LPOLEDOC lpOleDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPDATAOBJECT lpClipboardDataObj = NULL; + BOOL fLink = FALSE; + BOOL fLocalDataObj = FALSE; + BOOL fStatus; + HRESULT hrErr; + + hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj); + if (hrErr != NOERROR) + return; // Clipboard seems to be empty or can't be accessed + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + + /* check if the data on the clipboard is local to our application + ** instance. + */ + if (lpOutlineApp->m_lpClipboardDoc) { + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc; + if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject) + fLocalDataObj = TRUE; + } + + fStatus = OleDoc_PasteFromData( + lpOleDoc, + lpClipboardDataObj, + fLocalDataObj, + fLink + ); + + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + + if (! fStatus) + OutlineApp_ErrorMessage(g_lpApp,"Could not paste data from clipboard!"); + + if (lpClipboardDataObj) + OleStdRelease((LPUNKNOWN)lpClipboardDataObj); +} + + +/* OleDoc_PasteSpecialCommand +** -------------------------- +** Allow the user to paste data in a particular format from the +** clipboard. The paste special command displays a dialog to the +** user that allows him to choose the format to be pasted from the +** list of formats available. +** +** OLE2NOTE: the PasteSpecial dialog is one of the standard OLE 2.0 +** UI dialogs for which the dialog is implemented and in the OLE2UI +** library. +** +** OLE2NOTE: clipboard handling in an OLE 2.0 application is +** different than normal Windows clipboard handling. Data from the +** clipboard is retieved by getting the IDataObject* pointer +** returned by calling OleGetClipboard. +*/ +void OleDoc_PasteSpecialCommand(LPOLEDOC lpOleDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPDATAOBJECT lpClipboardDataObj = NULL; + CLIPFORMAT cfFormat; + int nFmtEtc; + UINT uInt; + BOOL fLink = FALSE; + BOOL fLocalDataObj = FALSE; + BOOL fStatus; + HRESULT hrErr; + OLEUIPASTESPECIAL ouiPasteSpl; + BOOL fDisplayAsIcon; + + hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj); + if (hrErr != NOERROR) + return; // Clipboard seems to be empty or can't be accessed + + /* check if the data on the clipboard is local to our application + ** instance. + */ + if (lpOutlineApp->m_lpClipboardDoc) { + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc; + if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject) + fLocalDataObj = TRUE; + } + + /* Display the PasteSpecial dialog and allow the user to select the + ** format to paste. + */ + _fmemset((LPOLEUIPASTESPECIAL)&ouiPasteSpl, 0, sizeof(ouiPasteSpl)); + ouiPasteSpl.cbStruct = sizeof(ouiPasteSpl); //Structure Size + ouiPasteSpl.dwFlags = PSF_SELECTPASTE | PSF_SHOWHELP; //IN-OUT: Flags + ouiPasteSpl.hWndOwner = lpOutlineApp->m_lpDoc->m_hWndDoc; //Owning window + ouiPasteSpl.lpszCaption = "Paste Special"; //Dialog caption bar contents + ouiPasteSpl.lpfnHook = NULL; //Hook callback + ouiPasteSpl.lCustData = 0; //Custom data to pass to hook + ouiPasteSpl.hInstance = NULL; //Instance for customized template name + ouiPasteSpl.lpszTemplate = NULL; //Customized template name + ouiPasteSpl.hResource = NULL; //Customized template handle + + ouiPasteSpl.arrPasteEntries = lpOleApp->m_arrPasteEntries; + ouiPasteSpl.cPasteEntries = lpOleApp->m_nPasteEntries; + ouiPasteSpl.lpSrcDataObj = lpClipboardDataObj; + ouiPasteSpl.arrLinkTypes = lpOleApp->m_arrLinkTypes; + ouiPasteSpl.cLinkTypes = lpOleApp->m_nLinkTypes; + ouiPasteSpl.cClsidExclude = 0; + + OLEDBG_BEGIN3("OleUIPasteSpecial called\r\n") + uInt = OleUIPasteSpecial(&ouiPasteSpl); + OLEDBG_END3 + + fDisplayAsIcon = + (ouiPasteSpl.dwFlags & PSF_CHECKDISPLAYASICON ? TRUE : FALSE); + + if (uInt == OLEUI_OK) { + nFmtEtc = ouiPasteSpl.nSelectedIndex; + fLink = ouiPasteSpl.fLink; + + if (nFmtEtc < 0 || nFmtEtc >= lpOleApp->m_nPasteEntries) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgBadFmt); + goto error; + } + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + + cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat; + + fStatus = OleDoc_PasteFormatFromData( + lpOleDoc, + cfFormat, + lpClipboardDataObj, + fLocalDataObj, + fLink, + fDisplayAsIcon, + ouiPasteSpl.hMetaPict, + (LPSIZEL)&ouiPasteSpl.sizel + ); + + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + + if (! fStatus) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPasteFailed); + goto error; + } + + } else if (uInt == OLEUI_PSERR_CLIPBOARDCHANGED) { + /* OLE2NOTE: this error code is returned when the contents of + ** the clipboard change while the PasteSpecial dialog is up. + ** in this situation the PasteSpecial dialog automatically + ** brings itself down and NO paste operation should be performed. + */ + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgClipboardChanged); + } + +error: + + if (lpClipboardDataObj) + OleStdRelease((LPUNKNOWN)lpClipboardDataObj); + + if (uInt == OLEUI_OK && ouiPasteSpl.hMetaPict) + // clean up metafile + OleUIMetafilePictIconFree(ouiPasteSpl.hMetaPict); +} + + + +/* OleDoc_CreateDataTransferDoc + * ---------------------------- + * + * Create a document to be use to transfer data (either via a + * drag/drop operation of the clipboard). Copy the selection of the + * source doc to the data transfer document. A data transfer document is + * the same as a document that is created by the user except that it is + * NOT made visible to the user. it is specially used to hold a copy of + * data that the user should not be able to change. + * + * OLE2NOTE: in the OLE version the data transfer document is used + * specifically to provide an IDataObject* that renders the data copied. + */ +LPOUTLINEDOC OleDoc_CreateDataTransferDoc(LPOLEDOC lpSrcOleDoc) +{ + LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpDestOutlineDoc; + LPLINELIST lpSrcLL = &lpSrcOutlineDoc->m_LineList; + LINERANGE lrSel; + int nCopied; + + lpDestOutlineDoc = OutlineApp_CreateDoc(lpOutlineApp, TRUE); + if (! lpDestOutlineDoc) return NULL; + + // set the ClipboardDoc to an (Untitled) doc. + if (! OutlineDoc_InitNewFile(lpDestOutlineDoc)) + goto error; + + LineList_GetSel(lpSrcLL, (LPLINERANGE)&lrSel); + nCopied = LineList_CopySelToDoc( + lpSrcLL, + (LPLINERANGE)&lrSel, + lpDestOutlineDoc + ); + + if (nCopied != (lrSel.m_nEndLine - lrSel.m_nStartLine + 1)) { + OleDbgAssertSz(FALSE,"OleDoc_CreateDataTransferDoc: entire selection NOT copied\r\n"); + goto error; // ERROR: all lines could NOT be copied + } + +#if defined( OLE_SERVER ) + { + LPOLEDOC lpSrcOleDoc = (LPOLEDOC)lpSrcOutlineDoc; + LPOLEDOC lpDestOleDoc = (LPOLEDOC)lpDestOutlineDoc; + LPSERVERDOC lpDestServerDoc = (LPSERVERDOC)lpDestOutlineDoc; + LPMONIKER lpmkDoc = NULL; + LPMONIKER lpmkItem = NULL; + + /* If source document is able to provide a moniker, then the + ** destination document (lpDestOutlineDoc) should offer + ** CF_LINKSOURCE via its IDataObject interface that it gives + ** to the clipboard or the drag/drop operation. + ** + ** OLE2NOTE: we want to ask the source document if it can + ** produce a moniker, but we do NOT want to FORCE moniker + ** assignment at this point. we only want to FORCE moniker + ** assignment later if a Paste Link occurs (ie. GetData for + ** CF_LINKSOURCE). if the source document is able to give + ** a moniker, then we store a pointer to the source document + ** so we can ask it at a later time to get the moniker. we + ** also save the range of the current selection so we can + ** generate a proper item name later when Paste Link occurs. + ** Also we need to give a string which identifies the source + ** of the copy in the CF_OBJECTDESCRIPTOR format. this + ** string is used to display in the PasteSpecial dialog. we + ** get and store a TEMPFORUSER moniker which identifies the + ** source of copy. + */ + lpDestOleDoc->m_lpSrcDocOfCopy = lpSrcOleDoc; + lpmkDoc = OleDoc_GetFullMoniker(lpSrcOleDoc, GETMONIKER_TEMPFORUSER); + if (lpmkDoc != NULL) { + lpDestOleDoc->m_fLinkSourceAvail = TRUE; + lpDestServerDoc->m_lrSrcSelOfCopy = lrSel; + OleStdRelease((LPUNKNOWN)lpmkDoc); + } + } +#endif +#if defined( OLE_CNTR ) + { + LPOLEDOC lpSrcOleDoc = (LPOLEDOC)lpSrcOutlineDoc; + LPOLEDOC lpDestOleDoc = (LPOLEDOC)lpDestOutlineDoc; + LPCONTAINERDOC lpDestContainerDoc = (LPCONTAINERDOC)lpDestOutlineDoc; + + /* If one line was copied from the source document, and it was a + ** single OLE object, then the destination document should + ** offer additional data formats to allow the transfer of + ** the OLE object via IDataObject::GetData. Specifically, the + ** following additional data formats are offered if a single + ** OLE object is copied: + ** CF_EMBEDDEDOBJECT + ** CF_OBJECTDESCRIPTOR (should be given even w/o object) + ** CF_METAFILEPICT (note: dwAspect depends on object) + ** CF_LINKSOURCE -- if linking is possible + ** CF_LINKSOURCEDESCRIPTOR -- if linking is possible + ** + ** optionally the container may give + ** <data format available in OLE object's cache> + */ + + if (nCopied == 1) { + LPOLEOBJECT lpSrcOleObj; + LPCONTAINERLINE lpSrcContainerLine; + DWORD dwStatus; + + lpSrcContainerLine = (LPCONTAINERLINE)LineList_GetLine( + lpSrcLL, + lrSel.m_nStartLine + ); + + if (! lpSrcContainerLine) + goto error; + + lpDestOleDoc->m_lpSrcDocOfCopy = lpSrcOleDoc; + + if ((((LPLINE)lpSrcContainerLine)->m_lineType==CONTAINERLINETYPE) + && ((lpSrcOleObj=lpSrcContainerLine->m_lpOleObj)!=NULL)) { + + lpDestContainerDoc->m_fEmbeddedObjectAvail = TRUE; + lpSrcOleObj->lpVtbl->GetUserClassID( + lpSrcOleObj, + &lpDestContainerDoc->m_clsidOleObjCopied + ); + lpDestContainerDoc->m_dwAspectOleObjCopied = + lpSrcContainerLine->m_dwDrawAspect; + + /* OLE2NOTE: if the object is allowed to be linked + ** to from the inside (ie. we are allowed to + ** give out a moniker which binds to the running + ** OLE object), then we want to offer + ** CF_LINKSOURCE format. if the object is an OLE + ** 2.0 embedded object then it is allowed to be + ** linked to from the inside. if the object is + ** either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we + ** could offer linking to the outside of the + ** object (ie. a pseudo object within our + ** document). we are a container only app that + ** does not support linking to ranges of its data. + */ + + lpSrcOleObj->lpVtbl->GetMiscStatus( + lpSrcOleObj, + DVASPECT_CONTENT, /* aspect is not important */ + (LPDWORD)&dwStatus + ); + if (! (dwStatus & OLEMISC_CANTLINKINSIDE)) { + /* Our container supports linking to an embedded + ** object. We want the lpDestContainerDoc to + ** offer CF_LINKSOURCE via the IDataObject + ** interface that it gives to the clipboard or + ** the drag/drop operation. The link source will + ** be identified by a composite moniker + ** comprised of the FileMoniker of the source + ** document and an ItemMoniker which identifies + ** the OLE object inside the container. we do + ** NOT want to force moniker assignment to the + ** OLE object now (at copy time); we only want + ** to FORCE moniker assignment later if a Paste + ** Link occurs (ie. GetData for CF_LINKSOURCE). + ** thus we store a pointer to the source document + ** and the source ContainerLine so we can + ** generate a proper ItemMoniker later when + ** Paste Link occurs. + */ + lpDestOleDoc->m_fLinkSourceAvail = TRUE; + lpDestContainerDoc->m_lpSrcContainerLine = + lpSrcContainerLine; + } + } + } + } + +#endif // OLE_CNTR + + return lpDestOutlineDoc; + +error: + if (lpDestOutlineDoc) + OutlineDoc_Destroy(lpDestOutlineDoc); + + return NULL; +} + + +/* OleDoc_PasteFromData +** -------------------- +** +** Paste data from an IDataObject*. The IDataObject* may come from +** the clipboard (GetClipboard) or from a drag/drop operation. +** In this function we choose the best format that we prefer. +** +** Returns TRUE if data was successfully pasted. +** FALSE if data could not be pasted. +*/ + +BOOL OleDoc_PasteFromData( + LPOLEDOC lpOleDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + CLIPFORMAT cfFormat; + BOOL fDisplayAsIcon = FALSE; + SIZEL sizelInSrc = {0, 0}; + HGLOBAL hMem = NULL; + HGLOBAL hMetaPict = NULL; + STGMEDIUM medium; + + if (fLink) { +#if defined( OLE_SERVER ) + return FALSE; // server version of app does NOT support links +#endif +#if defined( OLE_CNTR ) + // container version of app only supports OLE object type links + cfFormat = lpOleApp->m_cfLinkSource; +#endif + + } else { + + int nFmtEtc; + + nFmtEtc = OleStdGetPriorityClipboardFormat( + lpSrcDataObj, + lpOleApp->m_arrPasteEntries, + lpOleApp->m_nPasteEntries + ); + + if (nFmtEtc < 0) + return FALSE; // there is no format we like + + cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat; + } + + /* OLE2NOTE: we need to check what dwDrawAspect is being + ** transfered. if the data is an object that is displayed as an + ** icon in the source, then we want to keep it as an icon. the + ** aspect the object is displayed in at the source is transfered + ** via the CF_OBJECTDESCRIPTOR format for a Paste operation. + */ + if (hMem = OleStdGetData( + lpSrcDataObj, + lpOleApp->m_cfObjectDescriptor, + NULL, + DVASPECT_CONTENT, + (LPSTGMEDIUM)&medium)) { + LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem); + fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE); + sizelInSrc = lpOD->sizel; // size of object/picture in source (opt.) + GlobalUnlock(hMem); + ReleaseStgMedium((LPSTGMEDIUM)&medium); // equiv to GlobalFree + + if (fDisplayAsIcon) { + hMetaPict = OleStdGetData( + lpSrcDataObj, + CF_METAFILEPICT, + NULL, + DVASPECT_ICON, + (LPSTGMEDIUM)&medium + ); + if (hMetaPict == NULL) + fDisplayAsIcon = FALSE; // give up; failed to get icon MFP + } + } + + return OleDoc_PasteFormatFromData( + lpOleDoc, + cfFormat, + lpSrcDataObj, + fLocalDataObj, + fLink, + fDisplayAsIcon, + hMetaPict, + (LPSIZEL)&sizelInSrc + ); + + if (hMetaPict) + ReleaseStgMedium((LPSTGMEDIUM)&medium); // properly free METAFILEPICT +} + + +/* OleDoc_PasteFormatFromData +** -------------------------- +** +** Paste a particular data format from a IDataObject*. The +** IDataObject* may come from the clipboard (GetClipboard) or from a +** drag/drop operation. +** +** Returns TRUE if data was successfully pasted. +** FALSE if data could not be pasted. +*/ + +BOOL OleDoc_PasteFormatFromData( + LPOLEDOC lpOleDoc, + CLIPFORMAT cfFormat, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSIZEL lpSizelInSrc +) +{ +#if defined( OLE_SERVER ) + /* call server specific version of the function. */ + return ServerDoc_PasteFormatFromData( + (LPSERVERDOC)lpOleDoc, + cfFormat, + lpSrcDataObj, + fLocalDataObj, + fLink + ); +#endif +#if defined( OLE_CNTR ) + + /* call container specific version of the function. */ + return ContainerDoc_PasteFormatFromData( + (LPCONTAINERDOC)lpOleDoc, + cfFormat, + lpSrcDataObj, + fLocalDataObj, + fLink, + fDisplayAsIcon, + hMetaPict, + lpSizelInSrc + ); +#endif +} + + +/* OleDoc_QueryPasteFromData +** ------------------------- +** +** Check if the IDataObject* offers data in a format that we can +** paste. The IDataObject* may come from the clipboard +** (GetClipboard) or from a drag/drop operation. +** +** Returns TRUE if paste can be performed +** FALSE if paste is not possible. +*/ + +BOOL OleDoc_QueryPasteFromData( + LPOLEDOC lpOleDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLink +) +{ +#if defined( OLE_SERVER ) + return ServerDoc_QueryPasteFromData( + (LPSERVERDOC) lpOleDoc, + lpSrcDataObj, + fLink + ); +#endif +#if defined( OLE_CNTR ) + + return ContainerDoc_QueryPasteFromData( + (LPCONTAINERDOC) lpOleDoc, + lpSrcDataObj, + fLink + ); +#endif +} + + +/* OleDoc_GetExtent + * ---------------- + * + * Get the extent (width, height) of the entire document in Himetric. + */ +void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel) +{ + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + + LineList_CalcSelExtentInHimetric(lpLL, NULL, lpsizel); +} + + +/* OleDoc_GetObjectDescriptorData + * ------------------------------ + * + * Return a handle to an object's data in CF_OBJECTDESCRIPTOR form + * + */ +HGLOBAL OleDoc_GetObjectDescriptorData(LPOLEDOC lpOleDoc, LPLINERANGE lplrSel) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + /* Only our data transfer doc renders CF_OBJECTDESCRIPTOR */ + OleDbgAssert(lpOutlineDoc->m_fDataTransferDoc); + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + SIZEL sizel; + POINTL pointl; + LPSTR lpszSrcOfCopy = NULL; + IBindCtx FAR *pbc = NULL; + HGLOBAL hObjDesc; + DWORD dwStatus = 0; + LPOUTLINEDOC lpSrcDocOfCopy=(LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy; + LPMONIKER lpSrcMonikerOfCopy = ServerDoc_GetSelFullMoniker( + (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy, + &lpServerDoc->m_lrSrcSelOfCopy, + GETMONIKER_TEMPFORUSER + ); + + SvrDoc_OleObj_GetMiscStatus( + (LPOLEOBJECT)&lpServerDoc->m_OleObject, + DVASPECT_CONTENT, + &dwStatus + ); + + OleDoc_GetExtent(lpOleDoc, &sizel); + pointl.x = pointl.y = 0; + + if (lpSrcMonikerOfCopy) { + CreateBindCtx(0, (LPBC FAR*)&pbc); + CallIMonikerGetDisplayNameA( + lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy); + pbc->lpVtbl->Release(pbc); + lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy); + } else { + /* this document has no moniker; use our FullUserTypeName + ** as the description of the source of copy. + */ + lpszSrcOfCopy = FULLUSERTYPENAME; + } + + hObjDesc = OleStdGetObjectDescriptorData( + CLSID_APP, + DVASPECT_CONTENT, + sizel, + pointl, + dwStatus, + FULLUSERTYPENAME, + lpszSrcOfCopy + ); + + if (lpSrcMonikerOfCopy && lpszSrcOfCopy) + OleStdFreeString(lpszSrcOfCopy, NULL); + return hObjDesc; + + } +#endif +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + LPCONTAINERLINE lpContainerLine; + HGLOBAL hObjDesc; + BOOL fSelIsOleObject = FALSE; + LPOLEOBJECT lpOleObj; + SIZEL sizel; + POINTL pointl; + + if ( lpLL->m_nNumLines == 1 ) { + fSelIsOleObject = ContainerDoc_IsSelAnOleObject( + lpContainerDoc, + &IID_IOleObject, + (LPUNKNOWN FAR*)&lpOleObj, + NULL, /* we don't need the line index */ + (LPCONTAINERLINE FAR*)&lpContainerLine + ); + } + + pointl.x = pointl.y = 0; + + if (fSelIsOleObject) { + /* OLE2NOTE: a single OLE object is being transfered via + ** this DataTransferDoc. we need to generate the + ** CF_ObjectDescrioptor which describes the OLE object. + */ + + LPOUTLINEDOC lpSrcOutlineDoc = + (LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy; + LPSTR lpszSrcOfCopy = lpSrcOutlineDoc->m_szFileName; + BOOL fFreeSrcOfCopy = FALSE; + SIZEL sizelOleObject; + LPLINE lpLine = (LPLINE)lpContainerLine; + + /* if the object copied can be linked to then get a + ** TEMPFORUSER form of the moniker which identifies the + ** source of copy. we do not want to force the + ** assignment of the moniker until CF_LINKSOURCE is + ** rendered. + ** if the object copied can not be a link source then use + ** the source filename to identify the source of copy. + ** there is no need to generate a moniker for the object + ** copied. + */ + if (lpOleDoc->m_fLinkSourceAvail && + lpContainerDoc->m_lpSrcContainerLine) { + LPBINDCTX pbc = NULL; + LPMONIKER lpSrcMonikerOfCopy = ContainerLine_GetFullMoniker( + lpContainerDoc->m_lpSrcContainerLine, + GETMONIKER_TEMPFORUSER + ); + if (lpSrcMonikerOfCopy) { + CreateBindCtx(0, (LPBC FAR*)&pbc); + if (pbc != NULL) { + CallIMonikerGetDisplayNameA( + lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy); + + pbc->lpVtbl->Release(pbc); + fFreeSrcOfCopy = TRUE; + } + lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy); + } + } + + /* OLE2NOTE: Get size that object is being drawn. If the + ** object has been scaled because the user resized the + ** object, then we want to pass the scaled size of the + ** object in the ObjectDescriptor rather than the size + ** that the object would return via + ** IOleObject::GetExtent and IViewObject2::GetExtent. in + ** this way if the object is transfered to another container + ** (via clipboard or drag/drop), then the object will + ** remain the scaled size. + */ + sizelOleObject.cx = lpLine->m_nWidthInHimetric; + sizelOleObject.cy = lpLine->m_nHeightInHimetric; + + hObjDesc = OleStdGetObjectDescriptorDataFromOleObject( + lpOleObj, + lpszSrcOfCopy, + lpContainerLine->m_dwDrawAspect, + pointl, + (LPSIZEL)&sizelOleObject + ); + + if (fFreeSrcOfCopy && lpszSrcOfCopy) + OleStdFreeString(lpszSrcOfCopy, NULL); + OleStdRelease((LPUNKNOWN)lpOleObj); + return hObjDesc; + } else { + /* OLE2NOTE: the data being transfered via this + ** DataTransferDoc is NOT a single OLE object. thus in + ** this case the CF_ObjectDescriptor data should + ** describe our container app itself. + */ + OleDoc_GetExtent(lpOleDoc, &sizel); + return OleStdGetObjectDescriptorData( + CLSID_NULL, /* not used if no object formats */ + DVASPECT_CONTENT, + sizel, + pointl, + 0, + NULL, /* UserTypeName not used if no obj fmt's */ + FULLUSERTYPENAME /* string to identify source of copy */ + ); + + } + } +#endif // OLE_CNTR +} + + +#if defined( OLE_SERVER ) + +/************************************************************************* +** ServerDoc Supprt Functions Used by Server versions +*************************************************************************/ + + +/* ServerDoc_PasteFormatFromData +** ----------------------------- +** +** Paste a particular data format from a IDataObject*. The +** IDataObject* may come from the clipboard (GetClipboard) or from a +** drag/drop operation. +** +** NOTE: fLink is specified then FALSE if returned because the +** Server only version of the app can not support links. +** +** Returns TRUE if data was successfully pasted. +** FALSE if data could not be pasted. +*/ +BOOL ServerDoc_PasteFormatFromData( + LPSERVERDOC lpServerDoc, + CLIPFORMAT cfFormat, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink +) +{ + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpServerDoc)->m_LineList; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + int nIndex; + int nCount = 0; + HGLOBAL hData; + STGMEDIUM medium; + LINERANGE lrSel; + + if (LineList_GetCount(lpLL) == 0) + nIndex = -1; // pasting to empty list + else + nIndex=LineList_GetFocusLineIndex(lpLL); + + if (fLink) { + /* We should paste a Link to the data, but we do not support links */ + return FALSE; + + } else { + + if (cfFormat == lpOutlineApp->m_cfOutline) { + + hData = OleStdGetData( + lpSrcDataObj, + lpOutlineApp->m_cfOutline, + NULL, + DVASPECT_CONTENT, + (LPSTGMEDIUM)&medium + ); + if (hData == NULL) + return FALSE; + + nCount = OutlineDoc_PasteOutlineData( + (LPOUTLINEDOC)lpServerDoc, + hData, + nIndex + ); + // OLE2NOTE: we must free data handle by releasing the medium + ReleaseStgMedium((LPSTGMEDIUM)&medium); + + } else if(cfFormat == CF_TEXT) { + + hData = OleStdGetData( + lpSrcDataObj, + CF_TEXT, + NULL, + DVASPECT_CONTENT, + (LPSTGMEDIUM)&medium + ); + if (hData == NULL) + return FALSE; + + nCount = OutlineDoc_PasteTextData( + (LPOUTLINEDOC)lpServerDoc, + hData, + nIndex + ); + // OLE2NOTE: we must free data handle by releasing the medium + ReleaseStgMedium((LPSTGMEDIUM)&medium); + } + } + + lrSel.m_nEndLine = nIndex + 1; + lrSel.m_nStartLine = nIndex + nCount; + LineList_SetSel(lpLL, &lrSel); + return TRUE; +} + + +/* ServerDoc_QueryPasteFromData +** ---------------------------- +** +** Check if the IDataObject* offers data in a format that we can +** paste. The IDataObject* may come from the clipboard +** (GetClipboard) or from a drag/drop operation. +** In this function we look if one of the following formats is +** offered: +** CF_OUTLINE +** CF_TEXT +** +** NOTE: fLink is specified then FALSE if returned because the +** Server only version of the app can not support links. +** +** Returns TRUE if paste can be performed +** FALSE if paste is not possible. +*/ +BOOL ServerDoc_QueryPasteFromData( + LPSERVERDOC lpServerDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLink +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + + if (fLink) { + /* we do not support links */ + return FALSE; + + } else { + + int nFmtEtc; + + nFmtEtc = OleStdGetPriorityClipboardFormat( + lpSrcDataObj, + lpOleApp->m_arrPasteEntries, + lpOleApp->m_nPasteEntries + ); + + if (nFmtEtc < 0) + return FALSE; // there is no format we like + } + + return TRUE; +} + + +/* ServerDoc_GetData + * ----------------- + * + * Render data from the document on a CALLEE allocated STGMEDIUM. + * This routine is called via IDataObject::GetData. + */ + +HRESULT ServerDoc_GetData ( + LPSERVERDOC lpServerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + HRESULT hrErr; + SCODE sc; + + // OLE2NOTE: we must set out pointer parameters to NULL + lpMedium->pUnkForRelease = NULL; + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + lpMedium->tymed = TYMED_NULL; + lpMedium->pUnkForRelease = NULL; // we transfer ownership to caller + lpMedium->hGlobal = NULL; + + if(lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DV_E_FORMATETC; + goto error; + } + lpMedium->hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,NULL); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("ServerDoc_GetData: rendered CF_OUTLINE\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == CF_METAFILEPICT && + (lpformatetc->dwAspect & DVASPECT_CONTENT) ) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_MFPICT)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = ServerDoc_GetMetafilePictData(lpServerDoc,NULL); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_MFPICT; + OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == CF_METAFILEPICT && + (lpformatetc->dwAspect & DVASPECT_ICON) ) { + CLSID clsid; + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_MFPICT)) { + sc = DV_E_FORMATETC; + goto error; + } + + /* OLE2NOTE: we should return the default icon for our class. + ** we must be carefull to use the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to use the class of the object + ** written in the storage of the object. otherwise we would + ** use our own class id. + */ + if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal=GetIconOfClass(g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_MFPICT; + OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT (icon)\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == CF_TEXT) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OutlineDoc_GetTextData ( + (LPOUTLINEDOC)lpServerDoc, + NULL + ); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("ServerDoc_GetData: rendered CF_TEXT\r\n"); + return NOERROR; + } + + /* the above are the only formats supports by a user document (ie. + ** a non-data transfer doc). if the document is used for + ** purposes of data transfer, then additional formats are offered. + */ + if (! lpOutlineDoc->m_fDataTransferDoc) { + sc = DV_E_FORMATETC; + goto error; + } + + /* OLE2NOTE: ObjectDescriptor and LinkSrcDescriptor will + ** contain the same data for the pure container and pure server + ** type applications. only a container/server application may + ** have different content for ObjectDescriptor and + ** LinkSrcDescriptor. if a container/server copies a link for + ** example, then the ObjectDescriptor would give the class + ** of the link source but the LinkSrcDescriptor would give the + ** class of the container/server itself. in this situation if a + ** paste operation occurs, an equivalent link is pasted, but if + ** a pastelink operation occurs, then a link to a pseudo object + ** in the container/server is created. + */ + if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor || + (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor && + lpOleDoc->m_fLinkSourceAvail)) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OleDoc_GetObjectDescriptorData ( + (LPOLEDOC)lpServerDoc, + NULL + ); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("ServerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) { + hrErr = OleStdGetOleObjectData( + (LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage, + lpformatetc, + lpMedium, + FALSE /* fUseMemory -- (use file-base stg) */ + + ); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + OleDbgOut3("ServerDoc_GetData: rendered CF_EMBEDSOURCE\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) { + if (lpOleDoc->m_fLinkSourceAvail) { + LPMONIKER lpmk; + + lpmk = ServerDoc_GetSelFullMoniker( + (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy, + &lpServerDoc->m_lrSrcSelOfCopy, + GETMONIKER_FORCEASSIGN + ); + if (lpmk) { + hrErr = OleStdGetLinkSourceData( + lpmk, + (LPCLSID)&CLSID_APP, + lpformatetc, + lpMedium + ); + OleStdRelease((LPUNKNOWN)lpmk); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + OleDbgOut3("ServerDoc_GetData: rendered CF_LINKSOURCE\r\n"); + return NOERROR; + + } else { + sc = E_FAIL; + goto error; + } + } else { + sc = DV_E_FORMATETC; + goto error; + } + + } else { + sc = DV_E_FORMATETC; + goto error; + } + + return NOERROR; + +error: + return ResultFromScode(sc); +} + + +/* ServerDoc_GetDataHere + * --------------------- + * + * Render data from the document on a CALLER allocated STGMEDIUM. + * This routine is called via IDataObject::GetDataHere. + */ +HRESULT ServerDoc_GetDataHere ( + LPSERVERDOC lpServerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + HRESULT hrErr; + SCODE sc; + + // OLE2NOTE: lpMedium is an IN parameter. we should NOT set + // lpMedium->pUnkForRelease to NULL + + /* our user document does not support any formats for GetDataHere. + ** if the document is used for + ** purposes of data transfer, then additional formats are offered. + */ + if (! lpOutlineDoc->m_fDataTransferDoc) { + sc = DV_E_FORMATETC; + goto error; + } + + if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) { + hrErr = OleStdGetOleObjectData( + (LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage, + lpformatetc, + lpMedium, + FALSE /* fUseMemory -- (use file-base stg) */ + ); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + OleDbgOut3("ServerDoc_GetDataHere: rendered CF_EMBEDSOURCE\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) { + if (lpOleDoc->m_fLinkSourceAvail) { + LPMONIKER lpmk; + + lpmk = ServerDoc_GetSelFullMoniker( + (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy, + &lpServerDoc->m_lrSrcSelOfCopy, + GETMONIKER_FORCEASSIGN + ); + if (lpmk) { + hrErr = OleStdGetLinkSourceData( + lpmk, + (LPCLSID)&CLSID_APP, + lpformatetc, + lpMedium + ); + OleStdRelease((LPUNKNOWN)lpmk); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + + OleDbgOut3("ServerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n"); + return NOERROR; + + } else { + sc = E_FAIL; + goto error; + } + } else { + sc = DV_E_FORMATETC; + goto error; + } + } else { + + /* Caller is requesting data to be returned in Caller allocated + ** medium, but we do NOT support this. we only support + ** global memory blocks that WE allocate for the caller. + */ + sc = DV_E_FORMATETC; + goto error; + } + + return NOERROR; + +error: + return ResultFromScode(sc); +} + + +/* ServerDoc_QueryGetData + * ---------------------- + * + * Answer if a particular data format is supported via GetData/GetDataHere. + * This routine is called via IDataObject::QueryGetData. + */ + +HRESULT ServerDoc_QueryGetData (LPSERVERDOC lpServerDoc,LPFORMATETC lpformatetc) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + + /* Caller is querying if we support certain format but does not + ** want any data actually returned. + */ + if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline || + lpformatetc->cfFormat == CF_TEXT) { + // we only support HGLOBAL + return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL); + } else if (lpformatetc->cfFormat == CF_METAFILEPICT && + (lpformatetc->dwAspect & + (DVASPECT_CONTENT | DVASPECT_ICON)) ) { + return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT); + } + + /* the above are the only formats supports by a user document (ie. + ** a non-data transfer doc). if the document is used for + ** purposes of data transfer, then additional formats are offered. + */ + if (! lpOutlineDoc->m_fDataTransferDoc) + return ResultFromScode(DV_E_FORMATETC); + + if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) { + return OleStdQueryOleObjectData(lpformatetc); + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource && + lpOleDoc->m_fLinkSourceAvail) { + return OleStdQueryLinkSourceData(lpformatetc); + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor) { + return OleStdQueryObjectDescriptorData(lpformatetc); + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor && + lpOleDoc->m_fLinkSourceAvail) { + return OleStdQueryObjectDescriptorData(lpformatetc); + } + + return ResultFromScode(DV_E_FORMATETC); +} + + +/* ServerDoc_EnumFormatEtc + * ----------------------- + * + * Return an enumerator which enumerates the data accepted/offered by + * the document. + * This routine is called via IDataObject::EnumFormatEtc. + */ +HRESULT ServerDoc_EnumFormatEtc( + LPSERVERDOC lpServerDoc, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + int nActualFmts; + SCODE sc = S_OK; + + /* OLE2NOTE: the enumeration of formats for a data transfer + ** document is not a static list. the list of formats offered + ** may or may not include CF_LINKSOURCE depending on whether a + ** moniker is available for our document. thus we can NOT use + ** the default OLE enumerator which enumerates the formats that + ** are registered for our app in the registration database. + */ + if (dwDirection == DATADIR_GET) { + nActualFmts = lpOleApp->m_nDocGetFmts; + + /* If the document does not have a Moniker, then exclude + ** CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR from the list of + ** formats available. these formats are deliberately listed + ** last in the array of possible "Get" formats. + */ + if (! lpOleDoc->m_fLinkSourceAvail) + nActualFmts -= 2; + + *lplpenumFormatEtc = OleStdEnumFmtEtc_Create( + nActualFmts, lpOleApp->m_arrDocGetFmts); + if (*lplpenumFormatEtc == NULL) + sc = E_OUTOFMEMORY; + + } else if (dwDirection == DATADIR_SET) { + /* OLE2NOTE: a document that is used to transfer data + ** (either via the clipboard or drag/drop does NOT + ** accept SetData on ANY format! + */ + sc = E_NOTIMPL; + goto error; + } else { + sc = E_INVALIDARG; + goto error; + } + +error: + return ResultFromScode(sc); +} + + +/* ServerDoc_GetMetafilePictData + * ----------------------------- + * + * Return a handle to an object's picture data in metafile format. + * + * + * RETURNS: A handle to the object's data in metafile format. + * + */ +HGLOBAL ServerDoc_GetMetafilePictData( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc=(LPOUTLINEDOC)lpServerDoc; + LPLINELIST lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList; + LPLINE lpLine; + LPMETAFILEPICT lppict = NULL; + HGLOBAL hMFPict = NULL; + HMETAFILE hMF = NULL; + RECT rect; + RECT rectWBounds; + HDC hDC; + int i; + int nWidth; + int nStart = (lplrSel ? lplrSel->m_nStartLine : 0); + int nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1); + int nLines = nEnd - nStart + 1; + UINT fuAlign; + POINT point; + SIZE size; + + hDC = CreateMetaFile(NULL); + + rect.left = 0; + rect.right = 0; + rect.bottom = 0; + + if (nLines > 0) { + // calculate the total height/width of LineList in HIMETRIC + for(i = nStart; i <= nEnd; i++) { + lpLine = LineList_GetLine(lpLL,i); + if (! lpLine) + continue; + + nWidth = Line_GetTotalWidthInHimetric(lpLine); + rect.right = max(rect.right, nWidth); + rect.bottom -= Line_GetHeightInHimetric(lpLine); + } + + + SetMapMode(hDC, MM_ANISOTROPIC); + + SetWindowOrgEx(hDC, 0, 0, &point); + SetWindowExtEx(hDC, rect.right, rect.bottom, &size); + rectWBounds = rect; + + // Set the default font size, and font face name + SelectObject(hDC, OutlineApp_GetActiveFont(lpOutlineApp)); + + FillRect(hDC, (LPRECT) &rect, GetStockObject(WHITE_BRUSH)); + + rect.bottom = 0; + + fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP); + + /* While more lines print out the text */ + for(i = nStart; i <= nEnd; i++) { + lpLine = LineList_GetLine(lpLL,i); + if (! lpLine) + continue; + + rect.top = rect.bottom; + rect.bottom -= Line_GetHeightInHimetric(lpLine); + + /* Draw the line */ + Line_Draw(lpLine, hDC, &rect, &rectWBounds, FALSE /*fHighlight*/); + } + + SetTextAlign(hDC, fuAlign); + } + + // Get handle to the metafile. + if (!(hMF = CloseMetaFile (hDC))) + return NULL; + + if (!(hMFPict = GlobalAlloc (GMEM_SHARE | GMEM_ZEROINIT, + sizeof (METAFILEPICT)))) { + DeleteMetaFile (hMF); + return NULL; + } + + if (!(lppict = (LPMETAFILEPICT)GlobalLock(hMFPict))) { + DeleteMetaFile (hMF); + GlobalFree (hMFPict); + return NULL; + } + + lppict->mm = MM_ANISOTROPIC; + lppict->hMF = hMF; + lppict->xExt = rect.right; + lppict->yExt = - rect.bottom; // add minus sign to make it +ve + GlobalUnlock (hMFPict); + + return hMFPict; +} + +#endif // OLE_SERVER + + + +#if defined( OLE_CNTR ) + +/************************************************************************* +** ContainerDoc Supprt Functions Used by Container versions +*************************************************************************/ + + +/* Paste OLE Link from clipboard */ +void ContainerDoc_PasteLinkCommand(LPCONTAINERDOC lpContainerDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPDATAOBJECT lpClipboardDataObj = NULL; + BOOL fLink = TRUE; + BOOL fLocalDataObj = FALSE; + BOOL fDisplayAsIcon = FALSE; + SIZEL sizelInSrc; + HCURSOR hPrevCursor; + HGLOBAL hMem = NULL; + HGLOBAL hMetaPict = NULL; + STGMEDIUM medium; + BOOL fStatus; + HRESULT hrErr; + + hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj); + if (hrErr != NOERROR) + return; // Clipboard seems to be empty or can't be accessed + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + /* check if the data on the clipboard is local to our application + ** instance. + */ + if (lpOutlineApp->m_lpClipboardDoc) { + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc; + if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject) + fLocalDataObj = TRUE; + } + + /* OLE2NOTE: we need to check what dwDrawAspect is being + ** transfered. if the data is an object that is displayed as an + ** icon in the source, then we want to keep it as an icon. the + ** aspect the object is displayed in at the source is transfered + ** via the CF_LINKSOURCEDESCRIPTOR format for a PasteLink + ** operation. + */ + if (hMem = OleStdGetData( + lpClipboardDataObj, + lpOleApp->m_cfLinkSrcDescriptor, + NULL, + DVASPECT_CONTENT, + (LPSTGMEDIUM)&medium)) { + LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem); + fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE); + sizelInSrc = lpOD->sizel; // size of object/picture in source (opt.) + GlobalUnlock(hMem); + ReleaseStgMedium((LPSTGMEDIUM)&medium); // equiv to GlobalFree + + if (fDisplayAsIcon) { + hMetaPict = OleStdGetData( + lpClipboardDataObj, + CF_METAFILEPICT, + NULL, + DVASPECT_ICON, + (LPSTGMEDIUM)&medium + ); + if (hMetaPict == NULL) + fDisplayAsIcon = FALSE; // give up; failed to get icon MFP + } + } + + fStatus = ContainerDoc_PasteFormatFromData( + lpContainerDoc, + lpOleApp->m_cfLinkSource, + lpClipboardDataObj, + fLocalDataObj, + fLink, + fDisplayAsIcon, + hMetaPict, + (LPSIZEL)&sizelInSrc + ); + + if (!fStatus) + OutlineApp_ErrorMessage(g_lpApp, ErrMsgPasting); + + if (hMetaPict) + ReleaseStgMedium((LPSTGMEDIUM)&medium); // properly free METAFILEPICT + + if (lpClipboardDataObj) + OleStdRelease((LPUNKNOWN)lpClipboardDataObj); + + SetCursor(hPrevCursor); // restore original cursor +} + + +/* ContainerDoc_PasteFormatFromData +** -------------------------------- +** +** Paste a particular data format from a IDataObject*. The +** IDataObject* may come from the clipboard (GetClipboard) or from a +** drag/drop operation. +** +** Returns TRUE if data was successfully pasted. +** FALSE if data could not be pasted. +*/ +BOOL ContainerDoc_PasteFormatFromData( + LPCONTAINERDOC lpContainerDoc, + CLIPFORMAT cfFormat, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSIZEL lpSizelInSrc +) +{ + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + int nIndex; + int nCount = 0; + HGLOBAL hData; + STGMEDIUM medium; + FORMATETC formatetc; + HRESULT hrErr; + LINERANGE lrSel; + + if (LineList_GetCount(lpLL) == 0) + nIndex = -1; // pasting to empty list + else + nIndex=LineList_GetFocusLineIndex(lpLL); + + if (fLink) { + + /* We should paste a Link to the data */ + + if (cfFormat != lpOleApp->m_cfLinkSource) + return FALSE; // we only support OLE object type links + + nCount = ContainerDoc_PasteOleObject( + lpContainerDoc, + lpSrcDataObj, + OLECREATEFROMDATA_LINK, + cfFormat, + nIndex, + fDisplayAsIcon, + hMetaPict, + lpSizelInSrc + ); + return (nCount > 0 ? TRUE : FALSE); + + } else { + + if (cfFormat == lpContainerApp->m_cfCntrOutl) { + if (fLocalDataObj) { + + /* CASE I: IDataObject* is local to our app + ** + ** if the source of the data is local to our + ** application instance, then we can get direct + ** access to the original OleDoc object that + ** corresponds to the IDataObject* given. + ** CF_CNTROUTL data is passed through a LPSTORAGE. + ** if we call OleGetData asking for CF_CNTROUTL, we + ** will be returned a copy of the existing open pStg + ** of the original source document. we can NOT open + ** streams and sub-storages again via this pStg + ** since it is already open within our same + ** application instance. we must copy the data from + ** the original OleDoc source document. + */ + LPLINELIST lpSrcLL; + LPOLEDOC lpLocalSrcDoc = + ((struct CDocDataObjectImpl FAR*)lpSrcDataObj)->lpOleDoc; + + /* copy all lines from SrcDoc to DestDoc. */ + lpSrcLL = &((LPOUTLINEDOC)lpLocalSrcDoc)->m_LineList; + nCount = LineList_CopySelToDoc( + lpSrcLL, + NULL, + (LPOUTLINEDOC)lpContainerDoc + ); + + } else { + + /* CASE II: IDataObject* is NOT local to our app + ** + ** if the source of the data comes from another + ** application instance. we can call GetDataHere to + ** retrieve the CF_CNTROUTL data. CF_CNTROUTL data + ** is passed through a LPSTORAGE. we MUST use + ** IDataObject::GetDataHere. calling + ** IDataObject::GetData does NOT work because OLE + ** currently does NOT support remoting of a callee + ** allocated root storage back to the caller. this + ** hopefully will be supported in a future version. + ** in order to call GetDataHere we must allocate an + ** IStorage instance for the callee to write into. + ** we will allocate an IStorage docfile that will + ** delete-on-release. we could use either a + ** memory-based storage or a file-based storage. + */ + LPSTORAGE lpTmpStg = OleStdCreateTempStorage( + FALSE /*fUseMemory*/, + STGM_READWRITE | STGM_TRANSACTED |STGM_SHARE_EXCLUSIVE + ); + if (! lpTmpStg) + return FALSE; + + formatetc.cfFormat = cfFormat; + formatetc.ptd = NULL; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.tymed = TYMED_ISTORAGE; + formatetc.lindex = -1; + + medium.tymed = TYMED_ISTORAGE; + medium.pstg = lpTmpStg; + medium.pUnkForRelease = NULL; + + OLEDBG_BEGIN2("IDataObject::GetDataHere called\r\n") + hrErr = lpSrcDataObj->lpVtbl->GetDataHere( + lpSrcDataObj, + (LPFORMATETC)&formatetc, + (LPSTGMEDIUM)&medium + ); + OLEDBG_END2 + + if (hrErr == NOERROR) { + nCount = ContainerDoc_PasteCntrOutlData( + lpContainerDoc, + lpTmpStg, + nIndex + ); + } + OleStdVerifyRelease( + (LPUNKNOWN)lpTmpStg, "Temp stg NOT released!\r\n"); + return ((hrErr == NOERROR) ? TRUE : FALSE); + } + + } else if (cfFormat == lpOutlineApp->m_cfOutline) { + + hData = OleStdGetData( + lpSrcDataObj, + lpOutlineApp->m_cfOutline, + NULL, + DVASPECT_CONTENT, + (LPSTGMEDIUM)&medium + ); + nCount = OutlineDoc_PasteOutlineData( + (LPOUTLINEDOC)lpContainerDoc, + hData, + nIndex + ); + // OLE2NOTE: we must free data handle by releasing the medium + ReleaseStgMedium((LPSTGMEDIUM)&medium); + + } else if (cfFormat == lpOleApp->m_cfEmbedSource || + cfFormat == lpOleApp->m_cfEmbeddedObject || + cfFormat == lpOleApp->m_cfFileName) { + /* OLE2NOTE: OleCreateFromData API creates an OLE object if + ** CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are + ** available from the source data object. the + ** CF_FILENAME case arises when a file is copied to the + ** clipboard from the FileManager. if the file has an + ** associated class (see GetClassFile API), then an + ** object of that class is created. otherwise an OLE 1.0 + ** Packaged object is created. + */ + nCount = ContainerDoc_PasteOleObject( + lpContainerDoc, + lpSrcDataObj, + OLECREATEFROMDATA_OBJECT, + 0, /* N/A -- cfFormat */ + nIndex, + fDisplayAsIcon, + hMetaPict, + lpSizelInSrc + ); + return (nCount > 0 ? TRUE : FALSE); + + } else if (cfFormat == CF_METAFILEPICT + || cfFormat == CF_DIB + || cfFormat == CF_BITMAP) { + + /* OLE2NOTE: OleCreateStaticFromData API creates an static + ** OLE object if CF_METAFILEPICT, CF_DIB, or CF_BITMAP is + ** CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are + ** available from the source data object. + */ + nCount = ContainerDoc_PasteOleObject( + lpContainerDoc, + lpSrcDataObj, + OLECREATEFROMDATA_STATIC, + cfFormat, + nIndex, + fDisplayAsIcon, + hMetaPict, + lpSizelInSrc + ); + return (nCount > 0 ? TRUE : FALSE); + + } else if(cfFormat == CF_TEXT) { + + hData = OleStdGetData( + lpSrcDataObj, + CF_TEXT, + NULL, + DVASPECT_CONTENT, + (LPSTGMEDIUM)&medium + ); + nCount = OutlineDoc_PasteTextData( + (LPOUTLINEDOC)lpContainerDoc, + hData, + nIndex + ); + // OLE2NOTE: we must free data handle by releasing the medium + ReleaseStgMedium((LPSTGMEDIUM)&medium); + + } else { + return FALSE; // no acceptable format available to paste + } + } + + lrSel.m_nStartLine = nIndex + nCount; + lrSel.m_nEndLine = nIndex + 1; + LineList_SetSel(lpLL, &lrSel); + return TRUE; +} + + +/* ContainerDoc_PasteCntrOutlData + * ------------------------------- + * + * Load the lines stored in a lpSrcStg (stored in CF_CNTROUTL format) + * into the document. + * + * Return the number of items added + */ +int ContainerDoc_PasteCntrOutlData( + LPCONTAINERDOC lpDestContainerDoc, + LPSTORAGE lpSrcStg, + int nStartIndex +) +{ + int nCount; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpDestOutlineDoc = (LPOUTLINEDOC)lpDestContainerDoc; + LPOUTLINEDOC lpSrcOutlineDoc; + LPLINELIST lpSrcLL; + + // create a temp document that will be used to load the lpSrcStg data. + lpSrcOutlineDoc = (LPOUTLINEDOC)OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if ( ! lpSrcOutlineDoc ) + return 0; + + if (! OutlineDoc_LoadFromStg(lpSrcOutlineDoc, lpSrcStg)) + goto error; + + /* copy all lines from the SrcDoc to the DestDoc. */ + lpSrcLL = &lpSrcOutlineDoc->m_LineList; + nCount = LineList_CopySelToDoc(lpSrcLL, NULL, lpDestOutlineDoc); + + if (lpSrcOutlineDoc) // destroy temporary document. + OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE); + + return nCount; + +error: + if (lpSrcOutlineDoc) // destroy temporary document. + OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE); + + return 0; +} + + +/* ContainerDoc_QueryPasteFromData +** ------------------------------- +** +** Check if the IDataObject* offers data in a format that we can +** paste. The IDataObject* may come from the clipboard +** (GetClipboard) or from a drag/drop operation. +** In this function we look if one of the following formats is +** offered: +** CF_OUTLINE +** <OLE object -- CF_EMBEDSOURCE or CF_EMBEDDEDOBJECT> +** CF_TEXT +** +** NOTE: fLink is specified and CF_LINKSOURCE is available then TRUE +** is returned, else FALSE. +** +** Returns TRUE if paste can be performed +** FALSE if paste is not possible. +*/ +BOOL ContainerDoc_QueryPasteFromData( + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLink +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + + if (fLink) { + /* check if we can paste a Link to the data */ + if (OleQueryLinkFromData(lpSrcDataObj) != NOERROR) + return FALSE; // linking is NOT possible + } else { + + int nFmtEtc; + + nFmtEtc = OleStdGetPriorityClipboardFormat( + lpSrcDataObj, + lpOleApp->m_arrPasteEntries, + lpOleApp->m_nPasteEntries + ); + + if (nFmtEtc < 0) + return FALSE; // there is no format we like + } + + return TRUE; +} + + +/* ContainerDoc_PasteOleObject +** --------------------------- +** +** Embed or link an OLE object. the source of the data is a pointer +** to an IDataObject. normally this lpSrcDataObj comes from the +** clipboard after call OleGetClipboard. +** +** dwCreateType controls what type of object will created: +** OLECREATEFROMDATA_LINK -- OleCreateLinkFromData will be called +** OLECREATEFROMDATA_OBJECT -- OleCreateFromData will be called +** OLECREATEFROMDATA_STATIC -- OleCreateStaticFromData will be called +** cfFormat controls the type of static +** a CONTAINERLINE object is created to manage the OLE object. this +** CONTAINERLINE is added to the ContainerDoc after line nIndex. +** +*/ +int ContainerDoc_PasteOleObject( + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + DWORD dwCreateType, + CLIPFORMAT cfFormat, + int nIndex, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSIZEL lpSizelInSrc +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LPLINE lpLine = NULL; + HDC hDC; + int nTab = 0; + char szStgName[CWCSTORAGENAME]; + LPCONTAINERLINE lpContainerLine = NULL; + + ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName)); + + /* default the new line to have the same indent as previous line */ + lpLine = LineList_GetLine(lpLL, nIndex); + if (lpLine) + nTab = Line_GetTabLevel(lpLine); + + hDC = LineList_GetDC(lpLL); + + lpContainerLine = ContainerLine_CreateFromData( + hDC, + nTab, + lpContainerDoc, + lpSrcDataObj, + dwCreateType, + cfFormat, + fDisplayAsIcon, + hMetaPict, + szStgName + ); + LineList_ReleaseDC(lpLL, hDC); + + if (! lpContainerLine) + goto error; + + /* add a ContainerLine object to the document's LineList. The + ** ContainerLine manages the rectangle on the screen occupied by + ** the OLE object. later when the app is updated to support + ** extended layout, there could be more than one Line associated + ** with the OLE object. + */ + + LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex); + + /* OLE2NOTE: if the source of the OLE object just pasted, passed a + ** non-zero sizel in the ObjectDescriptor, then we will try to + ** keep the object the same size as it is in the source. this + ** may be a scaled size if the object had been resized in the + ** source container. if the source did not give a valid sizel, + ** then we will retrieve the size of the object by calling + ** IViewObject2::GetExtent. + */ + if (lpSizelInSrc && (lpSizelInSrc->cx != 0 || lpSizelInSrc->cy != 0)) { + ContainerLine_UpdateExtent(lpContainerLine, lpSizelInSrc); + } else + ContainerLine_UpdateExtent(lpContainerLine, NULL); + + OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE); + + return 1; // one line added to LineList + +error: + // NOTE: if ContainerLine_CreateFromClip failed + OutlineApp_ErrorMessage(g_lpApp, "Paste Object failed!"); + return 0; // no lines added to line list +} + + +/* ContainerDoc_GetData + * -------------------- + * + * Render data from the document on a CALLEE allocated STGMEDIUM. + * This routine is called via IDataObject::GetData. + */ +HRESULT ContainerDoc_GetData ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp; + HRESULT hrErr; + SCODE sc; + + // OLE2NOTE: we must set out pointer parameters to NULL + lpMedium->pUnkForRelease = NULL; + + /* OLE2NOTE: we must set all out pointer parameters to NULL. */ + lpMedium->tymed = TYMED_NULL; + lpMedium->pUnkForRelease = NULL; // we transfer ownership to caller + lpMedium->hGlobal = NULL; + + if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) { + + /* OLE2NOTE: currently OLE does NOT support remoting a root + ** level IStorage (either memory or file based) as an OUT + ** parameter. thus, we can NOT support GetData for this + ** TYMED_ISTORAGE based format. the caller MUST call GetDataHere. + */ + sc = DV_E_FORMATETC; + goto error; + + } else if (!lpContainerDoc->m_fEmbeddedObjectAvail && + lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("ContainerDoc_GetData: rendered CF_OUTLINE\r\n"); + return NOERROR; + + } else if (!lpContainerDoc->m_fEmbeddedObjectAvail && + lpformatetc->cfFormat == CF_TEXT) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OutlineDoc_GetTextData ( + (LPOUTLINEDOC)lpContainerDoc, + NULL + ); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("ContainerDoc_GetData: rendered CF_TEXT\r\n"); + return NOERROR; + + } else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor || + (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor && + lpOleDoc->m_fLinkSourceAvail) ) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OleDoc_GetObjectDescriptorData ( + (LPOLEDOC)lpContainerDoc, + NULL + ); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_HGLOBAL; +#if defined( _DEBUG ) + if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor) + OleDbgOut3( + "ContainerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n"); + else + OleDbgOut3( + "ContainerDoc_GetData: rendered CF_LINKSRCDESCRIPTOR\r\n"); +#endif + return NOERROR; + + } else if (lpContainerDoc->m_fEmbeddedObjectAvail) { + + /* OLE2NOTE: if this document contains a single OLE object + ** (ie. cfEmbeddedObject data format is available), then + ** the formats offered via our IDataObject must include + ** the formats available from the OLE object itself. + ** thus, we delegate this call to the IDataObject* of the + ** OLE object. + */ + + if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) { + LPPERSISTSTORAGE lpPersistStg = + (LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject( + lpContainerDoc, + &IID_IPersistStorage, + NULL + ); + + if (! lpPersistStg) + return ResultFromScode(DV_E_FORMATETC); + + /* render CF_EMBEDDEDOBJECT by asking the object to save + ** into a temporary, DELETEONRELEASE pStg allocated by us. + */ + + hrErr = OleStdGetOleObjectData( + lpPersistStg, + lpformatetc, + lpMedium, + FALSE /* fUseMemory -- (use file-base stg) */ + ); + OleStdRelease((LPUNKNOWN)lpPersistStg); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + OleDbgOut3("ContainerDoc_GetData: rendered CF_EMBEDDEDOBJECT\r\n"); + return hrErr; + + } else if (lpformatetc->cfFormat == CF_METAFILEPICT) { + + /* OLE2NOTE: as a container which draws objects, when a single + ** OLE object is copied, we can give the Metafile picture of + ** the object. + */ + LPCONTAINERLINE lpContainerLine; + LPOLEOBJECT lpOleObj; + SIZEL sizelOleObject; + + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_MFPICT)) { + sc = DV_E_FORMATETC; + goto error; + } + + lpOleObj = (LPOLEOBJECT)ContainerDoc_GetSingleOleObject( + lpContainerDoc, + &IID_IOleObject, + (LPCONTAINERLINE FAR*)&lpContainerLine + ); + + if (! lpOleObj) { + sc = E_OUTOFMEMORY; // could not load object + goto error; + } + if (lpformatetc->dwAspect & lpContainerLine->m_dwDrawAspect) { + LPLINE lpLine = (LPLINE)lpContainerLine; + + /* render CF_METAFILEPICT by drawing the object into + ** a metafile DC + */ + + /* OLE2NOTE: Get size that object is being drawn. If the + ** object has been scaled because the user resized the + ** object, then we want to render a metafile with the + ** scaled size. + */ + sizelOleObject.cx = lpLine->m_nWidthInHimetric; + sizelOleObject.cy = lpLine->m_nHeightInHimetric; + + lpMedium->hGlobal = OleStdGetMetafilePictFromOleObject( + lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSIZEL)&sizelOleObject, + lpformatetc->ptd + ); + OleStdRelease((LPUNKNOWN)lpOleObj); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_MFPICT; + OleDbgOut3("ContainerDoc_GetData: rendered CF_METAFILEPICT\r\n"); + return NOERROR; + } else { + // improper aspect requested + OleStdRelease((LPUNKNOWN)lpOleObj); + return ResultFromScode(DV_E_FORMATETC); + } + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) { + if (lpOleDoc->m_fLinkSourceAvail) { + LPMONIKER lpmk; + + lpmk = ContainerLine_GetFullMoniker( + lpContainerDoc->m_lpSrcContainerLine, + GETMONIKER_FORCEASSIGN + ); + if (lpmk) { + hrErr = OleStdGetLinkSourceData( + lpmk, + &lpContainerDoc->m_clsidOleObjCopied, + lpformatetc, + lpMedium + ); + OleStdRelease((LPUNKNOWN)lpmk); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + OleDbgOut3("ContainerDoc_GetData: rendered CF_LINKSOURCE\r\n"); + return hrErr; + } else { + sc = DV_E_FORMATETC; + goto error; + } + } else { + sc = DV_E_FORMATETC; + goto error; + } + + } +#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER ) + /* OLE2NOTE: optionally, a container that wants to have a + ** potentially richer data transfer, can enumerate the data + ** formats from the OLE object's cache and offer them too. if + ** the object has a special handler, then it might be able to + ** render additional data formats. in this case, the + ** container must delegate the GetData call to the object if + ** it does not directly support the format. + ** + ** CNTROUTL does NOT enumerate the cache; it implements the + ** simpler strategy of offering a static list of formats. + ** thus the delegation is NOT required. + */ + else { + + /* OLE2NOTE: we delegate this call to the IDataObject* of the + ** OLE object. + */ + LPDATAOBJECT lpDataObj; + + lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject( + lpContainerDoc, + &IID_IDataObject, + NULL + ); + + if (! lpDataObj) { + sc = DV_E_FORMATETC; + goto error; + } + + OLEDBG_BEGIN2("ContainerDoc_GetData: delegate to OLE obj\r\n") + hrErr=lpDataObj->lpVtbl->GetData(lpDataObj,lpformatetc,lpMedium); + OLEDBG_END2 + + OleStdRelease((LPUNKNOWN)lpDataObj); + return hrErr; + } +#endif // ! OPTIONAL_ADVANCED_DATA_TRANSFER + + } + + // if we get here then we do NOT support the requested format + sc = DV_E_FORMATETC; + +error: + return ResultFromScode(sc); +} + + +/* ContainerDoc_GetDataHere + * ------------------------ + * + * Render data from the document on a CALLER allocated STGMEDIUM. + * This routine is called via IDataObject::GetDataHere. + */ +HRESULT ContainerDoc_GetDataHere ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp; + HRESULT hrErr; + + // OLE2NOTE: lpMedium is an IN parameter. we should NOT set + // lpMedium->pUnkForRelease to NULL + + // we only support IStorage medium + if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) { + if (!(lpformatetc->tymed & TYMED_ISTORAGE)) + return ResultFromScode(DV_E_FORMATETC); + + if (lpMedium->tymed == TYMED_ISTORAGE) { + /* Caller has allocated the storage. we must copy all of our + ** data into his storage. + */ + + /* OLE2NOTE: we must be sure to write our class ID into our + ** storage. this information is used by OLE to determine the + ** class of the data stored in our storage. + */ + if((hrErr=WriteClassStg(lpMedium->pstg,&CLSID_APP)) != NOERROR) + return hrErr; + + OutlineDoc_SaveSelToStg( + (LPOUTLINEDOC)lpContainerDoc, + NULL, /* entire doc */ + lpContainerApp->m_cfCntrOutl, + lpMedium->pstg, + FALSE, /* fSameAsLoad */ + FALSE /* fRemember */ + ); + OleStdCommitStorage(lpMedium->pstg); + + OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_CNTROUTL\r\n"); + return NOERROR; + } else { + // we only support IStorage medium + return ResultFromScode(DV_E_FORMATETC); + } + + } else if (lpContainerDoc->m_fEmbeddedObjectAvail) { + + /* OLE2NOTE: if this document contains a single OLE object + ** (ie. cfEmbeddedObject data format is available), then + ** the formats offered via our IDataObject must include + ** CF_EMBEDDEDOBJECT and the formats available from the OLE + ** object itself. + */ + + if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) { + LPPERSISTSTORAGE lpPersistStg = + (LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject( + lpContainerDoc, + &IID_IPersistStorage, + NULL + ); + + if (! lpPersistStg) { + return ResultFromScode(E_OUTOFMEMORY); + } + /* render CF_EMBEDDEDOBJECT by asking the object to save + ** into the IStorage allocated by the caller. + */ + + hrErr = OleStdGetOleObjectData( + lpPersistStg, + lpformatetc, + lpMedium, + FALSE /* fUseMemory -- N/A */ + ); + OleStdRelease((LPUNKNOWN)lpPersistStg); + if (hrErr != NOERROR) { + return hrErr; + } + OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_EMBEDDEDOBJECT\r\n"); + return hrErr; + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) { + if (lpOleDoc->m_fLinkSourceAvail) { + LPMONIKER lpmk; + + lpmk = ContainerLine_GetFullMoniker( + lpContainerDoc->m_lpSrcContainerLine, + GETMONIKER_FORCEASSIGN + ); + if (lpmk) { + hrErr = OleStdGetLinkSourceData( + lpmk, + &lpContainerDoc->m_clsidOleObjCopied, + lpformatetc, + lpMedium + ); + OleStdRelease((LPUNKNOWN)lpmk); + OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n"); + return hrErr; + } else { + return ResultFromScode(E_FAIL); + } + } else { + return ResultFromScode(DV_E_FORMATETC); + } + + } else { +#if !defined( OPTIONAL_ADVANCED_DATA_TRANSFER ) + return ResultFromScode(DV_E_FORMATETC); +#endif +#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER ) + /* OLE2NOTE: optionally, a container that wants to have a + ** potentially richer data transfer, can enumerate the data + ** formats from the OLE object's cache and offer them too. if + ** the object has a special handler, then it might be able to + ** render additional data formats. in this case, the + ** container must delegate the GetData call to the object if + ** it does not directly support the format. + ** + ** CNTROUTL does NOT enumerate the cache; it implements the + ** simpler strategy of offering a static list of formats. + ** thus the delegation is NOT required. + */ + /* OLE2NOTE: we delegate this call to the IDataObject* of the + ** OLE object. + */ + LPDATAOBJECT lpDataObj; + + lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject( + lpContainerDoc, + &IID_IDataObject, + NULL + ); + + if (! lpDataObj) + return ResultFromScode(DV_E_FORMATETC); + + OLEDBG_BEGIN2("ContainerDoc_GetDataHere: delegate to OLE obj\r\n") + hrErr = lpDataObj->lpVtbl->GetDataHere( + lpDataObj, + lpformatetc, + lpMedium + ); + OLEDBG_END2 + + OleStdRelease((LPUNKNOWN)lpDataObj); + return hrErr; +#endif // OPTIONAL_ADVANCED_DATA_TRANSFER + } + } else { + return ResultFromScode(DV_E_FORMATETC); + } +} + + +/* ContainerDoc_QueryGetData + * ------------------------- + * + * Answer if a particular data format is supported via GetData/GetDataHere. + * This routine is called via IDataObject::QueryGetData. + */ +HRESULT ContainerDoc_QueryGetData ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp; + LPDATAOBJECT lpDataObj = NULL; + LPCONTAINERLINE lpContainerLine = NULL; + SCODE sc; + HRESULT hrErr; + + if (lpContainerDoc->m_fEmbeddedObjectAvail) { + lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject( + lpContainerDoc, + &IID_IDataObject, + (LPCONTAINERLINE FAR*)&lpContainerLine + ); + } + + /* Caller is querying if we support certain format but does not + ** want any data actually returned. + */ + if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) { + // we only support ISTORAGE medium + sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_ISTORAGE) ); + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject && + lpContainerDoc->m_fEmbeddedObjectAvail ) { + sc = GetScode( OleStdQueryOleObjectData(lpformatetc) ); + + } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource && + lpOleDoc->m_fLinkSourceAvail) { + sc = GetScode( OleStdQueryLinkSourceData(lpformatetc) ); + + // CF_TEXT and CF_OUTLINE are NOT supported when single object is copied + } else if (!lpContainerDoc->m_fEmbeddedObjectAvail && + (lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline || + lpformatetc->cfFormat == CF_TEXT) ) { + // we only support HGLOBAL medium + sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL) ); + + } else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor || + (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor && + lpOleDoc->m_fLinkSourceAvail) ) { + sc = GetScode( OleStdQueryObjectDescriptorData(lpformatetc) ); + + } else if (lpformatetc->cfFormat == CF_METAFILEPICT && + lpContainerDoc->m_fEmbeddedObjectAvail && lpContainerLine && + (lpformatetc->dwAspect & lpContainerLine->m_dwDrawAspect)) { + + /* OLE2NOTE: as a container which draws objects, when a single + ** OLE object is copied, we can give the Metafile picture of + ** the object. + */ + // we only support MFPICT medium + sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT) ); + + } else if (lpDataObj) { + + /* OLE2NOTE: if this document contains a single OLE object + ** (ie. cfEmbeddedObject data format is available), then + ** the formats offered via our IDataObject must include + ** the formats available from the OLE object itself. + ** thus we delegate this call to the IDataObject* of the + ** OLE object. + */ + OLEDBG_BEGIN2("ContainerDoc_QueryGetData: delegate to OLE obj\r\n") + hrErr = lpDataObj->lpVtbl->QueryGetData(lpDataObj, lpformatetc); + OLEDBG_END2 + + sc = GetScode(hrErr); + + } else { + sc = DV_E_FORMATETC; + } + + if (lpDataObj) + OleStdRelease((LPUNKNOWN)lpDataObj); + return ResultFromScode(sc); +} + + + +/* ContainerDoc_SetData + * -------------------- + * + * Set (modify) data of the document. + * This routine is called via IDataObject::SetData. + */ +HRESULT ContainerDoc_SetData ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpmedium, + BOOL fRelease +) +{ + /* in the container version of Outline, only DataTransferDoc's support + ** IDataObject interface; the user documents do not support + ** IDataObject. DataTransferDoc's do not accept SetData calls. + */ + return ResultFromScode(DV_E_FORMATETC); +} + + +/* ContainerDoc_EnumFormatEtc + * -------------------------- + * + * Return an enumerator which enumerates the data accepted/offered by + * the document. + * This routine is called via IDataObject::SetData. + */ +HRESULT ContainerDoc_EnumFormatEtc( + LPCONTAINERDOC lpContainerDoc, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp; + int nActualFmts; + int i; + SCODE sc = S_OK; + + /* the Container-Only version of Outline does NOT offer + ** IDataObject interface from its User documents. + */ + if (! lpOutlineDoc->m_fDataTransferDoc) + return ResultFromScode(E_FAIL); + + if (dwDirection == DATADIR_GET) { + if (lpContainerDoc->m_fEmbeddedObjectAvail) { + + /* OLE2NOTE: if this document contains a single OLE object + ** (ie. cfEmbeddedObject data format is available), then + ** the formats offered via our enumerator must include + ** the formats available from the OLE object itself. we + ** have previously set up a special array of FORMATETC's + ** in OutlineDoc_CreateDataTransferDoc routine which includes + ** the combination of data we offer directly and data + ** offered by the OLE object. + */ + + /* If the document does not have a Moniker, then exclude + ** CF_LINKSOURCE CF_LINKSRCDESCRIPTOR from the list of + ** formats available. these formats are deliberately + ** listed last in the array of possible "Get" formats. + */ + nActualFmts = lpContainerApp->m_nSingleObjGetFmts; + if (! lpOleDoc->m_fLinkSourceAvail) + nActualFmts -= 2; + + // set correct dwDrawAspect for METAFILEPICT of object copied + for (i = 0; i < nActualFmts; i++) { + if (lpContainerApp->m_arrSingleObjGetFmts[i].cfFormat == + CF_METAFILEPICT) { + lpContainerApp->m_arrSingleObjGetFmts[i].dwAspect = + lpContainerDoc->m_dwAspectOleObjCopied; + break; // DONE + } + } + *lplpenumFormatEtc = OleStdEnumFmtEtc_Create( + nActualFmts, lpContainerApp->m_arrSingleObjGetFmts); + if (*lplpenumFormatEtc == NULL) + sc = E_OUTOFMEMORY; + + } else { + + /* This document does NOT offer cfEmbeddedObject, + ** therefore we can simply enumerate the + ** static list of formats that we handle directly. + */ + *lplpenumFormatEtc = OleStdEnumFmtEtc_Create( + lpOleApp->m_nDocGetFmts, lpOleApp->m_arrDocGetFmts); + if (*lplpenumFormatEtc == NULL) + sc = E_OUTOFMEMORY; + } + } else if (dwDirection == DATADIR_SET) { + /* OLE2NOTE: a document that is used to transfer data + ** (either via the clipboard or drag/drop does NOT + ** accept SetData on ANY format! + */ + sc = E_NOTIMPL; + + } else { + sc = E_NOTIMPL; + } + + return ResultFromScode(sc); +} + + +#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER ) +/* OLE2NOTE: optionally, a container that wants to have a +** potentially richer data transfer, can enumerate the data +** formats from the OLE object's cache and offer them too. if +** the object has a special handler, then it might be able to +** render additional data formats. +** +** CNTROUTL does NOT enumerate the cache; it implements the simpler +** strategy of offering a static list of formats. the following +** function is included in order to illustrates how enumerating the +** cache could be done. CNTROUTL does NOT call this function. +** +*/ + +/* ContainerDoc_SetupDocGetFmts +** ---------------------------- +** Setup the combined list of formats that this data transfer +** ContainerDoc which contains a single OLE object should offer. +** +** OLE2NOTE: The list of formats that should be offered when a +** single OLE object is being transfered include the following: +** * any formats the container app wants to give +** * CF_EMBEDDEDOBJECT +** * CF_METAFILEPICT +** * any formats that the OLE object's cache can offer directly +** +** We will offer the following formats in the order given: +** 1. CF_CNTROUTL +** 2. CF_EMBEDDEDOBJECT +** 3. CF_OBJECTDESCRIPTOR +** 4. CF_METAFILEPICT +** 5. <data formats from OLE object's cache> +** 6. CF_LINKSOURCE +** 7. CF_LINKSRCDESCRIPTOR +*/ +BOOL ContainerDoc_SetupDocGetFmts( + LPCONTAINERDOC lpContainerDoc, + LPCONTAINERLINE lpContainerLine +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOLECACHE lpOleCache; + HRESULT hrErr; + STATDATA StatData; + LPENUMSTATDATA lpEnumStatData = NULL; + LPFORMATETC lparrDocGetFmts = NULL; + UINT nOleObjFmts = 0; + UINT nTotalFmts; + UINT i; + UINT iFmt; + + lpOleCache = (LPOLECACHE)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, + &IID_IOleCache + ); + if (lpOleCache) { + OLEDBG_BEGIN2("IOleCache::EnumCache called\r\n") + hrErr = lpOleCache->lpVtbl->EnumCache( + lpOleCache, + (LPENUMSTATDATA FAR*)&lpEnumStatData + ); + OLEDBG_END2 + } + + if (lpEnumStatData) { + /* Cache enumerator is available. count the number of + ** formats that the OLE object's cache offers. + */ + while(lpEnumStatData->lpVtbl->Next( + lpEnumStatData, + 1, + (LPSTATDATA)&StatData, + NULL) == NOERROR) { + nOleObjFmts++; + // OLE2NOTE: we MUST free the TargetDevice + OleStdFree(StatData.formatetc.ptd); + } + lpEnumStatData->lpVtbl->Reset(lpEnumStatData); // reset for next loop + } + + /* OLE2NOTE: the maximum total number of formats that our IDataObject + ** could offer equals the sum of the following: + ** n offered by the OLE object's cache + ** + n normally offered by our app + ** + 1 CF_EMBEDDEDOBJECT + ** + 1 CF_METAFILEPICT + ** + 1 CF_LINKSOURCE + ** + 1 CF_LINKSRCDESCRIPTOR + ** the actual number of formats that we can offer could be less + ** than this total if there is any clash between the formats + ** that we offer directly and those offered by the cache. if + ** there is a clash, the container's rendering overrides that of + ** the object. eg.: as a container transfering an OLE object we + ** should directly offer CF_METAFILEPICT to guarantee that this + ** format is always available. thus, if the cache offers + ** CF_METAFILEPICT then it is skipped. + */ + nTotalFmts = nOleObjFmts + lpOleApp->m_nDocGetFmts + 4; + lparrDocGetFmts = (LPFORMATETC)New (nTotalFmts * sizeof(FORMATETC)); + + OleDbgAssertSz(lparrDocGetFmts != NULL,"Error allocating arrDocGetFmts"); + if (lparrDocGetFmts == NULL) + return FALSE; + + for (i = 0, iFmt = 0; i < lpOleApp->m_nDocGetFmts; i++) { + _fmemcpy((LPFORMATETC)&lparrDocGetFmts[iFmt++], + (LPFORMATETC)&lpOleApp->m_arrDocGetFmts[i], + sizeof(FORMATETC) + ); + if (lpOleApp->m_arrDocGetFmts[i].cfFormat == + lpContainerApp->m_cfCntrOutl) { + /* insert CF_EMBEDDEDOBJECT, CF_METAFILEPICT, and formats + ** available from the OLE object's cache following + ** CF_CNTROUTL. + */ + lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfEmbeddedObject; + lparrDocGetFmts[iFmt].ptd = NULL; + lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT; + lparrDocGetFmts[iFmt].tymed = TYMED_ISTORAGE; + lparrDocGetFmts[iFmt].lindex = -1; + iFmt++; + lparrDocGetFmts[iFmt].cfFormat = CF_METAFILEPICT; + lparrDocGetFmts[iFmt].ptd = NULL; + lparrDocGetFmts[iFmt].dwAspect = lpContainerLine->m_dwDrawAspect; + lparrDocGetFmts[iFmt].tymed = TYMED_MFPICT; + lparrDocGetFmts[iFmt].lindex = -1; + iFmt++; + + if (lpEnumStatData) { + /* Cache enumerator is available. enumerate all of + ** the formats that the OLE object's cache offers. + */ + while(lpEnumStatData->lpVtbl->Next( + lpEnumStatData, + 1, + (LPSTATDATA)&StatData, + NULL) == NOERROR) { + /* check if the format clashes with one of our fmts */ + if (StatData.formatetc.cfFormat != CF_METAFILEPICT + && ! OleStdIsDuplicateFormat( + (LPFORMATETC)&StatData.formatetc, + lpOleApp->m_arrDocGetFmts, + lpOleApp->m_nDocGetFmts)) { + OleStdCopyFormatEtc( + &(lparrDocGetFmts[iFmt]),&StatData.formatetc); + iFmt++; + } + // OLE2NOTE: we MUST free the TargetDevice + OleStdFree(StatData.formatetc.ptd); + } + } + } + } + + if (lpOleCache) + OleStdRelease((LPUNKNOWN)lpOleCache); + + /* append CF_LINKSOURCE format */ + lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSource; + lparrDocGetFmts[iFmt].ptd = NULL; + lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT; + lparrDocGetFmts[iFmt].tymed = TYMED_ISTREAM; + lparrDocGetFmts[iFmt].lindex = -1; + iFmt++; + + /* append CF_LINKSRCDESCRIPTOR format */ + lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSrcDescriptor; + lparrDocGetFmts[iFmt].ptd = NULL; + lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT; + lparrDocGetFmts[iFmt].tymed = TYMED_HGLOBAL; + lparrDocGetFmts[iFmt].lindex = -1; + iFmt++; + + lpContainerDoc->m_lparrDocGetFmts = lparrDocGetFmts; + lpContainerDoc->m_nDocGetFmts = iFmt; + + if (lpEnumStatData) + OleStdVerifyRelease( + (LPUNKNOWN)lpEnumStatData, + "Cache enumerator not released properly" + ); + + return TRUE; +} +#endif // OPTIONAL_ADVANCED_DATA_TRANSFER + +#endif // OLE_CNTR diff --git a/private/oleutest/letest/outline/cntrbase.c b/private/oleutest/letest/outline/cntrbase.c new file mode 100644 index 000000000..6fc947998 --- /dev/null +++ b/private/oleutest/letest/outline/cntrbase.c @@ -0,0 +1,2002 @@ +/************************************************************************* +** +** OLE 2 Container Sample Code +** +** cntrbase.c +** +** This file contains all interfaces, methods and related support +** functions for the basic OLE Container application. The +** basic OLE Container application supports being a container for +** embedded and linked objects. +** The basic Container application includes the following +** implementation objects: +** +** ContainerDoc Object +** no required interfaces for basic functionality +** (see linking.c for linking related support) +** (see clipbrd.c for clipboard related support) +** (see dragdrop.c for drag/drop related support) +** +** ContainerLine Object +** (see cntrline.c for all ContainerLine functions and interfaces) +** exposed interfaces: +** IOleClientSite +** IAdviseSink +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" +#include <olethunk.h> + + +OLEDBGDATA + + +extern LPOUTLINEAPP g_lpApp; +extern IOleUILinkContainerVtbl g_CntrDoc_OleUILinkContainerVtbl; + +#if defined( INPLACE_CNTR ) +extern BOOL g_fInsideOutContainer; +#endif // INPLACE_CNTR + +// REVIEW: should use string resource for messages +char ErrMsgShowObj[] = "Could not show object server!"; +char ErrMsgInsertObj[] = "Insert Object failed!"; +char ErrMsgConvertObj[] = "Convert Object failed!"; +char ErrMsgCantConvert[] = "Unable to convert the selection!"; +char ErrMsgActivateAsObj[] = "Activate As Object failed!"; + +extern char ErrMsgSaving[]; +extern char ErrMsgOpening[]; + + +/* ContainerDoc_Init + * ----------------- + * + * Initialize the fields of a new ContainerDoc object. The doc is initially + * not associated with a file or an (Untitled) document. This function sets + * the docInitType to DOCTYPE_UNKNOWN. After calling this function the + * caller should call: + * 1.) Doc_InitNewFile to set the ContainerDoc to (Untitled) + * 2.) Doc_LoadFromFile to associate the ContainerDoc with a file. + * This function creates a new window for the document. + * + * NOTE: the window is initially created with a NIL size. it must be + * sized and positioned by the caller. also the document is initially + * created invisible. the caller must call Doc_ShowWindow + * after sizing it to make the document window visible. + */ +BOOL ContainerDoc_Init(LPCONTAINERDOC lpContainerDoc, BOOL fDataTransferDoc) +{ + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + + lpOutlineDoc->m_cfSaveFormat = lpContainerApp->m_cfCntrOutl; + lpContainerDoc->m_nNextObjNo = 0L; + lpContainerDoc->m_lpNewStg = NULL; + lpContainerDoc->m_fEmbeddedObjectAvail = FALSE; + lpContainerDoc->m_clsidOleObjCopied = CLSID_NULL; + lpContainerDoc->m_dwAspectOleObjCopied = DVASPECT_CONTENT; + lpContainerDoc->m_lpSrcContainerLine = NULL; + lpContainerDoc->m_fShowObject = TRUE; + +#if defined( INPLACE_CNTR ) + lpContainerDoc->m_lpLastIpActiveLine = NULL; + lpContainerDoc->m_lpLastUIActiveLine = NULL; + lpContainerDoc->m_hWndUIActiveObj = NULL; + lpContainerDoc->m_fAddMyUI = TRUE; // UI needs to be added + lpContainerDoc->m_cIPActiveObjects = 0; + lpContainerApp->m_fMenuHelpMode = FALSE; // F1 pressed in menu + +#if defined( INPLACE_CNTRSVR ) + lpContainerDoc->m_lpTopIPFrame = + (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceFrame; + lpContainerDoc->m_lpTopIPDoc = + (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc; + lpContainerDoc->m_hSharedMenu = NULL; + lpContainerDoc->m_hOleMenu = NULL; + +#endif // INPLACE_CNTRSVR +#endif // INPLACE_CNTR + + INIT_INTERFACEIMPL( + &lpContainerDoc->m_OleUILinkContainer, + &g_CntrDoc_OleUILinkContainerVtbl, + lpContainerDoc + ); + + return TRUE; +} + + +/* ContainerDoc_GetNextLink + * ------------------------ + * + * Update all links in the document. A dialog box will be popped up showing + * the progress of the update and allow the user to quit by pushing the + * stop button + */ +LPCONTAINERLINE ContainerDoc_GetNextLink( + LPCONTAINERDOC lpContainerDoc, + LPCONTAINERLINE lpContainerLine +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + DWORD dwNextLink = 0; + LPLINE lpLine; + static int nIndex = 0; + + if (lpContainerLine==NULL) + nIndex = 0; + + for ( ; nIndex < lpLL->m_nNumLines; nIndex++) { + lpLine = LineList_GetLine(lpLL, nIndex); + + if (lpLine + && (Line_GetLineType(lpLine) == CONTAINERLINETYPE) + && ContainerLine_IsOleLink((LPCONTAINERLINE)lpLine)) { + + nIndex++; + ContainerLine_LoadOleObject((LPCONTAINERLINE)lpLine); + return (LPCONTAINERLINE)lpLine; + } + } + + return NULL; +} + + + +/* ContainerDoc_UpdateLinks + * ------------------------ + * + * Update all links in the document. A dialog box will be popped up showing + * the progress of the update and allow the user to quit by pushing the + * stop button + */ +void ContainerDoc_UpdateLinks(LPCONTAINERDOC lpContainerDoc) +{ + int cLinks; + BOOL fAllLinksUpToDate = TRUE; + HWND hwndDoc = ((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc; + HCURSOR hCursor; + LPCONTAINERLINE lpContainerLine = NULL; + HRESULT hrErr; + DWORD dwUpdateOpt; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + + hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + /* OLE2NOTE: we do not want to ever give the Busy/NotResponding + ** dialogs when we are updating automatic links as part of + ** opening a document. even if the link source of data is busy, + ** we do not want put up the busy dialog. thus we will disable + ** the dialog and later re-enable them + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + /* get total number of automatic links */ + cLinks = 0; + while (lpContainerLine = ContainerDoc_GetNextLink( + lpContainerDoc, + lpContainerLine)) { + hrErr = CntrDoc_LinkCont_GetLinkUpdateOptions( + (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer, + (DWORD)lpContainerLine, + (LPDWORD)&dwUpdateOpt + ); + if (hrErr == NOERROR) { + if (dwUpdateOpt==OLEUPDATE_ALWAYS) { + cLinks++; + if (fAllLinksUpToDate) { + OLEDBG_BEGIN2("IOleObject::IsUpToDate called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->IsUpToDate( + lpContainerLine->m_lpOleObj); + OLEDBG_END2 + if (hrErr != NOERROR) + fAllLinksUpToDate = FALSE; + } + } + } +#if defined( _DEBUG ) + else + OleDbgOutHResult("IOleUILinkContainer::GetLinkUpdateOptions returned",hrErr); +#endif + + } + + if (fAllLinksUpToDate) + goto done; // don't bother user if all links are up-to-date + + SetCursor(hCursor); + + if ((cLinks > 0) && !OleUIUpdateLinks( + (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer, + hwndDoc, + (LPSTR)APPNAME, + cLinks)) { + if (ID_PU_LINKS == OleUIPromptUser( + (WORD)IDD_CANNOTUPDATELINK, + hwndDoc, + (LPSTR)APPNAME)) { + ContainerDoc_EditLinksCommand(lpContainerDoc); + } + } + +done: + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); +} + + + +/* ContainerDoc_SetShowObjectFlag + * ------------------------------ + * + * Set/Clear the ShowObject flag of ContainerDoc + */ +void ContainerDoc_SetShowObjectFlag(LPCONTAINERDOC lpContainerDoc, BOOL fShow) +{ + if (!lpContainerDoc) + return; + + lpContainerDoc->m_fShowObject = fShow; +} + + +/* ContainerDoc_GetShowObjectFlag + * ------------------------------ + * + * Get the ShowObject flag of ContainerDoc + */ +BOOL ContainerDoc_GetShowObjectFlag(LPCONTAINERDOC lpContainerDoc) +{ + if (!lpContainerDoc) + return FALSE; + + return lpContainerDoc->m_fShowObject; +} + + +/* ContainerDoc_InsertOleObjectCommand + * ----------------------------------- + * + * Insert a new OLE object in the ContainerDoc. + */ +void ContainerDoc_InsertOleObjectCommand(LPCONTAINERDOC lpContainerDoc) +{ + LPLINELIST lpLL =&((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LPLINE lpLine = NULL; + HDC hDC; + int nTab = 0; + int nIndex = LineList_GetFocusLineIndex(lpLL); + LPCONTAINERLINE lpContainerLine=NULL; + char szStgName[CWCSTORAGENAME]; + UINT uRet; + OLEUIINSERTOBJECT io; + char szFile[OLEUI_CCHPATHMAX]; + DWORD dwOleCreateType; + BOOL fDisplayAsIcon; + HCURSOR hPrevCursor; + + _fmemset((LPOLEUIINSERTOBJECT)&io, 0, sizeof(io)); + io.cbStruct=sizeof(io); + io.dwFlags=IOF_SELECTCREATENEW | IOF_SHOWHELP; + io.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc; + io.lpszFile=(LPSTR)szFile; + io.cchFile=sizeof(szFile); + _fmemset((LPSTR)szFile, 0, OLEUI_CCHPATHMAX); + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc); +#endif + + OLEDBG_BEGIN3("OleUIInsertObject called\r\n") + uRet=OleUIInsertObject((LPOLEUIINSERTOBJECT)&io); + OLEDBG_END3 + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc); +#endif + + if (OLEUI_OK != uRet) + return; // user canceled dialog + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + fDisplayAsIcon = (io.dwFlags & IOF_CHECKDISPLAYASICON ? TRUE : FALSE); + + // make up a storage name for the OLE object + ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName)); + + /* default the new line to have the same indent as previous line */ + lpLine = LineList_GetLine(lpLL, nIndex); + if (lpLine) + nTab = Line_GetTabLevel(lpLine); + + hDC = LineList_GetDC(lpLL); + + if ((io.dwFlags & IOF_SELECTCREATENEW)) + dwOleCreateType = IOF_SELECTCREATENEW; + else if ((io.dwFlags & IOF_CHECKLINK)) + dwOleCreateType = IOF_CHECKLINK; + else + dwOleCreateType = IOF_SELECTCREATEFROMFILE; + + lpContainerLine = ContainerLine_Create( + dwOleCreateType, + hDC, + nTab, + lpContainerDoc, + &io.clsid, + (LPSTR)szFile, + fDisplayAsIcon, + io.hMetaPict, + szStgName + ); + + if (!lpContainerLine) + goto error; // creation of OLE object FAILED + + if (io.hMetaPict) { + OleUIMetafilePictIconFree(io.hMetaPict); // clean up metafile + } + + /* add a ContainerLine object to the document's LineList. The + ** ContainerLine manages the rectangle on the screen occupied by + ** the OLE object. + */ + + LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex); + + /* before calling DoVerb(OLEIVERB_SHOW), check to see if the object + ** has any initial extents. + */ + ContainerLine_UpdateExtent(lpContainerLine, NULL); + + /* If a new embedded object was created, tell the object server to + ** make itself visible (show itself). + ** OLE2NOTE: the standard OLE 2 User Model is to only call + ** IOleObject::DoVerb(OLEIVERB_SHOW...) if a new object is + ** created. specifically, it should NOT be calld if the object + ** is created from file or link to file. + */ + if (dwOleCreateType == IOF_SELECTCREATENEW) { + if (! ContainerLine_DoVerb( + lpContainerLine, OLEIVERB_SHOW, NULL, TRUE, TRUE)) { + OutlineApp_ErrorMessage(g_lpApp, ErrMsgShowObj); + } + + /* OLE2NOTE: we will immediately force a save of the object + ** to guarantee that a valid initial object is saved + ** with our document. if the object is a OLE 1.0 object, + ** then it may exit without update. by forcing this + ** initial save we consistently always have a valid + ** object even if it is a OLE 1.0 object that exited + ** without saving. if we did NOT do this save here, then + ** we would have to worry about deleting the object if + ** it was a OLE 1.0 object that closed without saving. + ** the OLE 2.0 User Model dictates that the object + ** should always be valid after CreateNew performed. the + ** user must explicitly delete it. + */ + ContainerLine_SaveOleObjectToStg( + lpContainerLine, + lpContainerLine->m_lpStg, + lpContainerLine->m_lpStg, + TRUE /* fRemember */ + ); + } +#if defined( INPLACE_CNTR ) + else if (dwOleCreateType == IOF_SELECTCREATEFROMFILE) { + /* OLE2NOTE: an inside-out container should check if the object + ** created from file is an inside-out and prefers to be + ** activated when visible type of object. if so, the object + ** should be immediately activated in-place, BUT NOT UIActived. + */ + if (g_fInsideOutContainer && + lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT && + lpContainerLine->m_fInsideOutObj ) { + HWND hWndDoc = OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerDoc); + + ContainerLine_DoVerb( + lpContainerLine,OLEIVERB_INPLACEACTIVATE,NULL,FALSE,FALSE); + + /* OLE2NOTE: following this DoVerb(INPLACEACTIVATE) the + ** object may have taken focus. but because the + ** object is NOT UIActive it should NOT have focus. + ** we will make sure our document has focus. + */ + SetFocus(hWndDoc); + } + } +#endif // INPLACE_CNTR + + OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE); + + LineList_ReleaseDC(lpLL, hDC); + + SetCursor(hPrevCursor); // restore original cursor + + return; + +error: + // NOTE: if ContainerLine_Create failed + LineList_ReleaseDC(lpLL, hDC); + + if (OLEUI_OK == uRet && io.hMetaPict) + OleUIMetafilePictIconFree(io.hMetaPict); // clean up metafile + + SetCursor(hPrevCursor); // restore original cursor + OutlineApp_ErrorMessage(g_lpApp, ErrMsgInsertObj); +} + + + +void ContainerDoc_EditLinksCommand(LPCONTAINERDOC lpContainerDoc) +{ + UINT uRet; + OLEUIEDITLINKS el; + LPCONTAINERLINE lpContainerLine = NULL; + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + + _fmemset((LPOLEUIEDITLINKS)&el,0,sizeof(el)); + el.cbStruct=sizeof(el); + el.dwFlags=ELF_SHOWHELP; + el.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc; + el.lpOleUILinkContainer = + (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer; + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc); +#endif + + OLEDBG_BEGIN3("OleUIEditLinks called\r\n") + uRet=OleUIEditLinks((LPOLEUIEDITLINKS)&el); + OLEDBG_END3 + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc); +#endif + + OleDbgAssert((uRet==1) || (uRet==OLEUI_CANCEL)); + +} + + +/* Convert command - brings up the "Convert" dialog + */ +void ContainerDoc_ConvertCommand( + LPCONTAINERDOC lpContainerDoc, + BOOL fServerNotRegistered +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + OLEUICONVERT ct; + UINT uRet; + LPDATAOBJECT lpDataObj; + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LPCONTAINERLINE lpContainerLine = NULL; + BOOL fSelIsOleObject; + int nIndex; + STGMEDIUM medium; + LPSTR lpErrMsg = NULL; + HRESULT hrErr; + HCURSOR hPrevCursor; + BOOL fMustRun = FALSE; + BOOL fMustClose = FALSE; + BOOL fObjConverted = FALSE; + BOOL fDisplayChanged = FALSE; + BOOL fHaveCLSID = FALSE; + BOOL fHaveFmtUserType = FALSE; + char szUserType[128]; + BOOL fMustActivate; + + /* OLE2NOTE: if we came to the Convert dialog because the user + ** activated a non-registered object, then we should activate + ** the object after the user has converted it or setup an + ** ActivateAs server. + */ + fMustActivate = fServerNotRegistered; + + _fmemset((LPOLEUICONVERT)&ct,0,sizeof(ct)); + + fSelIsOleObject = ContainerDoc_IsSelAnOleObject( + (LPCONTAINERDOC)lpContainerDoc, + &IID_IDataObject, + (LPUNKNOWN FAR*)&lpDataObj, + &nIndex, + (LPCONTAINERLINE FAR*)&lpContainerLine + ); + + lpErrMsg = ErrMsgCantConvert; + + if (! fSelIsOleObject) + goto error; // can NOT do Convert. + + if (! lpContainerLine) { + OleStdRelease((LPUNKNOWN)lpDataObj); + goto error; // can NOT do Convert. + } + + ct.cbStruct = sizeof(OLEUICONVERT); + ct.dwFlags = CF_SHOWHELPBUTTON; + ct.hWndOwner = lpContainerDoc->m_OleDoc.m_OutlineDoc.m_hWndDoc; + ct.lpszCaption = (LPSTR)NULL; + ct.lpfnHook = NULL; + ct.lCustData = 0; + ct.hInstance = NULL; + ct.lpszTemplate = NULL; + ct.hResource = 0; + ct.fIsLinkedObject = ContainerLine_IsOleLink(lpContainerLine); + ct.dvAspect = lpContainerLine->m_dwDrawAspect; + ct.cClsidExclude = 0; + ct.lpClsidExclude = NULL; + + if (! ct.fIsLinkedObject || !lpContainerLine->m_lpOleLink) { + /* OLE2NOTE: the object is an embedded object. we should first + ** attempt to read the actual object CLSID, file data + ** format, and full user type name that is written inside of + ** the object's storage as this should be the most + ** definitive information. if this fails we will ask the + ** object what its class is and attempt to get the rest of + ** the information out of the REGDB. + */ + hrErr=ReadClassStg(lpContainerLine->m_lpStg,(CLSID FAR*)&(ct.clsid)); + if (hrErr == NOERROR) + fHaveCLSID = TRUE; + else { + OleDbgOutHResult("ReadClassStg returned", hrErr); + } + + hrErr = ReadFmtUserTypeStgA( + lpContainerLine->m_lpStg, + (CLIPFORMAT FAR*)&ct.wFormat, + &ct.lpszUserType); + + if (hrErr == NOERROR) + fHaveFmtUserType = TRUE; + else { + OleDbgOutHResult("ReadFmtUserTypeStg returned", hrErr); + } + } else { + /* OLE2NOTE: the object is a linked object. we should give the + ** DisplayName of the link source as the default icon label. + */ + OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n") + + hrErr = CallIOleLinkGetSourceDisplayNameA( + lpContainerLine->m_lpOleLink, &ct.lpszDefLabel); + + OLEDBG_END2 + } + + if (! fHaveCLSID) { + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID( + lpContainerLine->m_lpOleObj, + (CLSID FAR*)&ct.clsid + ); + if (hrErr != NOERROR) + ct.clsid = CLSID_NULL; + } + if (! fHaveFmtUserType) { + ct.wFormat = 0; + if (OleStdGetUserTypeOfClass( + (CLSID FAR*)&ct.clsid,szUserType,sizeof(szUserType),NULL)) { + ct.lpszUserType = OleStdCopyString(szUserType, NULL); + } else { + ct.lpszUserType = NULL; + } + } + + if (lpContainerLine->m_dwDrawAspect == DVASPECT_ICON) { + ct.hMetaPict = OleStdGetData( + lpDataObj, + CF_METAFILEPICT, + NULL, + DVASPECT_ICON, + (LPSTGMEDIUM)&medium + ); + } else { + ct.hMetaPict = NULL; + } + OleStdRelease((LPUNKNOWN)lpDataObj); + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc); +#endif + + OLEDBG_BEGIN3("OleUIConvert called\r\n") + uRet = OleUIConvert(&ct); + OLEDBG_END3 + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc); +#endif + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + if (uRet == OLEUI_OK) { + + /***************************************************************** + ** OLE2NOTE: the convert dialog actually allows the user to + ** change two orthogonal properties of the object: the + ** object's type/server and the object's display aspect. + ** first we will execute the ConvertTo/ActivateAs action and + ** then we will deal with any display aspect change. we want + ** to be careful to only call IOleObject::Update once + ** because this is an expensive operation; it results in + ** launching the object's server. + *****************************************************************/ + + if (ct.dwFlags & CF_SELECTCONVERTTO && + ! IsEqualCLSID(&ct.clsid, &ct.clsidNew)) { + + /* user selected CONVERT. + ** + ** OLE2NOTE: to achieve the "Convert To" at this point we + ** need to take the following steps: + ** 1. unload the object. + ** 2. write the NEW CLSID and NEW user type name + ** string into the storage of the object, + ** BUT write the OLD format tag. + ** 3. force an update to force the actual conversion of + ** the data bits. + */ + lpErrMsg = ErrMsgConvertObj; // setup correct msg in case of error + + ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_SAVEIFDIRTY); + + OLEDBG_BEGIN2("OleStdDoConvert called \r\n") + hrErr = OleStdDoConvert( + lpContainerLine->m_lpStg, (REFCLSID)&ct.clsidNew); + OLEDBG_END2 + if (hrErr != NOERROR) + goto error; + + // Reload the object + ContainerLine_LoadOleObject(lpContainerLine); + + /* we need to force the object to run to complete the + ** conversion. set flag to force OleRun to be called at + ** end of function. + */ + fMustRun = TRUE; + fObjConverted = TRUE; + + } else if (ct.dwFlags & CF_SELECTACTIVATEAS) { + /* user selected ACTIVATE AS. + ** + ** OLE2NOTE: to achieve the "Activate As" at this point we + ** need to take the following steps: + ** 1. unload ALL objects of the OLD class that app knows about + ** 2. add the TreatAs tag in the registration database + ** by calling CoTreatAsClass(). + ** 3. lazily it can reload the objects; when the objects + ** are reloaded the TreatAs will take effect. + */ + lpErrMsg = ErrMsgActivateAsObj; // setup msg in case of error + + ContainerDoc_UnloadAllOleObjectsOfClass( + lpContainerDoc, + (REFCLSID)&ct.clsid, + OLECLOSE_SAVEIFDIRTY + ); + + OLEDBG_BEGIN2("OleStdDoTreatAsClass called \r\n") + hrErr = OleStdDoTreatAsClass(ct.lpszUserType, (REFCLSID)&ct.clsid, + (REFCLSID)&ct.clsidNew); + OLEDBG_END2 + + // Reload the object + ContainerLine_LoadOleObject(lpContainerLine); + + fMustActivate = TRUE; // we should activate this object + } + + /***************************************************************** + ** OLE2NOTE: now we will try to change the display if + ** necessary. + *****************************************************************/ + + if (lpContainerLine->m_lpOleObj && + ct.dvAspect != lpContainerLine->m_dwDrawAspect) { + /* user has selected to change display aspect between icon + ** aspect and content aspect. + ** + ** OLE2NOTE: if we got here because the server was not + ** registered, then we will NOT delete the object's + ** original display aspect. because we do not have the + ** original server, we can NEVER get it back. this is a + ** safety precaution. + */ + + hrErr = OleStdSwitchDisplayAspect( + lpContainerLine->m_lpOleObj, + &lpContainerLine->m_dwDrawAspect, + ct.dvAspect, + ct.hMetaPict, + !fServerNotRegistered, /* fDeleteOldAspect */ + TRUE, /* fSetupViewAdvise */ + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + (BOOL FAR*)&fMustRun + ); + + if (hrErr == NOERROR) + fDisplayChanged = TRUE; + +#if defined( INPLACE_CNTR ) + ContainerDoc_UpdateInPlaceObjectRects( + lpContainerLine->m_lpDoc, nIndex); +#endif + + } else if (ct.dvAspect == DVASPECT_ICON && ct.fObjectsIconChanged) { + hrErr = OleStdSetIconInCache( + lpContainerLine->m_lpOleObj, + ct.hMetaPict + ); + + if (hrErr == NOERROR) + fDisplayChanged = TRUE; + } + + /* we deliberately run the object so that the update won't shut + ** the server down. + */ + if (fMustActivate || fMustRun) { + + /* if we force the object to run, then shut it down after + ** the update. do NOT force the object to close if we + ** want to activate the object or if the object was + ** already running. + */ + if (!fMustActivate && !OleIsRunning(lpContainerLine->m_lpOleObj)) + fMustClose = TRUE; // shutdown after update + + hrErr = ContainerLine_RunOleObject(lpContainerLine); + + if (fObjConverted && + FAILED(hrErr) && GetScode(hrErr)!=OLE_E_STATIC) { + + // ERROR: convert of the object failed. + // revert the storage to restore the original link. + // (OLE2NOTE: static object always return OLE_E_STATIC + // when told to run; this is NOT an error here. + // the OLE2 libraries have built in handlers for + // the static objects that do the conversion. + ContainerLine_UnloadOleObject( + lpContainerLine, OLECLOSE_NOSAVE); + lpContainerLine->m_lpStg->lpVtbl->Revert( + lpContainerLine->m_lpStg); + goto error; + + } else if (fObjConverted) { + FORMATETC FmtEtc; + DWORD dwNewConnection; + LPOLECACHE lpOleCache = (LPOLECACHE)OleStdQueryInterface + ((LPUNKNOWN)lpContainerLine->m_lpOleObj,&IID_IOleCache); + + /* OLE2NOTE: we need to force the converted object to + ** setup a new OLERENDER_DRAW cache. it is possible + ** that the new object needs to cache different data + ** in order to support drawing than the old object. + */ + if (lpOleCache && + lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) { + FmtEtc.cfFormat = 0; // whatever is needed for Draw + FmtEtc.ptd = NULL; + FmtEtc.dwAspect = DVASPECT_CONTENT; + FmtEtc.lindex = -1; + FmtEtc.tymed = TYMED_NULL; + + OLEDBG_BEGIN2("IOleCache::Cache called\r\n") + hrErr = lpOleCache->lpVtbl->Cache( + lpOleCache, + (LPFORMATETC)&FmtEtc, + ADVF_PRIMEFIRST, + (LPDWORD)&dwNewConnection + ); + OLEDBG_END2 +#if defined( _DEBUG ) + if (! SUCCEEDED(hrErr)) + OleDbgOutHResult("IOleCache::Cache returned", hrErr); +#endif + OleStdRelease((LPUNKNOWN)lpOleCache); + } + + // Close and force object to save; this will commit the stg + ContainerLine_CloseOleObject( + lpContainerLine, OLECLOSE_SAVEIFDIRTY); + fMustClose = FALSE; // we already closed the object + } + if (fMustClose) + ContainerLine_CloseOleObject(lpContainerLine,OLECLOSE_NOSAVE); + } + + if (fDisplayChanged) { + /* the Object's display was changed, force a repaint of + ** the line. note the extents of the object may have + ** changed. + */ + ContainerLine_UpdateExtent(lpContainerLine, NULL); + LineList_ForceLineRedraw(lpLL, nIndex, TRUE); + } + + if (fDisplayChanged || fObjConverted) { + /* mark ContainerDoc as now dirty. if display changed, then + ** the extents of the object may have changed. + */ + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fDisplayChanged); + } + + if (fMustActivate) { + ContainerLine_DoVerb( + lpContainerLine, OLEIVERB_PRIMARY, NULL, FALSE,FALSE); + } + } + + + if (ct.lpszUserType) + OleStdFreeString(ct.lpszUserType, NULL); + + if (ct.lpszDefLabel) + OleStdFreeString(ct.lpszDefLabel, NULL); + + if (ct.hMetaPict) + OleUIMetafilePictIconFree(ct.hMetaPict); // clean up metafile + + SetCursor(hPrevCursor); // restore original cursor + + return; + +error: + if (ct.lpszUserType) + OleStdFreeString(ct.lpszUserType, NULL); + + if (ct.hMetaPict) + OleUIMetafilePictIconFree(ct.hMetaPict); // clean up metafile + + SetCursor(hPrevCursor); // restore original cursor + if (lpErrMsg) + OutlineApp_ErrorMessage(g_lpApp, lpErrMsg); + +} + + +/* ContainerDoc_CloseAllOleObjects +** ------------------------------- +** Close all OLE objects. This forces all OLE objects to transition +** from the running state to the loaded state. +** +** Returns TRUE if all objects closed successfully +** FALSE if any object could not be closed. +*/ +BOOL ContainerDoc_CloseAllOleObjects( + LPCONTAINERDOC lpContainerDoc, + DWORD dwSaveOption +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + BOOL fStatus = TRUE; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) + if (! ContainerLine_CloseOleObject( + (LPCONTAINERLINE)lpLine,dwSaveOption)) + fStatus = FALSE; + } + + return fStatus; +} + + +/* ContainerDoc_UnloadAllOleObjectsOfClass +** --------------------------------------- +** Unload all OLE objects of a particular class. this is necessary +** when a class level "ActivateAs" (aka. TreatAs) is setup. the user +** can do this with the Convert dialog. for the TreatAs to take +** effect, all objects of the class have to loaded and reloaded. +*/ +void ContainerDoc_UnloadAllOleObjectsOfClass( + LPCONTAINERDOC lpContainerDoc, + REFCLSID rClsid, + DWORD dwSaveOption +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + CLSID clsid; + HRESULT hrErr; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (! lpContainerLine->m_lpOleObj) + continue; // this object is NOT loaded + + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID( + lpContainerLine->m_lpOleObj, + (CLSID FAR*)&clsid + ); + if (hrErr == NOERROR && + ( IsEqualCLSID((CLSID FAR*)&clsid,rClsid) + || IsEqualCLSID(rClsid,&CLSID_NULL) ) ) { + ContainerLine_UnloadOleObject(lpContainerLine, dwSaveOption); + } + } + } +} + + +/* ContainerDoc_UpdateExtentOfAllOleObjects +** ---------------------------------------- +** Update the extents of any OLE object that is marked that its size +** may have changed. when an IAdviseSink::OnViewChange notification +** is received, the corresponding ContainerLine is marked +** (m_fDoGetExtent==TRUE) and a message (WM_U_UPDATEOBJECTEXTENT) is +** posted to the document indicating that there are dirty objects. +** when this message is received, this function is called. +*/ +void ContainerDoc_UpdateExtentOfAllOleObjects(LPCONTAINERDOC lpContainerDoc) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + BOOL fStatus = TRUE; +#if defined( INPLACE_CNTR ) + int nFirstUpdate = -1; +#endif + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lpContainerLine->m_fDoGetExtent) { + ContainerLine_UpdateExtent(lpContainerLine, NULL); +#if defined( INPLACE_CNTR ) + if (nFirstUpdate == -1) + nFirstUpdate = i; +#endif + } + } + } + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: after changing the extents of any line, we need to + ** update the PosRect of the In-Place active + ** objects (if any) that follow the first modified line. + */ + if (nFirstUpdate != -1) + ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, nFirstUpdate+1); +#endif +} + + +BOOL ContainerDoc_SaveToFile( + LPCONTAINERDOC lpContainerDoc, + LPCSTR lpszFileName, + UINT uFormat, + BOOL fRemember +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPSTORAGE lpDestStg; + BOOL fStatus; + BOOL fMustRelDestStg = FALSE; + HRESULT hrErr; +#if defined( OPTIONAL ) + FILETIME filetimeBeforeSave; +#endif + + if (fRemember) { + if (lpszFileName) { + fStatus = OutlineDoc_SetFileName( + lpOutlineDoc, (LPSTR)lpszFileName, NULL); + if (! fStatus) goto error; + } + + /* The ContainerDoc keeps its storage open at all times. it is not + ** necessary to reopen the file. + ** if SaveAs is pending, then lpNewStg is the new destination for + ** the save operation, else the existing storage is the dest. + */ + lpDestStg = (lpContainerDoc->m_lpNewStg ? + lpContainerDoc->m_lpNewStg : lpOleDoc->m_lpStg); + +#if defined( OPTIONAL ) + /* OLE2NOTE: an automatic link to an embedded object within the + ** same container document (that uses ItemMonikers) will + ** always be considered "out-of-date' by OLE. if a container + ** application REALLY wants to fix this it can do one of the + ** following: + ** 1. implement a new moniker better than ItemMonikers + ** that look into the objects storage to find the real last + ** change time (rather then defaulting to that of the outer + ** container file). + ** or 2. using item monikers it is possible to fix the case + ** where the container document is saved while the embedded + ** object is running but it will NOT fix the case when the + ** document is saved when the embedded object was only + ** loaded. the fix is to: + ** a. remember the time (T) before the save operation starts + ** b. call IRunningObjectTable::NoteChangeTime(lpDoc, T) + ** c. do the saving and commit the file + ** d. call StgSetTimes to reset the file time to T + ** e. remember time T in document structure and when the + ** root storage is finally released reset the file time + ** again to T (closing the file on DOS sets the time). + */ + CoFileTimeNow( &filetimeBeforeSave ); + if (lpOleDoc->m_dwRegROT != 0) { + LPRUNNINGOBJECTTABLE lprot; + + if (GetRunningObjectTable(0,&lprot) == NOERROR) + { + OleDbgOut2("IRunningObjectTable::NoteChangeTime called\r\n"); + lprot->lpVtbl->NoteChangeTime( + lprot, lpOleDoc->m_dwRegROT, &filetimeBeforeSave ); + lprot->lpVtbl->Release(lprot); + } + } +#endif + } else { + if (! lpszFileName) + goto error; + + /* OLE2NOTE: since we are preforming a SaveCopyAs operation, we + ** do not need to have the DocFile open in STGM_TRANSACTED mode. + ** there is less overhead to use STGM_DIRECT mode. + */ + hrErr = StgCreateDocfileA( + lpszFileName, + STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_CREATE, + 0, + &lpDestStg + ); + + OleDbgAssertSz(hrErr == NOERROR, "Could not create Docfile"); + if (hrErr != NOERROR) { + OleDbgOutHResult("StgCreateDocfile returned", hrErr); + goto error; + } + fMustRelDestStg = TRUE; + } + + /* OLE2NOTE: we must be sure to write our class ID into our + ** storage. this information is used by OLE to determine the + ** class of the data stored in our storage. Even for top + ** "file-level" objects this information should be written to + ** the file. + */ + hrErr = WriteClassStg(lpDestStg, &CLSID_APP); + if(hrErr != NOERROR) goto error; + + fStatus = OutlineDoc_SaveSelToStg( + lpOutlineDoc, + NULL, // save all lines + uFormat, + lpDestStg, + FALSE, // fSameAsLoad + TRUE // remember this stg + ); + + if (fStatus) + fStatus = OleStdCommitStorage(lpDestStg); + + if (fRemember) { + /* if SaveAs was pending, then release the old storage and remember + ** the new storage as the active current storage. all data from + ** the old storage has been copied into the new storage. + */ + if (lpContainerDoc->m_lpNewStg) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg); // free old stg + lpOleDoc->m_lpStg = lpContainerDoc->m_lpNewStg; // save new stg + lpContainerDoc->m_lpNewStg = NULL; + } + if (! fStatus) goto error; + + OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE); + +#if defined( OPTIONAL ) + /* reset time of file on disk to be time just prior to saving. + ** NOTE: it would also be necessary to remember + ** filetimeBeforeSave in the document structure and when the + ** root storage is finally released reset the file time + ** again to this value (closing the file on DOS sets the time). + */ + StgSetTimesA(lpOutlineDoc->m_szFileName, + NULL, NULL, &filetimeBeforeSave); +#endif + } + + if (fMustRelDestStg) + OleStdRelease((LPUNKNOWN)lpDestStg); + return TRUE; + +error: + if (fMustRelDestStg) + OleStdRelease((LPUNKNOWN)lpDestStg); + OutlineApp_ErrorMessage(g_lpApp, ErrMsgSaving); + return FALSE; +} + + +/* ContainerDoc_ContainerLineDoVerbCommand +** --------------------------------------- +** Execute a verb of the OLE object in the current focus line. +*/ +void ContainerDoc_ContainerLineDoVerbCommand( + LPCONTAINERDOC lpContainerDoc, + LONG iVerb +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int nIndex = LineList_GetFocusLineIndex(lpLL); + LPLINE lpLine = LineList_GetLine(lpLL, nIndex); + HCURSOR hPrevCursor; + + if (! lpLine || (Line_GetLineType(lpLine) != CONTAINERLINETYPE) ) return; + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + ContainerLine_DoVerb((LPCONTAINERLINE) lpLine, iVerb, NULL, TRUE, TRUE); + + SetCursor(hPrevCursor); // restore original cursor +} + + +/* ContainerDoc_GetNextStgName +** --------------------------- +** Generate the next unused name for a sub-storage to be used by an +** OLE object. The ContainerDoc keeps a counter. The storages for +** OLE objects are simply numbered (eg. Obj 0, Obj 1). A "long" +** integer worth of storage names should be more than enough than we +** will ever need. +** +** NOTE: when an OLE object is transfered via drag/drop or the +** clipboard, we attempt to keep the currently assigned name for the +** object (if not currently in use). thus it is possible that an +** object with a the next default name (eg. "Obj 5") already exists +** in the current document if an object with this name was privously +** transfered (pasted or dropped). we therefore loop until we find +** the next lowest unused name. +*/ +void ContainerDoc_GetNextStgName( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszStgName, + int nLen +) +{ + wsprintf(lpszStgName, "%s %ld", + (LPSTR)DEFOBJNAMEPREFIX, + ++(lpContainerDoc->m_nNextObjNo) + ); + + while (ContainerDoc_IsStgNameUsed(lpContainerDoc, lpszStgName) == TRUE) { + wsprintf(lpszStgName, "%s %ld", + (LPSTR)DEFOBJNAMEPREFIX, + ++(lpContainerDoc->m_nNextObjNo) + ); + } +} + + +/* ContainerDoc_IsStgNameUsed +** -------------------------- +** Check if a given StgName is already in use. +*/ +BOOL ContainerDoc_IsStgNameUsed( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszStgName +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + if (lstrcmp(lpszStgName, + ((LPCONTAINERLINE)lpLine)->m_szStgName) == 0) { + return TRUE; // Match FOUND! + } + } + } + return FALSE; // if we get here, then NO match was found. +} + + +LPSTORAGE ContainerDoc_GetStg(LPCONTAINERDOC lpContainerDoc) +{ + return ((LPOLEDOC)lpContainerDoc)->m_lpStg; +} + + +/* ContainerDoc_GetSingleOleObject +** ------------------------------- +** If the entire document contains a single OLE object, then +** return the desired interface of the object. +** +** Returns NULL if there is are multiple lines in the document or +** the single line is not a ContainerLine. +*/ +LPUNKNOWN ContainerDoc_GetSingleOleObject( + LPCONTAINERDOC lpContainerDoc, + REFIID riid, + LPCONTAINERLINE FAR* lplpContainerLine +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LPLINE lpLine; + LPUNKNOWN lpObj = NULL; + + if (lplpContainerLine) + *lplpContainerLine = NULL; + + if (lpLL->m_nNumLines != 1) + return NULL; // doc does NOT contain a single line + + lpLine=LineList_GetLine(lpLL, 0); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) + lpObj = ContainerLine_GetOleObject((LPCONTAINERLINE)lpLine, riid); + + if (lplpContainerLine) + *lplpContainerLine = (LPCONTAINERLINE)lpLine; + + return lpObj; +} + + +/* ContainerDoc_IsSelAnOleObject +** ----------------------------- +** Check if the selection is a single selection of an OLE object. +** if so, then optionally return the desired interface of the object +** and/or index of the ContainerLine containing the OLE object. +** +** Returns FALSE if there is a multiple selection or the single +** selection is not a ContainerLine. +*/ +BOOL ContainerDoc_IsSelAnOleObject( + LPCONTAINERDOC lpContainerDoc, + REFIID riid, + LPUNKNOWN FAR* lplpvObj, + int FAR* lpnIndex, + LPCONTAINERLINE FAR* lplpContainerLine +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LINERANGE lrSel; + int nNumSel; + LPLINE lpLine; + + if (lplpvObj) *lplpvObj = NULL; + if (lpnIndex) *lpnIndex = -1; + if (lplpContainerLine) *lplpContainerLine = NULL; + + nNumSel = LineList_GetSel(lpLL, (LPLINERANGE)&lrSel); + if (nNumSel != 1) + return FALSE; // selection is not a single line + + lpLine = LineList_GetLine(lpLL, lrSel.m_nStartLine); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + if (lpnIndex) + *lpnIndex = lrSel.m_nStartLine; + if (lplpContainerLine) + *lplpContainerLine = (LPCONTAINERLINE)lpLine; + if (riid) { + *lplpvObj = ContainerLine_GetOleObject( + (LPCONTAINERLINE)lpLine, + riid + ); + } + + return (*lplpvObj ? TRUE : FALSE); + } + + return FALSE; +} + + +/************************************************************************* +** ContainerDoc::IOleUILinkContainer interface implementation +*************************************************************************/ + +STDMETHODIMP CntrDoc_LinkCont_QueryInterface( + LPOLEUILINKCONTAINER lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC) + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) CntrDoc_LinkCont_AddRef(LPOLEUILINKCONTAINER lpThis) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC) + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + + OleDbgAddRefMethod(lpThis, "IOleUILinkContainer"); + + return OleDoc_AddRef(lpOleDoc); +} + + +STDMETHODIMP_(ULONG) CntrDoc_LinkCont_Release(LPOLEUILINKCONTAINER lpThis) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC) + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + + OleDbgReleaseMethod(lpThis, "IOleUILinkContainer"); + + return OleDoc_Release(lpOleDoc); +} + + +STDMETHODIMP_(DWORD) CntrDoc_LinkCont_GetNextLink( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = NULL; + + OLEDBG_BEGIN2("CntrDoc_LinkCont_GetNextLink\r\n") + + lpContainerLine = ContainerDoc_GetNextLink( + lpContainerDoc, + (LPCONTAINERLINE)dwLink + ); + + OLEDBG_END2 + return (DWORD)lpContainerLine; +} + + +STDMETHODIMP CntrDoc_LinkCont_SetLinkUpdateOptions( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + DWORD dwUpdateOpt +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + SCODE sc = S_OK; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkUpdateOptions\r\n") + + OleDbgAssert(lpContainerLine); + + if (! lpOleLink) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleLink::SetUpdateOptions called\r\n") + hrErr = lpOleLink->lpVtbl->SetUpdateOptions( + lpOleLink, + dwUpdateOpt + ); + OLEDBG_END2 + + // save new link type update option + lpContainerLine->m_dwLinkType = dwUpdateOpt; + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleLink::SetUpdateOptions returned", hrErr); + sc = GetScode(hrErr); + goto error; + } + + OLEDBG_END2 + return ResultFromScode(sc); + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP CntrDoc_LinkCont_GetLinkUpdateOptions( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + DWORD FAR* lpdwUpdateOpt +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + SCODE sc = S_OK; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkUpdateOptions\r\n") + + OleDbgAssert(lpContainerLine); + + if (! lpOleLink) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n") + hrErr = lpOleLink->lpVtbl->GetUpdateOptions( + lpOleLink, + lpdwUpdateOpt + ); + OLEDBG_END2 + + // reset saved link type to ensure it is correct + lpContainerLine->m_dwLinkType = *lpdwUpdateOpt; + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleLink::GetUpdateOptions returned", hrErr); + sc = GetScode(hrErr); + goto error; + } + + OLEDBG_END2 + return ResultFromScode(sc); + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP CntrDoc_LinkCont_SetLinkSource( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + LPSTR lpszDisplayName, + ULONG lenFileName, + ULONG FAR* lpchEaten, + BOOL fValidateSource +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + SCODE sc = S_OK; + HRESULT hrErr; + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + LPBC lpbc = NULL; + LPMONIKER lpmk = NULL; + LPOLEOBJECT lpLinkSrcOleObj = NULL; + CLSID clsid = CLSID_NULL; + CLSID clsidOld = CLSID_NULL; + + + OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkSource\r\n") + + OleDbgAssert(lpContainerLine); + + lpContainerLine->m_fLinkUnavailable = TRUE; + + if (fValidateSource) { + + /* OLE2NOTE: validate the link source by parsing the string + ** into a Moniker. if this is successful, then the string is + ** valid. + */ + hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); // ERROR: OOM + goto cleanup; + } + + // Get class of orignial link source if it is available + if (lpContainerLine->m_lpOleObj) { + + OLEDBG_BEGIN2("IOleObject::GetUserClassID called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID( + lpContainerLine->m_lpOleObj, (CLSID FAR*)&clsidOld); + OLEDBG_END2 + if (hrErr != NOERROR) clsidOld = CLSID_NULL; + } + + hrErr = OleStdMkParseDisplayName( + &clsidOld,lpbc,lpszDisplayName,lpchEaten,(LPMONIKER FAR*)&lpmk); + + if (hrErr != NOERROR) { + sc = GetScode(hrErr); // ERROR in parsing moniker! + goto cleanup; + } + /* OLE2NOTE: the link source was validated; it successfully + ** parsed into a Moniker. we can set the source of the link + ** directly with this Moniker. if we want the link to be + ** able to know the correct class for the new link source, + ** we must bind to the moniker and get the CLSID. if we do + ** not do this then methods like IOleObject::GetUserType + ** will return nothing (NULL strings). + */ + + hrErr = lpmk->lpVtbl->BindToObject( + lpmk,lpbc,NULL,&IID_IOleObject,(LPVOID FAR*)&lpLinkSrcOleObj); + if (hrErr == NOERROR) { + OLEDBG_BEGIN2("IOleObject::GetUserClassID called\r\n") + hrErr = lpLinkSrcOleObj->lpVtbl->GetUserClassID( + lpLinkSrcOleObj, (CLSID FAR*)&clsid); + OLEDBG_END2 + lpContainerLine->m_fLinkUnavailable = FALSE; + + /* get the short user type name of the link because it may + ** have changed. we cache this name and must update our + ** cache. this name is used all the time when we have to + ** build the object verb menu. we cache this information + ** to make it quicker to build the verb menu. + */ + if (lpContainerLine->m_lpszShortType) { + OleStdFree(lpContainerLine->m_lpszShortType); + lpContainerLine->m_lpszShortType = NULL; + } + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + + CallIOleObjectGetUserTypeA( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_SHORT, + (LPSTR FAR*)&lpContainerLine->m_lpszShortType + ); + + OLEDBG_END2 + } + else + lpContainerLine->m_fLinkUnavailable = TRUE; + } + else { + LPMONIKER lpmkFile = NULL; + LPMONIKER lpmkItem = NULL; + char szDelim[2]; + LPSTR lpszName; + + szDelim[0] = lpszDisplayName[(int)lenFileName]; + szDelim[1] = '\0'; + lpszDisplayName[(int)lenFileName] = '\0'; + + OLEDBG_BEGIN2("CreateFileMoniker called\r\n") + + CreateFileMonikerA(lpszDisplayName, (LPMONIKER FAR*)&lpmkFile); + + OLEDBG_END2 + + lpszDisplayName[(int)lenFileName] = szDelim[0]; + + if (!lpmkFile) + goto cleanup; + + if (lstrlen(lpszDisplayName) > (int)lenFileName) { // have item name + lpszName = lpszDisplayName + lenFileName + 1; + + OLEDBG_BEGIN2("CreateItemMoniker called\r\n") + + CreateItemMonikerA( + szDelim, lpszName, (LPMONIKER FAR*)&lpmkItem); + + OLEDBG_END2 + + if (!lpmkItem) { + OleStdRelease((LPUNKNOWN)lpmkFile); + goto cleanup; + } + + OLEDBG_BEGIN2("CreateGenericComposite called\r\n") + CreateGenericComposite(lpmkFile, lpmkItem, (LPMONIKER FAR*)&lpmk); + OLEDBG_END2 + + if (lpmkFile) + OleStdRelease((LPUNKNOWN)lpmkFile); + if (lpmkItem) + OleStdRelease((LPUNKNOWN)lpmkItem); + + if (!lpmk) + goto cleanup; + } + else + lpmk = lpmkFile; + } + + if (! lpOleLink) { + OleDbgAssert(lpOleLink != NULL); + sc = E_FAIL; + goto cleanup; + } + + if (lpmk) { + + OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n") + hrErr = lpOleLink->lpVtbl->SetSourceMoniker( + lpOleLink, lpmk, (REFCLSID)&clsid); + OLEDBG_END2 + + if (FAILED(GetScode(hrErr))) { + OleDbgOutHResult("IOleLink::SetSourceMoniker returned",hrErr); + sc = GetScode(hrErr); + goto cleanup; + } + + /* OLE2NOTE: above we forced the link source moniker to bind. + ** because we deliberately hold on to the bind context + ** (lpbc) the link source object will not shut down. during + ** the call to IOleLink::SetSourceMoniker, the link will + ** connect to the running link source (the link internally + ** calls BindIfRunning). it is important to initially allow + ** the link to bind to the running object so that it can get + ** an update of the presentation for its cache. we do not + ** want the connection from our link to the link source be + ** the only reason the link source stays running. thus we + ** deliberately for the link to release (unbind) the source + ** object, we then release the bind context, and then we + ** allow the link to rebind to the link source if it is + ** running anyway. + */ + if (lpbc && lpmk->lpVtbl->IsRunning(lpmk,lpbc,NULL,NULL) == NOERROR) { + + OLEDBG_BEGIN2("IOleLink::Update called\r\n") + hrErr = lpOleLink->lpVtbl->Update(lpOleLink, NULL); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (FAILED(GetScode(hrErr))) + OleDbgOutHResult("IOleLink::Update returned",hrErr); +#endif + + OLEDBG_BEGIN2("IOleLink::UnbindSource called\r\n") + hrErr = lpOleLink->lpVtbl->UnbindSource(lpOleLink); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (FAILED(GetScode(hrErr))) + OleDbgOutHResult("IOleLink::UnbindSource returned",hrErr); +#endif + + if (lpLinkSrcOleObj) { + OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj); + lpLinkSrcOleObj = NULL; + } + + if (lpbc) { + OleStdRelease((LPUNKNOWN)lpbc); + lpbc = NULL; + } + + OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n") + hrErr = lpOleLink->lpVtbl->BindIfRunning(lpOleLink); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (FAILED(GetScode(hrErr))) + OleDbgOutHResult("IOleLink::BindIfRunning returned",hrErr); +#endif + } + } else { + /* OLE2NOTE: the link source was NOT validated; it was NOT + ** successfully parsed into a Moniker. we can only set the + ** display name string as the source of the link. this link + ** is not able to bind. + */ + OLEDBG_BEGIN2("IOleLink::SetSourceDisplayName called\r\n") + + hrErr = CallIOleLinkSetSourceDisplayNameA( + lpOleLink, lpszDisplayName); + + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleLink::SetSourceDisplayName returned",hrErr); + sc = GetScode(hrErr); + goto cleanup; + } + } + +cleanup: + if (lpLinkSrcOleObj) + OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj); + if (lpmk) + OleStdRelease((LPUNKNOWN)lpmk); + if (lpbc) + OleStdRelease((LPUNKNOWN)lpbc); + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP CntrDoc_LinkCont_GetLinkSource( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + LPSTR FAR* lplpszDisplayName, + ULONG FAR* lplenFileName, + LPSTR FAR* lplpszFullLinkType, + LPSTR FAR* lplpszShortLinkType, + BOOL FAR* lpfSourceAvailable, + BOOL FAR* lpfIsSelected +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + LPOLEOBJECT lpOleObj = NULL; + LPMONIKER lpmk = NULL; + LPMONIKER lpmkFirst = NULL; + LPBC lpbc = NULL; + SCODE sc = S_OK; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkSource\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpszDisplayName = NULL; + *lplpszFullLinkType = NULL; + *lplpszShortLinkType= NULL; + *lplenFileName = 0; + *lpfSourceAvailable = !lpContainerLine->m_fLinkUnavailable; + + OleDbgAssert(lpContainerLine); + + if (! lpOleLink) { + OLEDBG_END2 + return ResultFromScode(E_FAIL); + } + + OLEDBG_BEGIN2("IOleLink::GetSourceMoniker called\r\n") + hrErr = lpOleLink->lpVtbl->GetSourceMoniker( + lpOleLink, + (LPMONIKER FAR*)&lpmk + ); + OLEDBG_END2 + + if (hrErr == NOERROR) { + /* OLE2NOTE: the link has the Moniker form of the link source; + ** this is therefore a validated link source. if the first + ** part of the Moniker is a FileMoniker, then we need to + ** return the length of the filename string. we need to + ** return the ProgID associated with the link source as the + ** "lpszShortLinkType". we need to return the + ** FullUserTypeName associated with the link source as the + ** "lpszFullLinkType". + */ + + lpOleObj = (LPOLEOBJECT)OleStdQueryInterface( + (LPUNKNOWN)lpOleLink, &IID_IOleObject); + if (lpOleObj) { + CallIOleObjectGetUserTypeA( + lpOleObj, + USERCLASSTYPE_FULL, + lplpszFullLinkType + ); + + CallIOleObjectGetUserTypeA( + lpOleObj, + USERCLASSTYPE_SHORT, + lplpszShortLinkType + ); + + OleStdRelease((LPUNKNOWN)lpOleObj); + } + *lplenFileName = OleStdGetLenFilePrefixOfMoniker(lpmk); + lpmk->lpVtbl->Release(lpmk); + } + + OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n") + + hrErr = CallIOleLinkGetSourceDisplayNameA( + lpOleLink, + lplpszDisplayName + ); + + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleLink::GetSourceDisplayName returned", hrErr); + OLEDBG_END2 + return hrErr; + } + + OLEDBG_END2 + + if (lpfIsSelected) + *lpfIsSelected = Line_IsSelected((LPLINE)lpContainerLine); + + return NOERROR; +} + + +STDMETHODIMP CntrDoc_LinkCont_OpenLinkSource( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + SCODE sc = S_OK; + + OLEDBG_BEGIN2("CntrDoc_LinkCont_OpenLinkSource\r\n") + + OleDbgAssert(lpContainerLine); + + if (! ContainerLine_DoVerb( + lpContainerLine, OLEIVERB_SHOW, NULL, TRUE, FALSE)) { + sc = E_FAIL; + } + + lpContainerLine->m_fLinkUnavailable = (sc != S_OK); + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP CntrDoc_LinkCont_UpdateLink( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + BOOL fErrorMessage, + BOOL fErrorAction // ignore if fErrorMessage + // is FALSE +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + SCODE sc = S_OK; + /* Default to update of the link */ + HRESULT hrErr = S_FALSE; + + OLEDBG_BEGIN2("CntrDoc_LinkCont_UpdateLink\r\n") + + OleDbgAssert(lpContainerLine); + + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + if (!fErrorMessage) { + OLEDBG_BEGIN2("IOleObject::IsUpToDate called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->IsUpToDate( + lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + } + + if (hrErr != NOERROR) { + OLEDBG_BEGIN2("IOleObject::Update called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Update( + lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + } + + /* OLE2NOTE: If IOleObject::Update on the Link object returned + ** OLE_E_CLASSDIFF because the link source is no longer + ** the expected class, then the link should be re-created with + ** the new link source. thus the link will be updated with the + ** new link source. + */ + if (GetScode(hrErr) == OLE_E_CLASSDIFF) + hrErr = ContainerLine_ReCreateLinkBecauseClassDiff(lpContainerLine); + + lpContainerLine->m_fLinkUnavailable = (hrErr != NOERROR); + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleObject::Update returned", hrErr); + sc = GetScode(hrErr); + if (fErrorMessage) { + ContainerLine_ProcessOleRunError( + lpContainerLine,hrErr,fErrorAction,FALSE/*fMenuInvoked*/); + } + } + /* OLE2NOTE: if the update of the object requires us to update our + ** display, then we will automatically be sent a OnViewChange + ** advise. thus we do not need to take any action here to force + ** a repaint. + */ + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +/* CntrDoc_LinkCont_CancelLink +** --------------------------- +** Convert the link to a static picture. +** +** OLE2NOTE: OleCreateStaticFromData can be used to create a static +** picture object. +*/ +STDMETHODIMP CntrDoc_LinkCont_CancelLink( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink +) +{ + LPCONTAINERDOC lpContainerDoc = + ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc; + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink; + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + LPLINE lpLine = NULL; + HDC hDC; + int nTab = 0; + char szStgName[CWCSTORAGENAME]; + LPCONTAINERLINE lpNewContainerLine = NULL; + LPDATAOBJECT lpSrcDataObj; + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + + OLEDBG_BEGIN2("CntrDoc_LinkCont_CancelLink\r\n") + + /* we will first break the connection of the link to its source. */ + if (lpOleLink) { + lpContainerLine->m_dwLinkType = 0; + OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n") + lpOleLink->lpVtbl->SetSourceMoniker( + lpOleLink, NULL, (REFCLSID)&CLSID_NULL); + OLEDBG_END2 + } + + lpSrcDataObj = (LPDATAOBJECT)ContainerLine_GetOleObject( + lpContainerLine,&IID_IDataObject); + if (! lpSrcDataObj) + goto error; + + ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, sizeof(szStgName)); + nTab = Line_GetTabLevel((LPLINE)lpContainerLine); + hDC = LineList_GetDC(lpLL); + + lpNewContainerLine = ContainerLine_CreateFromData( + hDC, + nTab, + lpContainerDoc, + lpSrcDataObj, + OLECREATEFROMDATA_STATIC, + 0, /* no special cfFormat required */ + (lpContainerLine->m_dwDrawAspect == DVASPECT_ICON), + NULL, /* hMetaPict */ + szStgName + ); + LineList_ReleaseDC(lpLL, hDC); + + OleStdRelease((LPUNKNOWN)lpSrcDataObj); + + if (! lpNewContainerLine) + goto error; + + OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, FALSE); + + LineList_ReplaceLine(lpLL, (LPLINE)lpNewContainerLine, nIndex); + + OLEDBG_END2 + return ResultFromScode(NOERROR); + +error: + OutlineApp_ErrorMessage(g_lpApp, "Could not break the link."); + OLEDBG_END2 + return ResultFromScode(E_FAIL); +} diff --git a/private/oleutest/letest/outline/cntrinpl.c b/private/oleutest/letest/outline/cntrinpl.c new file mode 100644 index 000000000..3d8dcd8a8 --- /dev/null +++ b/private/oleutest/letest/outline/cntrinpl.c @@ -0,0 +1,1940 @@ +/************************************************************************* +** +** OLE 2 Container Sample Code +** +** cntrinpl.c +** +** This file contains all interfaces, methods and related support +** functions for an In-Place Container application (aka. Visual +** Editing). The in-place Container application includes the following +** implementation objects: +** +** ContainerApp Object +** exposed interfaces: +** IOleInPlaceFrame +** +** ContainerDoc Object +** support functions only +** (ICntrOtl is an SDI app; it doesn't support a Doc level IOleUIWindow) +** +** ContainerLin Object +** exposed interfaces: +** IOleInPlaceSite +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" +#if defined( USE_STATUSBAR ) +#include "status.h" +#endif + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; +extern BOOL g_fInsideOutContainer; +extern RECT g_rectNull; + +/************************************************************************* +** ContainerApp::IOleInPlaceFrame interface implementation +*************************************************************************/ + +// IOleInPlaceFrame::QueryInterface +STDMETHODIMP CntrApp_IPFrame_QueryInterface( + LPOLEINPLACEFRAME lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + SCODE sc = E_NOINTERFACE; + LPCONTAINERAPP lpContainerApp = + ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp; + + /* The object should not be able to access the other interfaces + ** of our App object by doing QI on this interface. + */ + *lplpvObj = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IOleWindow) || + IsEqualIID(riid, &IID_IOleInPlaceUIWindow) || + IsEqualIID(riid, &IID_IOleInPlaceFrame)) { + OleDbgOut4("CntrApp_IPFrame_QueryInterface: IOleInPlaceFrame* RETURNED\r\n"); + *lplpvObj = (LPVOID) &lpContainerApp->m_OleInPlaceFrame; + OleApp_AddRef((LPOLEAPP)lpContainerApp); + sc = S_OK; + } + + OleDbgQueryInterfaceMethod(*lplpvObj); + + return ResultFromScode(sc); +} + + +// IOleInPlaceFrame::AddRef +STDMETHODIMP_(ULONG) CntrApp_IPFrame_AddRef(LPOLEINPLACEFRAME lpThis) +{ + OleDbgAddRefMethod(lpThis, "IOleInPlaceFrame"); + + return OleApp_AddRef((LPOLEAPP)g_lpApp); +} + + +// IOleInPlaceFrame::Release +STDMETHODIMP_(ULONG) CntrApp_IPFrame_Release(LPOLEINPLACEFRAME lpThis) +{ + OleDbgReleaseMethod(lpThis, "IOleInPlaceFrame"); + + return OleApp_Release((LPOLEAPP)g_lpApp); +} + + +// IOleInPlaceFrame::GetWindow +STDMETHODIMP CntrApp_IPFrame_GetWindow( + LPOLEINPLACEFRAME lpThis, + HWND FAR* lphwnd +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + + OLEDBG_BEGIN2("CntrApp_IPFrame_GetWindow\r\n") + *lphwnd = lpOutlineApp->m_hWndApp; + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceFrame::ContextSensitiveHelp +STDMETHODIMP CntrApp_IPFrame_ContextSensitiveHelp( + LPOLEINPLACEFRAME lpThis, + BOOL fEnterMode +) +{ + LPCONTAINERAPP lpContainerApp = + ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp; + + OleDbgOut("CntrApp_IPFrame_ContextSensitiveHelp\r\n"); + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** This method is called when F1 is pressed when a menu item is + ** selected. We set the frame's m_fMenuMode flag here. later, + ** in WM_COMMAND processing in the AppWndProc, if this flag is + ** set then the command is NOT executed and help is given + ** instead. + */ + lpContainerApp->m_fMenuHelpMode = fEnterMode; + + return NOERROR; +} + + +// IOleInPlaceFrame::GetBorder +STDMETHODIMP CntrApp_IPFrame_GetBorder( + LPOLEINPLACEFRAME lpThis, + LPRECT lprectBorder +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + + OLEDBG_BEGIN2("CntrApp_IPFrame_GetBorder\r\n") + + OutlineApp_GetFrameRect(lpOutlineApp, lprectBorder); + + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceFrame::RequestBorderSpace +STDMETHODIMP CntrApp_IPFrame_RequestBorderSpace( + LPOLEINPLACEFRAME lpThis, + LPCBORDERWIDTHS lpWidths +) +{ +#if defined( _DEBUG ) + OleDbgOut2("CntrApp_IPFrame_RequestBorderSpace\r\n"); + + { + /* FOR DEBUGING PURPOSES ONLY -- we will fail to allow to an + ** object to get any frame border space for frame tools if + ** our own frame tools are poped up in the tool pallet. this + ** is NOT recommended UI behavior but it allows us to test + ** in the condition when the frame does not give border + ** space for the object. an object in this situation must + ** then either popup its tools in a floating pallet, do + ** without the tools, or fail to in-place activate. + */ + LPCONTAINERAPP lpContainerApp = + ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp; + LPFRAMETOOLS lpft = OutlineApp_GetFrameTools( + (LPOUTLINEAPP)lpContainerApp); + + if (lpft->m_ButtonBar.m_nState == BARSTATE_POPUP && + lpft->m_FormulaBar.m_nState == BARSTATE_POPUP) { + OleDbgOut3( + "CntrApp_IPFrame_RequestBorderSpace: allow NO SPACE\r\n"); + return ResultFromScode(E_FAIL); + } + } +#endif // _DEBUG + + /* OLE2NOTE: we allow the object to have as much border space as it + ** wants. + */ + return NOERROR; +} + + +// IOleInPlaceFrame::SetBorderSpace +STDMETHODIMP CntrApp_IPFrame_SetBorderSpace( + LPOLEINPLACEFRAME lpThis, + LPCBORDERWIDTHS lpWidths +) +{ + LPCONTAINERAPP lpContainerApp = + ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp; + OLEDBG_BEGIN2("CntrApp_IPFrame_SetBorderSpace\r\n") + + /* OLE2NOTE: this fMustResizeClientArea flag is used as part of our + ** defensive programming for frame window resizing. when the + ** frame window is resized,IOleInPlaceActiveObject::ResizeBorder + ** is called the object should normally call back to renegotiate + ** for frame-level tools space. if SetBorderSpace is called then + ** our client area windows are properly resized. if the in-place + ** active object does NOT call SetBorderSpace, then the + ** container must take care to resize its client area windows + ** itself (see ContainerDoc_FrameWindowResized) + */ + if (lpContainerApp->m_fMustResizeClientArea) + lpContainerApp->m_fMustResizeClientArea = FALSE; + + if (lpWidths == NULL) { + + /* OLE2NOTE: IOleInPlaceSite::SetBorderSpace(NULL) is called + ** when the in-place active object does NOT want any tool + ** space. in this situation the in-place container should + ** put up its tools. + */ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp; + LPCONTAINERDOC lpContainerDoc; + + lpContainerDoc =(LPCONTAINERDOC)OutlineApp_GetActiveDoc(lpOutlineApp); + ContainerDoc_AddFrameLevelTools(lpContainerDoc); + } else { + + // OLE2NOTE: you could do validation of borderwidths here +#if defined( _DEBUG ) + /* FOR DEBUGING PURPOSES ONLY -- we will fail to allow to an + ** object to get any frame border space for frame tools if + ** our own frame tools are poped up in the tool pallet. this + ** is NOT recommended UI behavior but it allows us to test + ** in the condition when the frame does not give border + ** space for the object. an object in this situation must + ** then either popup its tools in a floating pallet, do + ** without the tools, or fail to in-place activate. + */ + LPFRAMETOOLS lpft = OutlineApp_GetFrameTools( + (LPOUTLINEAPP)lpContainerApp); + + if ((lpft->m_ButtonBar.m_nState == BARSTATE_POPUP && + lpft->m_FormulaBar.m_nState == BARSTATE_POPUP) && + (lpWidths->top || lpWidths->bottom || + lpWidths->left || lpWidths->right) ) { + OleDbgOut3("CntrApp_IPFrame_SetBorderSpace: allow NO SPACE\r\n"); + OLEDBG_END2 + + OutlineApp_SetBorderSpace( + (LPOUTLINEAPP) lpContainerApp, + (LPBORDERWIDTHS)&g_rectNull + ); + OLEDBG_END2 + return ResultFromScode(E_FAIL); + } +#endif // _DEBUG + + OutlineApp_SetBorderSpace( + (LPOUTLINEAPP) lpContainerApp, + (LPBORDERWIDTHS)lpWidths + ); + } + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceFrame::SetActiveObject +STDMETHODIMP CntrApp_IPFrame_SetActiveObjectA( + LPOLEINPLACEFRAME lpThis, + LPOLEINPLACEACTIVEOBJECT lpActiveObject, + LPCSTR lpszObjName +) +{ + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + OLEDBG_BEGIN2("CntrApp_IPFrame_SetActiveObject\r\n") + + lpContainerApp->m_hWndUIActiveObj = NULL; + + if (lpContainerApp->m_lpIPActiveObj) + lpContainerApp->m_lpIPActiveObj->lpVtbl->Release(lpContainerApp->m_lpIPActiveObj); + + if ((lpContainerApp->m_lpIPActiveObj = lpActiveObject) != NULL) { + lpContainerApp->m_lpIPActiveObj->lpVtbl->AddRef( + lpContainerApp->m_lpIPActiveObj); + + OLEDBG_BEGIN2("IOleInPlaceActiveObject::GetWindow called\r\n") + lpActiveObject->lpVtbl->GetWindow( + lpActiveObject, + (HWND FAR*)&lpContainerApp->m_hWndUIActiveObj + ); + OLEDBG_END2 + + /* OLE2NOTE: see comment for ContainerDoc_ForwardPaletteChangedMsg */ + /* No need to do this if you don't allow object to own the palette */ + OleApp_QueryNewPalette((LPOLEAPP)lpContainerApp); + } + + /* OLE2NOTE: the new UI Guidelines recommend that in-place + ** containers do NOT change their window titles when an object + ** becomes in-place (UI) active. + */ + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP CntrApp_IPFrame_SetActiveObject( + LPOLEINPLACEFRAME lpThis, + LPOLEINPLACEACTIVEOBJECT lpActiveObject, + LPCOLESTR lpszObjName +) +{ + CREATESTR(pstr, lpszObjName) + + HRESULT hr = CntrApp_IPFrame_SetActiveObjectA(lpThis, lpActiveObject, pstr); + + FREESTR(pstr) + + return hr; +} + + +// IOleInPlaceFrame::InsertMenus +STDMETHODIMP CntrApp_IPFrame_InsertMenus( + LPOLEINPLACEFRAME lpThis, + HMENU hMenu, + LPOLEMENUGROUPWIDTHS lpMenuWidths +) +{ + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + BOOL fNoError = TRUE; + + OLEDBG_BEGIN2("CntrApp_IPFrame_InsertMenus\r\n") + + fNoError &= AppendMenu(hMenu, MF_POPUP, (UINT)lpContainerApp->m_hMenuFile, + "&File"); + fNoError &= AppendMenu(hMenu, MF_POPUP, (UINT)lpContainerApp->m_hMenuView, + "O&utline"); + fNoError &= AppendMenu(hMenu, MF_POPUP,(UINT)lpContainerApp->m_hMenuDebug, + "DbgI&Cntr"); + lpMenuWidths->width[0] = 1; + lpMenuWidths->width[2] = 1; + lpMenuWidths->width[4] = 1; + + OLEDBG_END2 + + return (fNoError ? NOERROR : ResultFromScode(E_FAIL)); +} + + +// IOleInPlaceFrame::SetMenu +STDMETHODIMP CntrApp_IPFrame_SetMenu( + LPOLEINPLACEFRAME lpThis, + HMENU hMenuShared, + HOLEMENU hOleMenu, + HWND hwndActiveObject +) +{ + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HMENU hMenu; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrApp_IPFrame_InsertMenus\r\n") + + + /* OLE2NOTE: either put up the shared menu (combined menu from + ** in-place server and in-place container) or our container's + ** normal menu as directed. + */ + if (hOleMenu && hMenuShared) + hMenu = hMenuShared; + else + hMenu = lpOutlineApp->m_hMenuApp; + + /* OLE2NOTE: SDI apps put menu on frame by calling SetMenu. + ** MDI apps would send WM_MDISETMENU message instead. + */ + SetMenu (lpOutlineApp->m_hWndApp, hMenu); + OLEDBG_BEGIN2("OleSetMenuDescriptor called\r\n") + hrErr = OleSetMenuDescriptor (hOleMenu, lpOutlineApp->m_hWndApp, + hwndActiveObject, NULL, NULL); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; +} + + +// IOleInPlaceFrame::RemoveMenus +STDMETHODIMP CntrApp_IPFrame_RemoveMenus( + LPOLEINPLACEFRAME lpThis, + HMENU hMenu +) +{ + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + BOOL fNoError = TRUE; + + OLEDBG_BEGIN2("CntrApp_IPFrame_RemoveMenus\r\n") + + /* Remove container group menus */ + while (GetMenuItemCount(hMenu)) + fNoError &= RemoveMenu(hMenu, 0, MF_BYPOSITION); + + OleDbgAssert(fNoError == TRUE); + + OLEDBG_END2 + + return (fNoError ? NOERROR : ResultFromScode(E_FAIL)); +} + + +// IOleInPlaceFrame::SetStatusText +STDMETHODIMP CntrApp_IPFrame_SetStatusTextA( + LPOLEINPLACEFRAME lpThis, + LPCSTR lpszStatusText +) +{ +#if defined( USE_STATUSBAR ) + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + static char szMessageHold[128]; + OleDbgOut2("CntrApp_IPFrame_SetStatusText\r\n"); + + /* OLE2NOTE: it is important to save a private copy of status text. + ** lpszStatusText is only valid for the duration of this call. + */ + LSTRCPYN(szMessageHold, lpszStatusText, sizeof(szMessageHold)); + OutlineApp_SetStatusText(lpOutlineApp, (LPSTR)szMessageHold); + + return ResultFromScode(S_OK); +#else + return ResultFromScode(E_NOTIMPL); +#endif // USE_STATUSBAR +} + + +STDMETHODIMP CntrApp_IPFrame_SetStatusText( + LPOLEINPLACEFRAME lpThis, + LPCOLESTR lpszStatusText +) +{ + CREATESTR(pstr, lpszStatusText) + + HRESULT hr = CntrApp_IPFrame_SetStatusTextA(lpThis, pstr); + + FREESTR(pstr) + + return hr; +} + + + +// IOleInPlaceFrame::EnableModeless +STDMETHODIMP CntrApp_IPFrame_EnableModeless( + LPOLEINPLACEFRAME lpThis, + BOOL fEnable +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP) + ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp; +#if defined( _DEBUG ) + if (fEnable) + OleDbgOut2("CntrApp_IPFrame_EnableModeless(TRUE)\r\n"); + else + OleDbgOut2("CntrApp_IPFrame_EnableModeless(FALSE)\r\n"); +#endif // _DEBUG + + /* OLE2NOTE: this method is called when an object puts up a modal + ** dialog. it tells the top-level in-place container to disable + ** it modeless dialogs for the duration that the object is + ** displaying a modal dialog. + ** + ** ICNTROTL does not use any modeless dialogs, thus we can + ** ignore this method. + */ + return NOERROR; +} + + +// IOleInPlaceFrame::TranslateAccelerator +STDMETHODIMP CntrApp_IPFrame_TranslateAccelerator( + LPOLEINPLACEFRAME lpThis, + LPMSG lpmsg, + WORD wID +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + SCODE sc; + + if (TranslateAccelerator (lpOutlineApp->m_hWndApp, + lpContainerApp->m_hAccelIPCntr, lpmsg)) + sc = S_OK; + +#if defined (MDI_VERSION) + else if (TranslateMDISysAccel(lpOutlineApp->m_hWndMDIClient, lpmsg)) + sc = S_OK; +#endif // MDI_VERSION + + else + sc = S_FALSE; + + return ResultFromScode(sc); +} + + + +/************************************************************************* +** ContainerDoc Support Functions +*************************************************************************/ + + +/* ContainerDoc_UpdateInPlaceObjectRects +** ------------------------------------- +** Update the PosRect and ClipRect of the currently in-place active +** object. if there is no object active in-place, then do nothing. +** +** OLE2NOTE: this function should be called when an action occurs +** that changes either the position of the object in the document +** (eg. changing document margins changes PosRect) or the clipRect +** changes (eg. resizing the document window changes the ClipRect). +*/ +void ContainerDoc_UpdateInPlaceObjectRects(LPCONTAINERDOC lpContainerDoc, int nIndex) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + RECT rcClipRect; + + if (g_fInsideOutContainer) { + + if (lpContainerDoc->m_cIPActiveObjects) { + + /* OLE2NOTE: (INSIDE-OUT CONTAINER) we must update the + ** PosRect/ClipRect for all in-place active objects + ** starting from line "nIndex". + */ + ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect); + +#if defined( _DEBUG ) + OleDbgOutRect3( + "ContainerDoc_UpdateInPlaceObjectRects (ClipRect)", + (LPRECT)&rcClipRect + ); +#endif + for (i = nIndex; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + ContainerLine_UpdateInPlaceObjectRects( + lpContainerLine, &rcClipRect); + } + } + } + } + else { + /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently + ** UIActive object, we must inform it that the + ** PosRect/ClipRect has now changed. + */ + LPCONTAINERLINE lpLastUIActiveLine = + lpContainerDoc->m_lpLastUIActiveLine; + if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) { + ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect); + + OleDbgOutRect3("OutlineDoc_Resize (ClipRect)",(LPRECT)&rcClipRect); + ContainerLine_UpdateInPlaceObjectRects( + lpLastUIActiveLine, &rcClipRect); + } + } +} + +/* ContainerDoc_IsUIDeactivateNeeded +** --------------------------------- +** Check if it is necessary to UIDeactivate an in-place active +** object upon a mouse LBUTTONDOWN event. The position of the button +** down click is given by "pt". +** If there is not currently an in-place active line, then +** UIDeactivate is NOT needed. +** If there is a current in-place active line, then check if the +** point position is outside of the object extents on the screen. If +** so, then the object should be UIDeactivated, otherwise not. +*/ +BOOL ContainerDoc_IsUIDeactivateNeeded( + LPCONTAINERDOC lpContainerDoc, + POINT pt +) +{ + LPCONTAINERLINE lpUIActiveLine=lpContainerDoc->m_lpLastUIActiveLine; + RECT rect; + + if (! lpUIActiveLine || ! lpUIActiveLine->m_fUIActive) + return FALSE; + + ContainerLine_GetPosRect( + lpUIActiveLine, + (LPRECT) &rect + ); + + if (! PtInRect((LPRECT) &rect, pt)) + return TRUE; + + return FALSE; +} + + +/* ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded +** ------------------------------------------------- +** OLE2NOTE: this function ONLY applies for OUTSIDE-IN containers +** +** If there is a previous in-place active server still running and +** this server will not be needed to support the next OLE object +** about to be activated, then shut it down. +** in this way we manage a policy of having at most one in-place +** server running at a time. we do not imediately shut down the +** in-place server when the object is UIDeactivated because we want +** it to be fast if the server decides to re-activate the object +** in-place. +** +** shutting down the server is achieved by forcing the object to +** transition from running to loaded by calling IOleObject::Close. +*/ +void ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + LPCONTAINERDOC lpContainerDoc, + LPCONTAINERLINE lpNextActiveLine +) +{ + LPCONTAINERLINE lpLastIpActiveLine = lpContainerDoc->m_lpLastIpActiveLine; + BOOL fEnableServerShutDown = TRUE; + LPMONIKER lpmkLinkSrc; + LPMONIKER lpmkLastActiveObj; + LPMONIKER lpmkCommonPrefix; + LPOLELINK lpOleLink; + HRESULT hrErr; + + /* OLE2NOTE: an inside-out style container can NOT use this scheme + ** to shut down in-place servers. it would have to have a more + ** sophistocated mechanism by which it keeps track of which + ** objects are on screen and which were the last recently used. + */ + if (g_fInsideOutContainer) + return; + + if (lpLastIpActiveLine != lpNextActiveLine) { + if (lpLastIpActiveLine) { + + /* OLE2NOTE: if the object which is about to be activated is + ** actually a link to the OLE object in last activated line, + ** then we do NOT want to shut down the last activated + ** server because it is about to be used. when activating a + ** linked object, the source of the link gets activated. + */ + lpOleLink = (LPOLELINK)ContainerLine_GetOleObject( + lpNextActiveLine, + &IID_IOleLink + ); + if (lpOleLink) { + OLEDBG_BEGIN2("IOleObject::GetSourceMoniker called\r\n") + lpOleLink->lpVtbl->GetSourceMoniker( + lpOleLink, + (LPMONIKER FAR*)&lpmkLinkSrc + ); + OLEDBG_END2 + + if (lpmkLinkSrc) { + lpmkLastActiveObj = ContainerLine_GetFullMoniker( + lpLastIpActiveLine, + GETMONIKER_ONLYIFTHERE + ); + if (lpmkLastActiveObj) { + hrErr = lpmkLinkSrc->lpVtbl->CommonPrefixWith( + lpmkLinkSrc, + lpmkLastActiveObj, + &lpmkCommonPrefix + + ); + if (GetScode(hrErr) == MK_S_HIM || + hrErr == NOERROR || + GetScode(hrErr) == MK_S_US) { + /* the link source IS to the object + ** contained in the last activated + ** line of the document; disable the + ** attempt to shut down the last + ** running in-place server. + */ + fEnableServerShutDown = FALSE; + } + if (lpmkCommonPrefix) + OleStdRelease((LPUNKNOWN)lpmkCommonPrefix); + OleStdRelease((LPUNKNOWN)lpmkLastActiveObj); + } + OleStdRelease((LPUNKNOWN)lpmkLinkSrc); + } + OleStdRelease((LPUNKNOWN)lpOleLink); + } + + /* if it is OK to shut down the previous in-place server + ** and one is still running, then shut it down. shutting + ** down the server is accomplished by forcing the OLE + ** object to close. this forces the object to transition + ** from running to loaded. if the object is actually + ** only loaded then this is a NOP. + */ + if (fEnableServerShutDown && + lpLastIpActiveLine->m_fIpServerRunning) { + + OleDbgOut1("@@@ previous in-place server SHUT DOWN\r\n"); + ContainerLine_CloseOleObject( + lpLastIpActiveLine, OLECLOSE_SAVEIFDIRTY); + + // we can now forget this last in-place active line. + lpContainerDoc->m_lpLastIpActiveLine = NULL; + } + } + } +} + + +/* ContainerDoc_GetUIActiveWindow +** ------------------------------ +** If there is an UIActive object, then return its HWND. +*/ +HWND ContainerDoc_GetUIActiveWindow(LPCONTAINERDOC lpContainerDoc) +{ + return lpContainerDoc->m_hWndUIActiveObj; +} + + +/* ContainerDoc_GetClipRect +** ------------------------ +** Get the ClipRect in client coordinates. +** +** OLE2NOTE: the ClipRect is defined as the maximum window rectangle +** that the in-place active object must be clipped to. this +** rectangle MUST be described in Client Coordinates of the window +** that is used as the Parent of the in-place active object's +** window. in our case, the LineList ListBox window is both the +** parent of the in-place active object AND defines precisely the +** clipping rectangle. +*/ +void ContainerDoc_GetClipRect( + LPCONTAINERDOC lpContainerDoc, + LPRECT lprcClipRect +) +{ + /* OLE2NOTE: the ClipRect can be used to ensure that the in-place + ** server does not overwrite areas of the window that the + ** container paints into but which should never be overwritten + ** (eg. if an app were to paint row and col headings directly in + ** the same window that is the parent of the in-place window. + ** whenever the window size changes or gets scrolled, in-place + ** active object must be informed of the new clip rect. + ** + ** normally an app would pass the rect returned from GetClientRect. + ** but because CntrOutl uses separate windows for row/column + ** headings, status line, formula/tool bars, etc. it is NOT + ** necessary to pass a constrained clip rect. Windows standard + ** window clipping will automatically take care of all clipping + ** that is necessary. thus we can take a short cut of passing an + ** "infinite" clip rect, and then we do NOT need to call + ** IOleInPlaceObject::SetObjectRects when our document is scrolled. + */ + + lprcClipRect->top = -32767; + lprcClipRect->left = -32767; + lprcClipRect->right = 32767; + lprcClipRect->bottom = 32767; +} + + +/* ContainerDoc_GetTopInPlaceFrame +** ------------------------------- +** returns NON-AddRef'ed pointer to Top In-Place Frame interface +*/ +LPOLEINPLACEFRAME ContainerDoc_GetTopInPlaceFrame( + LPCONTAINERDOC lpContainerDoc +) +{ +#if defined( INPLACE_CNTRSVR ) + return lpContainerDoc->m_lpTopIPFrame; +#else + return (LPOLEINPLACEFRAME)&((LPCONTAINERAPP)g_lpApp)->m_OleInPlaceFrame; +#endif +} + +void ContainerDoc_GetSharedMenuHandles( + LPCONTAINERDOC lpContainerDoc, + HMENU FAR* lphSharedMenu, + HOLEMENU FAR* lphOleMenu +) +{ +#if defined( INPLACE_CNTRSVR ) + if (lpContainerDoc->m_DocType == DOCTYPE_EMEBEDDEDOBJECT) { + *lphSharedMenu = lpContainerDoc->m_hSharedMenu; + *lphOleMenu = lpContainerDoc->m_hOleMenu; + return; + } +#endif + + *lphSharedMenu = NULL; + *lphOleMenu = NULL; +} + + +#if defined( USE_FRAMETOOLS ) +void ContainerDoc_RemoveFrameLevelTools(LPCONTAINERDOC lpContainerDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + OleDbgAssert(lpOutlineDoc->m_lpFrameTools != NULL); + + FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, FALSE); +} +#endif + + +void ContainerDoc_AddFrameLevelUI(LPCONTAINERDOC lpContainerDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + LPOLEINPLACEFRAME lpTopIPFrame = ContainerDoc_GetTopInPlaceFrame( + lpContainerDoc); + HMENU hSharedMenu; // combined obj/cntr menu + HOLEMENU hOleMenu; // returned by OleCreateMenuDesc. + + ContainerDoc_GetSharedMenuHandles( + lpContainerDoc, + &hSharedMenu, + &hOleMenu + ); + + lpTopIPFrame->lpVtbl->SetMenu( + lpTopIPFrame, + hSharedMenu, + hOleMenu, + lpOutlineDoc->m_hWndDoc + ); + + /* OLE2NOTE: even if our app does NOT use FrameTools, we must still + ** call IOleInPlaceFrame::SetBorderSpace. + */ + ContainerDoc_AddFrameLevelTools(lpContainerDoc); +} + + +void ContainerDoc_AddFrameLevelTools(LPCONTAINERDOC lpContainerDoc) +{ + LPOLEINPLACEFRAME lpTopIPFrame = ContainerDoc_GetTopInPlaceFrame( + lpContainerDoc); + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc; + + OleDbgAssert(lpTopIPFrame != NULL); + +#if defined( USE_FRAMETOOLS ) + + FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE); + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); + + FrameTools_NegotiateForSpaceAndShow( + lpOutlineDoc->m_lpFrameTools, + NULL, + lpTopIPFrame + ); + +#else // ! USE_FRAMETOOLS + +#if defined( INPLACE_CNTRSVR ) + if (lpContainerDoc->m_DocType == DOCTYPE_EMBEDDEDOBJECT) { + /* this says i do not need space, so the top Frame should + ** leave its tools behind + */ + OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(NULL) called\r\n") + lpTopIPFrame->lpVtbl->SetBorderSpace(lpTopIPFrame, NULL); + OLEDBG_END2 + return; + } +#else // INPLACE_CNTR && ! USE_FRAMETOOLS + + OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(0,0,0,0) called\r\n") + lpTopIPFrame->lpVtbl->SetBorderSpace( + lpTopIPFrame, + (LPCBORDERWIDTHS)&g_rectNull + ); + OLEDBG_END2 + +#endif // INPLACE_CNTR && ! USE_FRAMETOOLS +#endif // ! USE_FRAMETOOLS + +} + + +void ContainerDoc_FrameWindowResized(LPCONTAINERDOC lpContainerDoc) +{ + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + + if (lpContainerApp->m_lpIPActiveObj) { + RECT rcFrameRect; + + /* OLE2NOTE: this fMustResizeClientArea flag is used as part of + ** our defensive programming for frame window resizing. when + ** the frame window is + ** resized, IOleInPlaceActiveObject::ResizeBorder is called + ** the object should normally call back to renegotiate + ** for frame-level tools space. if SetBorderSpace is called + ** then our client area windows are properly resized. + ** CntrApp_IPFrame_SetBorderSpace clears this flag. if the + ** in-place active object does NOT call SetBorderSpace, then + ** the container must take care to resize its client area + ** windows itself. + */ + lpContainerApp->m_fMustResizeClientArea = TRUE; + + OutlineApp_GetFrameRect(g_lpApp, (LPRECT)&rcFrameRect); + + OLEDBG_BEGIN2("IOleInPlaceActiveObject::ResizeBorder called\r\n") + lpContainerApp->m_lpIPActiveObj->lpVtbl->ResizeBorder( + lpContainerApp->m_lpIPActiveObj, + (LPCRECT)&rcFrameRect, + (LPOLEINPLACEUIWINDOW)&lpContainerApp->m_OleInPlaceFrame, + TRUE /* fFrameWindow */ + ); + OLEDBG_END2 + + /* the object did NOT call IOleInPlaceUIWindow::SetBorderSpace + ** therefore we must resize our client area windows ourself. + */ + if (lpContainerApp->m_fMustResizeClientArea) { + lpContainerApp->m_fMustResizeClientArea = FALSE; + OutlineApp_ResizeClientArea(g_lpApp); + } + } + +#if defined( USE_FRAMETOOLS ) + else { + ContainerDoc_AddFrameLevelTools(lpContainerDoc); + } +#endif +} + + +#if defined( INPLACE_CNTRSVR ) || defined( INPLACE_MDICNTR ) + +/* ContainerDoc_GetTopInPlaceDoc +** returns NON-AddRef'ed pointer to Top In-Place Doc interface +*/ +LPOLEINPLACEUIWINDOW ContainerDoc_GetTopInPlaceDoc( + LPCONTAINERDOC lpContainerDoc +) +{ +#if defined( INPLACE_CNTRSVR ) + return lpContainerDoc->m_lpTopIPDoc; +#else + return (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc; +#endif +} + + +void ContainerDoc_RemoveDocLevelTools(LPCONTAINERDOC lpContainerDoc); +{ + LPOLEINPLACEUIWINDOW lpTopIPDoc = ContainerDoc_GetTopInPlaceDoc( + lpContainerDoc); + + if (lpTopIPDoc && lpContainerDoc->m_fMyToolsOnDoc) { + lpContainerDoc->m_fMyToolsOnDoc = FALSE; + + // if we had doc tools we would HIDE them here; + // but NOT call SetBorderSpace(NULL) + + } +} + +void ContainerDoc_AddDocLevelTools(LPCONTAINERDOC lpContainerDoc) +{ + LPOLEINPLACEUIWINDOW lpTopIPDoc = ContainerDoc_GetTopInPlaceDoc( + lpContainerDoc); + + if (! lpTopIPDoc) + return; + +#if defined( USE_DOCTOOLS ) + if (lpTopIPDoc && ! lpContainerDoc->m_fMyToolsOnDoc) { + + /* if we had doc tools we would negotiate for toolbar space at + ** doc level and SHOW them. + */ + + /* we do NOT have doc level tools, so we just call + ** SetBorderSpace() to indicate to the top doc that + ** our object does not need tool space. + */ + + lpContainerDoc->m_fMyToolsOnDoc = TRUE; + return; + } +#else // ! USE_DOCTOOLS + +#if defined( INPLACE_CNTRSVR ) + if (lpContainerDoc->m_DocType == DOCTYPE_EMBEDDEDOBJECT) { + /* this says i do not need space, so the top doc should + ** leave its tools behind + */ + lpTopIPDoc->lpVtbl->SetBorderSpace(lpTopIPDoc, NULL); + return; + } +#else + lpTopIPDoc->lpVtbl->SetBorderSpace( + lpTopIPDoc, + (LPCBORDERWIDTHS)&g_rectNull + ); + +#endif +#endif // ! USE_DOCTOOLS +} + +#endif // INPLACE_CNTRSVR || INPLACE_MDICNTR + + +/* ContainerDoc_ContextSensitiveHelp +** --------------------------------- +** forward the ContextSensitiveHelp mode on to any in-place objects +** that currently have their window visible. this informs the +** objects whether to give help or take action on subsequent mouse +** clicks and menu commands. this function is called from our +** IOleInPlaceSite::ContextSensitiveHelp implementation. +** +** OLE2NOTE: see context sensitive help technote (CSHELP.DOC). +** This function is called when SHIFT-F1 context sensitive help is +** entered. the cursor should then change to a question mark +** cursor and the app should enter a modal state where the next +** mouse click does not perform its normal action but rather +** gives help corresponding to the location clicked. if the app +** does not implement a help system, it should at least eat the +** click and do nothing. +*/ +void ContainerDoc_ContextSensitiveHelp( + LPCONTAINERDOC lpContainerDoc, + BOOL fEnterMode, + BOOL fInitiatedByObj +) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc; + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + + lpOleDoc->m_fCSHelpMode = fEnterMode; + + if (g_fInsideOutContainer) { + + if (lpContainerDoc->m_cIPActiveObjects) { + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + ContainerLine_ContextSensitiveHelp( + lpContainerLine, fEnterMode); + } + } + } + } + else if (! fInitiatedByObj) { + /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently + ** UIActive object (ie. its window is visible), we must + ** forward the ContextSensitiveHelp mode on to the + ** object--assuming it was not the object that initiated the + ** context sensitve help mode. + */ + LPCONTAINERLINE lpLastUIActiveLine = + lpContainerDoc->m_lpLastUIActiveLine; + if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) { + ContainerLine_ContextSensitiveHelp(lpLastUIActiveLine,fEnterMode); + } + } +} + +/* ContainerDoc_ForwardPaletteChangedMsg +** ------------------------------------- +** forward the WM_PALETTECHANGED message (via SendMessage) to any +** in-place objects that currently have their window visible. this +** gives these objects the chance to select their palette as a +** BACKGROUND palette. +** +** SEE THE TECHNOTE FOR DETAILED INFORMATION ON PALETTE COORDINATION +** +** OLE2NOTE: For containers and objects to manage palettes properly +** (when objects are getting inplace edited) they should follow a +** set of rules. +** +** Rule 1: The Container can decide if it wants to own the palette or +** it wants to allow its UIActive object to own the palette. +** a) If the container wants to let its UIActive object own the +** palette then it should forward WM_QUERYNEWPALETTE to the object +** when it is received to the top frame window. also it should send +** WM_QUERYNEWPALETTE to the object in its +** IOleInPlaceFrame::SetActiveObject implementation. if the object +** is given ownership of the palette, then it owns the palette until +** it is UIDeactivated. +** b) If the container wants to own the palette it should NOT send +** WM_QUERYNEWPALETTE to the UIActive object. +** +** Rule 2: Whether the container wants to own the palette or not, it +** should forward the WM_PALETTECHANGED to the immediate child +** inplace active objects in its documents. if it is an inside-out +** style container then it must forward it to ALL objects that +** currently have their windows visible. When the object recives the +** WM_PALETTECHANGED message it must select its color palette as the +** background palette. When the objects are in loaded state they will be +** drawn by (OLE) by selecting their palettes as background palettes +** anyway. +** +** Note: IOleObject::SetColorScheme is not related to the palette +** issue. +*/ +void ContainerDoc_ForwardPaletteChangedMsg( + LPCONTAINERDOC lpContainerDoc, + HWND hwndPalChg +) +{ + LPLINELIST lpLL; + int i; + LPLINE lpLine; + + if (!lpContainerDoc) + return; + + lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + if (g_fInsideOutContainer) { + + if (lpContainerDoc->m_cIPActiveObjects) { + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + ContainerLine_ForwardPaletteChangedMsg( + lpContainerLine, hwndPalChg); + } + } + } + } + else { + /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently + ** UIActive object (ie. its window is visible), we must + ** forward it the WM_PALETTECHANGED message. + */ + LPCONTAINERLINE lpLastUIActiveLine = + lpContainerDoc->m_lpLastUIActiveLine; + if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) { + ContainerLine_ForwardPaletteChangedMsg( + lpLastUIActiveLine, hwndPalChg); + } + } +} + + +/************************************************************************* +** ContainerLine Support Functions and Interfaces +*************************************************************************/ + + +/* ContainerLine_UIDeactivate +** -------------------------- +** tell the OLE object associated with the ContainerLine to +** UIDeactivate. this informs the in-place server to tear down +** the UI and window that it put up for the object. it will remove +** its active editor menus and any frame and object adornments +** (eg. toolbars, rulers, etc.). +*/ +void ContainerLine_UIDeactivate(LPCONTAINERLINE lpContainerLine) +{ + HRESULT hrErr; + + if (!lpContainerLine || !lpContainerLine->m_fUIActive) + return; + + OLEDBG_BEGIN2("IOleInPlaceObject::UIDeactivate called\r\n") + hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->UIDeactivate( + lpContainerLine->m_lpOleIPObj); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleInPlaceObject::UIDeactivate returned", hrErr); + return; + } +} + + + +/* ContainerLine_UpdateInPlaceObjectRects +** ------------------------------------- +** Update the PosRect and ClipRect of the given line +** currently in-place active +** object. if there is no object active in-place, then do nothing. +** +** OLE2NOTE: this function should be called when an action occurs +** that changes either the position of the object in the document +** (eg. changing document margins changes PosRect) or the clipRect +** changes (eg. resizing the document window changes the ClipRect). +*/ +void ContainerLine_UpdateInPlaceObjectRects( + LPCONTAINERLINE lpContainerLine, + LPRECT lprcClipRect +) +{ + LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc; + RECT rcClipRect; + RECT rcPosRect; + + + if (! lpContainerLine->m_fIpVisible) + return; + + if (! lprcClipRect) { + ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect); + lprcClipRect = (LPRECT)&rcClipRect; + } + +#if defined( _DEBUG ) + OleDbgOutRect3( + "ContainerLine_UpdateInPlaceObjectRects (ClipRect)", + (LPRECT)&rcClipRect + ); +#endif + ContainerLine_GetPosRect(lpContainerLine,(LPRECT)&rcPosRect); + +#if defined( _DEBUG ) + OleDbgOutRect3( + "ContainerLine_UpdateInPlaceObjectRects (PosRect)",(LPRECT)&rcPosRect); +#endif + + OLEDBG_BEGIN2("IOleInPlaceObject::SetObjectRects called\r\n") + lpContainerLine->m_lpOleIPObj->lpVtbl->SetObjectRects( + lpContainerLine->m_lpOleIPObj, + (LPRECT)&rcPosRect, + lprcClipRect + ); + OLEDBG_END2 +} + + +/* ContainerLine_ContextSensitveHelp +** --------------------------------- +** forward the ContextSensitiveHelp mode on to the in-place object +** if it currently has its window visible. this informs the +** object whether to give help or take action on subsequent mouse +** clicks and menu commands. +** +** this function is called from ContainerDoc_ContextSensitiveHelp +** function as a result of a call to +** IOleInPlaceSite::ContextSensitiveHelp if the in-place container +** is operating as an in-side out container. +*/ +void ContainerLine_ContextSensitiveHelp( + LPCONTAINERLINE lpContainerLine, + BOOL fEnterMode +) +{ + if (! lpContainerLine->m_fIpVisible) + return; + + OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp called\r\n") + lpContainerLine->m_lpOleIPObj->lpVtbl->ContextSensitiveHelp( + lpContainerLine->m_lpOleIPObj, fEnterMode); + OLEDBG_END2 +} + + +/* ContainerLine_ForwardPaletteChangedMsg +** -------------------------------------- +** forward it the WM_PALETTECHANGED message (via SendMessage) to the +** in-place object if it currently has its window visible. this +** gives the object the chance to select its palette as a BACKGROUND +** palette if it doesn't own the palette--or as the +** foreground palette if it currently DOES own the palette. +** +** SEE THE TECHNOTE FOR DETAILED INFORMATION ON PALETTE COORDINATION +*/ +void ContainerLine_ForwardPaletteChangedMsg( + LPCONTAINERLINE lpContainerLine, + HWND hwndPalChg +) +{ + if (! lpContainerLine->m_fIpVisible) + return; + + OleDbgAssert(lpContainerLine->m_hWndIpObject); + SendMessage( + lpContainerLine->m_hWndIpObject, + WM_PALETTECHANGED, + (WPARAM)hwndPalChg, + 0L + ); +} + + + +/************************************************************************* +** ContainerLine::IOleInPlaceSite interface implementation +*************************************************************************/ + +STDMETHODIMP CntrLine_IPSite_QueryInterface( + LPOLEINPLACESITE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) CntrLine_IPSite_AddRef(LPOLEINPLACESITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IOleInPlaceSite"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +STDMETHODIMP_(ULONG) CntrLine_IPSite_Release(LPOLEINPLACESITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IOleInPlaceSite"); + + return ContainerLine_Release(lpContainerLine); +} + + +STDMETHODIMP CntrLine_IPSite_GetWindow( + LPOLEINPLACESITE lpThis, + HWND FAR* lphwnd +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + OleDbgOut2("CntrLine_IPSite_GetWindow\r\n"); + + *lphwnd = LineList_GetWindow( + &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList); + return NOERROR; +} + +// IOleInPlaceSite::ContextSensitiveHelp +STDMETHODIMP CntrLine_IPSite_ContextSensitiveHelp( + LPOLEINPLACESITE lpThis, + BOOL fEnterMode +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerLine->m_lpDoc; + OleDbgOut2("CntrLine_IPSite_ContextSensitiveHelp\r\n"); + + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC). + ** This method is called when SHIFT-F1 context sensitive help is + ** entered. the cursor should then change to a question mark + ** cursor and the app should enter a modal state where the next + ** mouse click does not perform its normal action but rather + ** gives help corresponding to the location clicked. if the app + ** does not implement a help system, it should at least eat the + ** click and do nothing. + ** + ** NOTE: the implementation here is specific to an SDI simple + ** container. an MDI container or container/server application + ** would have additional work to do (see the technote). + ** + ** NOTE: (INSIDE-OUT CONTAINER) if there are currently + ** any in-place objects active with their windows visible + ** (ie. fIpVisible), we must forward the + ** ContextSensitiveHelp mode on to these objects. + */ + ContainerDoc_ContextSensitiveHelp( + lpContainerLine->m_lpDoc,fEnterMode,TRUE /*InitiatedByObj*/); + + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_CanInPlaceActivate(LPOLEINPLACESITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + OleDbgOut2("CntrLine_IPSite_CanInPlaceActivate\r\n"); + + /* OLE2NOTE: the container can NOT allow in-place activation if it + ** is currently displaying the object as an ICON + ** (DVASPECT_ICON). it can ONLY do in-place activation if it is + ** displaying the DVASPECT_CONTENT of the OLE object. + */ + if (lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) + return NOERROR; + else + return ResultFromScode(S_FALSE); +} + +STDMETHODIMP CntrLine_IPSite_OnInPlaceActivate(LPOLEINPLACESITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc; + SCODE sc = S_OK; + + OLEDBG_BEGIN2("CntrLine_IPSite_OnInPlaceActivate\r\n"); + + /* OLE2NOTE: (OUTSIDE-IN CONTAINER) as a policy for managing + ** running in-place servers, we will keep only 1 inplace server + ** active at any given time. so when we start to inp-place activate + ** another line, then we want to shut down the previously + ** activated server. in this way we keep at most one inplace + ** server active at a time. this is NOT a required policy. apps + ** may choose to have a more sophisticated strategy. inside-out + ** containers will HAVE to have a more sophisticated strategy, + ** because they need (at a minimum) to keep all visible object + ** servers running. + ** + ** if the in-place activation is the result of activating a + ** linked object in another container, then we may arrive at + ** this method while another object is currently active. + ** normally, if the object is in-place activated by + ** double-clicking or Edit.<verb> from our own container, then + ** the previous in-place object would have been de-activated in + ** ContainerLine_DoVerb method. + */ + if (!g_fInsideOutContainer) { + if (lpContainerDoc->m_lpLastIpActiveLine) { + ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + lpContainerDoc, lpContainerLine); + } + lpContainerDoc->m_lpLastIpActiveLine = lpContainerLine; + } + + /* OLE2NOTE: to avoid LRPC problems it is important to cache the + ** IOleInPlaceObject* pointer and NOT to call QueryInterface + ** each time it is needed. + */ + lpContainerLine->m_lpOleIPObj = (LPOLEINPLACEOBJECT) + ContainerLine_GetOleObject(lpContainerLine,&IID_IOleInPlaceObject); + + if (! lpContainerLine->m_lpOleIPObj) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpOleIPObj!=NULL, + "OLE object must support IOleInPlaceObject" + ); +#endif + return ResultFromScode(E_FAIL); // ERROR: refuse to in-place activate + } + + lpContainerLine->m_fIpActive = TRUE; + lpContainerLine->m_fIpVisible = TRUE; + + OLEDBG_BEGIN2("IOleInPlaceObject::GetWindow called\r\n") + lpContainerLine->m_lpOleIPObj->lpVtbl->GetWindow( + lpContainerLine->m_lpOleIPObj, + (HWND FAR*)&lpContainerLine->m_hWndIpObject + ); + OLEDBG_END2 + + if (! lpContainerLine->m_fIpServerRunning) { + /* OLE2NOTE: it is VERY important that an in-place container + ** that also support linking to embeddings properly manage + ** the running of its in-place objects. in an outside-in + ** style in-place container, when the user clicks + ** outside of the in-place active object, the object gets + ** UIDeactivated and the object hides its window. in order + ** to make the object fast to reactivate, the container + ** deliberately does not call IOleObject::Close. the object + ** stays running in the invisible unlocked state. the idea + ** here is if the user simply clicks outside of the object + ** and then wants to double click again to re-activate the + ** object, we do not want this to be slow. if we want to + ** keep the object running, however, we MUST Lock it + ** running. otherwise the object will be in an unstable + ** state where if a linking client does a "silent-update" + ** (eg. UpdateNow from the Links dialog), then the in-place + ** server will shut down even before the object has a chance + ** to be saved back in its container. this saving normally + ** occurs when the in-place container closes the object. also + ** keeping the object in the unstable, hidden, running, + ** not-locked state can cause problems in some scenarios. + ** ICntrOtl keeps only one object running. if the user + ** intiates a DoVerb on another object, then that last + ** running in-place active object is closed. a more + ** sophistocated in-place container may keep more object running. + ** this lock gets unlocked in ContainerLine_CloseOleObject. + */ + lpContainerLine->m_fIpServerRunning = TRUE; + + OLEDBG_BEGIN2("OleLockRunning(TRUE, 0) called\r\n") + OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleIPObj, TRUE, 0); + OLEDBG_END2 + } + + lpContainerLine->m_lpDoc->m_cIPActiveObjects++; + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_OnUIActivate (LPOLEINPLACESITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPCONTAINERLINE lpLastUIActiveLine = lpContainerDoc->m_lpLastUIActiveLine; + + OLEDBG_BEGIN2("CntrLine_IPSite_OnUIActivate\r\n"); + + lpContainerLine->m_fUIActive = TRUE; + lpContainerDoc->m_fAddMyUI = FALSE; + lpContainerDoc->m_lpLastUIActiveLine = lpContainerLine; + + if (g_fInsideOutContainer) { + /* OLE2NOTE: (INSIDE-OUT CONTAINER) an inside-out style + ** container must UIDeactivate the previous UIActive object + ** when a new object is going UIActive. since the inside-out + ** objects have their own windows visible, it is possible + ** that a click directly in an another server window will + ** cause it to UIActivate. OnUIActivate is the containers + ** notification that such has occured. it must then + ** UIDeactivate the other because at most one object can be + ** UIActive at a time. + */ + if (lpLastUIActiveLine && (lpLastUIActiveLine!=lpContainerLine)) { + ContainerLine_UIDeactivate(lpLastUIActiveLine); + + // Make sure new UIActive window is on top of all others + SetWindowPos( + lpContainerLine->m_hWndIpObject, + HWND_TOPMOST, + 0,0,0,0, + SWP_NOMOVE | SWP_NOSIZE + ); + + OLEDBG_END2 + return NOERROR; + } + } + + lpContainerDoc->m_hWndUIActiveObj = lpContainerLine->m_hWndIpObject; + +#if defined( USE_FRAMETOOLS ) + ContainerDoc_RemoveFrameLevelTools(lpContainerDoc); +#endif + +#if defined( USE_DOCTOOLS ) + ContainerDoc_RemoveDocLevelTools(lpContainerDoc); +#endif + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_GetWindowContext( + LPOLEINPLACESITE lpThis, + LPOLEINPLACEFRAME FAR* lplpFrame, + LPOLEINPLACEUIWINDOW FAR* lplpDoc, + LPRECT lprcPosRect, + LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp; + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + + OLEDBG_BEGIN2("CntrLine_IPSite_GetWindowContext\r\n") + + /* OLE2NOTE: The server should fill in the "cb" field so that the + ** container can tell what size structure the server is + ** expecting. this enables this structure to be easily extended + ** in future releases of OLE. the container should check this + ** field so that it doesn't try to use fields that do not exist + ** since the server may be using an old structure definition. + ** Since this is the first release of OLE2.0, the structure is + ** guaranteed to be at least large enough for the current + ** definition of OLEINPLACEFRAMEINFO struct. thus we do NOT need + ** to consider this an error if the server did not fill in this + ** field correctly. this server may have trouble in the future, + ** however, when the structure is extended. + */ + *lplpFrame = (LPOLEINPLACEFRAME)&lpContainerApp->m_OleInPlaceFrame; + (*lplpFrame)->lpVtbl->AddRef(*lplpFrame); // must return AddRef'ed ptr + + // OLE2NOTE: an MDI app would have to provide *lplpDoc + *lplpDoc = NULL; + + ContainerLine_GetPosRect(lpContainerLine, lprcPosRect); + ContainerDoc_GetClipRect(lpContainerLine->m_lpDoc, lprcClipRect); + + OleDbgOutRect3("CntrLine_IPSite_GetWindowContext (PosRect)", lprcPosRect); + OleDbgOutRect3("CntrLine_IPSite_GetWindowContext (ClipRect)",lprcClipRect); + lpFrameInfo->hwndFrame = lpOutlineApp->m_hWndApp; + +#if defined( MDI_VERSION ) + lpFrameInfo->fMDIApp = TRUE; +#else + lpFrameInfo->fMDIApp = FALSE; +#endif + + lpFrameInfo->haccel = lpContainerApp->m_hAccelIPCntr; + lpFrameInfo->cAccelEntries = + GetAccelItemCount(lpContainerApp->m_hAccelIPCntr); + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_Scroll( + LPOLEINPLACESITE lpThis, + SIZE scrollExtent +) +{ + OleDbgOut2("CntrLine_IPSite_Scroll\r\n"); + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP CntrLine_IPSite_OnUIDeactivate( + LPOLEINPLACESITE lpThis, + BOOL fUndoable +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP) g_lpApp; + LPLINELIST lpLL; + int nIndex; + MSG msg; + HRESULT hrErr; + OLEDBG_BEGIN2("CntrLine_IPSite_OnUIDeactivate\r\n") + + lpContainerLine->m_fUIActive = FALSE; + lpContainerLine->m_fIpChangesUndoable = fUndoable; + lpContainerLine->m_lpDoc->m_hWndUIActiveObj = NULL; + + if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine) { + + lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL; + + /* OLE2NOTE: here we look ahead if there is a DBLCLK sitting in our + ** message queue. if so, it could result in in-place activating + ** another object. we want to avoid placing our tools and + ** repainting if immediately another object is going to do the + ** same. SO, if there is a DBLCLK in the queue for this document + ** we will only set the fAddMyUI flag to indicate that this work + ** is still to be done. if another object actually in-place + ** activates then this flag will be cleared in + ** IOleInPlaceSite::OnUIActivate. if it does NOT get cleared, + ** then at the end of processing the DBLCLK message in our + ** OutlineDocWndProc we will put our tools back. + */ + if (! PeekMessage(&msg, lpOutlineDoc->m_hWndDoc, + WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, + PM_NOREMOVE | PM_NOYIELD)) { + + /* OLE2NOTE: You need to generate QueryNewPalette only if + ** you own the top level frame (ie. you are a top-level + ** inplace container). + */ + + OleApp_QueryNewPalette((LPOLEAPP)g_lpApp); + +#if defined( USE_DOCTOOLS ) + ContainerDoc_AddDocLevelTools(lpContainerLine->m_lpDoc); +#endif + +#if defined( USE_FRAMETOOLS ) + ContainerDoc_AddFrameLevelUI(lpContainerLine->m_lpDoc); +#endif + } else { + lpContainerLine->m_lpDoc->m_fAddMyUI = TRUE; + } + + /* OLE2NOTE: we should re-take focus. the in-place server window + ** previously had the focus; this window has just been removed. + */ + SetFocus(OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc)); + + // force the line to redraw to remove in-place active hatch + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + LineList_ForceLineRedraw(lpLL, nIndex, TRUE); + } + +#if defined( UNDOSUPPORTED ) + + /* OLE2NOTE: an outside-in style container that supports UNDO would + ** call IOleObject::DoVerb(OLEIVERB_HIDE) to make the in-place + ** object go invisible. when it wants the in-place active object + ** to discard its undo state, it would call + ** IOleInPlaceObject::InPlaceDeactivate when it wants the object + ** to discard its undo state. there is no need for an outside-in + ** style container to call + ** IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE). if either the + ** container or the object do not support UNDO, then the + ** container might as well immediately call InPlaceDeactivate + ** instead of calling DoVerb(HIDE). + ** + ** an inside-out style container that supports UNDO would simply + ** UIDeactivate the object. it would call + ** IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE) when it wants + ** the object discard its undo state. it would call + ** IOleInPlaceObject::InPlaceDeactivate if it wants the object + ** to take down its window. + */ + if (! g_fInsideOutContainer || !lpContainerLine->m_fInsideOutObj) { + + if (lpContainerLine->m_fIpChangesUndoable) { + ContainerLine_DoVerb( + lpContainerLine,OLEIVERB_HIDE,NULL,FALSE,FALSE); + } else { + lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate( + lpContainerLine->m_lpOleIPObj); + } + lpContainerLine->m_fIpVisible = FALSE; + lpContainerLine->m_hWndIpObject = NULL; + } +#else + + /* OLE2NOTE: an outside-in style container that does NOT support + ** UNDO would immediately tell the UIDeactivated server (UI + ** removed) to IOleInPlaceObject::InPlaceDeactivate. + ** + ** an inside-out style container that does NOT support UNDO + ** would call IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE) to + ** tell the object to discard its undo state. it would call + ** IOleInPlaceObject::InPlaceDeactivate if it wants the object + ** to take down its window. + */ + + if (g_fInsideOutContainer) { + + if (lpContainerLine->m_fInsideOutObj) { + + if (lpContainerLine->m_fIpChangesUndoable) { + OLEDBG_BEGIN3("ContainerLine_DoVerb(OLEIVERB_DISCARDUNDOSTATE) called!\r\n") + ContainerLine_DoVerb(lpContainerLine, + OLEIVERB_DISCARDUNDOSTATE,NULL,FALSE,FALSE); + OLEDBG_END3 + } + + } else { // !fInsideOutObj + + /* OLE2NOTE: (INSIDEOUT CONTAINER) if the object is not + ** registered OLEMISC_ACTIVATEWHENVISIBLE, then we will + ** make the object behave in an outside-in manner. since + ** we do NOT deal with UNDO we can simply + ** InPlaceDeactivate the object. it should NOT be + ** allowed to leave its window visible when + ** UIDeactivated. + */ + OLEDBG_BEGIN2("IOleInPlaceObject::InPlaceDeactivate called\r\n") + hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate( + lpContainerLine->m_lpOleIPObj); + OLEDBG_END2 + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleInPlaceObject::InPlaceDeactivate returned", hrErr); + } + } + + } else { + + /* OLE2NOTE: (OUTSIDE-IN CONTAINER) since we do NOT deal with + ** UNDO we can simply InPlaceDeactivate the object. it + ** should NOT be allowed to leave its window visible when + ** UIDeactivated. + ** + ** NOTE: In-place servers must handle InPlaceDeactivate + ** being called before its call to + ** IOleInPlaceSite::OnUIDeactivate returns. in case there + ** are misbehaving servers out there, one way to work around + ** this problem is to call + ** IOleObject::DoVerb(OLEIVERB_HIDE...) here. + */ + OLEDBG_BEGIN2("IOleInPlaceObject::InPlaceDeactivate called\r\n") + hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate( + lpContainerLine->m_lpOleIPObj); + OLEDBG_END2 + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleInPlaceObject::InPlaceDeactivate returned", hrErr); + } + } + +#endif // ! UNDOSUPPORTED + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_OnInPlaceDeactivate(LPOLEINPLACESITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + + OLEDBG_BEGIN2("CntrLine_IPSite_OnInPlaceDeactivate\r\n"); + + lpContainerLine->m_fIpActive = FALSE; + lpContainerLine->m_fIpVisible = FALSE; + lpContainerLine->m_fIpChangesUndoable = FALSE; + lpContainerLine->m_hWndIpObject = NULL; + + OleStdRelease((LPUNKNOWN) lpContainerLine->m_lpOleIPObj); + lpContainerLine->m_lpOleIPObj = NULL; + lpContainerLine->m_lpDoc->m_cIPActiveObjects--; + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_DiscardUndoState(LPOLEINPLACESITE lpThis) +{ + OleDbgOut2("CntrLine_IPSite_DiscardUndoState\r\n"); + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_DeactivateAndUndo(LPOLEINPLACESITE lpThis) +{ + OleDbgOut2("CntrLine_IPSite_DeactivateAndUndo\r\n"); + return NOERROR; +} + + +STDMETHODIMP CntrLine_IPSite_OnPosRectChange( + LPOLEINPLACESITE lpThis, + LPCRECT lprcPosRect +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPSCALEFACTOR lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc); + LPLINE lpLine = (LPLINE)lpContainerLine; + LPLINELIST lpLL; + int nIndex; + RECT rcClipRect; + RECT rcNewPosRect; + SIZEL sizelPix; + SIZEL sizelHim; + int nIPObjHeight = lprcPosRect->bottom - lprcPosRect->top; + int nIPObjWidth = lprcPosRect->right - lprcPosRect->left; + OLEDBG_BEGIN2("CntrLine_IPSite_OnPosRectChange\r\n") + OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (PosRect --IN)", (LPRECT)lprcPosRect); + + /* OLE2NOTE: if the in-place container does NOT impose any + ** size contraints on its in-place active objects, then it may + ** simply grant the size requested by the object by immediately + ** calling IOleInPlaceObject::SetObjectRects with the + ** lprcPosRect passed by the in-place object. + ** + ** Container Outline, however, imposes a size constraint on its + ** embedded objects (see comment in ContainerLine_UpdateExtent), + ** thus it is necessary to calculate the size that the in-place + ** active object is allowed to be. + ** + ** Here we need to know the new extents of the in-place object. + ** We can NOT directly ask the object via IOleObject::GetExtent + ** because this method will retreive the extents of the last + ** cached metafile. the cache has not yet been updated by this + ** point. We can not reliably call IOleObject::GetExtent + ** because, despite the fact that will be delegated to the + ** object properly, some objects may not have reformated their + ** object and computed the new extents at the time of calling + ** OnPosRectChange. + ** + ** the best we can do to get the new extents of the object is + ** to determine the scale factor that the object was operating at + ** prior to the OnPosRect call and scale the new lprcPosRect + ** using this scale factor back to HIMETRIC units. + */ + if (lpContainerLine->m_sizeInHimetric.cx > 0 && + lpContainerLine->m_sizeInHimetric.cy > 0) { + sizelHim.cx = lpLine->m_nWidthInHimetric; + sizelHim.cy = lpLine->m_nHeightInHimetric; + XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix); + sizelHim.cx = lpContainerLine->m_sizeInHimetric.cx * + nIPObjWidth / sizelPix.cx; + sizelHim.cy = lpContainerLine->m_sizeInHimetric.cy * + nIPObjHeight / sizelPix.cy; + + // Convert size back to 100% zoom + sizelHim.cx = sizelHim.cx * lpscale->dwSxD / lpscale->dwSxN; + sizelHim.cy = sizelHim.cy * lpscale->dwSyD / lpscale->dwSyN; + } else { + sizelHim.cx = (long)DEFOBJWIDTH; + sizelHim.cy = (long)DEFOBJHEIGHT; + XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix); + sizelHim.cx = sizelHim.cx * nIPObjWidth / sizelPix.cx; + sizelHim.cy = sizelHim.cy * nIPObjHeight / sizelPix.cy; + } + + ContainerLine_UpdateExtent(lpContainerLine, &sizelHim); + ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcNewPosRect); + ContainerDoc_GetClipRect(lpContainerLine->m_lpDoc, (LPRECT)&rcClipRect); + +#if defined( _DEBUG ) + OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (PosRect --OUT)", + (LPRECT)&rcNewPosRect); + OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (ClipRect--OUT)", + (LPRECT)&rcClipRect); +#endif + OLEDBG_BEGIN2("IOleInPlaceObject::SetObjectRects called\r\n") + lpContainerLine->m_lpOleIPObj->lpVtbl->SetObjectRects( + lpContainerLine->m_lpOleIPObj, + (LPRECT)&rcNewPosRect, + (LPRECT)&rcClipRect + ); + OLEDBG_END2 + + /* OLE2NOTE: (INSIDEOUT CONTAINER) Because this object just changed + ** size, this may cause other in-place active objects in the + ** document to move. in ICNTROTL's case any object below this + ** object would be affected. in this case it would be necessary + ** to call SetObjectRects to each affected in-place active object. + */ + if (g_fInsideOutContainer) { + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + + ContainerDoc_UpdateInPlaceObjectRects( + lpContainerLine->m_lpDoc, nIndex); + } + OLEDBG_END2 + return NOERROR; +} diff --git a/private/oleutest/letest/outline/cntrline.c b/private/oleutest/letest/outline/cntrline.c new file mode 100644 index 000000000..881925210 --- /dev/null +++ b/private/oleutest/letest/outline/cntrline.c @@ -0,0 +1,3540 @@ +/************************************************************************* +** +** OLE 2 Container Sample Code +** +** cntrline.c +** +** This file contains ContainerLine methods. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + + + +extern LPOUTLINEAPP g_lpApp; +extern IUnknownVtbl g_CntrLine_UnknownVtbl; +extern IOleClientSiteVtbl g_CntrLine_OleClientSiteVtbl; +extern IAdviseSinkVtbl g_CntrLine_AdviseSinkVtbl; + +#if defined( INPLACE_CNTR ) +extern IOleInPlaceSiteVtbl g_CntrLine_OleInPlaceSiteVtbl; +extern BOOL g_fInsideOutContainer; +#endif // INPLACE_CNTR + +// REVIEW: should use string resource for messages +char ErrMsgDoVerb[] = "OLE object action failed!"; + + +/* prototype for static functions */ +static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC); + + +/************************************************************************* +** ContainerLine +** This object represents the location within the container where +** the embedded/linked object lives. It exposes interfaces to the +** object that allow the object to get information about its +** embedding site and to announce notifications of important events +** (changed, closed, saved) +** +** The ContainerLine exposes the following interfaces: +** IUnknown +** IOleClientSite +** IAdviseSink +*************************************************************************/ + + + +/************************************************************************* +** ContainerLine::IUnknown interface implementation +*************************************************************************/ + + +// IUnknown::QueryInterface +STDMETHODIMP CntrLine_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +// IUnknown::AddRef +STDMETHODIMP_(ULONG) CntrLine_Unk_AddRef(LPUNKNOWN lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IUnknown"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +// IUnknown::Release +STDMETHODIMP_(ULONG) CntrLine_Unk_Release(LPUNKNOWN lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IUnknown"); + + return ContainerLine_Release(lpContainerLine); +} + + +/************************************************************************* +** ContainerLine::IOleClientSite interface implementation +*************************************************************************/ + +// IOleClientSite::QueryInterface +STDMETHODIMP CntrLine_CliSite_QueryInterface( + LPOLECLIENTSITE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +// IOleClientSite::AddRef +STDMETHODIMP_(ULONG) CntrLine_CliSite_AddRef(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IOleClientSite"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +// IOleClientSite::Release +STDMETHODIMP_(ULONG) CntrLine_CliSite_Release(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IOleClientSite"); + + return ContainerLine_Release(lpContainerLine); +} + + +// IOleClientSite::SaveObject +STDMETHODIMP CntrLine_CliSite_SaveObject(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg; + SCODE sc = S_OK; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrLine_CliSite_SaveObject\r\n") + + if (! lpPersistStg) { + /* OLE2NOTE: The object is NOT loaded. a container must be + ** prepared for the fact that an object that it thinks it + ** has unloaded may still call IOleClientSite::SaveObject. + ** in this case the container should fail the save call and + ** NOT try to reload the object. this scenario arises if you + ** have a in-process server (DLL object) which has a + ** connected linking client. even after the embedding + ** container unloads the DLL object, the link connection + ** keeps the object alive. it may then as part of its + ** shutdown try to call IOCS::SaveObject, but then it is too + ** late. + */ + OLEDBG_END2 + return ResultFromScode(E_FAIL); + } + + // mark ContainerDoc as now dirty + OutlineDoc_SetModified( + (LPOUTLINEDOC)lpContainerLine->m_lpDoc, TRUE, TRUE, FALSE); + + /* Tell OLE object to save itself + ** OLE2NOTE: it is NOT sufficient to ONLY call + ** IPersistStorage::Save method. it is also necessary to call + ** WriteClassStg. the helper API OleSave does this automatically. + */ + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr=OleSave(lpPersistStg,lpContainerLine->m_lpStg, TRUE/*fSameAsLoad*/); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + // OLE2NOTE: even if OleSave fails, SaveCompleted must be called. + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr = lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg, NULL); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleClientSite::GetMoniker +STDMETHODIMP CntrLine_CliSite_GetMoniker( + LPOLECLIENTSITE lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +) +{ + LPCONTAINERLINE lpContainerLine; + + lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OLEDBG_BEGIN2("CntrLine_CliSite_GetMoniker\r\n") + + // OLE2NOTE: we must make sure to set output pointer parameters to NULL + *lplpmk = NULL; + + switch (dwWhichMoniker) { + + case OLEWHICHMK_CONTAINER: + /* OLE2NOTE: create a FileMoniker which identifies the + ** entire container document. + */ + *lplpmk = OleDoc_GetFullMoniker( + (LPOLEDOC)lpContainerLine->m_lpDoc, + dwAssign + ); + break; + + case OLEWHICHMK_OBJREL: + + /* OLE2NOTE: create an ItemMoniker which identifies the + ** OLE object relative to the container document. + */ + *lplpmk = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign); + break; + + case OLEWHICHMK_OBJFULL: + { + /* OLE2NOTE: create an absolute moniker which identifies the + ** OLE object in the container document. this moniker is + ** created as a composite of the absolute moniker for the + ** entire document appended with an item moniker which + ** identifies the OLE object relative to the document. + */ + + *lplpmk = ContainerLine_GetFullMoniker(lpContainerLine, dwAssign); + break; + } + } + + OLEDBG_END2 + + if (*lplpmk != NULL) + return NOERROR; + else + return ResultFromScode(E_FAIL); +} + + +// IOleClientSite::GetContainer +STDMETHODIMP CntrLine_CliSite_GetContainer( + LPOLECLIENTSITE lpThis, + LPOLECONTAINER FAR* lplpContainer +) +{ + LPCONTAINERLINE lpContainerLine; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrLine_CliSite_GetContainer\r\n") + + lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + hrErr = OleDoc_QueryInterface( + (LPOLEDOC)lpContainerLine->m_lpDoc, + &IID_IOleContainer, + (LPVOID FAR*)lplpContainer + ); + + OLEDBG_END2 + return hrErr; +} + + +// IOleClientSite::ShowObject +STDMETHODIMP CntrLine_CliSite_ShowObject(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + HWND hWndFrame = OutlineApp_GetFrameWindow(g_lpApp); + + OLEDBG_BEGIN2("CntrLine_CliSite_ShowObject\r\n") + + /* make sure our doc window is visible and not minimized. + ** the OutlineDoc_ShowWindow function will cause the app window + ** to show itself SW_SHOWNORMAL. + */ + if (! IsWindowVisible(hWndFrame) || IsIconic(hWndFrame)) + OutlineDoc_ShowWindow(lpOutlineDoc); + + BringWindowToTop(hWndFrame); + + /* make sure that the OLE object is currently in view. if necessary + ** scroll the document in order to bring it into view. + */ + LineList_ScrollLineIntoView(lpLL, nIndex); + +#if defined( INPLACE_CNTR ) + /* after the in-place object is scrolled into view, we need to ask + ** it to update its rect for the new clip rect coordinates + */ + ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0); +#endif + + OLEDBG_END2 + return NOERROR; +} + + +// IOleClientSite::OnShowWindow +STDMETHODIMP CntrLine_CliSite_OnShowWindow(LPOLECLIENTSITE lpThis, BOOL fShow) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + + if (fShow) { + OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(TRUE)\r\n") + + /* OLE2NOTE: we need to hatch out the OLE object now; it has + ** just been opened in a window elsewhere (open editing as + ** opposed to in-place activation). + ** force the line to re-draw with the hatch. + */ + lpContainerLine->m_fObjWinOpen = TRUE; + LineList_ForceLineRedraw(lpLL, nIndex, FALSE /*fErase*/); + + } else { + OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(FALSE)\r\n") + + /* OLE2NOTE: the object associated with this container site has + ** just closed its server window. we should now remove the + ** hatching that indicates that the object is open + ** elsewhere. also our window should now come to the top. + ** force the line to re-draw without the hatch. + */ + lpContainerLine->m_fObjWinOpen = FALSE; + LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/); + + BringWindowToTop(lpOutlineDoc->m_hWndDoc); + SetFocus(lpOutlineDoc->m_hWndDoc); + } + + OLEDBG_END2 + return NOERROR; +} + + +// IOleClientSite::RequestNewObjectLayout +STDMETHODIMP CntrLine_CliSite_RequestNewObjectLayout(LPOLECLIENTSITE lpThis) +{ + OleDbgOut2("CntrLine_CliSite_RequestNewObjectLayout\r\n"); + + /* OLE2NOTE: this method is NOT yet used. it is for future layout + ** negotiation support. + */ + return ResultFromScode(E_NOTIMPL); +} + + +/************************************************************************* +** ContainerLine::IAdviseSink interface implementation +*************************************************************************/ + +// IAdviseSink::QueryInterface +STDMETHODIMP CntrLine_AdvSink_QueryInterface( + LPADVISESINK lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +// IAdviseSink::AddRef +STDMETHODIMP_(ULONG) CntrLine_AdvSink_AddRef(LPADVISESINK lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IAdviseSink"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +// IAdviseSink::Release +STDMETHODIMP_(ULONG) CntrLine_AdvSink_Release (LPADVISESINK lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IAdviseSink"); + + return ContainerLine_Release(lpContainerLine); +} + + +// IAdviseSink::OnDataChange +STDMETHODIMP_(void) CntrLine_AdvSink_OnDataChange( + LPADVISESINK lpThis, + FORMATETC FAR* lpFormatetc, + STGMEDIUM FAR* lpStgmed +) +{ + OleDbgOut2("CntrLine_AdvSink_OnDataChange\r\n"); + // We are not interested in data changes (only view changes) + // (ie. nothing to do) +} + + +STDMETHODIMP_(void) CntrLine_AdvSink_OnViewChange( + LPADVISESINK lpThis, + DWORD aspects, + LONG lindex +) +{ + LPCONTAINERLINE lpContainerLine; + LPOUTLINEDOC lpOutlineDoc; + HWND hWndDoc; + LPLINELIST lpLL; + MSG msg; + int nIndex; + + OLEDBG_BEGIN2("CntrLine_AdvSink_OnViewChange\r\n") + + lpContainerLine = ((struct CAdviseSinkImpl FAR*)lpThis)->lpContainerLine; + lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + + /* OLE2NOTE: at this point we simply invalidate the rectangle of + ** the object to force a repaint in the future, we mark + ** that the extents of the object may have changed + ** (m_fDoGetExtent=TRUE), and we post a message + ** (WM_U_UPDATEOBJECTEXTENT) to our document that one or more + ** OLE objects may need to have their extents updated. later + ** when this message is processed, the document loops through + ** all lines to see if any are marked as needing an extent update. + ** if infact the extents did change. this can be done by calling + ** IViewObject2::GetExtent to retreive the object's current + ** extents and comparing with the last known extents for the + ** object. if the extents changed, then relayout space for the + ** object before drawing. we postpone the check to get + ** the extents now because OnViewChange is an asyncronis method, + ** and we have to careful not to call any syncronis methods back + ** to the object. while it WOULD be OK to call the + ** IViewObject2::GetExtent method within the asyncronis + ** OnViewChange method (because this method is handled by the + ** object handler and never remoted), it is good practise to not + ** call any object methods from within an asyncronis + ** notification method. + ** if there is already WM_U_UPDATEOBJECTEXTENT message waiting + ** in our message queue, there is no need to post another one. + ** in this way, if the server is updating quicker than we can + ** keep up, we do not make unneccsary GetExtent calls. also if + ** drawing is disabled, we postpone updating the extents of any + ** objects until drawing is re-enabled. + */ + lpContainerLine->m_fDoGetExtent = TRUE; + hWndDoc = OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc); + + if (lpOutlineDoc->m_nDisableDraw == 0 && + ! PeekMessage(&msg, hWndDoc, + WM_U_UPDATEOBJECTEXTENT, WM_U_UPDATEOBJECTEXTENT, + PM_NOREMOVE | PM_NOYIELD)) { + PostMessage(hWndDoc, WM_U_UPDATEOBJECTEXTENT, 0, 0L); + } + + // force the modified line to redraw. + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/); + + OLEDBG_END2 +} + + +// IAdviseSink::OnRename +STDMETHODIMP_(void) CntrLine_AdvSink_OnRename( + LPADVISESINK lpThis, + LPMONIKER lpmk +) +{ + OleDbgOut2("CntrLine_AdvSink_OnRename\r\n"); + /* OLE2NOTE: the Embedding Container has nothing to do here. this + ** notification is important for linking situations. it tells + ** the OleLink objects to update their moniker because the + ** source object has been renamed (track the link source). + */ +} + + +// IAdviseSink::OnSave +STDMETHODIMP_(void) CntrLine_AdvSink_OnSave(LPADVISESINK lpThis) +{ + OleDbgOut2("CntrLine_AdvSink_OnSave\r\n"); + /* OLE2NOTE: the Embedding Container has nothing to do here. this + ** notification is only useful to clients which have set up a + ** data cache with the ADVFCACHE_ONSAVE flag. + */ +} + + +// IAdviseSink::OnClose +STDMETHODIMP_(void) CntrLine_AdvSink_OnClose(LPADVISESINK lpThis) +{ + OleDbgOut2("CntrLine_AdvSink_OnClose\r\n"); + /* OLE2NOTE: the Embedding Container has nothing to do here. this + ** notification is important for the OLE's default object handler + ** and the OleLink object. it tells them the remote object is + ** shutting down. + */ +} + + +/************************************************************************* +** ContainerLine Support Functions +*************************************************************************/ + + +/* ContainerLine_Init +** ------------------ +** Initialize fields in a newly constructed ContainerLine line object. +** NOTE: ref cnt of ContainerLine initialized to 0 +*/ +void ContainerLine_Init(LPCONTAINERLINE lpContainerLine, int nTab, HDC hDC) +{ + Line_Init((LPLINE)lpContainerLine, nTab, hDC); // init base class fields + + ((LPLINE)lpContainerLine)->m_lineType = CONTAINERLINETYPE; + ((LPLINE)lpContainerLine)->m_nWidthInHimetric = DEFOBJWIDTH; + ((LPLINE)lpContainerLine)->m_nHeightInHimetric = DEFOBJHEIGHT; + lpContainerLine->m_cRef = 0; + lpContainerLine->m_szStgName[0] = '\0'; + lpContainerLine->m_fObjWinOpen = FALSE; + lpContainerLine->m_fMonikerAssigned = FALSE; + lpContainerLine->m_dwDrawAspect = DVASPECT_CONTENT; + + lpContainerLine->m_fGuardObj = FALSE; + lpContainerLine->m_fDoGetExtent = FALSE; + lpContainerLine->m_fDoSetExtent = FALSE; + lpContainerLine->m_sizeInHimetric.cx = -1; + lpContainerLine->m_sizeInHimetric.cy = -1; + + lpContainerLine->m_lpStg = NULL; + lpContainerLine->m_lpDoc = NULL; + lpContainerLine->m_lpOleObj = NULL; + lpContainerLine->m_lpViewObj2 = NULL; + lpContainerLine->m_lpPersistStg = NULL; + lpContainerLine->m_lpOleLink = NULL; + lpContainerLine->m_dwLinkType = 0; + lpContainerLine->m_fLinkUnavailable = FALSE; + lpContainerLine->m_lpszShortType = NULL; + +#if defined( INPLACE_CNTR ) + lpContainerLine->m_fIpActive = FALSE; + lpContainerLine->m_fUIActive = FALSE; + lpContainerLine->m_fIpVisible = FALSE; + lpContainerLine->m_lpOleIPObj = NULL; + lpContainerLine->m_fInsideOutObj = FALSE; + lpContainerLine->m_fIpChangesUndoable = FALSE; + lpContainerLine->m_fIpServerRunning = FALSE; + lpContainerLine->m_hWndIpObject = NULL; + lpContainerLine->m_nHorizScrollShift = 0; +#endif // INPLACE_CNTR + + INIT_INTERFACEIMPL( + &lpContainerLine->m_Unknown, + &g_CntrLine_UnknownVtbl, + lpContainerLine + ); + + INIT_INTERFACEIMPL( + &lpContainerLine->m_OleClientSite, + &g_CntrLine_OleClientSiteVtbl, + lpContainerLine + ); + + INIT_INTERFACEIMPL( + &lpContainerLine->m_AdviseSink, + &g_CntrLine_AdviseSinkVtbl, + lpContainerLine + ); + +#if defined( INPLACE_CNTR ) + INIT_INTERFACEIMPL( + &lpContainerLine->m_OleInPlaceSite, + &g_CntrLine_OleInPlaceSiteVtbl, + lpContainerLine + ); +#endif // INPLACE_CNTR +} + + +/* Setup the OLE object associated with the ContainerLine */ +BOOL ContainerLine_SetupOleObject( + LPCONTAINERLINE lpContainerLine, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict +) +{ + DWORD dwDrawAspect = (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT); + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + + /* Cache a pointer to the IViewObject2* interface. *Required* + ** we need this everytime we draw the object. + ** + ** OLE2NOTE: We require the object to support IViewObject2 + ** interface. this is an extension to the IViewObject interface + ** that was added with the OLE 2.01 release. This interface must + ** be supported by all object handlers and DLL-based objects. + */ + lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2); + if (! lpContainerLine->m_lpViewObj2) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n"); +#endif + return FALSE; + } + + // Cache a pointer to the IPersistStorage* interface. *Required* + // we need this everytime we save the object. + lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage); + if (! lpContainerLine->m_lpPersistStg) { + OleDbgAssert(lpContainerLine->m_lpPersistStg); + return FALSE; + } + + // Cache a pointer to the IOleLink* interface if supported. *Optional* + // if supported the object is a link. we need this to manage the link + lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink); + if (lpContainerLine->m_lpOleLink) { + OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n") + lpContainerLine->m_lpOleLink->lpVtbl->GetUpdateOptions( + lpContainerLine->m_lpOleLink, &lpContainerLine->m_dwLinkType); + OLEDBG_END2 + } else + lpContainerLine->m_dwLinkType = 0; // NOT a link + + /* get the short user type name of the object. this + ** is used all the time when we have to build the object + ** verb menu. we will cache this information to make it + ** quicker to build the verb menu. + */ + OleDbgAssert(lpContainerLine->m_lpszShortType == NULL); + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + + CallIOleObjectGetUserTypeA( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_SHORT, + &lpContainerLine->m_lpszShortType + ); + + OLEDBG_END2 + + /* Perform that standard setup for the OLE object. this includes: + ** setup View advise + ** Call IOleObject::SetHostNames + ** Call OleSetContainedObject + */ + OleStdSetupAdvises( + lpContainerLine->m_lpOleObj, + dwDrawAspect, + (LPSTR)APPNAME, + lpOutlineDoc->m_lpszDocTitle, + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + TRUE /*fCreate*/ + ); + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: (INSIDE-OUT CONTAINER) An inside-out container should + ** check if the object is an inside-out and prefers to be + ** activated when visible type of object. if not the object + ** should not be allowed to keep its window up after it gets + ** UIDeactivated. + */ + if (g_fInsideOutContainer) { + DWORD mstat; + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, + (DWORD FAR*)&mstat + ); + OLEDBG_END2 + + lpContainerLine->m_fInsideOutObj = (BOOL) + (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)); + } +#endif // INPLACE_CNTR + + if (fDisplayAsIcon) { + /* user has requested to display icon aspect instead of content + ** aspect. + ** NOTE: we do not have to delete the previous aspect cache + ** because one did not get set up. + */ + OleStdSwitchDisplayAspect( + lpContainerLine->m_lpOleObj, + &lpContainerLine->m_dwDrawAspect, + dwDrawAspect, + hMetaPict, + FALSE, /* fDeleteOldAspect */ + TRUE, /* fSetupViewAdvise */ + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + NULL /*fMustUpdate*/ // this can be ignored; update + // for switch to icon not req'd + ); + } + return TRUE; +} + + +/* Create an ContainerLine object and return the pointer */ +LPCONTAINERLINE ContainerLine_Create( + DWORD dwOleCreateType, + HDC hDC, + UINT nTab, + LPCONTAINERDOC lpContainerDoc, + LPCLSID lpclsid, + LPSTR lpszFileName, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSTR lpszStgName +) +{ + LPCONTAINERLINE lpContainerLine = NULL; + LPOLEOBJECT lpObj = NULL; + LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerDoc); + DWORD dwDrawAspect = + (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT); + DWORD dwOleRenderOpt = + (fDisplayAsIcon ? OLERENDER_NONE : OLERENDER_DRAW); + HRESULT hrErr; + + OLEDBG_BEGIN3("ContainerLine_Create\r\n") + + if (lpDocStg == NULL) { + OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL"); + goto error; + } + + lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpContainerLine == NULL) { + OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine"); + goto error; + } + + ContainerLine_Init(lpContainerLine, nTab, hDC); + + /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to + ** guard our object. if this guard is set, then the object is + ** not ready to have any OLE interface methods called. it is + ** necessary to guard the object this way while it is being + ** created or loaded. + */ + lpContainerLine->m_fGuardObj = TRUE; + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpContainerLine); + + lstrcpy(lpContainerLine->m_szStgName, lpszStgName); + lpContainerLine->m_lpDoc = lpContainerDoc; + + /* Create a new storage for the object inside the doc's storage */ + lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName); + if (lpContainerLine->m_lpStg == NULL) { + OleDbgAssert(lpContainerLine->m_lpStg != NULL); + goto error; + } + + lpContainerLine->m_dwLinkType = 0; + + switch (dwOleCreateType) { + + case IOF_SELECTCREATENEW: + + OLEDBG_BEGIN2("OleCreate called\r\n") + hrErr = OleCreate ( + lpclsid, + &IID_IOleObject, + dwOleRenderOpt, + NULL, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreate returned", hrErr); +#endif + + break; + + case IOF_SELECTCREATEFROMFILE: + + OLEDBG_BEGIN2("OleCreateFromFile called\r\n") + + hrErr = OleCreateFromFileA( + &CLSID_NULL, + lpszFileName, + &IID_IOleObject, + dwOleRenderOpt, + NULL, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateFromFile returned", hrErr); +#endif + break; + + case IOF_CHECKLINK: + + OLEDBG_BEGIN2("OleCreateLinkToFile called\r\n") + + hrErr = OleCreateLinkToFileA( + lpszFileName, + &IID_IOleObject, + dwOleRenderOpt, + NULL, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateLinkToFile returned", hrErr); +#endif + break; + } + if (hrErr != NOERROR) + goto error; + + if (! ContainerLine_SetupOleObject( + lpContainerLine, fDisplayAsIcon, hMetaPict)) { + goto error; + } + + /* OLE2NOTE: clear our re-entrancy guard. the object is now ready + ** to have interface methods called. + */ + lpContainerLine->m_fGuardObj = FALSE; + + OLEDBG_END3 + return lpContainerLine; + +error: + OutlineApp_ErrorMessage(g_lpApp, "Could not create object!"); + + // Destroy partially created OLE object + if (lpContainerLine) + ContainerLine_Delete(lpContainerLine); + OLEDBG_END3 + return NULL; +} + + +LPCONTAINERLINE ContainerLine_CreateFromData( + HDC hDC, + UINT nTab, + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + DWORD dwCreateType, + CLIPFORMAT cfFormat, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSTR lpszStgName +) +{ + HGLOBAL hData = NULL; + LPCONTAINERLINE lpContainerLine = NULL; + LPOLEOBJECT lpObj = NULL; + LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerDoc); + DWORD dwDrawAspect = + (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT); + DWORD dwOleRenderOpt; + FORMATETC renderFmtEtc; + LPFORMATETC lpRenderFmtEtc = NULL; + HRESULT hrErr; + LPUNKNOWN lpUnk = NULL; + + OLEDBG_BEGIN3("ContainerLine_CreateFromData\r\n") + + if (dwCreateType == OLECREATEFROMDATA_STATIC && cfFormat != 0) { + // a particular type of static object should be created + + dwOleRenderOpt = OLERENDER_FORMAT; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + + if (cfFormat == CF_METAFILEPICT) + SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_MFPICT); + else if (cfFormat == CF_BITMAP) + SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_GDI); + else + SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_HGLOBAL); + + } else if (dwCreateType == OLECREATEFROMDATA_STATIC && fDisplayAsIcon) { + // a link that currently displayed as an icon needs to be + // converted to a STATIC picture object. this case is driven + // from "BreakLink" in the "Links" dialog. because the current + // data in the source object's cache is DVASPECT_ICON we need + // to tell the OleCreateStaticFromData API to look for + // DVASPECT_ICON data. the static object that results however, + // is considered to be displayed in the DVASPECT_CONTENT view. + + dwOleRenderOpt = OLERENDER_DRAW; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1); + dwDrawAspect = DVASPECT_CONTENT; // static obj displays only CONTENT + + } else if (fDisplayAsIcon && hMetaPict) { + // a special icon should be used. first we create the object + // OLERENDER_NONE and then we stuff the special icon into the cache. + + dwOleRenderOpt = OLERENDER_NONE; + + } else if (fDisplayAsIcon && hMetaPict == NULL) { + // the object's default icon should be used + + dwOleRenderOpt = OLERENDER_DRAW; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1); + + } else { + // create standard DVASPECT_CONTENT/OLERENDER_DRAW object + dwOleRenderOpt = OLERENDER_DRAW; + } + + if (lpDocStg == NULL) { + OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL"); + goto error; + } + + lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpContainerLine == NULL) { + OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine"); + goto error; + } + + ContainerLine_Init(lpContainerLine, nTab, hDC); + + /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to + ** guard our object. if this guard is set, then the object is + ** not ready to have any OLE interface methods called. it is + ** necessary to guard the object this way while it is being + ** created or loaded. + */ + lpContainerLine->m_fGuardObj = TRUE; + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpContainerLine); + + lstrcpy(lpContainerLine->m_szStgName, lpszStgName); + lpContainerLine->m_lpDoc = lpContainerDoc; + + /* Create a new storage for the object inside the doc's storage */ + lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName); + if (lpContainerLine->m_lpStg == NULL) { + OleDbgAssert(lpContainerLine->m_lpStg != NULL); + goto error; + } + + switch (dwCreateType) { + + case OLECREATEFROMDATA_LINK: + + OLEDBG_BEGIN2("OleCreateLinkFromData called\r\n") + hrErr = OleCreateLinkFromData ( + lpSrcDataObj, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateLinkFromData returned", hrErr); +#endif + break; + + case OLECREATEFROMDATA_OBJECT: + + OLEDBG_BEGIN2("OleCreateFromData called\r\n") + hrErr = OleCreateFromData ( + lpSrcDataObj, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateFromData returned", hrErr); +#endif + break; + + case OLECREATEFROMDATA_STATIC: + + OLEDBG_BEGIN2("OleCreateStaticFromData called\r\n") + hrErr = OleCreateStaticFromData ( + lpSrcDataObj, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateStaticFromData returned", hrErr); +#endif + break; + } + + if (hrErr != NOERROR) + goto error; + + if (! ContainerLine_SetupOleObject( + lpContainerLine, fDisplayAsIcon, hMetaPict)) { + goto error; + } + + /* OLE2NOTE: clear our re-entrancy guard. the object is now ready + ** to have interface methods called. + */ + lpContainerLine->m_fGuardObj = FALSE; + + OLEDBG_END3 + return lpContainerLine; + +error: + OutlineApp_ErrorMessage(g_lpApp, "Could not create object!"); + // Destroy partially created OLE object + if (lpContainerLine) + ContainerLine_Delete(lpContainerLine); + OLEDBG_END3 + return NULL; +} + + +/* ContainerLine_AddRef +** -------------------- +** +** increment the ref count of the line object. +** +** Returns the new ref count on the object +*/ +ULONG ContainerLine_AddRef(LPCONTAINERLINE lpContainerLine) +{ + ++lpContainerLine->m_cRef; + +#if defined( _DEBUG ) + OleDbgOutRefCnt4( + "ContainerLine_AddRef: cRef++\r\n", + lpContainerLine, + lpContainerLine->m_cRef + ); +#endif + return lpContainerLine->m_cRef; +} + + +/* ContainerLine_Release +** --------------------- +** +** decrement the ref count of the line object. +** if the ref count goes to 0, then the line is destroyed. +** +** Returns the remaining ref count on the object +*/ +ULONG ContainerLine_Release(LPCONTAINERLINE lpContainerLine) +{ + ULONG cRef; + + /********************************************************************* + ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. ** + ** otherwise the object is still in use. ** + *********************************************************************/ + + cRef = --lpContainerLine->m_cRef; + +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_cRef >= 0,"Release called with cRef == 0"); + + OleDbgOutRefCnt4( + "ContainerLine_Release: cRef--\r\n", + lpContainerLine, + cRef + ); +#endif + if (cRef == 0) + ContainerLine_Destroy(lpContainerLine); + + return cRef; +} + + +/* ContainerLine_QueryInterface +** ---------------------------- +** +** Retrieve a pointer to an interface on the ContainerLine object. +** +** Returns NOERROR if interface is successfully retrieved. +** E_NOINTERFACE if the interface is not supported +*/ +HRESULT ContainerLine_QueryInterface( + LPCONTAINERLINE lpContainerLine, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + SCODE sc = E_NOINTERFACE; + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) { + OleDbgOut4("ContainerLine_QueryInterface: IUnknown* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_Unknown; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } + else if (IsEqualIID(riid, &IID_IOleClientSite)) { + OleDbgOut4("ContainerLine_QueryInterface: IOleClientSite* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_OleClientSite; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } + else if (IsEqualIID(riid, &IID_IAdviseSink)) { + OleDbgOut4("ContainerLine_QueryInterface: IAdviseSink* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_AdviseSink; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } +#if defined( INPLACE_CNTR ) + else if (IsEqualIID(riid, &IID_IOleWindow) + || IsEqualIID(riid, &IID_IOleInPlaceSite)) { + OleDbgOut4("ContainerLine_QueryInterface: IOleInPlaceSite* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_OleInPlaceSite; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } +#endif // INPLACE_CNTR + + OleDbgQueryInterfaceMethod(*lplpvObj); + + return ResultFromScode(sc); +} + + +BOOL ContainerLine_LoadOleObject(LPCONTAINERLINE lpContainerLine) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerLine->m_lpDoc); + LPOLECLIENTSITE lpOleClientSite; + LPMONIKER lpmkObj; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + HRESULT hrErr; + + if (lpContainerLine->m_fGuardObj) + return FALSE; // object in process of creation + + if (lpContainerLine->m_lpOleObj) + return TRUE; // object already loaded + + OLEDBG_BEGIN3("ContainerLine_LoadOleObject\r\n") + + /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to + ** guard our object. if this guard is set, then the object is + ** not ready to have any OLE interface methods called. it is + ** necessary to guard the object this way while it is being + ** created or loaded. + */ + lpContainerLine->m_fGuardObj = TRUE; + + /* if object storage is not already open, then open it */ + if (! lpContainerLine->m_lpStg) { + lpContainerLine->m_lpStg = OleStdOpenChildStorage( + lpDocStg, + lpContainerLine->m_szStgName, + STGM_READWRITE + ); + if (lpContainerLine->m_lpStg == NULL) { + OleDbgAssert(lpContainerLine->m_lpStg != NULL); + goto error; + } + } + + /* OLE2NOTE: if the OLE object being loaded is in a data transfer + ** document, then we should NOT pass a IOleClientSite* pointer + ** to the OleLoad call. This particularly critical if the OLE + ** object is an OleLink object. If a non-NULL client site is + ** passed to the OleLoad function, then the link will bind to + ** the source if its is running. in the situation that we are + ** loading the object as part of a data transfer document we do + ** not want this connection to be established. even worse, if + ** the link source is currently blocked or busy, then this could + ** hang the system. it is simplest to never pass a + ** IOleClientSite* when loading an object in a data transfer + ** document. + */ + lpOleClientSite = (lpOutlineDoc->m_fDataTransferDoc ? + NULL : (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite); + + /* OLE2NOTE: we do not want to ever give the Busy/NotResponding + ** dialogs when we are loading an object. if the object is a + ** link, it will attempt to BindIfRunning to the link source. if + ** the link source is currently busy, this could cause the Busy + ** dialog to come up. even if the link source is busy, + ** we do not want put up the busy dialog. thus we will disable + ** the dialog and later re-enable them + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + OLEDBG_BEGIN2("OleLoad called\r\n") + hrErr = OleLoad ( + lpContainerLine->m_lpStg, + &IID_IOleObject, + lpOleClientSite, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr == NOERROR, "Could not load object!"); + OleDbgOutHResult("OleLoad returned", hrErr); + goto error; + } + + /* Cache a pointer to the IViewObject2* interface. *Required* + ** we need this everytime we draw the object. + ** + ** OLE2NOTE: We require the object to support IViewObject2 + ** interface. this is an extension to the IViewObject interface + ** that was added with the OLE 2.01 release. This interface must + ** be supported by all object handlers and DLL-based objects. + */ + lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2); + if (! lpContainerLine->m_lpViewObj2) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n"); +#endif + goto error; + } + + // Cache a pointer to the IPersistStorage* interface. *Required* + // we need this everytime we save the object. + lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage); + if (! lpContainerLine->m_lpPersistStg) { + OleDbgAssert(lpContainerLine->m_lpPersistStg); + goto error; + } + + // Cache a pointer to the IOleLink* interface if supported. *Optional* + // if supported the object is a link. we need this to manage the link + if (lpContainerLine->m_dwLinkType != 0) { + lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink); + if (! lpContainerLine->m_lpOleLink) { + OleDbgAssert(lpContainerLine->m_lpOleLink); + goto error; + } + } + + /* OLE2NOTE: clear our re-entrancy guard. the object is now ready + ** to have interface methods called. + */ + lpContainerLine->m_fGuardObj = FALSE; + + /* OLE2NOTE: similarly, if the OLE object being loaded is in a data + ** transfer document, then we do NOT need to setup any advises, + ** call SetHostNames, SetMoniker, etc. + */ + if (lpOleClientSite) { + /* Setup the Advises (OLE notifications) that we are interested + ** in receiving. + */ + OleStdSetupAdvises( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSTR)APPNAME, + lpOutlineDoc->m_lpszDocTitle, + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + FALSE /*fCreate*/ + ); + + /* OLE2NOTE: if the OLE object has a moniker assigned, we need to + ** inform the object by calling IOleObject::SetMoniker. this + ** will force the OLE object to register in the + ** RunningObjectTable when it enters the running state. + */ + if (lpContainerLine->m_fMonikerAssigned) { + lpmkObj = ContainerLine_GetRelMoniker( + lpContainerLine, + GETMONIKER_ONLYIFTHERE + ); + + if (lpmkObj) { + OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( + lpContainerLine->m_lpOleObj, + OLEWHICHMK_OBJREL, + lpmkObj + ); + OLEDBG_END2 + OleStdRelease((LPUNKNOWN)lpmkObj); + } + } + + /* get the Short form of the user type name of the object. this + ** is used all the time when we have to build the object + ** verb menu. we will cache this information to make it + ** quicker to build the verb menu. + */ + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + CallIOleObjectGetUserTypeA( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_SHORT, + &lpContainerLine->m_lpszShortType + ); + + OLEDBG_END2 + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: an inside-out container should check if the object + ** is an inside-out and prefers to be activated when visible + ** type of object. if so, the object should be immediately + ** activated in-place, BUT NOT UIActived. + */ + if (g_fInsideOutContainer && + lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) { + DWORD mstat; + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, + (DWORD FAR*)&mstat + ); + OLEDBG_END2 + + lpContainerLine->m_fInsideOutObj = (BOOL) + (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)); + + if ( lpContainerLine->m_fInsideOutObj ) { + HWND hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc); + + ContainerLine_DoVerb( + lpContainerLine, + OLEIVERB_INPLACEACTIVATE, + NULL, + FALSE, + FALSE + ); + + /* OLE2NOTE: following this DoVerb(INPLACEACTIVATE) the + ** object may have taken focus. but because the + ** object is NOT UIActive it should NOT have focus. + ** we will make sure our document has focus. + */ + SetFocus(hWndDoc); + } + } +#endif // INPLACE_CNTR + OLEDBG_END2 + + } + + OLEDBG_END2 + return TRUE; + +error: + OLEDBG_END2 + return FALSE; +} + + +/* ContainerLine_CloseOleObject +** ---------------------------- +** Close the OLE object associated with the ContainerLine. +** +** Closing the object forces the object to transition from the +** running state to the loaded state. if the object was not running, +** then there is no effect. it is necessary to close the OLE object +** before releasing the pointers to the OLE object. +** +** Returns TRUE if successfully closed, +** FALSE if closing was aborted. +*/ +BOOL ContainerLine_CloseOleObject( + LPCONTAINERLINE lpContainerLine, + DWORD dwSaveOption +) +{ + HRESULT hrErr; + SCODE sc; + + if (lpContainerLine->m_fGuardObj) + return FALSE; // object in process of creation + + if (! lpContainerLine->m_lpOleObj) + return TRUE; // object is NOT loaded + + OLEDBG_BEGIN2("IOleObject::Close called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Close( + lpContainerLine->m_lpOleObj, + (dwSaveOption == OLECLOSE_NOSAVE ? + OLECLOSE_NOSAVE : OLECLOSE_SAVEIFDIRTY) + ); + OLEDBG_END2 + +#if defined( INPLACE_CNTR ) + if (lpContainerLine->m_fIpServerRunning) { + /* OLE2NOTE: unlock the lock held on the in-place object. + ** it is VERY important that an in-place container + ** that also support linking to embeddings properly manage + ** the running of its in-place objects. in an outside-in + ** style in-place container, when the user clicks + ** outside of the in-place active object, the object gets + ** UIDeactivated and the object hides its window. in order + ** to make the object fast to reactivate, the container + ** deliberately does not call IOleObject::Close. the object + ** stays running in the invisible unlocked state. the idea + ** here is if the user simply clicks outside of the object + ** and then wants to double click again to re-activate the + ** object, we do not want this to be slow. if we want to + ** keep the object running, however, we MUST Lock it + ** running. otherwise the object will be in an unstable + ** state where if a linking client does a "silent-update" + ** (eg. UpdateNow from the Links dialog), then the in-place + ** server will shut down even before the object has a chance + ** to be saved back in its container. this saving normally + ** occurs when the in-place container closes the object. also + ** keeping the object in the unstable, hidden, running, + ** not-locked state can cause problems in some scenarios. + ** ICntrOtl keeps only one object running. if the user + ** intiates a DoVerb on another object, then that last + ** running in-place active object is closed. a more + ** sophistocated in-place container may keep more object running. + ** (see CntrLine_IPSite_OnInPlaceActivate) + */ + lpContainerLine->m_fIpServerRunning = FALSE; + + OLEDBG_BEGIN2("OleLockRunning(FALSE,TRUE) called\r\n") + OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleObj, FALSE, TRUE); + OLEDBG_END2 + } +#endif + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleObject::Close returned", hrErr); + sc = GetScode(hrErr); + if (sc == RPC_E_CALL_REJECTED || sc==OLE_E_PROMPTSAVECANCELLED) + return FALSE; // object aborted shutdown + } + return TRUE; +} + + +/* ContainerLine_UnloadOleObject +** ----------------------------- +** Close the OLE object associated with the ContainerLine and +** release all pointer held to the object. +** +** Closing the object forces the object to transition from the +** running state to the loaded state. if the object was not running, +** then there is no effect. it is necessary to close the OLE object +** before releasing the pointers to the OLE object. releasing all +** pointers to the object allows the object to transition from +** loaded to unloaded (or passive). +*/ +void ContainerLine_UnloadOleObject( + LPCONTAINERLINE lpContainerLine, + DWORD dwSaveOption +) +{ + if (lpContainerLine->m_lpOleObj) { + + OLEDBG_BEGIN2("IOleObject::Close called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->Close( + lpContainerLine->m_lpOleObj, dwSaveOption); + OLEDBG_END2 + + /* OLE2NOTE: we will take our IOleClientSite* pointer away from + ** the object before we release all pointers to the object. + ** in the scenario where the object is implemented as an + ** in-proc server (DLL object), then, if there are link + ** connections to the DLL object, it is possible that the + ** object will not be destroyed when we release our pointers + ** to the object. the existance of the remote link + ** connections will hold the object alive. later when these + ** strong connections are released, then the object may + ** attempt to call IOleClientSite::Save if we had not taken + ** away the client site pointer. + */ + OLEDBG_BEGIN2("IOleObject::SetClientSite(NULL) called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetClientSite( + lpContainerLine->m_lpOleObj, NULL); + OLEDBG_END2 + + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleObj); + lpContainerLine->m_lpOleObj = NULL; + + if (lpContainerLine->m_lpViewObj2) { + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpViewObj2); + lpContainerLine->m_lpViewObj2 = NULL; + } + if (lpContainerLine->m_lpPersistStg) { + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpPersistStg); + lpContainerLine->m_lpPersistStg = NULL; + } + + if (lpContainerLine->m_lpOleLink) { + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleLink); + lpContainerLine->m_lpOleLink = NULL; + } + } + + if (lpContainerLine->m_lpszShortType) { + OleStdFreeString(lpContainerLine->m_lpszShortType, NULL); + lpContainerLine->m_lpszShortType = NULL; + } +} + + +/* ContainerLine_Delete +** -------------------- +** Delete the ContainerLine. +** +** NOTE: we can NOT directly destroy the memory for the +** ContainerLine; the ContainerLine maintains a reference count. a +** non-zero reference count indicates that the object is still +** in-use. The OleObject keeps a reference-counted pointer to the +** ClientLine object. we must take the actions necessary so that the +** ContainerLine object receives Releases for outstanding +** references. when the reference count of the ContainerLine reaches +** zero, then the memory for the object will actually be destroyed +** (ContainerLine_Destroy called). +** +*/ +void ContainerLine_Delete(LPCONTAINERLINE lpContainerLine) +{ + OLEDBG_BEGIN2("ContainerLine_Delete\r\n") + +#if defined( INPLACE_CNTR ) + if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastIpActiveLine) + lpContainerLine->m_lpDoc->m_lpLastIpActiveLine = NULL; + if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine) + lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL; +#endif + + /* OLE2NOTE: in order to have a stable line object during the + ** process of deleting, we intially AddRef the line ref cnt and + ** later Release it. This initial AddRef is artificial; it is + ** simply done to guarantee that our object does not destroy + ** itself until the END of this routine. + */ + ContainerLine_AddRef(lpContainerLine); + + // Unload the loaded OLE object + if (lpContainerLine->m_lpOleObj) + ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_NOSAVE); + + /* OLE2NOTE: we can NOT directly free the memory for the ContainerLine + ** data structure until everyone holding on to a pointer to our + ** ClientSite interface and IAdviseSink interface has released + ** their pointers. There is one refcnt on the ContainerLine object + ** which is held by the container itself. we will release this + ** refcnt here. + */ + ContainerLine_Release(lpContainerLine); + + /* OLE2NOTE: this call forces all external connections to our + ** ContainerLine to close down and therefore guarantees that + ** we receive all releases associated with those external + ** connections. Strictly this call should NOT be necessary, but + ** it is defensive coding to make this call. + */ + OLEDBG_BEGIN2("CoDisconnectObject(lpContainerLine) called\r\n") + CoDisconnectObject((LPUNKNOWN)&lpContainerLine->m_Unknown, 0); + OLEDBG_END2 + +#if defined( _DEBUG ) + /* at this point the object all references from the OLE object to + ** our ContainerLine object should have been released. there + ** should only be 1 remaining reference that will be released below. + */ + if (lpContainerLine->m_cRef != 1) { + OleDbgOutRefCnt( + "WARNING: ContainerLine_Delete: cRef != 1\r\n", + lpContainerLine, + lpContainerLine->m_cRef + ); + } +#endif + + ContainerLine_Release(lpContainerLine); // release artificial AddRef above + OLEDBG_END2 +} + + +/* ContainerLine_Destroy +** --------------------- +** Destroy (Free) the memory used by a ContainerLine structure. +** This function is called when the ref count of the ContainerLine goes +** to zero. the ref cnt goes to zero after ContainerLine_Delete forces +** the OleObject to unload and release its pointers to the +** ContainerLine IOleClientSite and IAdviseSink interfaces. +*/ + +void ContainerLine_Destroy(LPCONTAINERLINE lpContainerLine) +{ + LPUNKNOWN lpTmpObj; + + OLEDBG_BEGIN2("ContainerLine_Destroy\r\n") + + // Release the storage opened for the OLE object + if (lpContainerLine->m_lpStg) { + lpTmpObj = (LPUNKNOWN)lpContainerLine->m_lpStg; + lpContainerLine->m_lpStg = NULL; + + OleStdRelease(lpTmpObj); + } + + if (lpContainerLine->m_lpszShortType) { + OleStdFreeString(lpContainerLine->m_lpszShortType, NULL); + lpContainerLine->m_lpszShortType = NULL; + } + + Delete(lpContainerLine); // Free the memory for the structure itself + OLEDBG_END2 +} + + +/* ContainerLine_CopyToDoc + * ----------------------- + * + * Copy a ContainerLine to another Document (usually ClipboardDoc) + */ +BOOL ContainerLine_CopyToDoc( + LPCONTAINERLINE lpSrcLine, + LPOUTLINEDOC lpDestDoc, + int nIndex +) +{ + LPCONTAINERLINE lpDestLine = NULL; + LPLINELIST lpDestLL = &lpDestDoc->m_LineList; + HDC hDC; + HRESULT hrErr; + BOOL fStatus; + LPSTORAGE lpDestDocStg = ((LPOLEDOC)lpDestDoc)->m_lpStg; + LPSTORAGE lpDestObjStg = NULL; + + lpDestLine = (LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpDestLine == NULL) { + OleDbgAssertSz(lpDestLine!=NULL, "Error allocating ContainerLine"); + return FALSE; + } + + hDC = LineList_GetDC(lpDestLL); + ContainerLine_Init(lpDestLine, ((LPLINE)lpSrcLine)->m_nTabLevel, hDC); + LineList_ReleaseDC(lpDestLL, hDC); + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpDestLine); + + lpDestLine->m_lpDoc = (LPCONTAINERDOC)lpDestDoc; + + // Copy data of the original source ContainerLine. + ((LPLINE)lpDestLine)->m_nWidthInHimetric = + ((LPLINE)lpSrcLine)->m_nWidthInHimetric; + ((LPLINE)lpDestLine)->m_nHeightInHimetric = + ((LPLINE)lpSrcLine)->m_nHeightInHimetric; + lpDestLine->m_fMonikerAssigned = lpSrcLine->m_fMonikerAssigned; + lpDestLine->m_dwDrawAspect = lpSrcLine->m_dwDrawAspect; + lpDestLine->m_sizeInHimetric = lpSrcLine->m_sizeInHimetric; + lpDestLine->m_dwLinkType = lpSrcLine->m_dwLinkType; + + + /* We must create a new sub-storage for the embedded object within + ** the destination document's storage. We will first attempt to + ** use the same storage name as the source line. if this name is + ** in use, then we will allocate a new name. in this way we try + ** to keep the name associated with the OLE object unchanged + ** through a Cut/Paste operation. + */ + lpDestObjStg = OleStdCreateChildStorage( + lpDestDocStg, + lpSrcLine->m_szStgName + ); + if (lpDestObjStg) { + lstrcpy(lpDestLine->m_szStgName, lpSrcLine->m_szStgName); + } else { + /* the original name was in use, make up a new name. */ + ContainerDoc_GetNextStgName( + (LPCONTAINERDOC)lpDestDoc, + lpDestLine->m_szStgName, + sizeof(lpDestLine->m_szStgName) + ); + lpDestObjStg = OleStdCreateChildStorage( + lpDestDocStg, + lpDestLine->m_szStgName + ); + } + if (lpDestObjStg == NULL) { + OleDbgAssertSz(lpDestObjStg != NULL, "Error creating child stg"); + goto error; + } + + // Copy over storage of the embedded object itself + + if (! lpSrcLine->m_lpOleObj) { + + /***************************************************************** + ** CASE 1: object is NOT loaded. + ** because the object is not loaded, we can simply copy the + ** object's current storage to the new storage. + *****************************************************************/ + + /* if current object storage is not already open, then open it */ + if (! lpSrcLine->m_lpStg) { + LPSTORAGE lpSrcDocStg = ((LPOLEDOC)lpSrcLine->m_lpDoc)->m_lpStg; + + if (! lpSrcDocStg) goto error; + + // open object storage. + lpSrcLine->m_lpStg = OleStdOpenChildStorage( + lpSrcDocStg, + lpSrcLine->m_szStgName, + STGM_READWRITE + ); + if (lpSrcLine->m_lpStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpSrcLine->m_lpStg != NULL, + "Error opening child stg" + ); +#endif + goto error; + } + } + + hrErr = lpSrcLine->m_lpStg->lpVtbl->CopyTo( + lpSrcLine->m_lpStg, + 0, + NULL, + NULL, + lpDestObjStg + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: lpSrcObjStg->CopyTo returned", hrErr); + goto error; + } + + fStatus = OleStdCommitStorage(lpDestObjStg); + + } else { + + /***************************************************************** + ** CASE 2: object IS loaded. + ** we must tell the object to save into the new storage. + *****************************************************************/ + + SCODE sc = S_OK; + LPPERSISTSTORAGE lpPersistStg = lpSrcLine->m_lpPersistStg; + OleDbgAssert(lpPersistStg); + + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr = OleSave(lpPersistStg, lpDestObjStg, FALSE /*fSameAsLoad*/); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + // OLE2NOTE: even if OleSave fails, SaveCompleted must be called. + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + if (sc != S_OK) + goto error; + + } + + OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex); + OleStdVerifyRelease( + (LPUNKNOWN)lpDestObjStg, + "Copied object stg not released" + ); + + return TRUE; + +error: + + // Delete any partially created storage. + if (lpDestObjStg) { + + OleStdVerifyRelease( + (LPUNKNOWN)lpDestObjStg, + "Copied object stg not released" + ); + + CallIStorageDestroyElementA( + lpDestDocStg, + lpDestLine->m_szStgName + ); + + lpDestLine->m_szStgName[0] = '\0'; + } + + // destroy partially created ContainerLine + if (lpDestLine) + ContainerLine_Delete(lpDestLine); + return FALSE; +} + + +/* ContainerLine_UpdateExtent +** -------------------------- +** Update the size of the ContainerLine because the extents of the +** object may have changed. +** +** NOTE: because we are using a Windows OwnerDraw ListBox, we must +** constrain the maximum possible height of a line. the ListBox has +** a limitation (unfortunately) that no line can become larger than +** 255 pixels. thus we force the object to scale maintaining its +** aspect ratio if this maximum line height limit is reached. the +** actual maximum size for an object at 100% Zoom is +** 255 +** +** RETURNS TRUE -- if the extents of the object changed +** FALSE -- if the extents did NOT change +*/ +BOOL ContainerLine_UpdateExtent( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizelHim +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + LPLINE lpLine = (LPLINE)lpContainerLine; + int nIndex = LineList_GetLineIndex(lpLL, lpLine); + UINT nOrgWidthInHimetric = lpLine->m_nWidthInHimetric; + UINT nOrgHeightInHimetric = lpLine->m_nHeightInHimetric; + BOOL fWidthChanged = FALSE; + BOOL fHeightChanged = FALSE; + SIZEL sizelHim; + HRESULT hrErr; + + if (!lpContainerLine || !lpContainerLine->m_lpOleObj) + return FALSE; + + if (lpContainerLine->m_fGuardObj) + return FALSE; // object in process of creation + + OLEDBG_BEGIN3("ContainerLine_UpdateExtent\r\n"); + + lpContainerLine->m_fDoGetExtent = FALSE; + + if (! lpsizelHim) { + /* OLE2NOTE: We want to call IViewObject2::GetExtent instead of + ** IOleObject::GetExtent. IViewObject2::GetExtent method was + ** added in OLE 2.01 release. It always retrieves the + ** extents of the object corresponding to that which will be + ** drawn by calling IViewObject::Draw. Normally, this is + ** determined by the data stored in the data cache. This + ** call will never result in a remoted (LRPC) call. + */ + OLEDBG_BEGIN2("IViewObject2::GetExtent called\r\n") + hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->GetExtent( + lpContainerLine->m_lpViewObj2, + lpContainerLine->m_dwDrawAspect, + -1, /*lindex*/ + NULL, /*ptd*/ + (LPSIZEL)&sizelHim + ); + OLEDBG_END2 + if (hrErr != NOERROR) + sizelHim.cx = sizelHim.cy = 0; + + lpsizelHim = (LPSIZEL)&sizelHim; + } + + if (lpsizelHim->cx == lpContainerLine->m_sizeInHimetric.cx && + lpsizelHim->cy == lpContainerLine->m_sizeInHimetric.cy) { + goto noupdate; + } + + if (lpsizelHim->cx > 0 || lpsizelHim->cy > 0) { + lpContainerLine->m_sizeInHimetric = *lpsizelHim; + } else { + /* object does not have any extents; let's use our container + ** chosen arbitrary size for OLE objects. + */ + lpContainerLine->m_sizeInHimetric.cx = (long)DEFOBJWIDTH; + lpContainerLine->m_sizeInHimetric.cy = (long)DEFOBJHEIGHT; + } + + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine, + (LPSIZEL)&lpContainerLine->m_sizeInHimetric); + + // if height of object changed, then reset the height of line in LineList + if (nOrgHeightInHimetric != lpLine->m_nHeightInHimetric) { + LineList_SetLineHeight(lpLL, nIndex, lpLine->m_nHeightInHimetric); + fHeightChanged = TRUE; + } + + fWidthChanged = LineList_RecalcMaxLineWidthInHimetric( + lpLL, + nOrgWidthInHimetric + ); + fWidthChanged |= (nOrgWidthInHimetric != lpLine->m_nWidthInHimetric); + + if (fHeightChanged || fWidthChanged) { + OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE); + + // mark ContainerDoc as now dirty + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE); + } + + OLEDBG_END3 + return TRUE; + +noupdate: + OLEDBG_END3 + return FALSE; // No UPDATE necessary +} + + +/* ContainerLine_DoVerb +** -------------------- +** Activate the OLE object and perform a specific verb. +*/ +BOOL ContainerLine_DoVerb( + LPCONTAINERLINE lpContainerLine, + LONG iVerb, + LPMSG lpMsg, + BOOL fMessage, + BOOL fAction +) +{ + HRESULT hrErr; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + RECT rcPosRect; + OLEDBG_BEGIN3("ContainerLine_DoVerb\r\n") + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail the DoVerb call + hrErr = ResultFromScode(E_FAIL); + goto error; + } + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + if (! lpContainerLine->m_lpOleObj) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpOleObj != NULL, + "OLE object not loaded" + ); +#endif + goto error; + } + +ExecuteDoVerb: + + ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcPosRect); + + // run the object + hrErr = ContainerLine_RunOleObject(lpContainerLine); + if (hrErr != NOERROR) + goto error; + + /* Tell object server to perform a "verb". */ + OLEDBG_BEGIN2("IOleObject::DoVerb called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->DoVerb ( + lpContainerLine->m_lpOleObj, + iVerb, + lpMsg, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + -1, + OutlineDoc_GetWindow(lpOutlineDoc), + (LPCRECT)&rcPosRect + ); + OLEDBG_END2 + + /* OLE2NOTE: IOleObject::DoVerb may return a success code + ** OLE_S_INVALIDVERB. this SCODE should NOT be considered an + ** error; thus it is important to use the "FAILED" macro to + ** check for an error SCODE. + */ + if (FAILED(GetScode(hrErr))) { + OleDbgOutHResult("WARNING: lpOleObj->DoVerb returned", hrErr); + goto error; + } + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: we want to keep only 1 inplace server active at any + ** given time. so when we start to do a DoVerb on another line, + ** then we want to shut down the previously activated server. in + ** this way we keep at most one inplace server active at a time. + ** because it is possible that the object we want to do DoVerb + ** on is handled by the same EXE as that of the previously + ** activated server, then we do not want the EXE to be shut down + ** only to be launched again. in order to avoid this we will do + ** the DoVerb BEFORE trying to shutdown the previous object. + */ + if (!g_fInsideOutContainer) { + ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + lpContainerLine->m_lpDoc, lpContainerLine); + } +#endif // INPLACE_CNTR + + OLEDBG_END3 + return TRUE; + +error: + + if (lpContainerLine->m_dwLinkType != 0) + lpContainerLine->m_fLinkUnavailable = TRUE; + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: we want to keep only 1 inplace server active at any + ** given time. so when we start to do a DoVerb on another line, + ** then we want to shut down the previously activated server. in + ** this way we keep at most one inplace server active at a time. + ** even though the DoVerb failed, we will still shutdown the + ** previous server. it is possible that we ran out of memory and + ** that the DoVerb will succeed next time after shutting down + ** the pervious server. + */ + if (!g_fInsideOutContainer) { + ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + lpContainerLine->m_lpDoc, lpContainerLine); + } +#endif // INPLACE_CNTR + + /* OLE2NOTE: if an error occurs we must give the appropriate error + ** message box. there are many potential errors that can occur. + ** the OLE2.0 user model has specific guidelines as to the + ** dialogs that should be displayed given the various potential + ** errors (eg. server not registered, unavailable link source. + ** the OLE2UI library includes support for most of the + ** recommended message dialogs. (see OleUIPrompUser function) + */ + if (fMessage) { + BOOL fReDoVerb = ContainerLine_ProcessOleRunError( + lpContainerLine, + hrErr, + fAction, + (lpMsg==NULL && iVerb>=0) /* fMenuInvoked */ + ); + if (fReDoVerb) { + goto ExecuteDoVerb; + } + } + + OLEDBG_END3 + return FALSE; +} + + + +/* ContainerLine_ProcessOleRunError + * -------------------------------- + * + * Handle the various errors possible when attempting OleRun of an object. + * Popup up appropriate message according to the error and/or take action + * specified button pressed by the user. + * + * OLE2NOTE: The OLE 2.0 User Interface Guidelines specify the messages + * that should be given for the following situations: + * 1. Link Source Unavailable...goto Links dialog + * 2. Server Not Registered...goto Convert dialog + * 3. Link Type Changed + * 4. Server Not Found + * + * Returns: TRUE -- repeat IOleObject::DoVerb call. + * FALSE -- do NOT repeat IOleObject::DoVerb call. + * + * Comments: + * (see LinkTypeChanged case) + */ +BOOL ContainerLine_ProcessOleRunError( + LPCONTAINERLINE lpContainerLine, + HRESULT hrErr, + BOOL fAction, + BOOL fMenuInvoked +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + HWND hwndParent = OutlineDoc_GetWindow(lpOutlineDoc); + SCODE sc = GetScode(hrErr); + BOOL fReDoVerb = FALSE; + + OleDbgOutHResult("ProcessError", hrErr); + if ((sc >= MK_E_FIRST) && (sc <= MK_E_LAST)) + goto LinkSourceUnavailable; + if (sc == OLE_E_CANT_BINDTOSOURCE) + goto LinkSourceUnavailable; + if (sc == STG_E_PATHNOTFOUND) + goto LinkSourceUnavailable; + if (sc == REGDB_E_CLASSNOTREG) + goto ServerNotReg; + if (sc == OLE_E_STATIC) + goto ServerNotReg; // user dblclk'ed a static object w/ no svr reg'd + if (sc == OLE_E_CLASSDIFF) + goto LinkTypeChanged; + if (sc == CO_E_APPDIDNTREG) + goto ServerNotFound; + if (sc == CO_E_APPNOTFOUND) + goto ServerNotFound; + if (sc == E_OUTOFMEMORY) + goto OutOfMemory; + + if (ContainerLine_IsOleLink(lpContainerLine)) + goto LinkSourceUnavailable; + else + goto ServerNotFound; + + +/************************************************************************* +** Error handling routines ** +*************************************************************************/ +LinkSourceUnavailable: + if (ID_PU_LINKS == OleUIPromptUser( + (WORD)IDD_LINKSOURCEUNAVAILABLE, + hwndParent, + (LPSTR)APPNAME)) { + if (fAction) { + ContainerDoc_EditLinksCommand(lpContainerLine->m_lpDoc); + } + } + return fReDoVerb; + +ServerNotReg: + { + LPSTR lpszUserType = NULL; + CLIPFORMAT cfFormat; // not used + + hrErr = ReadFmtUserTypeStgA( + lpContainerLine->m_lpStg, &cfFormat, &lpszUserType); + + if (ID_PU_CONVERT == OleUIPromptUser( + (WORD)IDD_SERVERNOTREG, + hwndParent, + (LPSTR)APPNAME, + (hrErr == NOERROR) ? lpszUserType : (LPSTR)"Unknown Object")) { + if (fAction) { + ContainerDoc_ConvertCommand( + lpContainerLine->m_lpDoc, + TRUE // fMustActivate + ); + } + } + + if (lpszUserType) + OleStdFreeString(lpszUserType, NULL); + + return fReDoVerb; + } + + +LinkTypeChanged: + { + /* OLE2NOTE: If IOleObject::DoVerb is executed on a Link object and it + ** returns OLE_E_CLASSDIFF because the link source is no longer + ** the expected class, then if the verb is a semantically + ** defined verb (eg. OLEIVERB_PRIMARY, OLEIVERB_SHOW, + ** OLEIVERB_OPEN, etc.), then the link should be re-created with + ** the new link source and the same verb executed on the new + ** link. there is no need to give a message to the user. if the + ** user had selected a verb from the object's verb menu + ** (fMenuInvoked==TRUE), then we can not be certain of the + ** semantics of the verb and whether the new link can still + ** support the verb. in this case the user is given a prompt + ** telling him to "choose a different command offered by the new + ** type". + */ + + LPSTR lpszUserType = NULL; + + if (fMenuInvoked) { + hrErr = CallIOleObjectGetUserTypeA( + lpContainerLine->m_lpOleObj,USERCLASSTYPE_FULL, &lpszUserType); + + OleUIPromptUser( + (WORD)IDD_LINKTYPECHANGED, + hwndParent, + (LPSTR)APPNAME, + (hrErr == NOERROR) ? lpszUserType : (LPSTR)"Unknown Object" + ); + } else { + fReDoVerb = TRUE; + } + ContainerLine_ReCreateLinkBecauseClassDiff(lpContainerLine); + + if (lpszUserType) + OleStdFreeString(lpszUserType, NULL); + + return fReDoVerb; + } + +ServerNotFound: + + OleUIPromptUser( + (WORD)IDD_SERVERNOTFOUND, + hwndParent, + (LPSTR)APPNAME); + return fReDoVerb; + +OutOfMemory: + + OleUIPromptUser( + (WORD)IDD_OUTOFMEMORY, + hwndParent, + (LPSTR)APPNAME); + return fReDoVerb; +} + + +/* ContainerLine_ReCreateLinkBecauseClassDiff +** ------------------------------------------ +** Re-create the link. The existing link was created when +** the moniker binds to a link source bound of a different class +** than the same moniker currently binds to. the link may be a +** special link object specifically used with the old link +** source class. thus the link object needs to be re-created to +** give the new link source the opportunity to create its own +** special link object. (see description "Custom Link Source") +*/ +HRESULT ContainerLine_ReCreateLinkBecauseClassDiff( + LPCONTAINERLINE lpContainerLine +) +{ + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + HGLOBAL hMetaPict = NULL; + LPMONIKER lpmkLinkSrc = NULL; + SCODE sc = E_FAIL; + HRESULT hrErr; + + if (lpOleLink && + lpOleLink->lpVtbl->GetSourceMoniker( + lpOleLink, (LPMONIKER FAR*)&lpmkLinkSrc) == NOERROR) { + + BOOL fDisplayAsIcon = + (lpContainerLine->m_dwDrawAspect==DVASPECT_ICON); + STGMEDIUM medium; + LPDATAOBJECT lpDataObj = NULL; + DWORD dwOleRenderOpt; + FORMATETC renderFmtEtc; + LPFORMATETC lpRenderFmtEtc = NULL; + + // get the current icon if object is displayed as icon + if (fDisplayAsIcon && + (lpDataObj = (LPDATAOBJECT)OleStdQueryInterface( (LPUNKNOWN) + lpContainerLine->m_lpOleObj,&IID_IDataObject)) != NULL ) { + hMetaPict = OleStdGetData( + lpDataObj, CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium); + OleStdRelease((LPUNKNOWN)lpDataObj); + } + + if (fDisplayAsIcon && hMetaPict) { + // a special icon should be used. first we create the object + // OLERENDER_NONE. then we stuff the special icon into the cache. + + dwOleRenderOpt = OLERENDER_NONE; + + } else if (fDisplayAsIcon && hMetaPict == NULL) { + // the object's default icon should be used + + dwOleRenderOpt = OLERENDER_DRAW; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1); + + } else { + // create standard DVASPECT_CONTENT/OLERENDER_DRAW object + dwOleRenderOpt = OLERENDER_DRAW; + } + + // unload original link object + ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_SAVEIFDIRTY); + + // delete entire contents of the current object's storage + OleStdDestroyAllElements(lpContainerLine->m_lpStg); + + OLEDBG_BEGIN2("OleCreateLink called\r\n") + hrErr = OleCreateLink ( + lpmkLinkSrc, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + + if (hrErr == NOERROR) { + if (! ContainerLine_SetupOleObject( + lpContainerLine, fDisplayAsIcon, hMetaPict) ) { + + // ERROR: setup of the new link failed. + // revert the storage to restore the original link. + ContainerLine_UnloadOleObject( + lpContainerLine, OLECLOSE_NOSAVE); + lpContainerLine->m_lpStg->lpVtbl->Revert( + lpContainerLine->m_lpStg); + sc = E_FAIL; + } else { + sc = S_OK; // IT WORKED! + + } + } + else { + sc = GetScode(hrErr); + OleDbgOutHResult("OleCreateLink returned", hrErr); + // ERROR: Re-creating the link failed. + // revert the storage to restore the original link. + lpContainerLine->m_lpStg->lpVtbl->Revert( + lpContainerLine->m_lpStg); + } + } + + if (hMetaPict) + OleUIMetafilePictIconFree(hMetaPict); // clean up metafile + return ResultFromScode(sc); +} + +/* ContainerLine_GetOleObject +** -------------------------- +** return pointer to desired interface of embedded/linked object. +** +** NOTE: this function causes an AddRef to the object. when the caller is +** finished with the object, it must call Release. +** this function does not AddRef the ContainerLine object. +*/ +LPUNKNOWN ContainerLine_GetOleObject( + LPCONTAINERLINE lpContainerLine, + REFIID riid +) +{ + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + if (lpContainerLine->m_lpOleObj) + return OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, + riid + ); + else + return NULL; +} + + + +/* ContainerLine_RunOleObject +** -------------------------- +** Load and run the object. Upon running and if size of object has changed, +** use SetExtent to change to new size. +** +*/ +HRESULT ContainerLine_RunOleObject(LPCONTAINERLINE lpContainerLine) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + SIZEL sizelNew; + HRESULT hrErr; + HCURSOR hPrevCursor; + + if (! lpContainerLine) + return NOERROR; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to Run the object + return ResultFromScode(E_FAIL); + } + + if (lpContainerLine->m_lpOleObj && + OleIsRunning(lpContainerLine->m_lpOleObj)) + return NOERROR; // object already running + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + OLEDBG_BEGIN3("ContainerLine_RunOleObject\r\n") + + if (! lpContainerLine->m_lpOleObj) { + if (! ContainerLine_LoadOleObject(lpContainerLine)) + return ResultFromScode(E_OUTOFMEMORY); // Error: couldn't load obj + } + + OLEDBG_BEGIN2("OleRun called\r\n") + hrErr = OleRun((LPUNKNOWN)lpContainerLine->m_lpOleObj); + OLEDBG_END2 + + if (hrErr != NOERROR) { + SetCursor(hPrevCursor); // restore original cursor + + OleDbgOutHResult("OleRun returned", hrErr); + OLEDBG_END3 + return hrErr; + } + + if (lpContainerLine->m_fDoSetExtent) { + /* OLE2NOTE: the OLE object was resized when it was not running + ** and the object did not have the OLEMISC_RECOMPOSEONRESIZE + ** bit set. if it had, the object would have been run + ** immediately when it was resized. this flag indicates that + ** the object does something other than simple scaling when + ** it is resized. because the object is being run now, we + ** will call IOleObject::SetExtent. + */ + lpContainerLine->m_fDoSetExtent = FALSE; + + // the size stored in our Line includes the border around the object. + // we must subtract the border to get the size of the object itself. + sizelNew.cx = lpLine->m_nWidthInHimetric; + sizelNew.cy = lpLine->m_nHeightInHimetric; + + if ((sizelNew.cx != lpContainerLine->m_sizeInHimetric.cx) || + (sizelNew.cy != lpContainerLine->m_sizeInHimetric.cy)) { + + OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetExtent( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSIZEL)&sizelNew + ); + OLEDBG_END2 + } + } + + SetCursor(hPrevCursor); // restore original cursor + + OLEDBG_END3 + return NOERROR; + +} + + +/* ContainerLine_IsOleLink +** ----------------------- +** +** return TRUE if the ContainerLine has an OleLink. +** FALSE if the ContainerLine has an embedding +*/ +BOOL ContainerLine_IsOleLink(LPCONTAINERLINE lpContainerLine) +{ + if (!lpContainerLine) + return FALSE; + + return (lpContainerLine->m_dwLinkType != 0); +} + + +/* ContainerLine_Draw +** ------------------ +** +** Draw a ContainerLine object on a DC. +** +** Parameters: +** hDC - DC to which the line will be drawn +** lpRect - the object rect in logical coordinates +** lpRectWBounds - bounding rect of the metafile underneath hDC +** (NULL if hDC is not a metafile DC) +** fHighlight - TRUE if line has selection highlight +*/ +void ContainerLine_Draw( + LPCONTAINERLINE lpContainerLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight +) +{ + LPLINE lpLine = (LPLINE) lpContainerLine; + HRESULT hrErr = NOERROR; + RECTL rclHim; + RECTL rclHimWBounds; + RECT rcHim; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--do NOT try to draw + return; + } + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpViewObj2) { + if (! ContainerLine_LoadOleObject(lpContainerLine)) + return; // Error: could not load object + } + + if (lpRectWBounds) { + rclHimWBounds.left = (long) lpRectWBounds->left; + rclHimWBounds.bottom = (long) lpRectWBounds->bottom; + rclHimWBounds.top = (long) lpRectWBounds->top; + rclHimWBounds.right = (long) lpRectWBounds->right; + } + + /* construct bounds rectangle for the object. + ** offset origin for object to correct tab indentation + */ + rclHim.left = (long) lpRect->left; + rclHim.bottom = (long) lpRect->bottom; + rclHim.top = (long) lpRect->top; + rclHim.right = (long) lpRect->right; + + rclHim.left += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric; + rclHim.right += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric; + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: if the OLE object currently has a visible in-place + ** window, then we do NOT want to draw on top of its window. + ** this could interfere with the object's display. + */ + if ( !lpContainerLine->m_fIpVisible ) +#endif + { + hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->Draw( + lpContainerLine->m_lpViewObj2, + lpContainerLine->m_dwDrawAspect, + -1, + NULL, + NULL, + NULL, + hDC, + (LPRECTL)&rclHim, + (lpRectWBounds ? (LPRECTL)&rclHimWBounds : NULL), + NULL, + 0 + ); + if (hrErr != NOERROR) + OleDbgOutHResult("IViewObject::Draw returned", hrErr); + + if (lpContainerLine->m_fObjWinOpen) + { + rcHim.left = (int) rclHim.left; + rcHim.top = (int) rclHim.top; + rcHim.right = (int) rclHim.right; + rcHim.bottom = (int) rclHim.bottom; + + /* OLE2NOTE: if the object servers window is Open (ie. not active + ** in-place) then we must shade the object in our document to + ** indicate to the user that the object is open elsewhere. + */ + OleUIDrawShading((LPRECT)&rcHim, hDC, OLEUI_SHADE_FULLRECT, 0); + } + } + + /* if the object associated with the ContainerLine is an automatic + ** link then try to connect it with its LinkSource if the + ** LinkSource is already running. we do not want to force the + ** LinkSource to run. + ** + ** OLE2NOTE: a sophistocated container will want to continually + ** attempt to connect its automatic links. OLE does NOT + ** automatically connect links when link sources become + ** available. some containers will want to attempt to connect + ** its links as part of idle time processing. another strategy + ** is to attempt to connect an automatic link every time it is + ** drawn on the screen. (this is the strategy used by this + ** CntrOutl sample application.) + */ + if (lpContainerLine->m_dwLinkType == OLEUPDATE_ALWAYS) + ContainerLine_BindLinkIfLinkSrcIsRunning(lpContainerLine); + + return; +} + + +void ContainerLine_DrawSelHilight( + LPCONTAINERLINE lpContainerLine, + HDC hDC, // MM_TEXT mode + LPRECT lprcPix, // listbox rect + UINT itemAction, + UINT itemState +) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + RECT rcObj; + DWORD dwFlags = OLEUI_HANDLES_INSIDE | OLEUI_HANDLES_USEINVERSE; + int nHandleSize; + LPCONTAINERDOC lpContainerDoc; + + if (!lpContainerLine || !hDC || !lprcPix) + return; + + lpContainerDoc = lpContainerLine->m_lpDoc; + + // Get size of OLE object + ContainerLine_GetOleObjectRectInPixels(lpContainerLine, (LPRECT)&rcObj); + + nHandleSize = GetProfileInt("windows", "oleinplaceborderwidth", + DEFAULT_HATCHBORDER_WIDTH) + 1; + + OleUIDrawHandles((LPRECT)&rcObj, hDC, dwFlags, nHandleSize, TRUE); +} + +/* InvertDiffRect +** -------------- +** +** Paint the surrounding of the Obj rect black but within lprcPix +** (similar to the lprcPix minus lprcObj) +*/ +static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC) +{ + RECT rcBlack; + + // draw black in all space outside of object's rectangle + rcBlack.top = lprcPix->top; + rcBlack.bottom = lprcPix->bottom; + + rcBlack.left = lprcPix->left + 1; + rcBlack.right = lprcObj->left - 1; + InvertRect(hDC, (LPRECT)&rcBlack); + + rcBlack.left = lprcObj->right + 1; + rcBlack.right = lprcPix->right - 1; + InvertRect(hDC, (LPRECT)&rcBlack); + + rcBlack.top = lprcPix->top; + rcBlack.bottom = lprcPix->top + 1; + rcBlack.left = lprcObj->left - 1; + rcBlack.right = lprcObj->right + 1; + InvertRect(hDC, (LPRECT)&rcBlack); + + rcBlack.top = lprcPix->bottom; + rcBlack.bottom = lprcPix->bottom - 1; + rcBlack.left = lprcObj->left - 1; + rcBlack.right = lprcObj->right + 1; + InvertRect(hDC, (LPRECT)&rcBlack); +} + + +/* Edit the ContainerLine line object. +** returns TRUE if line was changed +** FALSE if the line was NOT changed +*/ +BOOL ContainerLine_Edit(LPCONTAINERLINE lpContainerLine, HWND hWndDoc,HDC hDC) +{ + ContainerLine_DoVerb(lpContainerLine, OLEIVERB_PRIMARY, NULL, TRUE, TRUE); + + /* assume object was NOT changed, if it was obj will send Changed + ** or Saved notification. + */ + return FALSE; +} + + + +/* ContainerLine_SetHeightInHimetric +** --------------------------------- +** +** Set the height of a ContainerLine object. The widht will be changed +** to keep the aspect ratio +*/ +void ContainerLine_SetHeightInHimetric(LPCONTAINERLINE lpContainerLine, int nHeight) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + SIZEL sizelOleObject; + HRESULT hrErr; + + if (!lpContainerLine) + return; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to set the Height + return; + } + + if (nHeight != -1) { + BOOL fMustClose = FALSE; + BOOL fMustRun = FALSE; + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + // the height argument specifies the desired height for the Line. + sizelOleObject.cy = nHeight; + + // we will calculate the corresponding width for the object by + // maintaining the current aspect ratio of the object. + sizelOleObject.cx = (int)(sizelOleObject.cy * + lpContainerLine->m_sizeInHimetric.cx / + lpContainerLine->m_sizeInHimetric.cy); + + /* OLE2NOTE: if the OLE object is already running then we can + ** immediately call SetExtent. But, if the object is NOT + ** currently running then we will check if the object + ** indicates that it is normally recomposes itself on + ** resizing. ie. that the object does not simply scale its + ** display when it it resized. if so then we will force the + ** object to run so that we can call IOleObject::SetExtent. + ** SetExtent does not have any effect if the object is only + ** loaded. if the object does NOT indicate that it + ** recomposes on resize (OLEMISC_RECOMPOSEONRESIZE) then we + ** will wait till the next time that the object is run to + ** call SetExtent. we will store a flag in the ContainerLine + ** to indicate that a SetExtent is necessary. It is + ** necessary to persist this flag. + */ + if (! OleIsRunning(lpContainerLine->m_lpOleObj)) { + DWORD dwStatus; + + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPDWORD)&dwStatus + ); + OLEDBG_END2 + if (hrErr == NOERROR && (dwStatus & OLEMISC_RECOMPOSEONRESIZE)) { + // force the object to run + ContainerLine_RunOleObject(lpContainerLine); + fMustClose = TRUE; + } else { + /* the OLE object is NOT running and does NOT + ** recompose on resize. simply scale the object now + ** and do the SetExtent the next time the object is + ** run. we set the Line to the new size even though + ** the object's extents have not been changed. + ** this has the result of scaling the object's + ** display to the new size. + */ + lpContainerLine->m_fDoSetExtent = TRUE; + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine, (LPSIZEL)&sizelOleObject); + return; + } + } + + OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->SetExtent( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSIZEL)&sizelOleObject); + OLEDBG_END2 + + if (hrErr != NOERROR) { + /* OLE Object refuses to take on the new extents. Set the + ** Line to the new size even though the object refused + ** the new extents. this has the result of scaling the + ** object's display to the new size. + ** + ** if the object HAD accepted the new extents, then it + ** will send out an OnViewChange/OnDataChange + ** notification. this results in our container receiving + ** an OnViewChange notification; the line height will be + ** reset when this notification is received. + */ + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine, (LPSIZEL)&sizelOleObject); + } + + if (fMustClose) + ContainerLine_CloseOleObject( + lpContainerLine, OLECLOSE_SAVEIFDIRTY); + } + else { + /* Set the line to default height given the natural (unscaled) + ** extents of the OLE object. + */ + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine,(LPSIZEL)&lpContainerLine->m_sizeInHimetric); + } + +} + + +/* ContainerLine_SetLineHeightFromObjectExtent + * + * Purpose: + * Calculate the corresponding line height from the OleObject size + * Scale the line height to fit the limit if necessary + * + * Parameters: + * lpsizelOleObject pointer to size of OLE Object + * + * Returns: + * nil + */ +void ContainerLine_SetLineHeightFromObjectExtent( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizelOleObject +) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + + UINT uMaxObjectHeight = XformHeightInPixelsToHimetric(NULL, + LISTBOX_HEIGHT_LIMIT); + + if (!lpContainerLine || !lpsizelOleObject) + return; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to set the Height + return; + } + + lpLine->m_nWidthInHimetric = (int)lpsizelOleObject->cx; + lpLine->m_nHeightInHimetric = (int)lpsizelOleObject->cy; + + // Rescale the object if height is greater than the limit + if (lpLine->m_nHeightInHimetric > (UINT)uMaxObjectHeight) { + + lpLine->m_nWidthInHimetric = (UINT) + ((long)lpLine->m_nWidthInHimetric * + (long)uMaxObjectHeight / + (long)lpLine->m_nHeightInHimetric); + + lpLine->m_nHeightInHimetric = uMaxObjectHeight; + } + +} + + +/* ContainerLine_SaveToStg +** ----------------------- +** Save a given ContainerLine and associated OLE object to an IStorage*. +*/ +BOOL ContainerLine_SaveToStm( + LPCONTAINERLINE lpContainerLine, + LPSTREAM lpLLStm +) +{ + CONTAINERLINERECORD_ONDISK objLineRecord; + ULONG nWritten; + HRESULT hrErr; + + // Compilers should handle aligment correctly + lstrcpy(objLineRecord.m_szStgName, lpContainerLine->m_szStgName); + objLineRecord.m_fMonikerAssigned = (USHORT) lpContainerLine->m_fMonikerAssigned; + objLineRecord.m_dwDrawAspect = lpContainerLine->m_dwDrawAspect; + objLineRecord.m_sizeInHimetric = lpContainerLine->m_sizeInHimetric; + objLineRecord.m_dwLinkType = lpContainerLine->m_dwLinkType; + objLineRecord.m_fDoSetExtent = (USHORT) lpContainerLine->m_fDoSetExtent; + + /* write line record */ + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&objLineRecord, + sizeof(objLineRecord), + &nWritten + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr == NOERROR,"Could not write to LineList stream"); + return FALSE; + } + + return TRUE; +} + + +/* ContainerLine_SaveOleObjectToStg +** -------------------------------- +** Save the OLE object associated with the ContainerLine to an IStorage*. +*/ +BOOL ContainerLine_SaveOleObjectToStg( + LPCONTAINERLINE lpContainerLine, + LPSTORAGE lpSrcStg, + LPSTORAGE lpDestStg, + BOOL fRemember +) +{ + HRESULT hrErr; + SCODE sc = S_OK; + BOOL fStatus; + BOOL fSameAsLoad = (lpSrcStg==lpDestStg ? TRUE : FALSE); + LPSTORAGE lpObjDestStg; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to save + return FALSE; + } + + if (! lpContainerLine->m_lpOleObj) { + + /***************************************************************** + ** CASE 1: object is NOT loaded. + *****************************************************************/ + + if (fSameAsLoad) { + /************************************************************* + ** CASE 1A: we are saving to the current storage. because + ** the object is not loaded, it is up-to-date + ** (ie. nothing to do). + *************************************************************/ + + ; + + } else { + /************************************************************* + ** CASE 1B: we are saving to a new storage. because + ** the object is not loaded, we can simply copy the + ** object's current storage to the new storage. + *************************************************************/ + + /* if current object storage is not already open, then open it */ + if (! lpContainerLine->m_lpStg) { + lpContainerLine->m_lpStg = OleStdOpenChildStorage( + lpSrcStg, + lpContainerLine->m_szStgName, + STGM_READWRITE + ); + if (lpContainerLine->m_lpStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpStg != NULL, + "Error opening child stg" + ); +#endif + return FALSE; + } + } + + /* Create a child storage inside the destination storage. */ + lpObjDestStg = OleStdCreateChildStorage( + lpDestStg, + lpContainerLine->m_szStgName + ); + + if (lpObjDestStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpObjDestStg != NULL, + "Could not create obj storage!" + ); +#endif + return FALSE; + } + + hrErr = lpContainerLine->m_lpStg->lpVtbl->CopyTo( + lpContainerLine->m_lpStg, + 0, + NULL, + NULL, + lpObjDestStg + ); + // REVIEW: should we handle error here? + fStatus = OleStdCommitStorage(lpObjDestStg); + + /* if we are supposed to remember this storage as the new + ** storage for the object, then release the old one and + ** save the new one. else, throw away the new one. + */ + if (fRemember) { + OleStdVerifyRelease( + (LPUNKNOWN)lpContainerLine->m_lpStg, + "Original object stg not released" + ); + lpContainerLine->m_lpStg = lpObjDestStg; + } else { + OleStdVerifyRelease( + (LPUNKNOWN)lpObjDestStg, + "Copied object stg not released" + ); + } + } + + } else { + + /***************************************************************** + ** CASE 2: object IS loaded. + *****************************************************************/ + + if (fSameAsLoad) { + /************************************************************* + ** CASE 2A: we are saving to the current storage. if the object + ** is not dirty, then the current storage is up-to-date + ** (ie. nothing to do). + *************************************************************/ + + LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg; + OleDbgAssert(lpPersistStg); + + hrErr = lpPersistStg->lpVtbl->IsDirty(lpPersistStg); + + /* OLE2NOTE: we will only accept an explicit "no i + ** am NOT dirty statement" (ie. S_FALSE) as an + ** indication that the object is clean. eg. if + ** the object returns E_NOTIMPL we must + ** interpret it as the object IS dirty. + */ + if (GetScode(hrErr) != S_FALSE) { + + /* OLE object IS dirty */ + + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr = OleSave( + lpPersistStg, lpContainerLine->m_lpStg, fSameAsLoad); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + // OLE2NOTE: if OleSave fails, SaveCompleted must be called. + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + if (sc != S_OK) + return FALSE; + } + + } else { + /************************************************************* + ** CASE 2B: we are saving to a new storage. we must + ** tell the object to save into the new storage. + *************************************************************/ + + LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg; + + if (! lpPersistStg) return FALSE; + + /* Create a child storage inside the destination storage. */ + lpObjDestStg = OleStdCreateChildStorage( + lpDestStg, + lpContainerLine->m_szStgName + ); + + if (lpObjDestStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpObjDestStg != NULL, + "Could not create object storage!" + ); +#endif + return FALSE; + } + + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr = OleSave(lpPersistStg, lpObjDestStg, fSameAsLoad); + OLEDBG_END2 + + // OLE2NOTE: even if OleSave fails, must still call SaveCompleted + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + /* OLE2NOTE: a root level container should immediately + ** call IPersistStorage::SaveCompleted after calling + ** OleSave. a nested level container should not call + ** SaveCompleted now, but must wait until SaveCompleted + ** is call on it by its container. since our container + ** is not a container/server, then we always call + ** SaveComplete here. + ** + ** if this is a SaveAs operation, then we need to pass + ** the lpStg back in SaveCompleted to inform the object + ** of its new storage that it may hold on to. if this is + ** a Save or a SaveCopyAs operation, then we simply pass + ** NULL in SaveCompleted; the object can continue to hold + ** its current storage. if an error occurs during the + ** OleSave call we must still call SaveCompleted but we + ** must pass NULL. + */ + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr = lpPersistStg->lpVtbl->SaveCompleted( + lpPersistStg, + ((FAILED(sc) || !fRemember) ? NULL : lpObjDestStg) + ); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + if (sc != S_OK) { + OleStdVerifyRelease( + (LPUNKNOWN)lpObjDestStg, + "Copied object stg not released" + ); + return FALSE; + } + + /* if we are supposed to remember this storage as the new + ** storage for the object, then release the old one and + ** save the new one. else, throw away the new one. + */ + if (fRemember) { + OleStdVerifyRelease( + (LPUNKNOWN)lpContainerLine->m_lpStg, + "Original object stg not released" + ); + lpContainerLine->m_lpStg = lpObjDestStg; + } else { + OleStdVerifyRelease( + (LPUNKNOWN)lpObjDestStg, + "Copied object stg not released" + ); + } + } + } + + /* OLE2NOTE: after saving an OLE object it is possible that it sent + ** an OnViewChange notification because it had been modified. in + ** this situation it is possible that the extents of the object + ** have changed. if so we want to relayout the space for the + ** object immediately so that the extent information saved with + ** the ContainerLine match the data saved with the OLE object + ** itself. + */ + if (lpContainerLine->m_fDoGetExtent) { + BOOL fSizeChanged = ContainerLine_UpdateExtent(lpContainerLine, NULL); +#if defined( INPLACE_CNTR ) + /* if the extents of this ContainerLine have changed, then we + ** need to reset the fDoGetExtent flag to TRUE so that later + ** when ContainerDoc_UpdateExtentOfAllOleObjects is called + ** (when the WM_U_UPDATEOBJECTEXTENT message is processed), + ** it is recognized that the extents of this line have + ** changed. if any line changes size, then any in-place + ** active object below this line must be told to update the + ** position of their windows (via SetObjectRects -- see + ** ContainerDoc_UpdateInPlaceObjectRects function). + */ + lpContainerLine->m_fDoGetExtent = fSizeChanged; +#endif + } + + return TRUE; +} + + +/* ContainerLine_LoadFromStg +** ------------------------- +** Create a ContainerLine object and initialize it with data that +** was previously writen to an IStorage*. this function does not +** immediately OleLoad the associated OLE object, only the data of +** the ContainerLine object itself is loaded from the IStorage*. +*/ +LPLINE ContainerLine_LoadFromStg( + LPSTORAGE lpSrcStg, + LPSTREAM lpLLStm, + LPOUTLINEDOC lpDestDoc +) +{ + HDC hDC; + LPLINELIST lpDestLL = &lpDestDoc->m_LineList; + ULONG nRead; + HRESULT hrErr; + LPCONTAINERLINE lpContainerLine; + CONTAINERLINERECORD_ONDISK objLineRecord; + + lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpContainerLine == NULL) { + OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine"); + return NULL; + } + + hDC = LineList_GetDC(lpDestLL); + ContainerLine_Init(lpContainerLine, 0, hDC); + LineList_ReleaseDC(lpDestLL, hDC); + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpContainerLine); + + lpContainerLine->m_lpDoc = (LPCONTAINERDOC) lpDestDoc; + + /* read line record */ + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&objLineRecord, + sizeof(objLineRecord), + &nRead + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR, "Could not read from LineList stream"); + goto error; + } + + // Compilers should handle aligment correctly + lstrcpy(lpContainerLine->m_szStgName, objLineRecord.m_szStgName); + lpContainerLine->m_fMonikerAssigned = (BOOL) objLineRecord.m_fMonikerAssigned; + lpContainerLine->m_dwDrawAspect = objLineRecord.m_dwDrawAspect; + lpContainerLine->m_sizeInHimetric = objLineRecord.m_sizeInHimetric; + lpContainerLine->m_dwLinkType = objLineRecord.m_dwLinkType; + lpContainerLine->m_fDoSetExtent = (BOOL) objLineRecord.m_fDoSetExtent; + + return (LPLINE)lpContainerLine; + +error: + // destroy partially created ContainerLine + if (lpContainerLine) + ContainerLine_Delete(lpContainerLine); + return NULL; +} + + +/* ContainerLine_GetTextLen + * ------------------------ + * + * Return length of the string representation of the ContainerLine + * (not considering the tab level). we will use the following as the + * string representation of a ContainerLine: + * "<" + user type name of OLE object + ">" + * eg: + * <Microsoft Excel Worksheet> + */ +int ContainerLine_GetTextLen(LPCONTAINERLINE lpContainerLine) +{ + LPSTR lpszUserType = NULL; + HRESULT hrErr; + int nLen; + BOOL fIsLink = ContainerLine_IsOleLink(lpContainerLine); + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + + hrErr = CallIOleObjectGetUserTypeA( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_FULL, + &lpszUserType + ); + + OLEDBG_END2 + + if (hrErr != NOERROR) { + // user type is NOT available + nLen = sizeof(UNKNOWN_OLEOBJ_TYPE) + 2; // allow space for '<' + '>' + nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1; + } else { + nLen = lstrlen(lpszUserType) + 2; // allow space for '<' + '>' + nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1; + + /* OLE2NOTE: we must free the string that was allocated by the + ** IOleObject::GetUserType method. + */ + OleStdFreeString(lpszUserType, NULL); + } + + return nLen; +} + + +/* ContainerLine_GetTextData + * ------------------------- + * + * Return the string representation of the ContainerLine + * (not considering the tab level). we will use the following as the + * string representation of a ContainerLine: + * "<" + user type name of OLE object + ">" + * eg: + * <Microsoft Excel Worksheet> + */ +void ContainerLine_GetTextData(LPCONTAINERLINE lpContainerLine, LPSTR lpszBuf) +{ + LPSTR lpszUserType = NULL; + BOOL fIsLink = ContainerLine_IsOleLink(lpContainerLine); + HRESULT hrErr; + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + hrErr = CallIOleObjectGetUserTypeA( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_FULL, + &lpszUserType + ); + + if (hrErr != NOERROR) { + // user type is NOT available + wsprintf( + lpszBuf, + "<%s %s>", + UNKNOWN_OLEOBJ_TYPE, + (LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT) + ); + } else { + wsprintf( + lpszBuf, + "<%s %s>", + lpszUserType, + (LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT) + ); + + /* OLE2NOTE: we must free the string that was allocated by the + ** IOleObject::GetUserType method. + */ + OleStdFreeString(lpszUserType, NULL); + } +} + + +/* ContainerLine_GetOutlineData + * ---------------------------- + * + * Return the CF_OUTLINE format data for the ContainerLine. + */ +BOOL ContainerLine_GetOutlineData( + LPCONTAINERLINE lpContainerLine, + LPTEXTLINE lpBuf +) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList; + HDC hDC; + char szTmpBuf[MAXSTRLEN+1]; + LPTEXTLINE lpTmpTextLine; + + // Create a TextLine with the Text representation of the ContainerLine. + ContainerLine_GetTextData(lpContainerLine, (LPSTR)szTmpBuf); + + hDC = LineList_GetDC(lpLL); + lpTmpTextLine = TextLine_Create(hDC, lpLine->m_nTabLevel, szTmpBuf); + LineList_ReleaseDC(lpLL, hDC); + + TextLine_Copy(lpTmpTextLine, lpBuf); + + // Delete the temporary TextLine + TextLine_Delete(lpTmpTextLine); + return TRUE; +} + + +/* ContainerLine_GetPosRect +** ----------------------- +** Get the PosRect in client coordinates for the OLE object's window. +** +** OLE2NOTE: the PosRect must take into account the scroll postion of +** the document window. +*/ +void ContainerLine_GetPosRect( + LPCONTAINERLINE lpContainerLine, + LPRECT lprcPosRect +) +{ + ContainerLine_GetOleObjectRectInPixels(lpContainerLine,lprcPosRect); + + // shift rect for left margin + lprcPosRect->left += lpContainerLine->m_nHorizScrollShift; + lprcPosRect->right += lpContainerLine->m_nHorizScrollShift; +} + + +/* ContainerLine_GetOleObjectRectInPixels +** -------------------------------------- +** Get the extent of the OLE Object contained in the given Line in +** client coordinates after scaling. +*/ +void ContainerLine_GetOleObjectRectInPixels(LPCONTAINERLINE lpContainerLine, LPRECT lprc) +{ + LPOUTLINEDOC lpOutlineDoc; + LPSCALEFACTOR lpscale; + LPLINELIST lpLL; + LPLINE lpLine; + int nIndex; + HDC hdcLL; + + if (!lpContainerLine || !lprc) + return; + + lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc); + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + lpLine = (LPLINE)lpContainerLine; + nIndex = LineList_GetLineIndex(lpLL, lpLine); + + LineList_GetLineRect(lpLL, nIndex, lprc); + + hdcLL = GetDC(lpLL->m_hWndListBox); + + /* lprc is set to be size of Line Object (including the boundary) */ + lprc->left += (int)( + (long)XformWidthInHimetricToPixels(hdcLL, + lpLine->m_nTabWidthInHimetric + + LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) * + lpscale->dwSxN / lpscale->dwSxD); + lprc->right = (int)( + lprc->left + (long) + XformWidthInHimetricToPixels(hdcLL, lpLine->m_nWidthInHimetric) * + lpscale->dwSxN / lpscale->dwSxD); + + ReleaseDC(lpLL->m_hWndListBox, hdcLL); +} + + +/* ContainerLine_GetOleObjectSizeInHimetric +** ---------------------------------------- +** Get the size of the OLE Object contained in the given Line +*/ +void ContainerLine_GetOleObjectSizeInHimetric(LPCONTAINERLINE lpContainerLine, LPSIZEL lpsizel) +{ + if (!lpContainerLine || !lpsizel) + return; + + *lpsizel = lpContainerLine->m_sizeInHimetric; +} + + +/* ContainerLine_BindLinkIfLinkSrcIsRunning +** ---------------------------------------- +** Try to connect the OLE link object associated with the +** ContainerLine with its LinkSource if the LinkSource is already +** running and the link is an automatic link. we do not want to +** force the LinkSource to run. +** +** OLE2NOTE: a sophistocated container will want to continually +** attempt to connect its automatic links. OLE does NOT +** automatically connect links when link source become available. some +** containers will want to attempt to connect its links as part of +** idle time processing. another strategy is to attempt to connect +** an automatic link every time it is drawn on the screen. (this is +** the strategy used by this CntrOutl sample application.) +*/ +void ContainerLine_BindLinkIfLinkSrcIsRunning(LPCONTAINERLINE lpContainerLine) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + HRESULT hrErr; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + + // if the link source is known to be un-bindable, then don't even try + if (lpContainerLine->m_fLinkUnavailable) + return; + + /* OLE2NOTE: we do not want to ever give the Busy/NotResponding + ** dialogs when we are attempting to BindIfRunning to the link + ** source. if the link source is currently busy, this could + ** cause the Busy dialog to come up. even if the link source is + ** busy, we do not want put up the busy dialog. thus we will + ** disable the dialog and later re-enable them + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n") + hrErr = lpContainerLine->m_lpOleLink->lpVtbl->BindIfRunning( + lpContainerLine->m_lpOleLink); + OLEDBG_END2 + + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); +} diff --git a/private/oleutest/letest/outline/cntrline.h b/private/oleutest/letest/outline/cntrline.h new file mode 100644 index 000000000..16b153aa8 --- /dev/null +++ b/private/oleutest/letest/outline/cntrline.h @@ -0,0 +1,3584 @@ +/************************************************************************* +** +** OLE 2 Container Sample Code +** +** cntrline.c +** +** This file contains ContainerLine methods. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + + + +extern LPOUTLINEAPP g_lpApp; +extern IUnknownVtbl g_CntrLine_UnknownVtbl; +extern IOleClientSiteVtbl g_CntrLine_OleClientSiteVtbl; +extern IAdviseSinkVtbl g_CntrLine_AdviseSinkVtbl; + +#if defined( INPLACE_CNTR ) +extern IOleInPlaceSiteVtbl g_CntrLine_OleInPlaceSiteVtbl; +extern BOOL g_fInsideOutContainer; +#endif // INPLACE_CNTR + +// REVIEW: should use string resource for messages +char ErrMsgDoVerb[] = "OLE object action failed!"; + + +/* prototype for static functions */ +static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC); + + +/************************************************************************* +** ContainerLine +** This object represents the location within the container where +** the embedded/linked object lives. It exposes interfaces to the +** object that allow the object to get information about its +** embedding site and to announce notifications of important events +** (changed, closed, saved) +** +** The ContainerLine exposes the following interfaces: +** IUnknown +** IOleClientSite +** IAdviseSink +*************************************************************************/ + + + +/************************************************************************* +** ContainerLine::IUnknown interface implementation +*************************************************************************/ + + +// IUnknown::QueryInterface +STDMETHODIMP CntrLine_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +// IUnknown::AddRef +STDMETHODIMP_(ULONG) CntrLine_Unk_AddRef(LPUNKNOWN lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IUnknown"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +// IUnknown::Release +STDMETHODIMP_(ULONG) CntrLine_Unk_Release(LPUNKNOWN lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IUnknown"); + + return ContainerLine_Release(lpContainerLine); +} + + +/************************************************************************* +** ContainerLine::IOleClientSite interface implementation +*************************************************************************/ + +// IOleClientSite::QueryInterface +STDMETHODIMP CntrLine_CliSite_QueryInterface( + LPOLECLIENTSITE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +// IOleClientSite::AddRef +STDMETHODIMP_(ULONG) CntrLine_CliSite_AddRef(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IOleClientSite"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +// IOleClientSite::Release +STDMETHODIMP_(ULONG) CntrLine_CliSite_Release(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IOleClientSite"); + + return ContainerLine_Release(lpContainerLine); +} + + +// IOleClientSite::SaveObject +STDMETHODIMP CntrLine_CliSite_SaveObject(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg; + SCODE sc = S_OK; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrLine_CliSite_SaveObject\r\n") + + if (! lpPersistStg) { + /* OLE2NOTE: The object is NOT loaded. a container must be + ** prepared for the fact that an object that it thinks it + ** has unloaded may still call IOleClientSite::SaveObject. + ** in this case the container should fail the save call and + ** NOT try to reload the object. this scenario arises if you + ** have a in-process server (DLL object) which has a + ** connected linking client. even after the embedding + ** container unloads the DLL object, the link connection + ** keeps the object alive. it may then as part of its + ** shutdown try to call IOCS::SaveObject, but then it is too + ** late. + */ + OLEDBG_END2 + return ResultFromScode(E_FAIL); + } + + // mark ContainerDoc as now dirty + OutlineDoc_SetModified( + (LPOUTLINEDOC)lpContainerLine->m_lpDoc, TRUE, TRUE, FALSE); + + /* Tell OLE object to save itself + ** OLE2NOTE: it is NOT sufficient to ONLY call + ** IPersistStorage::Save method. it is also necessary to call + ** WriteClassStg. the helper API OleSave does this automatically. + */ + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr=OleSave(lpPersistStg,lpContainerLine->m_lpStg, TRUE/*fSameAsLoad*/); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + // OLE2NOTE: even if OleSave fails, SaveCompleted must be called. + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr = lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg, NULL); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleClientSite::GetMoniker +STDMETHODIMP CntrLine_CliSite_GetMoniker( + LPOLECLIENTSITE lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +) +{ + LPCONTAINERLINE lpContainerLine; + + lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OLEDBG_BEGIN2("CntrLine_CliSite_GetMoniker\r\n") + + // OLE2NOTE: we must make sure to set output pointer parameters to NULL + *lplpmk = NULL; + + switch (dwWhichMoniker) { + + case OLEWHICHMK_CONTAINER: + /* OLE2NOTE: create a FileMoniker which identifies the + ** entire container document. + */ + *lplpmk = OleDoc_GetFullMoniker( + (LPOLEDOC)lpContainerLine->m_lpDoc, + dwAssign + ); + break; + + case OLEWHICHMK_OBJREL: + + /* OLE2NOTE: create an ItemMoniker which identifies the + ** OLE object relative to the container document. + */ + *lplpmk = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign); + break; + + case OLEWHICHMK_OBJFULL: + { + /* OLE2NOTE: create an absolute moniker which identifies the + ** OLE object in the container document. this moniker is + ** created as a composite of the absolute moniker for the + ** entire document appended with an item moniker which + ** identifies the OLE object relative to the document. + */ + + *lplpmk = ContainerLine_GetFullMoniker(lpContainerLine, dwAssign); + break; + } + } + + OLEDBG_END2 + + if (*lplpmk != NULL) + return NOERROR; + else + return ResultFromScode(E_FAIL); +} + + +// IOleClientSite::GetContainer +STDMETHODIMP CntrLine_CliSite_GetContainer( + LPOLECLIENTSITE lpThis, + LPOLECONTAINER FAR* lplpContainer +) +{ + LPCONTAINERLINE lpContainerLine; + HRESULT hrErr; + + OLEDBG_BEGIN2("CntrLine_CliSite_GetContainer\r\n") + + lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + hrErr = OleDoc_QueryInterface( + (LPOLEDOC)lpContainerLine->m_lpDoc, + &IID_IOleContainer, + (LPVOID FAR*)lplpContainer + ); + + OLEDBG_END2 + return hrErr; +} + + +// IOleClientSite::ShowObject +STDMETHODIMP CntrLine_CliSite_ShowObject(LPOLECLIENTSITE lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + HWND hWndFrame = OutlineApp_GetFrameWindow(g_lpApp); + + OLEDBG_BEGIN2("CntrLine_CliSite_ShowObject\r\n") + + /* make sure our doc window is visible and not minimized. + ** the OutlineDoc_ShowWindow function will cause the app window + ** to show itself SW_SHOWNORMAL. + */ + if (! IsWindowVisible(hWndFrame) || IsIconic(hWndFrame)) + OutlineDoc_ShowWindow(lpOutlineDoc); + + BringWindowToTop(hWndFrame); + + /* make sure that the OLE object is currently in view. if necessary + ** scroll the document in order to bring it into view. + */ + LineList_ScrollLineIntoView(lpLL, nIndex); + +#if defined( INPLACE_CNTR ) + /* after the in-place object is scrolled into view, we need to ask + ** it to update its rect for the new clip rect coordinates + */ + ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0); +#endif + + OLEDBG_END2 + return NOERROR; +} + + +// IOleClientSite::OnShowWindow +STDMETHODIMP CntrLine_CliSite_OnShowWindow(LPOLECLIENTSITE lpThis, BOOL fShow) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + + if (fShow) { + OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(TRUE)\r\n") + + /* OLE2NOTE: we need to hatch out the OLE object now; it has + ** just been opened in a window elsewhere (open editing as + ** opposed to in-place activation). + ** force the line to re-draw with the hatch. + */ + lpContainerLine->m_fObjWinOpen = TRUE; + LineList_ForceLineRedraw(lpLL, nIndex, FALSE /*fErase*/); + + } else { + OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(FALSE)\r\n") + + /* OLE2NOTE: the object associated with this container site has + ** just closed its server window. we should now remove the + ** hatching that indicates that the object is open + ** elsewhere. also our window should now come to the top. + ** force the line to re-draw without the hatch. + */ + lpContainerLine->m_fObjWinOpen = FALSE; + LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/); + + BringWindowToTop(lpOutlineDoc->m_hWndDoc); + SetFocus(lpOutlineDoc->m_hWndDoc); + } + + OLEDBG_END2 + return NOERROR; +} + + +// IOleClientSite::RequestNewObjectLayout +STDMETHODIMP CntrLine_CliSite_RequestNewObjectLayout(LPOLECLIENTSITE lpThis) +{ + OleDbgOut2("CntrLine_CliSite_RequestNewObjectLayout\r\n"); + + /* OLE2NOTE: this method is NOT yet used. it is for future layout + ** negotiation support. + */ + return ResultFromScode(E_NOTIMPL); +} + + +/************************************************************************* +** ContainerLine::IAdviseSink interface implementation +*************************************************************************/ + +// IAdviseSink::QueryInterface +STDMETHODIMP CntrLine_AdvSink_QueryInterface( + LPADVISESINK lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj); +} + + +// IAdviseSink::AddRef +STDMETHODIMP_(ULONG) CntrLine_AdvSink_AddRef(LPADVISESINK lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgAddRefMethod(lpThis, "IAdviseSink"); + + return ContainerLine_AddRef(lpContainerLine); +} + + +// IAdviseSink::Release +STDMETHODIMP_(ULONG) CntrLine_AdvSink_Release (LPADVISESINK lpThis) +{ + LPCONTAINERLINE lpContainerLine = + ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine; + + OleDbgReleaseMethod(lpThis, "IAdviseSink"); + + return ContainerLine_Release(lpContainerLine); +} + + +// IAdviseSink::OnDataChange +STDMETHODIMP_(void) CntrLine_AdvSink_OnDataChange( + LPADVISESINK lpThis, + FORMATETC FAR* lpFormatetc, + STGMEDIUM FAR* lpStgmed +) +{ + OleDbgOut2("CntrLine_AdvSink_OnDataChange\r\n"); + // We are not interested in data changes (only view changes) + // (ie. nothing to do) +} + + +STDMETHODIMP_(void) CntrLine_AdvSink_OnViewChange( + LPADVISESINK lpThis, + DWORD aspects, + LONG lindex +) +{ + LPCONTAINERLINE lpContainerLine; + LPOUTLINEDOC lpOutlineDoc; + HWND hWndDoc; + LPLINELIST lpLL; + MSG msg; + int nIndex; + + OLEDBG_BEGIN2("CntrLine_AdvSink_OnViewChange\r\n") + + lpContainerLine = ((struct CAdviseSinkImpl FAR*)lpThis)->lpContainerLine; + lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + + /* OLE2NOTE: at this point we simply invalidate the rectangle of + ** the object to force a repaint in the future, we mark + ** that the extents of the object may have changed + ** (m_fDoGetExtent=TRUE), and we post a message + ** (WM_U_UPDATEOBJECTEXTENT) to our document that one or more + ** OLE objects may need to have their extents updated. later + ** when this message is processed, the document loops through + ** all lines to see if any are marked as needing an extent update. + ** if infact the extents did change. this can be done by calling + ** IViewObject2::GetExtent to retreive the object's current + ** extents and comparing with the last known extents for the + ** object. if the extents changed, then relayout space for the + ** object before drawing. we postpone the check to get + ** the extents now because OnViewChange is an asyncronis method, + ** and we have to careful not to call any syncronis methods back + ** to the object. while it WOULD be OK to call the + ** IViewObject2::GetExtent method within the asyncronis + ** OnViewChange method (because this method is handled by the + ** object handler and never remoted), it is good practise to not + ** call any object methods from within an asyncronis + ** notification method. + ** if there is already WM_U_UPDATEOBJECTEXTENT message waiting + ** in our message queue, there is no need to post another one. + ** in this way, if the server is updating quicker than we can + ** keep up, we do not make unneccsary GetExtent calls. also if + ** drawing is disabled, we postpone updating the extents of any + ** objects until drawing is re-enabled. + */ + lpContainerLine->m_fDoGetExtent = TRUE; + hWndDoc = OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc); + + if (lpOutlineDoc->m_nDisableDraw == 0 && + ! PeekMessage(&msg, hWndDoc, + WM_U_UPDATEOBJECTEXTENT, WM_U_UPDATEOBJECTEXTENT, + PM_NOREMOVE | PM_NOYIELD)) { + PostMessage(hWndDoc, WM_U_UPDATEOBJECTEXTENT, 0, 0L); + } + + // force the modified line to redraw. + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine); + LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/); + + OLEDBG_END2 +} + + +// IAdviseSink::OnRename +STDMETHODIMP_(void) CntrLine_AdvSink_OnRename( + LPADVISESINK lpThis, + LPMONIKER lpmk +) +{ + OleDbgOut2("CntrLine_AdvSink_OnRename\r\n"); + /* OLE2NOTE: the Embedding Container has nothing to do here. this + ** notification is important for linking situations. it tells + ** the OleLink objects to update their moniker because the + ** source object has been renamed (track the link source). + */ +} + + +// IAdviseSink::OnSave +STDMETHODIMP_(void) CntrLine_AdvSink_OnSave(LPADVISESINK lpThis) +{ + OleDbgOut2("CntrLine_AdvSink_OnSave\r\n"); + /* OLE2NOTE: the Embedding Container has nothing to do here. this + ** notification is only useful to clients which have set up a + ** data cache with the ADVFCACHE_ONSAVE flag. + */ +} + + +// IAdviseSink::OnClose +STDMETHODIMP_(void) CntrLine_AdvSink_OnClose(LPADVISESINK lpThis) +{ + OleDbgOut2("CntrLine_AdvSink_OnClose\r\n"); + /* OLE2NOTE: the Embedding Container has nothing to do here. this + ** notification is important for the OLE's default object handler + ** and the OleLink object. it tells them the remote object is + ** shutting down. + */ +} + + +/************************************************************************* +** ContainerLine Support Functions +*************************************************************************/ + + +/* ContainerLine_Init +** ------------------ +** Initialize fields in a newly constructed ContainerLine line object. +** NOTE: ref cnt of ContainerLine initialized to 0 +*/ +void ContainerLine_Init(LPCONTAINERLINE lpContainerLine, int nTab, HDC hDC) +{ + Line_Init((LPLINE)lpContainerLine, nTab, hDC); // init base class fields + + ((LPLINE)lpContainerLine)->m_lineType = CONTAINERLINETYPE; + ((LPLINE)lpContainerLine)->m_nWidthInHimetric = DEFOBJWIDTH; + ((LPLINE)lpContainerLine)->m_nHeightInHimetric = DEFOBJHEIGHT; + lpContainerLine->m_cRef = 0; + lpContainerLine->m_szStgName[0] = '\0'; + lpContainerLine->m_fObjWinOpen = FALSE; + lpContainerLine->m_fMonikerAssigned = FALSE; + lpContainerLine->m_dwDrawAspect = DVASPECT_CONTENT; + + lpContainerLine->m_fGuardObj = FALSE; + lpContainerLine->m_fDoGetExtent = FALSE; + lpContainerLine->m_fDoSetExtent = FALSE; + lpContainerLine->m_sizeInHimetric.cx = -1; + lpContainerLine->m_sizeInHimetric.cy = -1; + + lpContainerLine->m_lpStg = NULL; + lpContainerLine->m_lpDoc = NULL; + lpContainerLine->m_lpOleObj = NULL; + lpContainerLine->m_lpViewObj2 = NULL; + lpContainerLine->m_lpPersistStg = NULL; + lpContainerLine->m_lpOleLink = NULL; + lpContainerLine->m_dwLinkType = 0; + lpContainerLine->m_fLinkUnavailable = FALSE; + lpContainerLine->m_lpszShortType = NULL; + +#if defined( INPLACE_CNTR ) + lpContainerLine->m_fIpActive = FALSE; + lpContainerLine->m_fUIActive = FALSE; + lpContainerLine->m_fIpVisible = FALSE; + lpContainerLine->m_lpOleIPObj = NULL; + lpContainerLine->m_fInsideOutObj = FALSE; + lpContainerLine->m_fIpChangesUndoable = FALSE; + lpContainerLine->m_fIpServerRunning = FALSE; + lpContainerLine->m_hWndIpObject = NULL; + lpContainerLine->m_nHorizScrollShift = 0; +#endif // INPLACE_CNTR + + INIT_INTERFACEIMPL( + &lpContainerLine->m_Unknown, + &g_CntrLine_UnknownVtbl, + lpContainerLine + ); + + INIT_INTERFACEIMPL( + &lpContainerLine->m_OleClientSite, + &g_CntrLine_OleClientSiteVtbl, + lpContainerLine + ); + + INIT_INTERFACEIMPL( + &lpContainerLine->m_AdviseSink, + &g_CntrLine_AdviseSinkVtbl, + lpContainerLine + ); + +#if defined( INPLACE_CNTR ) + INIT_INTERFACEIMPL( + &lpContainerLine->m_OleInPlaceSite, + &g_CntrLine_OleInPlaceSiteVtbl, + lpContainerLine + ); +#endif // INPLACE_CNTR +} + + +/* Setup the OLE object associated with the ContainerLine */ +BOOL ContainerLine_SetupOleObject( + LPCONTAINERLINE lpContainerLine, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict +) +{ + DWORD dwDrawAspect = (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT); + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + + /* Cache a pointer to the IViewObject2* interface. *Required* + ** we need this everytime we draw the object. + ** + ** OLE2NOTE: We require the object to support IViewObject2 + ** interface. this is an extension to the IViewObject interface + ** that was added with the OLE 2.01 release. This interface must + ** be supported by all object handlers and DLL-based objects. + */ + lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2); + if (! lpContainerLine->m_lpViewObj2) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n"); +#endif + return FALSE; + } + + // Cache a pointer to the IPersistStorage* interface. *Required* + // we need this everytime we save the object. + lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage); + if (! lpContainerLine->m_lpPersistStg) { + OleDbgAssert(lpContainerLine->m_lpPersistStg); + return FALSE; + } + + // Cache a pointer to the IOleLink* interface if supported. *Optional* + // if supported the object is a link. we need this to manage the link + lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink); + if (lpContainerLine->m_lpOleLink) { + OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n") + lpContainerLine->m_lpOleLink->lpVtbl->GetUpdateOptions( + lpContainerLine->m_lpOleLink, &lpContainerLine->m_dwLinkType); + OLEDBG_END2 + } else + lpContainerLine->m_dwLinkType = 0; // NOT a link + + /* get the short user type name of the object. this + ** is used all the time when we have to build the object + ** verb menu. we will cache this information to make it + ** quicker to build the verb menu. + */ + OleDbgAssert(lpContainerLine->m_lpszShortType == NULL); + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + { + LPOLESTR polestr; + + lpContainerLine->m_lpOleObj->lpVtbl->GetUserType( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_SHORT, + &polestr + ); + CopyAndFreeOLESTR(polestr, &lpContainerLine->m_lpszShortType); + } + OLEDBG_END2 + + /* Perform that standard setup for the OLE object. this includes: + ** setup View advise + ** Call IOleObject::SetHostNames + ** Call OleSetContainedObject + */ + OleStdSetupAdvises( + lpContainerLine->m_lpOleObj, + dwDrawAspect, + (LPSTR)APPNAME, + lpOutlineDoc->m_lpszDocTitle, + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + TRUE /*fCreate*/ + ); + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: (INSIDE-OUT CONTAINER) An inside-out container should + ** check if the object is an inside-out and prefers to be + ** activated when visible type of object. if not the object + ** should not be allowed to keep its window up after it gets + ** UIDeactivated. + */ + if (g_fInsideOutContainer) { + DWORD mstat; + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, + (DWORD FAR*)&mstat + ); + OLEDBG_END2 + + lpContainerLine->m_fInsideOutObj = (BOOL) + (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)); + } +#endif // INPLACE_CNTR + + if (fDisplayAsIcon) { + /* user has requested to display icon aspect instead of content + ** aspect. + ** NOTE: we do not have to delete the previous aspect cache + ** because one did not get set up. + */ + OleStdSwitchDisplayAspect( + lpContainerLine->m_lpOleObj, + &lpContainerLine->m_dwDrawAspect, + dwDrawAspect, + hMetaPict, + FALSE, /* fDeleteOldAspect */ + TRUE, /* fSetupViewAdvise */ + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + NULL /*fMustUpdate*/ // this can be ignored; update + // for switch to icon not req'd + ); + } + return TRUE; +} + + +/* Create an ContainerLine object and return the pointer */ +LPCONTAINERLINE ContainerLine_Create( + DWORD dwOleCreateType, + HDC hDC, + UINT nTab, + LPCONTAINERDOC lpContainerDoc, + LPCLSID lpclsid, + LPSTR lpszFileName, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSTR lpszStgName +) +{ + LPCONTAINERLINE lpContainerLine = NULL; + LPOLEOBJECT lpObj = NULL; + LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerDoc); + DWORD dwDrawAspect = + (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT); + DWORD dwOleRenderOpt = + (fDisplayAsIcon ? OLERENDER_NONE : OLERENDER_DRAW); + HRESULT hrErr; + + OLEDBG_BEGIN3("ContainerLine_Create\r\n") + + if (lpDocStg == NULL) { + OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL"); + goto error; + } + + lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpContainerLine == NULL) { + OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine"); + goto error; + } + + ContainerLine_Init(lpContainerLine, nTab, hDC); + + /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to + ** guard our object. if this guard is set, then the object is + ** not ready to have any OLE interface methods called. it is + ** necessary to guard the object this way while it is being + ** created or loaded. + */ + lpContainerLine->m_fGuardObj = TRUE; + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpContainerLine); + + lstrcpy(lpContainerLine->m_szStgName, lpszStgName); + lpContainerLine->m_lpDoc = lpContainerDoc; + + /* Create a new storage for the object inside the doc's storage */ + lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName); + if (lpContainerLine->m_lpStg == NULL) { + OleDbgAssert(lpContainerLine->m_lpStg != NULL); + goto error; + } + + lpContainerLine->m_dwLinkType = 0; + + switch (dwOleCreateType) { + + case IOF_SELECTCREATENEW: + + OLEDBG_BEGIN2("OleCreate called\r\n") + hrErr = OleCreate ( + lpclsid, + &IID_IOleObject, + dwOleRenderOpt, + NULL, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreate returned", hrErr); +#endif + + break; + + case IOF_SELECTCREATEFROMFILE: + + OLEDBG_BEGIN2("OleCreateFromFile called\r\n") + { + CREATEOLESTR(polestr, lpszFileName) + + hrErr = OleCreateFromFile ( + &CLSID_NULL, + polestr, + &IID_IOleObject, + dwOleRenderOpt, + NULL, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + + FREEOLESTR(polestr) + } + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateFromFile returned", hrErr); +#endif + break; + + case IOF_CHECKLINK: + + OLEDBG_BEGIN2("OleCreateLinkToFile called\r\n") + { + CREATEOLESTR(polestr, lpszFileName) + + hrErr = OleCreateLinkToFile ( + polestr, + &IID_IOleObject, + dwOleRenderOpt, + NULL, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + + FREEOLESTR(polestr) + } + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateLinkToFile returned", hrErr); +#endif + break; + } + if (hrErr != NOERROR) + goto error; + + if (! ContainerLine_SetupOleObject( + lpContainerLine, fDisplayAsIcon, hMetaPict)) { + goto error; + } + + /* OLE2NOTE: clear our re-entrancy guard. the object is now ready + ** to have interface methods called. + */ + lpContainerLine->m_fGuardObj = FALSE; + + OLEDBG_END3 + return lpContainerLine; + +error: + OutlineApp_ErrorMessage(g_lpApp, "Could not create object!"); + + // Destroy partially created OLE object + if (lpContainerLine) + ContainerLine_Delete(lpContainerLine); + OLEDBG_END3 + return NULL; +} + + +LPCONTAINERLINE ContainerLine_CreateFromData( + HDC hDC, + UINT nTab, + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + DWORD dwCreateType, + CLIPFORMAT cfFormat, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSTR lpszStgName +) +{ + HGLOBAL hData = NULL; + LPCONTAINERLINE lpContainerLine = NULL; + LPOLEOBJECT lpObj = NULL; + LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerDoc); + DWORD dwDrawAspect = + (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT); + DWORD dwOleRenderOpt; + FORMATETC renderFmtEtc; + LPFORMATETC lpRenderFmtEtc = NULL; + HRESULT hrErr; + LPUNKNOWN lpUnk = NULL; + + OLEDBG_BEGIN3("ContainerLine_CreateFromData\r\n") + + if (dwCreateType == OLECREATEFROMDATA_STATIC && cfFormat != 0) { + // a particular type of static object should be created + + dwOleRenderOpt = OLERENDER_FORMAT; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + + if (cfFormat == CF_METAFILEPICT) + SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_MFPICT); + else if (cfFormat == CF_BITMAP) + SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_GDI); + else + SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_HGLOBAL); + + } else if (dwCreateType == OLECREATEFROMDATA_STATIC && fDisplayAsIcon) { + // a link that currently displayed as an icon needs to be + // converted to a STATIC picture object. this case is driven + // from "BreakLink" in the "Links" dialog. because the current + // data in the source object's cache is DVASPECT_ICON we need + // to tell the OleCreateStaticFromData API to look for + // DVASPECT_ICON data. the static object that results however, + // is considered to be displayed in the DVASPECT_CONTENT view. + + dwOleRenderOpt = OLERENDER_DRAW; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1); + dwDrawAspect = DVASPECT_CONTENT; // static obj displays only CONTENT + + } else if (fDisplayAsIcon && hMetaPict) { + // a special icon should be used. first we create the object + // OLERENDER_NONE and then we stuff the special icon into the cache. + + dwOleRenderOpt = OLERENDER_NONE; + + } else if (fDisplayAsIcon && hMetaPict == NULL) { + // the object's default icon should be used + + dwOleRenderOpt = OLERENDER_DRAW; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1); + + } else { + // create standard DVASPECT_CONTENT/OLERENDER_DRAW object + dwOleRenderOpt = OLERENDER_DRAW; + } + + if (lpDocStg == NULL) { + OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL"); + goto error; + } + + lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpContainerLine == NULL) { + OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine"); + goto error; + } + + ContainerLine_Init(lpContainerLine, nTab, hDC); + + /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to + ** guard our object. if this guard is set, then the object is + ** not ready to have any OLE interface methods called. it is + ** necessary to guard the object this way while it is being + ** created or loaded. + */ + lpContainerLine->m_fGuardObj = TRUE; + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpContainerLine); + + lstrcpy(lpContainerLine->m_szStgName, lpszStgName); + lpContainerLine->m_lpDoc = lpContainerDoc; + + /* Create a new storage for the object inside the doc's storage */ + lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName); + if (lpContainerLine->m_lpStg == NULL) { + OleDbgAssert(lpContainerLine->m_lpStg != NULL); + goto error; + } + + switch (dwCreateType) { + + case OLECREATEFROMDATA_LINK: + + OLEDBG_BEGIN2("OleCreateLinkFromData called\r\n") + hrErr = OleCreateLinkFromData ( + lpSrcDataObj, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateLinkFromData returned", hrErr); +#endif + break; + + case OLECREATEFROMDATA_OBJECT: + + OLEDBG_BEGIN2("OleCreateFromData called\r\n") + hrErr = OleCreateFromData ( + lpSrcDataObj, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateFromData returned", hrErr); +#endif + break; + + case OLECREATEFROMDATA_STATIC: + + OLEDBG_BEGIN2("OleCreateStaticFromData called\r\n") + hrErr = OleCreateStaticFromData ( + lpSrcDataObj, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) + OleDbgOutHResult("OleCreateStaticFromData returned", hrErr); +#endif + break; + } + + if (hrErr != NOERROR) + goto error; + + if (! ContainerLine_SetupOleObject( + lpContainerLine, fDisplayAsIcon, hMetaPict)) { + goto error; + } + + /* OLE2NOTE: clear our re-entrancy guard. the object is now ready + ** to have interface methods called. + */ + lpContainerLine->m_fGuardObj = FALSE; + + OLEDBG_END3 + return lpContainerLine; + +error: + OutlineApp_ErrorMessage(g_lpApp, "Could not create object!"); + // Destroy partially created OLE object + if (lpContainerLine) + ContainerLine_Delete(lpContainerLine); + OLEDBG_END3 + return NULL; +} + + +/* ContainerLine_AddRef +** -------------------- +** +** increment the ref count of the line object. +** +** Returns the new ref count on the object +*/ +ULONG ContainerLine_AddRef(LPCONTAINERLINE lpContainerLine) +{ + ++lpContainerLine->m_cRef; + +#if defined( _DEBUG ) + OleDbgOutRefCnt4( + "ContainerLine_AddRef: cRef++\r\n", + lpContainerLine, + lpContainerLine->m_cRef + ); +#endif + return lpContainerLine->m_cRef; +} + + +/* ContainerLine_Release +** --------------------- +** +** decrement the ref count of the line object. +** if the ref count goes to 0, then the line is destroyed. +** +** Returns the remaining ref count on the object +*/ +ULONG ContainerLine_Release(LPCONTAINERLINE lpContainerLine) +{ + ULONG cRef; + + /********************************************************************* + ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. ** + ** otherwise the object is still in use. ** + *********************************************************************/ + + cRef = --lpContainerLine->m_cRef; + +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_cRef >= 0,"Release called with cRef == 0"); + + OleDbgOutRefCnt4( + "ContainerLine_Release: cRef--\r\n", + lpContainerLine, + cRef + ); +#endif + if (cRef == 0) + ContainerLine_Destroy(lpContainerLine); + + return cRef; +} + + +/* ContainerLine_QueryInterface +** ---------------------------- +** +** Retrieve a pointer to an interface on the ContainerLine object. +** +** Returns NOERROR if interface is successfully retrieved. +** E_NOINTERFACE if the interface is not supported +*/ +HRESULT ContainerLine_QueryInterface( + LPCONTAINERLINE lpContainerLine, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + SCODE sc = E_NOINTERFACE; + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) { + OleDbgOut4("ContainerLine_QueryInterface: IUnknown* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_Unknown; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } + else if (IsEqualIID(riid, &IID_IOleClientSite)) { + OleDbgOut4("ContainerLine_QueryInterface: IOleClientSite* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_OleClientSite; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } + else if (IsEqualIID(riid, &IID_IAdviseSink)) { + OleDbgOut4("ContainerLine_QueryInterface: IAdviseSink* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_AdviseSink; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } +#if defined( INPLACE_CNTR ) + else if (IsEqualIID(riid, &IID_IOleWindow) + || IsEqualIID(riid, &IID_IOleInPlaceSite)) { + OleDbgOut4("ContainerLine_QueryInterface: IOleInPlaceSite* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpContainerLine->m_OleInPlaceSite; + ContainerLine_AddRef(lpContainerLine); + sc = S_OK; + } +#endif // INPLACE_CNTR + + OleDbgQueryInterfaceMethod(*lplpvObj); + + return ResultFromScode(sc); +} + + +BOOL ContainerLine_LoadOleObject(LPCONTAINERLINE lpContainerLine) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPSTORAGE lpDocStg = ContainerDoc_GetStg(lpContainerLine->m_lpDoc); + LPOLECLIENTSITE lpOleClientSite; + LPMONIKER lpmkObj; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + HRESULT hrErr; + + if (lpContainerLine->m_fGuardObj) + return FALSE; // object in process of creation + + if (lpContainerLine->m_lpOleObj) + return TRUE; // object already loaded + + OLEDBG_BEGIN3("ContainerLine_LoadOleObject\r\n") + + /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to + ** guard our object. if this guard is set, then the object is + ** not ready to have any OLE interface methods called. it is + ** necessary to guard the object this way while it is being + ** created or loaded. + */ + lpContainerLine->m_fGuardObj = TRUE; + + /* if object storage is not already open, then open it */ + if (! lpContainerLine->m_lpStg) { + lpContainerLine->m_lpStg = OleStdOpenChildStorage( + lpDocStg, + lpContainerLine->m_szStgName, + STGM_READWRITE + ); + if (lpContainerLine->m_lpStg == NULL) { + OleDbgAssert(lpContainerLine->m_lpStg != NULL); + goto error; + } + } + + /* OLE2NOTE: if the OLE object being loaded is in a data transfer + ** document, then we should NOT pass a IOleClientSite* pointer + ** to the OleLoad call. This particularly critical if the OLE + ** object is an OleLink object. If a non-NULL client site is + ** passed to the OleLoad function, then the link will bind to + ** the source if its is running. in the situation that we are + ** loading the object as part of a data transfer document we do + ** not want this connection to be established. even worse, if + ** the link source is currently blocked or busy, then this could + ** hang the system. it is simplest to never pass a + ** IOleClientSite* when loading an object in a data transfer + ** document. + */ + lpOleClientSite = (lpOutlineDoc->m_fDataTransferDoc ? + NULL : (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite); + + /* OLE2NOTE: we do not want to ever give the Busy/NotResponding + ** dialogs when we are loading an object. if the object is a + ** link, it will attempt to BindIfRunning to the link source. if + ** the link source is currently busy, this could cause the Busy + ** dialog to come up. even if the link source is busy, + ** we do not want put up the busy dialog. thus we will disable + ** the dialog and later re-enable them + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + OLEDBG_BEGIN2("OleLoad called\r\n") + hrErr = OleLoad ( + lpContainerLine->m_lpStg, + &IID_IOleObject, + lpOleClientSite, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr == NOERROR, "Could not load object!"); + OleDbgOutHResult("OleLoad returned", hrErr); + goto error; + } + + /* Cache a pointer to the IViewObject2* interface. *Required* + ** we need this everytime we draw the object. + ** + ** OLE2NOTE: We require the object to support IViewObject2 + ** interface. this is an extension to the IViewObject interface + ** that was added with the OLE 2.01 release. This interface must + ** be supported by all object handlers and DLL-based objects. + */ + lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2); + if (! lpContainerLine->m_lpViewObj2) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n"); +#endif + goto error; + } + + // Cache a pointer to the IPersistStorage* interface. *Required* + // we need this everytime we save the object. + lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage); + if (! lpContainerLine->m_lpPersistStg) { + OleDbgAssert(lpContainerLine->m_lpPersistStg); + goto error; + } + + // Cache a pointer to the IOleLink* interface if supported. *Optional* + // if supported the object is a link. we need this to manage the link + if (lpContainerLine->m_dwLinkType != 0) { + lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink); + if (! lpContainerLine->m_lpOleLink) { + OleDbgAssert(lpContainerLine->m_lpOleLink); + goto error; + } + } + + /* OLE2NOTE: clear our re-entrancy guard. the object is now ready + ** to have interface methods called. + */ + lpContainerLine->m_fGuardObj = FALSE; + + /* OLE2NOTE: similarly, if the OLE object being loaded is in a data + ** transfer document, then we do NOT need to setup any advises, + ** call SetHostNames, SetMoniker, etc. + */ + if (lpOleClientSite) { + /* Setup the Advises (OLE notifications) that we are interested + ** in receiving. + */ + OleStdSetupAdvises( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSTR)APPNAME, + lpOutlineDoc->m_lpszDocTitle, + (LPADVISESINK)&lpContainerLine->m_AdviseSink, + FALSE /*fCreate*/ + ); + + /* OLE2NOTE: if the OLE object has a moniker assigned, we need to + ** inform the object by calling IOleObject::SetMoniker. this + ** will force the OLE object to register in the + ** RunningObjectTable when it enters the running state. + */ + if (lpContainerLine->m_fMonikerAssigned) { + lpmkObj = ContainerLine_GetRelMoniker( + lpContainerLine, + GETMONIKER_ONLYIFTHERE + ); + + if (lpmkObj) { + OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( + lpContainerLine->m_lpOleObj, + OLEWHICHMK_OBJREL, + lpmkObj + ); + OLEDBG_END2 + OleStdRelease((LPUNKNOWN)lpmkObj); + } + } + + /* get the Short form of the user type name of the object. this + ** is used all the time when we have to build the object + ** verb menu. we will cache this information to make it + ** quicker to build the verb menu. + */ + // block is only for polestr declaration + { + LPOLESTR polestr; + + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetUserType( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_SHORT, + &polestr + ); + + CopyAndFreeOLESTR(polestr, &lpContainerLine->m_lpszShortType); + } + OLEDBG_END2 + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: an inside-out container should check if the object + ** is an inside-out and prefers to be activated when visible + ** type of object. if so, the object should be immediately + ** activated in-place, BUT NOT UIActived. + */ + if (g_fInsideOutContainer && + lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) { + DWORD mstat; + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, + (DWORD FAR*)&mstat + ); + OLEDBG_END2 + + lpContainerLine->m_fInsideOutObj = (BOOL) + (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)); + + if ( lpContainerLine->m_fInsideOutObj ) { + HWND hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc); + + ContainerLine_DoVerb( + lpContainerLine, + OLEIVERB_INPLACEACTIVATE, + NULL, + FALSE, + FALSE + ); + + /* OLE2NOTE: following this DoVerb(INPLACEACTIVATE) the + ** object may have taken focus. but because the + ** object is NOT UIActive it should NOT have focus. + ** we will make sure our document has focus. + */ + SetFocus(hWndDoc); + } + } +#endif // INPLACE_CNTR + OLEDBG_END2 + + } + + OLEDBG_END2 + return TRUE; + +error: + OLEDBG_END2 + return FALSE; +} + + +/* ContainerLine_CloseOleObject +** ---------------------------- +** Close the OLE object associated with the ContainerLine. +** +** Closing the object forces the object to transition from the +** running state to the loaded state. if the object was not running, +** then there is no effect. it is necessary to close the OLE object +** before releasing the pointers to the OLE object. +** +** Returns TRUE if successfully closed, +** FALSE if closing was aborted. +*/ +BOOL ContainerLine_CloseOleObject( + LPCONTAINERLINE lpContainerLine, + DWORD dwSaveOption +) +{ + HRESULT hrErr; + SCODE sc; + + if (lpContainerLine->m_fGuardObj) + return FALSE; // object in process of creation + + if (! lpContainerLine->m_lpOleObj) + return TRUE; // object is NOT loaded + + OLEDBG_BEGIN2("IOleObject::Close called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Close( + lpContainerLine->m_lpOleObj, + (dwSaveOption == OLECLOSE_NOSAVE ? + OLECLOSE_NOSAVE : OLECLOSE_SAVEIFDIRTY) + ); + OLEDBG_END2 + +#if defined( INPLACE_CNTR ) + if (lpContainerLine->m_fIpServerRunning) { + /* OLE2NOTE: unlock the lock held on the in-place object. + ** it is VERY important that an in-place container + ** that also support linking to embeddings properly manage + ** the running of its in-place objects. in an outside-in + ** style in-place container, when the user clicks + ** outside of the in-place active object, the object gets + ** UIDeactivated and the object hides its window. in order + ** to make the object fast to reactivate, the container + ** deliberately does not call IOleObject::Close. the object + ** stays running in the invisible unlocked state. the idea + ** here is if the user simply clicks outside of the object + ** and then wants to double click again to re-activate the + ** object, we do not want this to be slow. if we want to + ** keep the object running, however, we MUST Lock it + ** running. otherwise the object will be in an unstable + ** state where if a linking client does a "silent-update" + ** (eg. UpdateNow from the Links dialog), then the in-place + ** server will shut down even before the object has a chance + ** to be saved back in its container. this saving normally + ** occurs when the in-place container closes the object. also + ** keeping the object in the unstable, hidden, running, + ** not-locked state can cause problems in some scenarios. + ** ICntrOtl keeps only one object running. if the user + ** intiates a DoVerb on another object, then that last + ** running in-place active object is closed. a more + ** sophistocated in-place container may keep more object running. + ** (see CntrLine_IPSite_OnInPlaceActivate) + */ + lpContainerLine->m_fIpServerRunning = FALSE; + + OLEDBG_BEGIN2("OleLockRunning(FALSE,TRUE) called\r\n") + OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleObj, FALSE, TRUE); + OLEDBG_END2 + } +#endif + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleObject::Close returned", hrErr); + sc = GetScode(hrErr); + if (sc == RPC_E_CALL_REJECTED || sc==OLE_E_PROMPTSAVECANCELLED) + return FALSE; // object aborted shutdown + } + return TRUE; +} + + +/* ContainerLine_UnloadOleObject +** ----------------------------- +** Close the OLE object associated with the ContainerLine and +** release all pointer held to the object. +** +** Closing the object forces the object to transition from the +** running state to the loaded state. if the object was not running, +** then there is no effect. it is necessary to close the OLE object +** before releasing the pointers to the OLE object. releasing all +** pointers to the object allows the object to transition from +** loaded to unloaded (or passive). +*/ +void ContainerLine_UnloadOleObject( + LPCONTAINERLINE lpContainerLine, + DWORD dwSaveOption +) +{ + if (lpContainerLine->m_lpOleObj) { + + OLEDBG_BEGIN2("IOleObject::Close called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->Close( + lpContainerLine->m_lpOleObj, dwSaveOption); + OLEDBG_END2 + + /* OLE2NOTE: we will take our IOleClientSite* pointer away from + ** the object before we release all pointers to the object. + ** in the scenario where the object is implemented as an + ** in-proc server (DLL object), then, if there are link + ** connections to the DLL object, it is possible that the + ** object will not be destroyed when we release our pointers + ** to the object. the existance of the remote link + ** connections will hold the object alive. later when these + ** strong connections are released, then the object may + ** attempt to call IOleClientSite::Save if we had not taken + ** away the client site pointer. + */ + OLEDBG_BEGIN2("IOleObject::SetClientSite(NULL) called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetClientSite( + lpContainerLine->m_lpOleObj, NULL); + OLEDBG_END2 + + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleObj); + lpContainerLine->m_lpOleObj = NULL; + + if (lpContainerLine->m_lpViewObj2) { + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpViewObj2); + lpContainerLine->m_lpViewObj2 = NULL; + } + if (lpContainerLine->m_lpPersistStg) { + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpPersistStg); + lpContainerLine->m_lpPersistStg = NULL; + } + + if (lpContainerLine->m_lpOleLink) { + OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleLink); + lpContainerLine->m_lpOleLink = NULL; + } + } + + if (lpContainerLine->m_lpszShortType) { + OleStdFreeString(lpContainerLine->m_lpszShortType, NULL); + lpContainerLine->m_lpszShortType = NULL; + } +} + + +/* ContainerLine_Delete +** -------------------- +** Delete the ContainerLine. +** +** NOTE: we can NOT directly destroy the memory for the +** ContainerLine; the ContainerLine maintains a reference count. a +** non-zero reference count indicates that the object is still +** in-use. The OleObject keeps a reference-counted pointer to the +** ClientLine object. we must take the actions necessary so that the +** ContainerLine object receives Releases for outstanding +** references. when the reference count of the ContainerLine reaches +** zero, then the memory for the object will actually be destroyed +** (ContainerLine_Destroy called). +** +*/ +void ContainerLine_Delete(LPCONTAINERLINE lpContainerLine) +{ + OLEDBG_BEGIN2("ContainerLine_Delete\r\n") + +#if defined( INPLACE_CNTR ) + if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastIpActiveLine) + lpContainerLine->m_lpDoc->m_lpLastIpActiveLine = NULL; + if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine) + lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL; +#endif + + /* OLE2NOTE: in order to have a stable line object during the + ** process of deleting, we intially AddRef the line ref cnt and + ** later Release it. This initial AddRef is artificial; it is + ** simply done to guarantee that our object does not destroy + ** itself until the END of this routine. + */ + ContainerLine_AddRef(lpContainerLine); + + // Unload the loaded OLE object + if (lpContainerLine->m_lpOleObj) + ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_NOSAVE); + + /* OLE2NOTE: we can NOT directly free the memory for the ContainerLine + ** data structure until everyone holding on to a pointer to our + ** ClientSite interface and IAdviseSink interface has released + ** their pointers. There is one refcnt on the ContainerLine object + ** which is held by the container itself. we will release this + ** refcnt here. + */ + ContainerLine_Release(lpContainerLine); + + /* OLE2NOTE: this call forces all external connections to our + ** ContainerLine to close down and therefore guarantees that + ** we receive all releases associated with those external + ** connections. Strictly this call should NOT be necessary, but + ** it is defensive coding to make this call. + */ + OLEDBG_BEGIN2("CoDisconnectObject(lpContainerLine) called\r\n") + CoDisconnectObject((LPUNKNOWN)&lpContainerLine->m_Unknown, 0); + OLEDBG_END2 + +#if defined( _DEBUG ) + /* at this point the object all references from the OLE object to + ** our ContainerLine object should have been released. there + ** should only be 1 remaining reference that will be released below. + */ + if (lpContainerLine->m_cRef != 1) { + OleDbgOutRefCnt( + "WARNING: ContainerLine_Delete: cRef != 1\r\n", + lpContainerLine, + lpContainerLine->m_cRef + ); + } +#endif + + ContainerLine_Release(lpContainerLine); // release artificial AddRef above + OLEDBG_END2 +} + + +/* ContainerLine_Destroy +** --------------------- +** Destroy (Free) the memory used by a ContainerLine structure. +** This function is called when the ref count of the ContainerLine goes +** to zero. the ref cnt goes to zero after ContainerLine_Delete forces +** the OleObject to unload and release its pointers to the +** ContainerLine IOleClientSite and IAdviseSink interfaces. +*/ + +void ContainerLine_Destroy(LPCONTAINERLINE lpContainerLine) +{ + LPUNKNOWN lpTmpObj; + + OLEDBG_BEGIN2("ContainerLine_Destroy\r\n") + + // Release the storage opened for the OLE object + if (lpContainerLine->m_lpStg) { + lpTmpObj = (LPUNKNOWN)lpContainerLine->m_lpStg; + lpContainerLine->m_lpStg = NULL; + + OleStdRelease(lpTmpObj); + } + + if (lpContainerLine->m_lpszShortType) { + OleStdFreeString(lpContainerLine->m_lpszShortType, NULL); + lpContainerLine->m_lpszShortType = NULL; + } + + Delete(lpContainerLine); // Free the memory for the structure itself + OLEDBG_END2 +} + + +/* ContainerLine_CopyToDoc + * ----------------------- + * + * Copy a ContainerLine to another Document (usually ClipboardDoc) + */ +BOOL ContainerLine_CopyToDoc( + LPCONTAINERLINE lpSrcLine, + LPOUTLINEDOC lpDestDoc, + int nIndex +) +{ + LPCONTAINERLINE lpDestLine = NULL; + LPLINELIST lpDestLL = &lpDestDoc->m_LineList; + HDC hDC; + HRESULT hrErr; + BOOL fStatus; + LPSTORAGE lpDestDocStg = ((LPOLEDOC)lpDestDoc)->m_lpStg; + LPSTORAGE lpDestObjStg = NULL; + + lpDestLine = (LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpDestLine == NULL) { + OleDbgAssertSz(lpDestLine!=NULL, "Error allocating ContainerLine"); + return FALSE; + } + + hDC = LineList_GetDC(lpDestLL); + ContainerLine_Init(lpDestLine, ((LPLINE)lpSrcLine)->m_nTabLevel, hDC); + LineList_ReleaseDC(lpDestLL, hDC); + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpDestLine); + + lpDestLine->m_lpDoc = (LPCONTAINERDOC)lpDestDoc; + + // Copy data of the original source ContainerLine. + ((LPLINE)lpDestLine)->m_nWidthInHimetric = + ((LPLINE)lpSrcLine)->m_nWidthInHimetric; + ((LPLINE)lpDestLine)->m_nHeightInHimetric = + ((LPLINE)lpSrcLine)->m_nHeightInHimetric; + lpDestLine->m_fMonikerAssigned = lpSrcLine->m_fMonikerAssigned; + lpDestLine->m_dwDrawAspect = lpSrcLine->m_dwDrawAspect; + lpDestLine->m_sizeInHimetric = lpSrcLine->m_sizeInHimetric; + lpDestLine->m_dwLinkType = lpSrcLine->m_dwLinkType; + + + /* We must create a new sub-storage for the embedded object within + ** the destination document's storage. We will first attempt to + ** use the same storage name as the source line. if this name is + ** in use, then we will allocate a new name. in this way we try + ** to keep the name associated with the OLE object unchanged + ** through a Cut/Paste operation. + */ + lpDestObjStg = OleStdCreateChildStorage( + lpDestDocStg, + lpSrcLine->m_szStgName + ); + if (lpDestObjStg) { + lstrcpy(lpDestLine->m_szStgName, lpSrcLine->m_szStgName); + } else { + /* the original name was in use, make up a new name. */ + ContainerDoc_GetNextStgName( + (LPCONTAINERDOC)lpDestDoc, + lpDestLine->m_szStgName, + sizeof(lpDestLine->m_szStgName) + ); + lpDestObjStg = OleStdCreateChildStorage( + lpDestDocStg, + lpDestLine->m_szStgName + ); + } + if (lpDestObjStg == NULL) { + OleDbgAssertSz(lpDestObjStg != NULL, "Error creating child stg"); + goto error; + } + + // Copy over storage of the embedded object itself + + if (! lpSrcLine->m_lpOleObj) { + + /***************************************************************** + ** CASE 1: object is NOT loaded. + ** because the object is not loaded, we can simply copy the + ** object's current storage to the new storage. + *****************************************************************/ + + /* if current object storage is not already open, then open it */ + if (! lpSrcLine->m_lpStg) { + LPSTORAGE lpSrcDocStg = ((LPOLEDOC)lpSrcLine->m_lpDoc)->m_lpStg; + + if (! lpSrcDocStg) goto error; + + // open object storage. + lpSrcLine->m_lpStg = OleStdOpenChildStorage( + lpSrcDocStg, + lpSrcLine->m_szStgName, + STGM_READWRITE + ); + if (lpSrcLine->m_lpStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpSrcLine->m_lpStg != NULL, + "Error opening child stg" + ); +#endif + goto error; + } + } + + hrErr = lpSrcLine->m_lpStg->lpVtbl->CopyTo( + lpSrcLine->m_lpStg, + 0, + NULL, + NULL, + lpDestObjStg + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: lpSrcObjStg->CopyTo returned", hrErr); + goto error; + } + + fStatus = OleStdCommitStorage(lpDestObjStg); + + } else { + + /***************************************************************** + ** CASE 2: object IS loaded. + ** we must tell the object to save into the new storage. + *****************************************************************/ + + SCODE sc = S_OK; + LPPERSISTSTORAGE lpPersistStg = lpSrcLine->m_lpPersistStg; + OleDbgAssert(lpPersistStg); + + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr = OleSave(lpPersistStg, lpDestObjStg, FALSE /*fSameAsLoad*/); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + // OLE2NOTE: even if OleSave fails, SaveCompleted must be called. + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + if (sc != S_OK) + goto error; + + } + + OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex); + OleStdVerifyRelease( + (LPUNKNOWN)lpDestObjStg, + "Copied object stg not released" + ); + + return TRUE; + +error: + + // Delete any partially created storage. + if (lpDestObjStg) { + + OleStdVerifyRelease( + (LPUNKNOWN)lpDestObjStg, + "Copied object stg not released" + ); + + { + CREATEOLESTR(polestr, lpDestLine->m_szStgName) + + lpDestDocStg->lpVtbl->DestroyElement( + lpDestDocStg, + lpDestLine->m_szStgName + ); + + FREEOLESTR(polestr); + } + + lpDestLine->m_szStgName[0] = '\0'; + } + + // destroy partially created ContainerLine + if (lpDestLine) + ContainerLine_Delete(lpDestLine); + return FALSE; +} + + +/* ContainerLine_UpdateExtent +** -------------------------- +** Update the size of the ContainerLine because the extents of the +** object may have changed. +** +** NOTE: because we are using a Windows OwnerDraw ListBox, we must +** constrain the maximum possible height of a line. the ListBox has +** a limitation (unfortunately) that no line can become larger than +** 255 pixels. thus we force the object to scale maintaining its +** aspect ratio if this maximum line height limit is reached. the +** actual maximum size for an object at 100% Zoom is +** 255 +** +** RETURNS TRUE -- if the extents of the object changed +** FALSE -- if the extents did NOT change +*/ +BOOL ContainerLine_UpdateExtent( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizelHim +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + LPLINE lpLine = (LPLINE)lpContainerLine; + int nIndex = LineList_GetLineIndex(lpLL, lpLine); + UINT nOrgWidthInHimetric = lpLine->m_nWidthInHimetric; + UINT nOrgHeightInHimetric = lpLine->m_nHeightInHimetric; + BOOL fWidthChanged = FALSE; + BOOL fHeightChanged = FALSE; + SIZEL sizelHim; + HRESULT hrErr; + + if (!lpContainerLine || !lpContainerLine->m_lpOleObj) + return FALSE; + + if (lpContainerLine->m_fGuardObj) + return FALSE; // object in process of creation + + OLEDBG_BEGIN3("ContainerLine_UpdateExtent\r\n"); + + lpContainerLine->m_fDoGetExtent = FALSE; + + if (! lpsizelHim) { + /* OLE2NOTE: We want to call IViewObject2::GetExtent instead of + ** IOleObject::GetExtent. IViewObject2::GetExtent method was + ** added in OLE 2.01 release. It always retrieves the + ** extents of the object corresponding to that which will be + ** drawn by calling IViewObject::Draw. Normally, this is + ** determined by the data stored in the data cache. This + ** call will never result in a remoted (LRPC) call. + */ + OLEDBG_BEGIN2("IViewObject2::GetExtent called\r\n") + hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->GetExtent( + lpContainerLine->m_lpViewObj2, + lpContainerLine->m_dwDrawAspect, + -1, /*lindex*/ + NULL, /*ptd*/ + (LPSIZEL)&sizelHim + ); + OLEDBG_END2 + if (hrErr != NOERROR) + sizelHim.cx = sizelHim.cy = 0; + + lpsizelHim = (LPSIZEL)&sizelHim; + } + + if (lpsizelHim->cx == lpContainerLine->m_sizeInHimetric.cx && + lpsizelHim->cy == lpContainerLine->m_sizeInHimetric.cy) { + goto noupdate; + } + + if (lpsizelHim->cx > 0 || lpsizelHim->cy > 0) { + lpContainerLine->m_sizeInHimetric = *lpsizelHim; + } else { + /* object does not have any extents; let's use our container + ** chosen arbitrary size for OLE objects. + */ + lpContainerLine->m_sizeInHimetric.cx = (long)DEFOBJWIDTH; + lpContainerLine->m_sizeInHimetric.cy = (long)DEFOBJHEIGHT; + } + + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine, + (LPSIZEL)&lpContainerLine->m_sizeInHimetric); + + // if height of object changed, then reset the height of line in LineList + if (nOrgHeightInHimetric != lpLine->m_nHeightInHimetric) { + LineList_SetLineHeight(lpLL, nIndex, lpLine->m_nHeightInHimetric); + fHeightChanged = TRUE; + } + + fWidthChanged = LineList_RecalcMaxLineWidthInHimetric( + lpLL, + nOrgWidthInHimetric + ); + fWidthChanged |= (nOrgWidthInHimetric != lpLine->m_nWidthInHimetric); + + if (fHeightChanged || fWidthChanged) { + OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE); + + // mark ContainerDoc as now dirty + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE); + } + + OLEDBG_END3 + return TRUE; + +noupdate: + OLEDBG_END3 + return FALSE; // No UPDATE necessary +} + + +/* ContainerLine_DoVerb +** -------------------- +** Activate the OLE object and perform a specific verb. +*/ +BOOL ContainerLine_DoVerb( + LPCONTAINERLINE lpContainerLine, + LONG iVerb, + LPMSG lpMsg, + BOOL fMessage, + BOOL fAction +) +{ + HRESULT hrErr; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + RECT rcPosRect; + OLEDBG_BEGIN3("ContainerLine_DoVerb\r\n") + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail the DoVerb call + hrErr = ResultFromScode(E_FAIL); + goto error; + } + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + if (! lpContainerLine->m_lpOleObj) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpOleObj != NULL, + "OLE object not loaded" + ); +#endif + goto error; + } + +ExecuteDoVerb: + + ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcPosRect); + + // run the object + hrErr = ContainerLine_RunOleObject(lpContainerLine); + if (hrErr != NOERROR) + goto error; + + /* Tell object server to perform a "verb". */ + OLEDBG_BEGIN2("IOleObject::DoVerb called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->DoVerb ( + lpContainerLine->m_lpOleObj, + iVerb, + lpMsg, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + -1, + OutlineDoc_GetWindow(lpOutlineDoc), + (LPCRECT)&rcPosRect + ); + OLEDBG_END2 + + /* OLE2NOTE: IOleObject::DoVerb may return a success code + ** OLE_S_INVALIDVERB. this SCODE should NOT be considered an + ** error; thus it is important to use the "FAILED" macro to + ** check for an error SCODE. + */ + if (FAILED(GetScode(hrErr))) { + OleDbgOutHResult("WARNING: lpOleObj->DoVerb returned", hrErr); + goto error; + } + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: we want to keep only 1 inplace server active at any + ** given time. so when we start to do a DoVerb on another line, + ** then we want to shut down the previously activated server. in + ** this way we keep at most one inplace server active at a time. + ** because it is possible that the object we want to do DoVerb + ** on is handled by the same EXE as that of the previously + ** activated server, then we do not want the EXE to be shut down + ** only to be launched again. in order to avoid this we will do + ** the DoVerb BEFORE trying to shutdown the previous object. + */ + if (!g_fInsideOutContainer) { + ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + lpContainerLine->m_lpDoc, lpContainerLine); + } +#endif // INPLACE_CNTR + + OLEDBG_END3 + return TRUE; + +error: + + if (lpContainerLine->m_dwLinkType != 0) + lpContainerLine->m_fLinkUnavailable = TRUE; + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: we want to keep only 1 inplace server active at any + ** given time. so when we start to do a DoVerb on another line, + ** then we want to shut down the previously activated server. in + ** this way we keep at most one inplace server active at a time. + ** even though the DoVerb failed, we will still shutdown the + ** previous server. it is possible that we ran out of memory and + ** that the DoVerb will succeed next time after shutting down + ** the pervious server. + */ + if (!g_fInsideOutContainer) { + ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + lpContainerLine->m_lpDoc, lpContainerLine); + } +#endif // INPLACE_CNTR + + /* OLE2NOTE: if an error occurs we must give the appropriate error + ** message box. there are many potential errors that can occur. + ** the OLE2.0 user model has specific guidelines as to the + ** dialogs that should be displayed given the various potential + ** errors (eg. server not registered, unavailable link source. + ** the OLE2UI library includes support for most of the + ** recommended message dialogs. (see OleUIPrompUser function) + */ + if (fMessage) { + BOOL fReDoVerb = ContainerLine_ProcessOleRunError( + lpContainerLine, + hrErr, + fAction, + (lpMsg==NULL && iVerb>=0) /* fMenuInvoked */ + ); + if (fReDoVerb) { + goto ExecuteDoVerb; + } + } + + OLEDBG_END3 + return FALSE; +} + + + +/* ContainerLine_ProcessOleRunError + * -------------------------------- + * + * Handle the various errors possible when attempting OleRun of an object. + * Popup up appropriate message according to the error and/or take action + * specified button pressed by the user. + * + * OLE2NOTE: The OLE 2.0 User Interface Guidelines specify the messages + * that should be given for the following situations: + * 1. Link Source Unavailable...goto Links dialog + * 2. Server Not Registered...goto Convert dialog + * 3. Link Type Changed + * 4. Server Not Found + * + * Returns: TRUE -- repeat IOleObject::DoVerb call. + * FALSE -- do NOT repeat IOleObject::DoVerb call. + * + * Comments: + * (see LinkTypeChanged case) + */ +BOOL ContainerLine_ProcessOleRunError( + LPCONTAINERLINE lpContainerLine, + HRESULT hrErr, + BOOL fAction, + BOOL fMenuInvoked +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + HWND hwndParent = OutlineDoc_GetWindow(lpOutlineDoc); + SCODE sc = GetScode(hrErr); + BOOL fReDoVerb = FALSE; + + OleDbgOutHResult("ProcessError", hrErr); + if ((sc >= MK_E_FIRST) && (sc <= MK_E_LAST)) + goto LinkSourceUnavailable; + if (sc == OLE_E_CANT_BINDTOSOURCE) + goto LinkSourceUnavailable; + if (sc == STG_E_PATHNOTFOUND) + goto LinkSourceUnavailable; + if (sc == REGDB_E_CLASSNOTREG) + goto ServerNotReg; + if (sc == OLE_E_STATIC) + goto ServerNotReg; // user dblclk'ed a static object w/ no svr reg'd + if (sc == OLE_E_CLASSDIFF) + goto LinkTypeChanged; + if (sc == CO_E_APPDIDNTREG) + goto ServerNotFound; + if (sc == CO_E_APPNOTFOUND) + goto ServerNotFound; + if (sc == E_OUTOFMEMORY) + goto OutOfMemory; + + if (ContainerLine_IsOleLink(lpContainerLine)) + goto LinkSourceUnavailable; + else + goto ServerNotFound; + + +/************************************************************************* +** Error handling routines ** +*************************************************************************/ +LinkSourceUnavailable: + if (ID_PU_LINKS == OleUIPromptUser( + (WORD)IDD_LINKSOURCEUNAVAILABLE, + hwndParent, + (LPSTR)APPNAME)) { + if (fAction) { + ContainerDoc_EditLinksCommand(lpContainerLine->m_lpDoc); + } + } + return fReDoVerb; + +ServerNotReg: + { + LPSTR lpszUserType = NULL; + CLIPFORMAT cfFormat; // not used + LPOLESTR polestr; + + hrErr = ReadFmtUserTypeStg( + lpContainerLine->m_lpStg, &cfFormat, &polestr); + + CopyAndFreeOLESTR(polestr, &lpszUserType); + + if (ID_PU_CONVERT == OleUIPromptUser( + (WORD)IDD_SERVERNOTREG, + hwndParent, + (LPSTR)APPNAME, + (hrErr == NOERROR) ? lpszUserType : (LPSTR)"Unknown Object")) { + if (fAction) { + ContainerDoc_ConvertCommand( + lpContainerLine->m_lpDoc, + TRUE // fMustActivate + ); + } + } + + if (lpszUserType) + OleStdFreeString(lpszUserType, NULL); + + return fReDoVerb; + } + + +LinkTypeChanged: + { + /* OLE2NOTE: If IOleObject::DoVerb is executed on a Link object and it + ** returns OLE_E_CLASSDIFF because the link source is no longer + ** the expected class, then if the verb is a semantically + ** defined verb (eg. OLEIVERB_PRIMARY, OLEIVERB_SHOW, + ** OLEIVERB_OPEN, etc.), then the link should be re-created with + ** the new link source and the same verb executed on the new + ** link. there is no need to give a message to the user. if the + ** user had selected a verb from the object's verb menu + ** (fMenuInvoked==TRUE), then we can not be certain of the + ** semantics of the verb and whether the new link can still + ** support the verb. in this case the user is given a prompt + ** telling him to "choose a different command offered by the new + ** type". + */ + + LPSTR lpszUserType = NULL; + + if (fMenuInvoked) { + LPOLESTR polestr; + + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserType( + lpContainerLine->m_lpOleObj,USERCLASSTYPE_FULL, polestr); + + CopyAndFreeOLESTR(polestr, &lpszUserType); + + OleUIPromptUser( + (WORD)IDD_LINKTYPECHANGED, + hwndParent, + (LPSTR)APPNAME, + (hrErr == NOERROR) ? lpszUserType : (LPSTR)"Unknown Object" + ); + } else { + fReDoVerb = TRUE; + } + ContainerLine_ReCreateLinkBecauseClassDiff(lpContainerLine); + + if (lpszUserType) + OleStdFreeString(lpszUserType, NULL); + + return fReDoVerb; + } + +ServerNotFound: + + OleUIPromptUser( + (WORD)IDD_SERVERNOTFOUND, + hwndParent, + (LPSTR)APPNAME); + return fReDoVerb; + +OutOfMemory: + + OleUIPromptUser( + (WORD)IDD_OUTOFMEMORY, + hwndParent, + (LPSTR)APPNAME); + return fReDoVerb; +} + + +/* ContainerLine_ReCreateLinkBecauseClassDiff +** ------------------------------------------ +** Re-create the link. The existing link was created when +** the moniker binds to a link source bound of a different class +** than the same moniker currently binds to. the link may be a +** special link object specifically used with the old link +** source class. thus the link object needs to be re-created to +** give the new link source the opportunity to create its own +** special link object. (see description "Custom Link Source") +*/ +HRESULT ContainerLine_ReCreateLinkBecauseClassDiff( + LPCONTAINERLINE lpContainerLine +) +{ + LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink; + HGLOBAL hMetaPict = NULL; + LPMONIKER lpmkLinkSrc = NULL; + SCODE sc = E_FAIL; + HRESULT hrErr; + + if (lpOleLink && + lpOleLink->lpVtbl->GetSourceMoniker( + lpOleLink, (LPMONIKER FAR*)&lpmkLinkSrc) == NOERROR) { + + BOOL fDisplayAsIcon = + (lpContainerLine->m_dwDrawAspect==DVASPECT_ICON); + STGMEDIUM medium; + LPDATAOBJECT lpDataObj = NULL; + DWORD dwOleRenderOpt; + FORMATETC renderFmtEtc; + LPFORMATETC lpRenderFmtEtc = NULL; + + // get the current icon if object is displayed as icon + if (fDisplayAsIcon && + (lpDataObj = (LPDATAOBJECT)OleStdQueryInterface( (LPUNKNOWN) + lpContainerLine->m_lpOleObj,&IID_IDataObject)) != NULL ) { + hMetaPict = OleStdGetData( + lpDataObj, CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium); + OleStdRelease((LPUNKNOWN)lpDataObj); + } + + if (fDisplayAsIcon && hMetaPict) { + // a special icon should be used. first we create the object + // OLERENDER_NONE. then we stuff the special icon into the cache. + + dwOleRenderOpt = OLERENDER_NONE; + + } else if (fDisplayAsIcon && hMetaPict == NULL) { + // the object's default icon should be used + + dwOleRenderOpt = OLERENDER_DRAW; + lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc; + SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1); + + } else { + // create standard DVASPECT_CONTENT/OLERENDER_DRAW object + dwOleRenderOpt = OLERENDER_DRAW; + } + + // unload original link object + ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_SAVEIFDIRTY); + + // delete entire contents of the current object's storage + OleStdDestroyAllElements(lpContainerLine->m_lpStg); + + OLEDBG_BEGIN2("OleCreateLink called\r\n") + hrErr = OleCreateLink ( + lpmkLinkSrc, + &IID_IOleObject, + dwOleRenderOpt, + lpRenderFmtEtc, + (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite, + lpContainerLine->m_lpStg, + (LPVOID FAR*)&lpContainerLine->m_lpOleObj + ); + OLEDBG_END2 + + if (hrErr == NOERROR) { + if (! ContainerLine_SetupOleObject( + lpContainerLine, fDisplayAsIcon, hMetaPict) ) { + + // ERROR: setup of the new link failed. + // revert the storage to restore the original link. + ContainerLine_UnloadOleObject( + lpContainerLine, OLECLOSE_NOSAVE); + lpContainerLine->m_lpStg->lpVtbl->Revert( + lpContainerLine->m_lpStg); + sc = E_FAIL; + } else { + sc = S_OK; // IT WORKED! + + } + } + else { + sc = GetScode(hrErr); + OleDbgOutHResult("OleCreateLink returned", hrErr); + // ERROR: Re-creating the link failed. + // revert the storage to restore the original link. + lpContainerLine->m_lpStg->lpVtbl->Revert( + lpContainerLine->m_lpStg); + } + } + + if (hMetaPict) + OleUIMetafilePictIconFree(hMetaPict); // clean up metafile + return ResultFromScode(sc); +} + +/* ContainerLine_GetOleObject +** -------------------------- +** return pointer to desired interface of embedded/linked object. +** +** NOTE: this function causes an AddRef to the object. when the caller is +** finished with the object, it must call Release. +** this function does not AddRef the ContainerLine object. +*/ +LPUNKNOWN ContainerLine_GetOleObject( + LPCONTAINERLINE lpContainerLine, + REFIID riid +) +{ + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + if (lpContainerLine->m_lpOleObj) + return OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, + riid + ); + else + return NULL; +} + + + +/* ContainerLine_RunOleObject +** -------------------------- +** Load and run the object. Upon running and if size of object has changed, +** use SetExtent to change to new size. +** +*/ +HRESULT ContainerLine_RunOleObject(LPCONTAINERLINE lpContainerLine) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + SIZEL sizelNew; + HRESULT hrErr; + HCURSOR hPrevCursor; + + if (! lpContainerLine) + return NOERROR; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to Run the object + return ResultFromScode(E_FAIL); + } + + if (lpContainerLine->m_lpOleObj && + OleIsRunning(lpContainerLine->m_lpOleObj)) + return NOERROR; // object already running + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + OLEDBG_BEGIN3("ContainerLine_RunOleObject\r\n") + + if (! lpContainerLine->m_lpOleObj) { + if (! ContainerLine_LoadOleObject(lpContainerLine)) + return ResultFromScode(E_OUTOFMEMORY); // Error: couldn't load obj + } + + OLEDBG_BEGIN2("OleRun called\r\n") + hrErr = OleRun((LPUNKNOWN)lpContainerLine->m_lpOleObj); + OLEDBG_END2 + + if (hrErr != NOERROR) { + SetCursor(hPrevCursor); // restore original cursor + + OleDbgOutHResult("OleRun returned", hrErr); + OLEDBG_END3 + return hrErr; + } + + if (lpContainerLine->m_fDoSetExtent) { + /* OLE2NOTE: the OLE object was resized when it was not running + ** and the object did not have the OLEMISC_RECOMPOSEONRESIZE + ** bit set. if it had, the object would have been run + ** immediately when it was resized. this flag indicates that + ** the object does something other than simple scaling when + ** it is resized. because the object is being run now, we + ** will call IOleObject::SetExtent. + */ + lpContainerLine->m_fDoSetExtent = FALSE; + + // the size stored in our Line includes the border around the object. + // we must subtract the border to get the size of the object itself. + sizelNew.cx = lpLine->m_nWidthInHimetric; + sizelNew.cy = lpLine->m_nHeightInHimetric; + + if ((sizelNew.cx != lpContainerLine->m_sizeInHimetric.cx) || + (sizelNew.cy != lpContainerLine->m_sizeInHimetric.cy)) { + + OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetExtent( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSIZEL)&sizelNew + ); + OLEDBG_END2 + } + } + + SetCursor(hPrevCursor); // restore original cursor + + OLEDBG_END3 + return NOERROR; + +} + + +/* ContainerLine_IsOleLink +** ----------------------- +** +** return TRUE if the ContainerLine has an OleLink. +** FALSE if the ContainerLine has an embedding +*/ +BOOL ContainerLine_IsOleLink(LPCONTAINERLINE lpContainerLine) +{ + if (!lpContainerLine) + return FALSE; + + return (lpContainerLine->m_dwLinkType != 0); +} + + +/* ContainerLine_Draw +** ------------------ +** +** Draw a ContainerLine object on a DC. +** +** Parameters: +** hDC - DC to which the line will be drawn +** lpRect - the object rect in logical coordinates +** lpRectWBounds - bounding rect of the metafile underneath hDC +** (NULL if hDC is not a metafile DC) +** fHighlight - TRUE if line has selection highlight +*/ +void ContainerLine_Draw( + LPCONTAINERLINE lpContainerLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight +) +{ + LPLINE lpLine = (LPLINE) lpContainerLine; + HRESULT hrErr = NOERROR; + RECTL rclHim; + RECTL rclHimWBounds; + RECT rcHim; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--do NOT try to draw + return; + } + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpViewObj2) { + if (! ContainerLine_LoadOleObject(lpContainerLine)) + return; // Error: could not load object + } + + if (lpRectWBounds) { + rclHimWBounds.left = (long) lpRectWBounds->left; + rclHimWBounds.bottom = (long) lpRectWBounds->bottom; + rclHimWBounds.top = (long) lpRectWBounds->top; + rclHimWBounds.right = (long) lpRectWBounds->right; + } + + /* construct bounds rectangle for the object. + ** offset origin for object to correct tab indentation + */ + rclHim.left = (long) lpRect->left; + rclHim.bottom = (long) lpRect->bottom; + rclHim.top = (long) lpRect->top; + rclHim.right = (long) lpRect->right; + + rclHim.left += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric; + rclHim.right += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric; + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: if the OLE object currently has a visible in-place + ** window, then we do NOT want to draw on top of its window. + ** this could interfere with the object's display. + */ + if ( !lpContainerLine->m_fIpVisible ) +#endif + { + hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->Draw( + lpContainerLine->m_lpViewObj2, + lpContainerLine->m_dwDrawAspect, + -1, + NULL, + NULL, + NULL, + hDC, + (LPRECTL)&rclHim, + (lpRectWBounds ? (LPRECTL)&rclHimWBounds : NULL), + NULL, + 0 + ); + if (hrErr != NOERROR) + OleDbgOutHResult("IViewObject::Draw returned", hrErr); + + if (lpContainerLine->m_fObjWinOpen) + { + rcHim.left = (int) rclHim.left; + rcHim.top = (int) rclHim.top; + rcHim.right = (int) rclHim.right; + rcHim.bottom = (int) rclHim.bottom; + + /* OLE2NOTE: if the object servers window is Open (ie. not active + ** in-place) then we must shade the object in our document to + ** indicate to the user that the object is open elsewhere. + */ + OleUIDrawShading((LPRECT)&rcHim, hDC, OLEUI_SHADE_FULLRECT, 0); + } + } + + /* if the object associated with the ContainerLine is an automatic + ** link then try to connect it with its LinkSource if the + ** LinkSource is already running. we do not want to force the + ** LinkSource to run. + ** + ** OLE2NOTE: a sophistocated container will want to continually + ** attempt to connect its automatic links. OLE does NOT + ** automatically connect links when link sources become + ** available. some containers will want to attempt to connect + ** its links as part of idle time processing. another strategy + ** is to attempt to connect an automatic link every time it is + ** drawn on the screen. (this is the strategy used by this + ** CntrOutl sample application.) + */ + if (lpContainerLine->m_dwLinkType == OLEUPDATE_ALWAYS) + ContainerLine_BindLinkIfLinkSrcIsRunning(lpContainerLine); + + return; +} + + +void ContainerLine_DrawSelHilight( + LPCONTAINERLINE lpContainerLine, + HDC hDC, // MM_TEXT mode + LPRECT lprcPix, // listbox rect + UINT itemAction, + UINT itemState +) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + RECT rcObj; + DWORD dwFlags = OLEUI_HANDLES_INSIDE | OLEUI_HANDLES_USEINVERSE; + int nHandleSize; + LPCONTAINERDOC lpContainerDoc; + + if (!lpContainerLine || !hDC || !lprcPix) + return; + + lpContainerDoc = lpContainerLine->m_lpDoc; + + // Get size of OLE object + ContainerLine_GetOleObjectRectInPixels(lpContainerLine, (LPRECT)&rcObj); + + nHandleSize = GetProfileInt("windows", "oleinplaceborderwidth", + DEFAULT_HATCHBORDER_WIDTH) + 1; + + OleUIDrawHandles((LPRECT)&rcObj, hDC, dwFlags, nHandleSize, TRUE); +} + +/* InvertDiffRect +** -------------- +** +** Paint the surrounding of the Obj rect black but within lprcPix +** (similar to the lprcPix minus lprcObj) +*/ +static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC) +{ + RECT rcBlack; + + // draw black in all space outside of object's rectangle + rcBlack.top = lprcPix->top; + rcBlack.bottom = lprcPix->bottom; + + rcBlack.left = lprcPix->left + 1; + rcBlack.right = lprcObj->left - 1; + InvertRect(hDC, (LPRECT)&rcBlack); + + rcBlack.left = lprcObj->right + 1; + rcBlack.right = lprcPix->right - 1; + InvertRect(hDC, (LPRECT)&rcBlack); + + rcBlack.top = lprcPix->top; + rcBlack.bottom = lprcPix->top + 1; + rcBlack.left = lprcObj->left - 1; + rcBlack.right = lprcObj->right + 1; + InvertRect(hDC, (LPRECT)&rcBlack); + + rcBlack.top = lprcPix->bottom; + rcBlack.bottom = lprcPix->bottom - 1; + rcBlack.left = lprcObj->left - 1; + rcBlack.right = lprcObj->right + 1; + InvertRect(hDC, (LPRECT)&rcBlack); +} + + +/* Edit the ContainerLine line object. +** returns TRUE if line was changed +** FALSE if the line was NOT changed +*/ +BOOL ContainerLine_Edit(LPCONTAINERLINE lpContainerLine, HWND hWndDoc,HDC hDC) +{ + ContainerLine_DoVerb(lpContainerLine, OLEIVERB_PRIMARY, NULL, TRUE, TRUE); + + /* assume object was NOT changed, if it was obj will send Changed + ** or Saved notification. + */ + return FALSE; +} + + + +/* ContainerLine_SetHeightInHimetric +** --------------------------------- +** +** Set the height of a ContainerLine object. The widht will be changed +** to keep the aspect ratio +*/ +void ContainerLine_SetHeightInHimetric(LPCONTAINERLINE lpContainerLine, int nHeight) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + SIZEL sizelOleObject; + HRESULT hrErr; + + if (!lpContainerLine) + return; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to set the Height + return; + } + + if (nHeight != -1) { + BOOL fMustClose = FALSE; + BOOL fMustRun = FALSE; + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + // the height argument specifies the desired height for the Line. + sizelOleObject.cy = nHeight; + + // we will calculate the corresponding width for the object by + // maintaining the current aspect ratio of the object. + sizelOleObject.cx = (int)(sizelOleObject.cy * + lpContainerLine->m_sizeInHimetric.cx / + lpContainerLine->m_sizeInHimetric.cy); + + /* OLE2NOTE: if the OLE object is already running then we can + ** immediately call SetExtent. But, if the object is NOT + ** currently running then we will check if the object + ** indicates that it is normally recomposes itself on + ** resizing. ie. that the object does not simply scale its + ** display when it it resized. if so then we will force the + ** object to run so that we can call IOleObject::SetExtent. + ** SetExtent does not have any effect if the object is only + ** loaded. if the object does NOT indicate that it + ** recomposes on resize (OLEMISC_RECOMPOSEONRESIZE) then we + ** will wait till the next time that the object is run to + ** call SetExtent. we will store a flag in the ContainerLine + ** to indicate that a SetExtent is necessary. It is + ** necessary to persist this flag. + */ + if (! OleIsRunning(lpContainerLine->m_lpOleObj)) { + DWORD dwStatus; + + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPDWORD)&dwStatus + ); + OLEDBG_END2 + if (hrErr == NOERROR && (dwStatus & OLEMISC_RECOMPOSEONRESIZE)) { + // force the object to run + ContainerLine_RunOleObject(lpContainerLine); + fMustClose = TRUE; + } else { + /* the OLE object is NOT running and does NOT + ** recompose on resize. simply scale the object now + ** and do the SetExtent the next time the object is + ** run. we set the Line to the new size even though + ** the object's extents have not been changed. + ** this has the result of scaling the object's + ** display to the new size. + */ + lpContainerLine->m_fDoSetExtent = TRUE; + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine, (LPSIZEL)&sizelOleObject); + return; + } + } + + OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n") + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->SetExtent( + lpContainerLine->m_lpOleObj, + lpContainerLine->m_dwDrawAspect, + (LPSIZEL)&sizelOleObject); + OLEDBG_END2 + + if (hrErr != NOERROR) { + /* OLE Object refuses to take on the new extents. Set the + ** Line to the new size even though the object refused + ** the new extents. this has the result of scaling the + ** object's display to the new size. + ** + ** if the object HAD accepted the new extents, then it + ** will send out an OnViewChange/OnDataChange + ** notification. this results in our container receiving + ** an OnViewChange notification; the line height will be + ** reset when this notification is received. + */ + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine, (LPSIZEL)&sizelOleObject); + } + + if (fMustClose) + ContainerLine_CloseOleObject( + lpContainerLine, OLECLOSE_SAVEIFDIRTY); + } + else { + /* Set the line to default height given the natural (unscaled) + ** extents of the OLE object. + */ + ContainerLine_SetLineHeightFromObjectExtent( + lpContainerLine,(LPSIZEL)&lpContainerLine->m_sizeInHimetric); + } + +} + + +/* ContainerLine_SetLineHeightFromObjectExtent + * + * Purpose: + * Calculate the corresponding line height from the OleObject size + * Scale the line height to fit the limit if necessary + * + * Parameters: + * lpsizelOleObject pointer to size of OLE Object + * + * Returns: + * nil + */ +void ContainerLine_SetLineHeightFromObjectExtent( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizelOleObject +) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + + UINT uMaxObjectHeight = XformHeightInPixelsToHimetric(NULL, + LISTBOX_HEIGHT_LIMIT); + + if (!lpContainerLine || !lpsizelOleObject) + return; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to set the Height + return; + } + + lpLine->m_nWidthInHimetric = (int)lpsizelOleObject->cx; + lpLine->m_nHeightInHimetric = (int)lpsizelOleObject->cy; + + // Rescale the object if height is greater than the limit + if (lpLine->m_nHeightInHimetric > (UINT)uMaxObjectHeight) { + + lpLine->m_nWidthInHimetric = (UINT) + ((long)lpLine->m_nWidthInHimetric * + (long)uMaxObjectHeight / + (long)lpLine->m_nHeightInHimetric); + + lpLine->m_nHeightInHimetric = uMaxObjectHeight; + } + +} + + +/* ContainerLine_SaveToStg +** ----------------------- +** Save a given ContainerLine and associated OLE object to an IStorage*. +*/ +BOOL ContainerLine_SaveToStm( + LPCONTAINERLINE lpContainerLine, + LPSTREAM lpLLStm +) +{ + CONTAINERLINERECORD objLineRecord; + ULONG nWritten; + HRESULT hrErr; + + lstrcpy(objLineRecord.m_szStgName, lpContainerLine->m_szStgName); + objLineRecord.m_fMonikerAssigned = lpContainerLine->m_fMonikerAssigned; + objLineRecord.m_dwDrawAspect = lpContainerLine->m_dwDrawAspect; + objLineRecord.m_sizeInHimetric = lpContainerLine->m_sizeInHimetric; + objLineRecord.m_dwLinkType = lpContainerLine->m_dwLinkType; + objLineRecord.m_fDoSetExtent = lpContainerLine->m_fDoSetExtent; + + /* write line record */ + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&objLineRecord, + sizeof(CONTAINERLINERECORD), + &nWritten + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr == NOERROR,"Could not write to LineList stream"); + return FALSE; + } + + return TRUE; +} + + +/* ContainerLine_SaveOleObjectToStg +** -------------------------------- +** Save the OLE object associated with the ContainerLine to an IStorage*. +*/ +BOOL ContainerLine_SaveOleObjectToStg( + LPCONTAINERLINE lpContainerLine, + LPSTORAGE lpSrcStg, + LPSTORAGE lpDestStg, + BOOL fRemember +) +{ + HRESULT hrErr; + SCODE sc = S_OK; + BOOL fStatus; + BOOL fSameAsLoad = (lpSrcStg==lpDestStg ? TRUE : FALSE); + LPSTORAGE lpObjDestStg; + + if (lpContainerLine->m_fGuardObj) { + // object in process of creation--Fail to save + return FALSE; + } + + if (! lpContainerLine->m_lpOleObj) { + + /***************************************************************** + ** CASE 1: object is NOT loaded. + *****************************************************************/ + + if (fSameAsLoad) { + /************************************************************* + ** CASE 1A: we are saving to the current storage. because + ** the object is not loaded, it is up-to-date + ** (ie. nothing to do). + *************************************************************/ + + ; + + } else { + /************************************************************* + ** CASE 1B: we are saving to a new storage. because + ** the object is not loaded, we can simply copy the + ** object's current storage to the new storage. + *************************************************************/ + + /* if current object storage is not already open, then open it */ + if (! lpContainerLine->m_lpStg) { + lpContainerLine->m_lpStg = OleStdOpenChildStorage( + lpSrcStg, + lpContainerLine->m_szStgName, + STGM_READWRITE + ); + if (lpContainerLine->m_lpStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpContainerLine->m_lpStg != NULL, + "Error opening child stg" + ); +#endif + return FALSE; + } + } + + /* Create a child storage inside the destination storage. */ + lpObjDestStg = OleStdCreateChildStorage( + lpDestStg, + lpContainerLine->m_szStgName + ); + + if (lpObjDestStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpObjDestStg != NULL, + "Could not create obj storage!" + ); +#endif + return FALSE; + } + + hrErr = lpContainerLine->m_lpStg->lpVtbl->CopyTo( + lpContainerLine->m_lpStg, + 0, + NULL, + NULL, + lpObjDestStg + ); + // REVIEW: should we handle error here? + fStatus = OleStdCommitStorage(lpObjDestStg); + + /* if we are supposed to remember this storage as the new + ** storage for the object, then release the old one and + ** save the new one. else, throw away the new one. + */ + if (fRemember) { + OleStdVerifyRelease( + (LPUNKNOWN)lpContainerLine->m_lpStg, + "Original object stg not released" + ); + lpContainerLine->m_lpStg = lpObjDestStg; + } else { + OleStdVerifyRelease( + (LPUNKNOWN)lpObjDestStg, + "Copied object stg not released" + ); + } + } + + } else { + + /***************************************************************** + ** CASE 2: object IS loaded. + *****************************************************************/ + + if (fSameAsLoad) { + /************************************************************* + ** CASE 2A: we are saving to the current storage. if the object + ** is not dirty, then the current storage is up-to-date + ** (ie. nothing to do). + *************************************************************/ + + LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg; + OleDbgAssert(lpPersistStg); + + hrErr = lpPersistStg->lpVtbl->IsDirty(lpPersistStg); + + /* OLE2NOTE: we will only accept an explicit "no i + ** am NOT dirty statement" (ie. S_FALSE) as an + ** indication that the object is clean. eg. if + ** the object returns E_NOTIMPL we must + ** interpret it as the object IS dirty. + */ + if (GetScode(hrErr) != S_FALSE) { + + /* OLE object IS dirty */ + + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr = OleSave( + lpPersistStg, lpContainerLine->m_lpStg, fSameAsLoad); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + // OLE2NOTE: if OleSave fails, SaveCompleted must be called. + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + if (sc != S_OK) + return FALSE; + } + + } else { + /************************************************************* + ** CASE 2B: we are saving to a new storage. we must + ** tell the object to save into the new storage. + *************************************************************/ + + LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg; + + if (! lpPersistStg) return FALSE; + + /* Create a child storage inside the destination storage. */ + lpObjDestStg = OleStdCreateChildStorage( + lpDestStg, + lpContainerLine->m_szStgName + ); + + if (lpObjDestStg == NULL) { +#if defined( _DEBUG ) + OleDbgAssertSz( + lpObjDestStg != NULL, + "Could not create object storage!" + ); +#endif + return FALSE; + } + + OLEDBG_BEGIN2("OleSave called\r\n") + hrErr = OleSave(lpPersistStg, lpObjDestStg, fSameAsLoad); + OLEDBG_END2 + + // OLE2NOTE: even if OleSave fails, must still call SaveCompleted + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: OleSave returned", hrErr); + sc = GetScode(hrErr); + } + + /* OLE2NOTE: a root level container should immediately + ** call IPersistStorage::SaveCompleted after calling + ** OleSave. a nested level container should not call + ** SaveCompleted now, but must wait until SaveCompleted + ** is call on it by its container. since our container + ** is not a container/server, then we always call + ** SaveComplete here. + ** + ** if this is a SaveAs operation, then we need to pass + ** the lpStg back in SaveCompleted to inform the object + ** of its new storage that it may hold on to. if this is + ** a Save or a SaveCopyAs operation, then we simply pass + ** NULL in SaveCompleted; the object can continue to hold + ** its current storage. if an error occurs during the + ** OleSave call we must still call SaveCompleted but we + ** must pass NULL. + */ + OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n") + hrErr = lpPersistStg->lpVtbl->SaveCompleted( + lpPersistStg, + ((FAILED(sc) || !fRemember) ? NULL : lpObjDestStg) + ); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr); + if (sc == S_OK) + sc = GetScode(hrErr); + } + + if (sc != S_OK) { + OleStdVerifyRelease( + (LPUNKNOWN)lpObjDestStg, + "Copied object stg not released" + ); + return FALSE; + } + + /* if we are supposed to remember this storage as the new + ** storage for the object, then release the old one and + ** save the new one. else, throw away the new one. + */ + if (fRemember) { + OleStdVerifyRelease( + (LPUNKNOWN)lpContainerLine->m_lpStg, + "Original object stg not released" + ); + lpContainerLine->m_lpStg = lpObjDestStg; + } else { + OleStdVerifyRelease( + (LPUNKNOWN)lpObjDestStg, + "Copied object stg not released" + ); + } + } + } + + /* OLE2NOTE: after saving an OLE object it is possible that it sent + ** an OnViewChange notification because it had been modified. in + ** this situation it is possible that the extents of the object + ** have changed. if so we want to relayout the space for the + ** object immediately so that the extent information saved with + ** the ContainerLine match the data saved with the OLE object + ** itself. + */ + if (lpContainerLine->m_fDoGetExtent) { + BOOL fSizeChanged = ContainerLine_UpdateExtent(lpContainerLine, NULL); +#if defined( INPLACE_CNTR ) + /* if the extents of this ContainerLine have changed, then we + ** need to reset the fDoGetExtent flag to TRUE so that later + ** when ContainerDoc_UpdateExtentOfAllOleObjects is called + ** (when the WM_U_UPDATEOBJECTEXTENT message is processed), + ** it is recognized that the extents of this line have + ** changed. if any line changes size, then any in-place + ** active object below this line must be told to update the + ** position of their windows (via SetObjectRects -- see + ** ContainerDoc_UpdateInPlaceObjectRects function). + */ + lpContainerLine->m_fDoGetExtent = fSizeChanged; +#endif + } + + return TRUE; +} + + +/* ContainerLine_LoadFromStg +** ------------------------- +** Create a ContainerLine object and initialize it with data that +** was previously writen to an IStorage*. this function does not +** immediately OleLoad the associated OLE object, only the data of +** the ContainerLine object itself is loaded from the IStorage*. +*/ +LPLINE ContainerLine_LoadFromStg( + LPSTORAGE lpSrcStg, + LPSTREAM lpLLStm, + LPOUTLINEDOC lpDestDoc +) +{ + HDC hDC; + LPLINELIST lpDestLL = &lpDestDoc->m_LineList; + ULONG nRead; + HRESULT hrErr; + LPCONTAINERLINE lpContainerLine; + CONTAINERLINERECORD objLineRecord; + + lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE)); + if (lpContainerLine == NULL) { + OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine"); + return NULL; + } + + hDC = LineList_GetDC(lpDestLL); + ContainerLine_Init(lpContainerLine, 0, hDC); + LineList_ReleaseDC(lpDestLL, hDC); + + /* OLE2NOTE: In order to have a stable ContainerLine object we must + ** AddRef the object's refcnt. this will be later released when + ** the ContainerLine is deleted. + */ + ContainerLine_AddRef(lpContainerLine); + + lpContainerLine->m_lpDoc = (LPCONTAINERDOC) lpDestDoc; + + /* read line record */ + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&objLineRecord, + sizeof(CONTAINERLINERECORD), + &nRead + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR, "Could not read from LineList stream"); + goto error; + } + + lstrcpy(lpContainerLine->m_szStgName, objLineRecord.m_szStgName); + lpContainerLine->m_fMonikerAssigned = objLineRecord.m_fMonikerAssigned; + lpContainerLine->m_dwDrawAspect = objLineRecord.m_dwDrawAspect; + lpContainerLine->m_sizeInHimetric = objLineRecord.m_sizeInHimetric; + lpContainerLine->m_dwLinkType = objLineRecord.m_dwLinkType; + lpContainerLine->m_fDoSetExtent = objLineRecord.m_fDoSetExtent; + + return (LPLINE)lpContainerLine; + +error: + // destroy partially created ContainerLine + if (lpContainerLine) + ContainerLine_Delete(lpContainerLine); + return NULL; +} + + +/* ContainerLine_GetTextLen + * ------------------------ + * + * Return length of the string representation of the ContainerLine + * (not considering the tab level). we will use the following as the + * string representation of a ContainerLine: + * "<" + user type name of OLE object + ">" + * eg: + * <Microsoft Excel Worksheet> + */ +int ContainerLine_GetTextLen(LPCONTAINERLINE lpContainerLine) +{ + LPSTR lpszUserType = NULL; + HRESULT hrErr; + int nLen; + BOOL fIsLink = ContainerLine_IsOleLink(lpContainerLine); + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n") + + { + LPOLESTR polestr; + + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserType( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_FULL, + &polestr + ); + + CopyAndFreeOLESTR(polestr, &lpszUserType); + } + + OLEDBG_END2 + + if (hrErr != NOERROR) { + // user type is NOT available + nLen = sizeof(UNKNOWN_OLEOBJ_TYPE) + 2; // allow space for '<' + '>' + nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1; + } else { + nLen = lstrlen(lpszUserType) + 2; // allow space for '<' + '>' + nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1; + + /* OLE2NOTE: we must free the string that was allocated by the + ** IOleObject::GetUserType method. + */ + OleStdFreeString(lpszUserType, NULL); + } + + return nLen; +} + + +/* ContainerLine_GetTextData + * ------------------------- + * + * Return the string representation of the ContainerLine + * (not considering the tab level). we will use the following as the + * string representation of a ContainerLine: + * "<" + user type name of OLE object + ">" + * eg: + * <Microsoft Excel Worksheet> + */ +void ContainerLine_GetTextData(LPCONTAINERLINE lpContainerLine, LPSTR lpszBuf) +{ + LPSTR lpszUserType = NULL; + BOOL fIsLink = ContainerLine_IsOleLink(lpContainerLine); + HRESULT hrErr; + LPOLESTR polestr; + + /* if object is not already loaded, then load it now. objects are + ** loaded lazily in this manner. + */ + if (! lpContainerLine->m_lpOleObj) + ContainerLine_LoadOleObject(lpContainerLine); + + { + LPOLESTR polestr; + + hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserType( + lpContainerLine->m_lpOleObj, + USERCLASSTYPE_FULL, + &lpszUserType + ); + + CopyAndFree(polestr, &lpszUserType); + } + + // Convert output to mbs + CopyAndFree(polestr, &lpszUserType); + + if (hrErr != NOERROR) { + // user type is NOT available + wsprintf( + lpszBuf, + "<%s %s>", + UNKNOWN_OLEOBJ_TYPE, + (LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT) + ); + } else { + wsprintf( + lpszBuf, + "<%s %s>", + lpszUserType, + (LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT) + ); + + /* OLE2NOTE: we must free the string that was allocated by the + ** IOleObject::GetUserType method. + */ + OleStdFreeString(lpszUserType, NULL); + } +} + + +/* ContainerLine_GetOutlineData + * ---------------------------- + * + * Return the CF_OUTLINE format data for the ContainerLine. + */ +BOOL ContainerLine_GetOutlineData( + LPCONTAINERLINE lpContainerLine, + LPTEXTLINE lpBuf +) +{ + LPLINE lpLine = (LPLINE)lpContainerLine; + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList; + HDC hDC; + char szTmpBuf[MAXSTRLEN+1]; + LPTEXTLINE lpTmpTextLine; + + // Create a TextLine with the Text representation of the ContainerLine. + ContainerLine_GetTextData(lpContainerLine, (LPSTR)szTmpBuf); + + hDC = LineList_GetDC(lpLL); + lpTmpTextLine = TextLine_Create(hDC, lpLine->m_nTabLevel, szTmpBuf); + LineList_ReleaseDC(lpLL, hDC); + + TextLine_Copy(lpTmpTextLine, lpBuf); + + // Delete the temporary TextLine + TextLine_Delete(lpTmpTextLine); + return TRUE; +} + + +/* ContainerLine_GetPosRect +** ----------------------- +** Get the PosRect in client coordinates for the OLE object's window. +** +** OLE2NOTE: the PosRect must take into account the scroll postion of +** the document window. +*/ +void ContainerLine_GetPosRect( + LPCONTAINERLINE lpContainerLine, + LPRECT lprcPosRect +) +{ + ContainerLine_GetOleObjectRectInPixels(lpContainerLine,lprcPosRect); + + // shift rect for left margin + lprcPosRect->left += lpContainerLine->m_nHorizScrollShift; + lprcPosRect->right += lpContainerLine->m_nHorizScrollShift; +} + + +/* ContainerLine_GetOleObjectRectInPixels +** -------------------------------------- +** Get the extent of the OLE Object contained in the given Line in +** client coordinates after scaling. +*/ +void ContainerLine_GetOleObjectRectInPixels(LPCONTAINERLINE lpContainerLine, LPRECT lprc) +{ + LPOUTLINEDOC lpOutlineDoc; + LPSCALEFACTOR lpscale; + LPLINELIST lpLL; + LPLINE lpLine; + int nIndex; + HDC hdcLL; + + if (!lpContainerLine || !lprc) + return; + + lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc; + lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc); + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + lpLine = (LPLINE)lpContainerLine; + nIndex = LineList_GetLineIndex(lpLL, lpLine); + + LineList_GetLineRect(lpLL, nIndex, lprc); + + hdcLL = GetDC(lpLL->m_hWndListBox); + + /* lprc is set to be size of Line Object (including the boundary) */ + lprc->left += (int)( + (long)XformWidthInHimetricToPixels(hdcLL, + lpLine->m_nTabWidthInHimetric + + LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) * + lpscale->dwSxN / lpscale->dwSxD); + lprc->right = (int)( + lprc->left + (long) + XformWidthInHimetricToPixels(hdcLL, lpLine->m_nWidthInHimetric) * + lpscale->dwSxN / lpscale->dwSxD); + + ReleaseDC(lpLL->m_hWndListBox, hdcLL); +} + + +/* ContainerLine_GetOleObjectSizeInHimetric +** ---------------------------------------- +** Get the size of the OLE Object contained in the given Line +*/ +void ContainerLine_GetOleObjectSizeInHimetric(LPCONTAINERLINE lpContainerLine, LPSIZEL lpsizel) +{ + if (!lpContainerLine || !lpsizel) + return; + + *lpsizel = lpContainerLine->m_sizeInHimetric; +} + + +/* ContainerLine_BindLinkIfLinkSrcIsRunning +** ---------------------------------------- +** Try to connect the OLE link object associated with the +** ContainerLine with its LinkSource if the LinkSource is already +** running and the link is an automatic link. we do not want to +** force the LinkSource to run. +** +** OLE2NOTE: a sophistocated container will want to continually +** attempt to connect its automatic links. OLE does NOT +** automatically connect links when link source become available. some +** containers will want to attempt to connect its links as part of +** idle time processing. another strategy is to attempt to connect +** an automatic link every time it is drawn on the screen. (this is +** the strategy used by this CntrOutl sample application.) +*/ +void ContainerLine_BindLinkIfLinkSrcIsRunning(LPCONTAINERLINE lpContainerLine) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + HRESULT hrErr; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + + // if the link source is known to be un-bindable, then don't even try + if (lpContainerLine->m_fLinkUnavailable) + return; + + /* OLE2NOTE: we do not want to ever give the Busy/NotResponding + ** dialogs when we are attempting to BindIfRunning to the link + ** source. if the link source is currently busy, this could + ** cause the Busy dialog to come up. even if the link source is + ** busy, we do not want put up the busy dialog. thus we will + ** disable the dialog and later re-enable them + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n") + hrErr = lpContainerLine->m_lpOleLink->lpVtbl->BindIfRunning( + lpContainerLine->m_lpOleLink); + OLEDBG_END2 + + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); +} diff --git a/private/oleutest/letest/outline/cntroutl.h b/private/oleutest/letest/outline/cntroutl.h new file mode 100644 index 000000000..48930f3b3 --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl.h @@ -0,0 +1,855 @@ +/************************************************************************* +** +** OLE 2.0 Container Sample Code +** +** cntroutl.h +** +** This file contains file contains data structure defintions, +** function prototypes, constants, etc. used by the OLE 2.0 container +** app version of the Outline series of sample applications: +** Outline -- base version of the app (without OLE functionality) +** SvrOutl -- OLE 2.0 Server sample app +** CntrOutl -- OLE 2.0 Containter (Container) sample app +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if !defined( _CNTROUTL_H_ ) +#define _CNTROUTL_H_ + +#ifndef RC_INVOKED +#pragma message ("INCLUDING CNTROUTL.H from " __FILE__) +#endif /* RC_INVOKED */ + +#include "oleoutl.h" +#include "cntrrc.h" + +// REVIEW: should load from string resource +#define DEFOBJNAMEPREFIX "Obj" // Prefix for auto-generated stg names +#define DEFOBJWIDTH 5000 // default size for embedded obj. +#define DEFOBJHEIGHT 5000 // default size for embedded obj. +#define UNKNOWN_OLEOBJ_TYPE "Unknown OLE Object Type" +#define szOLEOBJECT "Object" +#define szOLELINK "Link" + +#define CONTAINERDOCFORMAT "CntrOutl" // CF_CntrOutl format name + +/* Forward definition of types */ +typedef struct tagCONTAINERDOC FAR* LPCONTAINERDOC; +typedef struct tagCONTAINERLINE FAR* LPCONTAINERLINE; + + +// Flags to specify type of OLECREATE???FROMDATA call required +typedef enum tagOLECREATEFROMDATATYPE { + OLECREATEFROMDATA_LINK = 1, + OLECREATEFROMDATA_OBJECT = 2, + OLECREATEFROMDATA_STATIC = 3 +} OLECREATEFROMDATATYPE; + +/************************************************************************* +** class CONTAINERLINE : LINE +** The class CONTAINERLINE is a concrete subclass of the abstract base +** class LINE. The CONTAINERLINE maintains all information about the +** place within the CONTAINERDOC that an OLE object is embedded. This +** object implements the following OLE 2.0 interfaces: +** IOleClientSite +** IAdviseSink +** In the CntrOutl client app either CONTAINERLINE objects or TEXTLINE +** objects can be created. The CONTAINERLINE class inherits all fields +** from the LINE class. This inheritance is achieved by including a +** member variable of type LINE as the first field in the CONTAINERLINE +** structure. Thus a pointer to a CONTAINERLINE object can be cast to be +** a pointer to a LINE object. +** Each CONTAINERLINE object that is created in added to the LINELIST of +** the associated OUTLINEDOC document. +*************************************************************************/ + +typedef struct tagCONTAINERLINE { + LINE m_Line; // ContainerLine inherits fields of Line + ULONG m_cRef; // total ref count for line + char m_szStgName[CWCSTORAGENAME]; // stg name w/i cntr stg + BOOL m_fObjWinOpen; // is obj window open? if so, shade obj. + BOOL m_fMonikerAssigned; // has a moniker been assigned to obj + DWORD m_dwDrawAspect; // current display aspect for obj + // (either DVASPECT_CONTENT or + // DVASPECT_ICON) + BOOL m_fGuardObj; // Guard against re-entrancy while + // loading or creating an OLE object + BOOL m_fDoGetExtent; // indicates extents may have changed + BOOL m_fDoSetExtent; // obj was resized when not running + // IOO::SetExtent needed on next run + SIZEL m_sizeInHimetric; // extents of obj in himetric units + LPSTORAGE m_lpStg; // open pstg when obj is loaded + LPCONTAINERDOC m_lpDoc; // ptr to associated client doc + LPOLEOBJECT m_lpOleObj; // ptr to IOleObject* when obj is loaded + LPVIEWOBJECT2 m_lpViewObj2; // ptr to IViewObject2* when obj is loaded + LPPERSISTSTORAGE m_lpPersistStg;// ptr to IPersistStorage* when obj loaded + LPOLELINK m_lpOleLink; // ptr to IOleLink* if link is loaded + DWORD m_dwLinkType; // is it a linked object? + // 0 -- NOT a link + // OLEUPDATE_ALWAYS (1) -- auto link + // OLEUPDATE_ONCALL (3) -- man. link + BOOL m_fLinkUnavailable; // is the link unavailable? + LPSTR m_lpszShortType;// short type name of OLE object needed + // to make the Edit.Object.Verb menu + int m_nHorizScrollShift; // horiz scroll shift required + // for object's inplace window. + // (note: this is ICNTROTL specific) + +#if defined( INPLACE_CNTR ) + BOOL m_fIpActive; // is object in-place active (undo valid) + BOOL m_fUIActive; // is object UIActive + BOOL m_fIpVisible; // is object's in-place window visible + BOOL m_fInsideOutObj;// is obj inside-out (visible when loaded) + LPOLEINPLACEOBJECT m_lpOleIPObj; // IOleInPlaceObject* of in-place obj + BOOL m_fIpChangesUndoable; // can in-place object do undo + BOOL m_fIpServerRunning; // is in-place server running + HWND m_hWndIpObject; + + struct COleInPlaceSiteImpl { + IOleInPlaceSiteVtbl FAR* lpVtbl; + LPCONTAINERLINE lpContainerLine; + int cRef; // interface specific ref count. + } m_OleInPlaceSite; +#endif // INPLACE_CNTR + + struct CUnknownImpl { + IUnknownVtbl FAR* lpVtbl; + LPCONTAINERLINE lpContainerLine; + int cRef; // interface specific ref count. + } m_Unknown; + + struct COleClientSiteImpl { + IOleClientSiteVtbl FAR* lpVtbl; + LPCONTAINERLINE lpContainerLine; + int cRef; // interface specific ref count. + } m_OleClientSite; + + struct CAdviseSinkImpl { + IAdviseSinkVtbl FAR* lpVtbl; + LPCONTAINERLINE lpContainerLine; + int cRef; // interface specific ref count. + } m_AdviseSink; + +} CONTAINERLINE; + + +/* ContainerLine methods (functions) */ +void ContainerLine_Init(LPCONTAINERLINE lpContainerLine, int nTab, HDC hDC); +BOOL ContainerLine_SetupOleObject( + LPCONTAINERLINE lpContainerLine, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict +); +LPCONTAINERLINE ContainerLine_Create( + DWORD dwOleCreateType, + HDC hDC, + UINT nTab, + LPCONTAINERDOC lpContainerDoc, + LPCLSID lpclsid, + LPSTR lpszFileName, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSTR lpszStgName +); +LPCONTAINERLINE ContainerLine_CreateFromData( + HDC hDC, + UINT nTab, + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + DWORD dwCreateType, + CLIPFORMAT cfFormat, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSTR lpszStgName +); +ULONG ContainerLine_AddRef(LPCONTAINERLINE lpContainerLine); +ULONG ContainerLine_Release(LPCONTAINERLINE lpContainerLine); +HRESULT ContainerLine_QueryInterface( + LPCONTAINERLINE lpContainerLine, + REFIID riid, + LPVOID FAR* lplpUnk +); +BOOL ContainerLine_CloseOleObject( + LPCONTAINERLINE lpContainerLine, + DWORD dwSaveOption +); +void ContainerLine_UnloadOleObject( + LPCONTAINERLINE lpContainerLine, + DWORD dwSaveOption +); +void ContainerLine_Delete(LPCONTAINERLINE lpContainerLine); +void ContainerLine_Destroy(LPCONTAINERLINE lpContainerLine); +BOOL ContainerLine_CopyToDoc( + LPCONTAINERLINE lpSrcLine, + LPOUTLINEDOC lpDestDoc, + int nIndex +); +BOOL ContainerLine_LoadOleObject(LPCONTAINERLINE lpContainerLine); +BOOL ContainerLine_UpdateExtent( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizelHim +); +BOOL ContainerLine_DoVerb( + LPCONTAINERLINE lpContainerLine, + LONG iVerb, + LPMSG lpMsg, + BOOL fMessage, + BOOL fAction +); +LPUNKNOWN ContainerLine_GetOleObject( + LPCONTAINERLINE lpContainerLine, + REFIID riid +); +HRESULT ContainerLine_RunOleObject(LPCONTAINERLINE lpContainerLine); +BOOL ContainerLine_ProcessOleRunError( + LPCONTAINERLINE lpContainerLine, + HRESULT hrErr, + BOOL fAction, + BOOL fMenuInvoked +); +HRESULT ContainerLine_ReCreateLinkBecauseClassDiff( + LPCONTAINERLINE lpContainerLine +); +BOOL ContainerLine_IsOleLink(LPCONTAINERLINE lpContainerLine); +void ContainerLine_BindLinkIfLinkSrcIsRunning(LPCONTAINERLINE lpContainerLine); +void ContainerLine_Draw( + LPCONTAINERLINE lpContainerLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight + +); +void ContainerLine_DrawSelHilight( + LPCONTAINERLINE lpContainerLine, + HDC hDC, + LPRECT lpRect, + UINT itemAction, + UINT itemState +); +BOOL ContainerLine_Edit(LPCONTAINERLINE lpContainerLine,HWND hWndDoc,HDC hDC); +void ContainerLine_SetHeightInHimetric(LPCONTAINERLINE lpContainerLine, int nHeight); +void ContainerLine_SetLineHeightFromObjectExtent( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizelOleObject +); +BOOL ContainerLine_SaveToStm( + LPCONTAINERLINE lpContainerLine, + LPSTREAM lpLLStm +); +BOOL ContainerLine_SaveOleObjectToStg( + LPCONTAINERLINE lpContainerLine, + LPSTORAGE lpSrcStg, + LPSTORAGE lpDestStg, + BOOL fRemember +); +LPLINE ContainerLine_LoadFromStg( + LPSTORAGE lpSrcStg, + LPSTREAM lpLLStm, + LPOUTLINEDOC lpDestDoc +); +LPMONIKER ContainerLine_GetRelMoniker( + LPCONTAINERLINE lpContainerLine, + DWORD dwAssign +); +LPMONIKER ContainerLine_GetFullMoniker( + LPCONTAINERLINE lpContainerLine, + DWORD dwAssign +); +int ContainerLine_GetTextLen(LPCONTAINERLINE lpContainerLine); +void ContainerLine_GetTextData(LPCONTAINERLINE lpContainerLine,LPSTR lpszBuf); +BOOL ContainerLine_GetOutlineData( + LPCONTAINERLINE lpContainerLine, + LPTEXTLINE lpBuf +); +void ContainerLine_GetOleObjectRectInPixels( + LPCONTAINERLINE lpContainerLine, + LPRECT lprc +); +void ContainerLine_GetPosRect( + LPCONTAINERLINE lpContainerLine, + LPRECT lprcPosRect +); +void ContainerLine_GetOleObjectSizeInHimetric( + LPCONTAINERLINE lpContainerLine, + LPSIZEL lpsizel +); + +#if defined( INPLACE_CNTR ) +void ContainerLine_UIDeactivate(LPCONTAINERLINE lpContainerLine); +void ContainerLine_InPlaceDeactivate(LPCONTAINERLINE lpContainerLine); +void ContainerLine_UpdateInPlaceObjectRects( + LPCONTAINERLINE lpContainerLine, + LPRECT lprcClipRect +); +void ContainerLine_ContextSensitiveHelp( + LPCONTAINERLINE lpContainerLine, + BOOL fEnterMode +); +void ContainerLine_ForwardPaletteChangedMsg( + LPCONTAINERLINE lpContainerLine, + HWND hwndPalChg +); +void ContainerDoc_ContextSensitiveHelp( + LPCONTAINERDOC lpContainerDoc, + BOOL fEnterMode, + BOOL fInitiatedByObj +); +void ContainerDoc_ForwardPaletteChangedMsg( + LPCONTAINERDOC lpContainerDoc, + HWND hwndPalChg +); +#endif // INPLACE_CNTR + +/* ContainerLine::IUnknown methods (functions) */ +STDMETHODIMP CntrLine_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) CntrLine_Unk_AddRef(LPUNKNOWN lpThis); +STDMETHODIMP_(ULONG) CntrLine_Unk_Release(LPUNKNOWN lpThis); + +/* ContainerLine::IOleClientSite methods (functions) */ +STDMETHODIMP CntrLine_CliSite_QueryInterface( + LPOLECLIENTSITE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) CntrLine_CliSite_AddRef(LPOLECLIENTSITE lpThis); +STDMETHODIMP_(ULONG) CntrLine_CliSite_Release(LPOLECLIENTSITE lpThis); +STDMETHODIMP CntrLine_CliSite_SaveObject(LPOLECLIENTSITE lpThis); +STDMETHODIMP CntrLine_CliSite_GetMoniker( + LPOLECLIENTSITE lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +); +STDMETHODIMP CntrLine_CliSite_GetContainer( + LPOLECLIENTSITE lpThis, + LPOLECONTAINER FAR* lplpContainer +); +STDMETHODIMP CntrLine_CliSite_ShowObject(LPOLECLIENTSITE lpThis); +STDMETHODIMP CntrLine_CliSite_OnShowWindow(LPOLECLIENTSITE lpThis,BOOL fShow); +STDMETHODIMP CntrLine_CliSite_RequestNewObjectLayout(LPOLECLIENTSITE lpThis); + +/* ContainerLine::IAdviseSink methods (functions) */ +STDMETHODIMP CntrLine_AdvSink_QueryInterface( + LPADVISESINK lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) CntrLine_AdvSink_AddRef(LPADVISESINK lpThis); +STDMETHODIMP_(ULONG) CntrLine_AdvSink_Release (LPADVISESINK lpThis); +STDMETHODIMP_(void) CntrLine_AdvSink_OnDataChange( + LPADVISESINK lpThis, + FORMATETC FAR* lpFormatetc, + STGMEDIUM FAR* lpStgmed +); +STDMETHODIMP_(void) CntrLine_AdvSink_OnViewChange( + LPADVISESINK lpThis, + DWORD aspects, + LONG lindex +); +STDMETHODIMP_(void) CntrLine_AdvSink_OnRename( + LPADVISESINK lpThis, + LPMONIKER lpmk +); +STDMETHODIMP_(void) CntrLine_AdvSink_OnSave(LPADVISESINK lpThis); +STDMETHODIMP_(void) CntrLine_AdvSink_OnClose(LPADVISESINK lpThis); + +#if defined( INPLACE_CNTR ) +/* ContainerLine::IOleInPlaceSite methods (functions) */ + +STDMETHODIMP CntrLine_IPSite_QueryInterface( + LPOLEINPLACESITE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) CntrLine_IPSite_AddRef(LPOLEINPLACESITE lpThis); +STDMETHODIMP_(ULONG) CntrLine_IPSite_Release(LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_GetWindow( + LPOLEINPLACESITE lpThis, + HWND FAR* lphwnd +); +STDMETHODIMP CntrLine_IPSite_ContextSensitiveHelp( + LPOLEINPLACESITE lpThis, + BOOL fEnterMode +); +STDMETHODIMP CntrLine_IPSite_CanInPlaceActivate(LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_OnInPlaceActivate(LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_OnUIActivate (LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_GetWindowContext( + LPOLEINPLACESITE lpThis, + LPOLEINPLACEFRAME FAR* lplpFrame, + LPOLEINPLACEUIWINDOW FAR* lplpDoc, + LPRECT lprcPosRect, + LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo +); +STDMETHODIMP CntrLine_IPSite_Scroll( + LPOLEINPLACESITE lpThis, + SIZE scrollExtent +); +STDMETHODIMP CntrLine_IPSite_OnUIDeactivate( + LPOLEINPLACESITE lpThis, + BOOL fUndoable +); +STDMETHODIMP CntrLine_IPSite_OnInPlaceDeactivate(LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_DiscardUndoState(LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_DeactivateAndUndo(LPOLEINPLACESITE lpThis); +STDMETHODIMP CntrLine_IPSite_OnPosRectChange( + LPOLEINPLACESITE lpThis, + LPCRECT lprcPosRect +); +#endif // INPLACE_CNTR + + +/* struct definition for persistant data storage of ContainerLine */ + +#pragma pack(push, 2) +typedef struct tagCONTAINERLINERECORD_ONDISK +{ + char m_szStgName[CWCSTORAGENAME]; // stg name w/i cntr stg + USHORT m_fMonikerAssigned; // has a moniker been assigned to obj + DWORD m_dwDrawAspect; // current display aspect for obj + // (either DVASPECT_CONTENT or + // DVASPECT_ICON) + SIZEL m_sizeInHimetric; // extents of obj in himetric units + DWORD m_dwLinkType; // is it a linked object? + // 0 -- NOT a link + // OLEUPDATE_ALWAYS (1) -- auto link + // OLEUPDATE_ONCALL (3) -- man. link + USHORT m_fDoSetExtent; // obj was resized when not running + // IOO::SetExtent needed on next run +} CONTAINERLINERECORD_ONDISK, FAR* LPCONTAINERLINERECORD_ONDISK; +#pragma pack(pop) + +typedef struct tagCONTAINERLINERECORD { + char m_szStgName[CWCSTORAGENAME]; // stg name w/i cntr stg + BOOL m_fMonikerAssigned; // has a moniker been assigned to obj + DWORD m_dwDrawAspect; // current display aspect for obj + // (either DVASPECT_CONTENT or + // DVASPECT_ICON) + SIZEL m_sizeInHimetric; // extents of obj in himetric units + DWORD m_dwLinkType; // is it a linked object? + // 0 -- NOT a link + // OLEUPDATE_ALWAYS (1) -- auto link + // OLEUPDATE_ONCALL (3) -- man. link + BOOL m_fDoSetExtent; // obj was resized when not running + // IOO::SetExtent needed on next run +} CONTAINERLINERECORD, FAR* LPCONTAINERLINERECORD; + + +/************************************************************************* +** class CONTAINERDOC : OUTLINEDOC +** CONTAINERDOC is an extention to the base OUTLINEDOC object (structure) +** that adds OLE 2.0 Container functionality. There is one instance of +** CONTAINERDOC object created per document open in the app. The SDI +** version of the app supports one CONTAINERDOC at a time. The MDI +** version of the app can manage multiple documents at one time. +** The CONTAINERDOC class inherits all fields +** from the OUTLINEDOC class. This inheritance is achieved by including a +** member variable of type OUTLINEDOC as the first field in the +** CONTAINERDOC structure. Thus a pointer to a CONTAINERDOC object +** can be cast to be a pointer to a OUTLINEDOC object. +*************************************************************************/ + +typedef struct tagCONTAINERDOC { + OLEDOC m_OleDoc; // ContainerDoc inherits all fields of OleDoc + ULONG m_nNextObjNo; // next available obj no. for stg name + LPSTORAGE m_lpNewStg; // holds new pStg when SaveAs is pending + BOOL m_fEmbeddedObjectAvail; // is single OLE embed copied to doc + CLSID m_clsidOleObjCopied; // if obj copied, CLSID of obj + DWORD m_dwAspectOleObjCopied; // if obj copied, draw aspect of obj + LPCONTAINERLINE m_lpSrcContainerLine; // src line if doc created for copy + BOOL m_fShowObject; // show object flag + +#if defined( INPLACE_CNTR ) + LPCONTAINERLINE m_lpLastIpActiveLine; // last in-place active line + LPCONTAINERLINE m_lpLastUIActiveLine; // last UIActive line + HWND m_hWndUIActiveObj; // HWND of UIActive obj. + BOOL m_fAddMyUI; // if adding tools/menu postponed + int m_cIPActiveObjects; + +#if defined( INPLACE_CNTRSVR ) + LPOLEINPLACEFRAME m_lpTopIPFrame; // ptr to Top In-place frame. + LPOLEINPLACEFRAME m_lpTopIPDoc; // ptr to Top In-place Doc window. + HMENU m_hSharedMenu; // combined obj/cntr menu + // NULL if we are top container + HOLEMENU m_hOleMenu; // returned by OleCreateMenuDesc. + // NULL if we are top container +#endif // INPLACE_CNTRSVR +#endif // INPLACE_CNTR + + struct CDocOleUILinkContainerImpl { + IOleUILinkContainerVtbl FAR* lpVtbl; + LPCONTAINERDOC lpContainerDoc; + int cRef; // interface specific ref count. + } m_OleUILinkContainer; + +} CONTAINERDOC; + +/* ContainerDoc methods (functions) */ +BOOL ContainerDoc_Init(LPCONTAINERDOC lpContainerDoc, BOOL fDataTransferDoc); +LPCONTAINERLINE ContainerDoc_GetNextLink( + LPCONTAINERDOC lpContainerDoc, + LPCONTAINERLINE lpContainerLine +); +void ContainerDoc_UpdateLinks(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_SetShowObjectFlag(LPCONTAINERDOC lpContainerDoc, BOOL fShow); +BOOL ContainerDoc_GetShowObjectFlag(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_InsertOleObjectCommand(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_EditLinksCommand(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_PasteLinkCommand(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_ConvertCommand( + LPCONTAINERDOC lpContainerDoc, + BOOL fServerNotRegistered +); +BOOL ContainerDoc_PasteFormatFromData( + LPCONTAINERDOC lpContainerDoc, + CLIPFORMAT cfFormat, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSIZEL lpSizelInSrc +); +int ContainerDoc_PasteCntrOutlData( + LPCONTAINERDOC lpDestContainerDoc, + LPSTORAGE lpSrcStg, + int nStartIndex +); +BOOL ContainerDoc_QueryPasteFromData( + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLink +); +int ContainerDoc_PasteOleObject( + LPCONTAINERDOC lpContainerDoc, + LPDATAOBJECT lpSrcDataObj, + DWORD dwCreateType, + CLIPFORMAT cfFormat, + int nIndex, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSIZEL lpSizelInSrc +); +BOOL ContainerDoc_CloseAllOleObjects( + LPCONTAINERDOC lpContainerDoc, + DWORD dwSaveOption +); +void ContainerDoc_UnloadAllOleObjectsOfClass( + LPCONTAINERDOC lpContainerDoc, + REFCLSID rClsid, + DWORD dwSaveOption +); +void ContainerDoc_InformAllOleObjectsDocRenamed( + LPCONTAINERDOC lpContainerDoc, + LPMONIKER lpmkDoc +); +void ContainerDoc_UpdateExtentOfAllOleObjects(LPCONTAINERDOC lpContainerDoc); +BOOL ContainerDoc_SaveToFile( + LPCONTAINERDOC lpContainerDoc, + LPCSTR lpszFileName, + UINT uFormat, + BOOL fRemember +); +void ContainerDoc_ContainerLineDoVerbCommand( + LPCONTAINERDOC lpContainerDoc, + LONG iVerb +); +void ContainerDoc_GetNextStgName( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszStgName, + int nLen +); +BOOL ContainerDoc_IsStgNameUsed( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszStgName +); +LPSTORAGE ContainerDoc_GetStg(LPCONTAINERDOC lpContainerDoc); +HRESULT ContainerDoc_GetObject( + LPCONTAINERDOC lpContainerDoc, + LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR* lplpvObject +); +HRESULT ContainerDoc_GetObjectStorage( + LPCONTAINERDOC lpContainerDoc, + LPOLESTR lpszItem, + LPSTORAGE FAR* lplpStg +); +HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC lpContainerDoc, LPOLESTR lpszItem); +LPUNKNOWN ContainerDoc_GetSingleOleObject( + LPCONTAINERDOC lpContainerDoc, + REFIID riid, + LPCONTAINERLINE FAR* lplpContainerLine +); +BOOL ContainerDoc_IsSelAnOleObject( + LPCONTAINERDOC lpContainerDoc, + REFIID riid, + LPUNKNOWN FAR* lplpvObj, + int FAR* lpnIndex, + LPCONTAINERLINE FAR* lplpContainerLine +); +HRESULT ContainerDoc_GetData ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +); +HRESULT ContainerDoc_GetDataHere ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +); +HRESULT ContainerDoc_QueryGetData ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc +); +HRESULT ContainerDoc_SetData ( + LPCONTAINERDOC lpContainerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpmedium, + BOOL fRelease +); +HRESULT ContainerDoc_EnumFormatEtc( + LPCONTAINERDOC lpContainerDoc, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +); +BOOL ContainerDoc_SetupDocGetFmts( + LPCONTAINERDOC lpContainerDoc, + LPCONTAINERLINE lpContainerLine +); + +#if defined( INPLACE_CNTR ) + +void ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded( + LPCONTAINERDOC lpContainerDoc, + LPCONTAINERLINE lpNextActiveLine +); +BOOL ContainerDoc_IsUIDeactivateNeeded( + LPCONTAINERDOC lpContainerDoc, + POINT pt +); +HWND ContainerDoc_GetUIActiveWindow(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_UpdateInPlaceObjectRects(LPCONTAINERDOC lpContainerDoc, int nIndex); +void ContainerDoc_GetClipRect( + LPCONTAINERDOC lpContainerDoc, + LPRECT lprcClipRect +); +void ContainerDoc_FrameWindowResized(LPCONTAINERDOC lpContainerDoc); +LPOLEINPLACEFRAME ContainerDoc_GetTopInPlaceFrame( + LPCONTAINERDOC lpContainerDoc +); +void ContainerDoc_GetSharedMenuHandles( + LPCONTAINERDOC lpContainerDoc, + HMENU FAR* lphSharedMenu, + HOLEMENU FAR* lphOleMenu +); +void ContainerDoc_RemoveFrameLevelTools(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_AddFrameLevelUI(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_AddFrameLevelTools(LPCONTAINERDOC lpContainerDoc); + +#if defined( INPLACE_CNTRSVR ) || defined( INPLACE_MDICNTR ) + +LPOLEINPLACEUIWINDOW ContainerDoc_GetTopInPlaceDoc( + LPCONTAINERDOC lpContainerDoc +); +void ContainerDoc_RemoveDocLevelTools(LPCONTAINERDOC lpContainerDoc); +void ContainerDoc_AddDocLevelTools(LPCONTAINERDOC lpContainerDoc); + +#endif // INPLACE_CNTRSVR || INPLACE_MDICNTR +#endif // INPLACE_CNTR + +/* ContainerDoc::IOleUILinkContainer methods (functions) */ +STDMETHODIMP CntrDoc_LinkCont_QueryInterface( + LPOLEUILINKCONTAINER lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) CntrDoc_LinkCont_AddRef(LPOLEUILINKCONTAINER lpThis); +STDMETHODIMP_(ULONG) CntrDoc_LinkCont_Release(LPOLEUILINKCONTAINER lpThis); +STDMETHODIMP_(DWORD) CntrDoc_LinkCont_GetNextLink( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink +); +STDMETHODIMP CntrDoc_LinkCont_SetLinkUpdateOptions( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + DWORD dwUpdateOpt +); +STDMETHODIMP CntrDoc_LinkCont_GetLinkUpdateOptions( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + DWORD FAR* dwUpdateOpt +); + +STDMETHODIMP CntrDoc_LinkCont_SetLinkSource( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + LPSTR lpszDisplayName, + ULONG clenFileName, + ULONG FAR* lpchEaten, + BOOL fValidateSource +); +STDMETHODIMP CntrDoc_LinkCont_GetLinkSource( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + LPSTR FAR* lplpszDisplayName, + ULONG FAR* lplenFileName, + LPSTR FAR* lplpszFullLinkType, + LPSTR FAR* lplpszShortLinkType, + BOOL FAR* lpfSourceAvailable, + BOOL FAR* lpfIsSelected +); +STDMETHODIMP CntrDoc_LinkCont_OpenLinkSource( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink +); +STDMETHODIMP CntrDoc_LinkCont_UpdateLink( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink, + BOOL fErrorMessage, + BOOL fErrorAction +); +STDMETHODIMP CntrDoc_LinkCont_CancelLink( + LPOLEUILINKCONTAINER lpThis, + DWORD dwLink +); + + + +/************************************************************************* +** class CONTAINERAPP : OLEAPP +** CONTAINERAPP is an extention to the base OLEAPP object (structure) +** that adds special Container functionality. There is one instance of +** CONTAINERApp object created per running application instance. This +** object holds many fields that could otherwise be organized as +** global variables. The CONTAINERAPP class inherits all fields +** from the OLEAPP class. This inheritance is achieved by including a +** member variable of type OLEAPP as the first field in the CONTAINERAPP +** structure. OLEAPP inherits from OUTLINEAPP. This inheritance is +** achieved in the same manner. Thus a pointer to a CONTAINERAPP object +** can be cast to be a pointer to an OLEAPP or an OUTLINEAPP object +*************************************************************************/ + +/* Forward definition of types */ +typedef struct tagCONTAINERAPP FAR* LPCONTAINERAPP; + +typedef struct tagCONTAINERAPP { + OLEAPP m_OleApp; // ContainerApp inherits all fields of OleApp + UINT m_cfCntrOutl; // clipboard format for CntrOutl (client ver) data + int m_nSingleObjGetFmts; // no. formats avail when single obj copied + FORMATETC m_arrSingleObjGetFmts[MAXNOFMTS]; + // array of FormatEtc's available via + // IDataObject::GetData when a single + // OLE object is copied. + +#if defined( INPLACE_CNTR ) + HACCEL m_hAccelIPCntr; // accelerators for container's workspace commands + HMENU m_hMenuFile; // handle to File menu of container app + HMENU m_hMenuView; // handle to View menu of container app + HMENU m_hMenuDebug; // handle to Debug menu of container app + LPOLEINPLACEACTIVEOBJECT m_lpIPActiveObj; // ptr to inplace active OLE obj + HWND m_hWndUIActiveObj; // HWND of UIActive obj. + BOOL m_fPendingUIDeactivate; // should app UIDeactivate on LBUTTONUP + BOOL m_fMustResizeClientArea;// if client area resize pending + // (see Doc_FrameWindowResized) + BOOL m_fMenuHelpMode;// is F1 pressed in menu, if so give help +#ifdef _DEBUG + BOOL m_fOutSideIn; +#endif + + struct COleInPlaceFrameImpl { + IOleInPlaceFrameVtbl FAR* lpVtbl; + LPCONTAINERAPP lpContainerApp; + int cRef; // interface specific ref count. + } m_OleInPlaceFrame; + +#endif // INPLACE_CNTR + +} CONTAINERAPP; + +/* ContainerApp methods (functions) */ +BOOL ContainerApp_InitInstance( + LPCONTAINERAPP lpContainerApp, + HINSTANCE hInst, + int nCmdShow +); +BOOL ContainerApp_InitVtbls(LPCONTAINERAPP lpApp); + +#if defined( INPLACE_CNTR ) + +/* ContainerApp::IOleInPlaceFrame methods (functions) */ + +STDMETHODIMP CntrApp_IPFrame_QueryInterface( + LPOLEINPLACEFRAME lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) CntrApp_IPFrame_AddRef(LPOLEINPLACEFRAME lpThis); +STDMETHODIMP_(ULONG) CntrApp_IPFrame_Release(LPOLEINPLACEFRAME lpThis); +STDMETHODIMP CntrApp_IPFrame_GetWindow( + LPOLEINPLACEFRAME lpThis, + HWND FAR* lphwnd +); +STDMETHODIMP CntrApp_IPFrame_ContextSensitiveHelp( + LPOLEINPLACEFRAME lpThis, + BOOL fEnterMode +); +STDMETHODIMP CntrApp_IPFrame_GetBorder( + LPOLEINPLACEFRAME lpThis, + LPRECT lprectBorder +); +STDMETHODIMP CntrApp_IPFrame_RequestBorderSpace( + LPOLEINPLACEFRAME lpThis, + LPCBORDERWIDTHS lpWidths +); +STDMETHODIMP CntrApp_IPFrame_SetBorderSpace( + LPOLEINPLACEFRAME lpThis, + LPCBORDERWIDTHS lpWidths +); +STDMETHODIMP CntrApp_IPFrame_SetActiveObject( + LPOLEINPLACEFRAME lpThis, + LPOLEINPLACEACTIVEOBJECT lpActiveObject, + LPCOLESTR lpszObjName +); +STDMETHODIMP CntrApp_IPFrame_InsertMenus( + LPOLEINPLACEFRAME lpThis, + HMENU hmenu, + LPOLEMENUGROUPWIDTHS lpMenuWidths +); +STDMETHODIMP CntrApp_IPFrame_SetMenu( + LPOLEINPLACEFRAME lpThis, + HMENU hmenuShared, + HOLEMENU holemenu, + HWND hwndActiveObject +); +STDMETHODIMP CntrApp_IPFrame_RemoveMenus( + LPOLEINPLACEFRAME lpThis, + HMENU hmenu +); +STDMETHODIMP CntrApp_IPFrame_SetStatusText( + LPOLEINPLACEFRAME lpThis, + LPCOLESTR lpszStatusText +); +STDMETHODIMP CntrApp_IPFrame_EnableModeless( + LPOLEINPLACEFRAME lpThis, + BOOL fEnable +); +STDMETHODIMP CntrApp_IPFrame_TranslateAccelerator( + LPOLEINPLACEFRAME lpThis, + LPMSG lpmsg, + WORD wID +); + +#endif // INPLACE_CNTR + + +#endif // _CNTROUTL_H_ diff --git a/private/oleutest/letest/outline/cntroutl.ico b/private/oleutest/letest/outline/cntroutl.ico Binary files differnew file mode 100644 index 000000000..313a0000f --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl.ico diff --git a/private/oleutest/letest/outline/cntroutl/cntroutl.rc b/private/oleutest/letest/outline/cntroutl/cntroutl.rc new file mode 100644 index 000000000..02679d04b --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl/cntroutl.rc @@ -0,0 +1,179 @@ +/************************************************************************* +** +** OLE 2.0 Container Sample Code +** +** cntroutl.rc +** +** Resource file for cntroutl.exe +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "windows.h" +#include "outlrc.h" +#include "cntrrc.h" + +SelCur CURSOR selcross.cur +DragMoveCur CURSOR dragmove.cur + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) +DragNoneCur CURSOR dragnone.cur +DragCopyCur CURSOR dragcopy.cur +DragLinkCur CURSOR draglink.cur +#endif // IF_SPECIAL_DD_CURSORS_NEEDED + +CntrOutlMenu MENU + BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", IDM_F_NEW + MENUITEM "&Open...\t Ctrl+F12", IDM_F_OPEN + MENUITEM "&Save\t Shift+F12", IDM_F_SAVE + MENUITEM "Save &As...\t F12", IDM_F_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print...\t Ctrl+Shift+F12", IDM_F_PRINT + MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP + MENUITEM SEPARATOR + MENUITEM "E&xit\t Alt+F4", IDM_F_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", IDM_E_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\t Ctrl+X", IDM_E_CUT + MENUITEM "&Copy\t Ctrl+C", IDM_E_COPY + MENUITEM "&Paste\t Ctrl+V", IDM_E_PASTE + MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL + MENUITEM "Paste &Link", IDM_E_PASTELINK + MENUITEM "Cl&ear\t Del", IDM_E_CLEAR + MENUITEM SEPARATOR + MENUITEM "&Insert Object...", IDM_E_INSERTOBJECT + MENUITEM "Li&nks...", IDM_E_EDITLINKS + MENUITEM "&Object", IDM_E_OBJECTVERBMIN + MENUITEM SEPARATOR + MENUITEM "Select &All\t Ctrl+A", IDM_E_SELECTALL + END + POPUP "O&utline" + BEGIN + POPUP "&Zoom" + BEGIN + MENUITEM "&100%", IDM_V_ZOOM_100 + MENUITEM "&75%", IDM_V_ZOOM_75 + MENUITEM "&50%", IDM_V_ZOOM_50 + MENUITEM "&25%", IDM_V_ZOOM_25 + END + POPUP "&Left and Right margins" + BEGIN + MENUITEM "&nil", IDM_V_SETMARGIN_0 + MENUITEM "&1 cm", IDM_V_SETMARGIN_1 + MENUITEM "&2 cm", IDM_V_SETMARGIN_2 + MENUITEM "&3 cm", IDM_V_SETMARGIN_3 + MENUITEM "&4 cm", IDM_V_SETMARGIN_4 + END + POPUP "Add &Top Line" + BEGIN + MENUITEM "&1 cm", IDM_V_ADDTOP_1 + MENUITEM "&2 cm", IDM_V_ADDTOP_2 + MENUITEM "&3 cm", IDM_V_ADDTOP_3 + MENUITEM "&4 cm", IDM_V_ADDTOP_4 + END + END + POPUP "&Line" + BEGIN + MENUITEM "&Add Line\t Enter", IDM_L_ADDLINE + MENUITEM "E&dit Line\t Alt+Enter", IDM_L_EDITLINE + MENUITEM SEPARATOR + MENUITEM "&Indent Line\t Tab", IDM_L_INDENTLINE + MENUITEM "U&nindent Line\t Shift+Tab", IDM_L_UNINDENTLINE + MENUITEM SEPARATOR + MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT + END + POPUP "&Name" + BEGIN + MENUITEM "&Define Name...", IDM_N_DEFINENAME + MENUITEM "&Goto Name...", IDM_N_GOTONAME + END + POPUP "&Options" + BEGIN + POPUP "&Button Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_BB_TOP + MENUITEM "At &Bottom", IDM_O_BB_BOTTOM + MENUITEM "&Popup", IDM_O_BB_POPUP + MENUITEM "&Hide", IDM_O_BB_HIDE + END + POPUP "&Formula Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_FB_TOP + MENUITEM "At &Bottom", IDM_O_FB_BOTTOM + MENUITEM "&Popup", IDM_O_FB_POPUP + END + POPUP "&Row and Column Heading" + BEGIN + MENUITEM "&Show", IDM_O_HEAD_SHOW + MENUITEM "&Hide", IDM_O_HEAD_HIDE + END + MENUITEM "&Show Object", IDM_O_SHOWOBJECT + END + POPUP "Dbg&Cntr" + BEGIN + MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL + MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER + MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING + END + POPUP "&Help" + BEGIN + MENUITEM "&About...", IDM_H_ABOUT + END + END + +CntrOutlAccel ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CLEAR, VIRTKEY + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + + VK_F2, IDM_F2, VIRTKEY + END + +; Same as CntrOutlAccel but without Delete and Backspace +; used when edit control of Formula Bar in focus +; +CntrOutlAccelFocusEdit ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + + VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY + END + +CntrOutlIcon ICON cntroutl.ico + +Image72 BITMAP image72.bmp +Image96 BITMAP image96.bmp +Image120 BITMAP image120.bmp +LogoBitmap BITMAP ole2.bmp + +#include "DIALOGS.DLG" diff --git a/private/oleutest/letest/outline/cntroutl/daytona/makefile b/private/oleutest/letest/outline/cntroutl/daytona/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl/daytona/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/oleutest/letest/outline/cntroutl/daytona/makefile.inc b/private/oleutest/letest/outline/cntroutl/daytona/makefile.inc new file mode 100644 index 000000000..462f38133 --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl/daytona/makefile.inc @@ -0,0 +1,2 @@ +copyfiles: + xcopy ..\..\*.c . /D diff --git a/private/oleutest/letest/outline/cntroutl/daytona/sources b/private/oleutest/letest/outline/cntroutl/daytona/sources new file mode 100644 index 000000000..45f65e8c8 --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl/daytona/sources @@ -0,0 +1,114 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Kenneth MacLeod (Kennethm) 9-Mar-1994 + +!ENDIF + +MAJORCOMP = ctoleui +MINORCOMP = cntroutl + +# This links with "bttncur", "gizmobar", etc... Block multiprocessor +# threads here to assure that these are finished building before +# proceeding. This also protects the build of "icntrot", "isvrrotl", +# and "svroutl" which are build after this. + +SYNCHRONIZE_BLOCK=1 +SYNCHRONIZE_DRAIN=1 + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= cntroutl + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= PROGRAM + +INCLUDES= ..\..\..\ole2ui; \ + ..\..\..\bttncur; \ + ..\..\..\gizmobar; \ + ..\..\..\..\inc; \ + ..\.. + +C_DEFINES= \ + $(C_DEFINES) \ + -DFLAT \ + -DWIN32=100 \ + -D_NT1X_=100 \ + -DUNICODE \ + -DNOEXCEPTIONS \ + -DOLE_CNTR + +SOURCES= \ + ..\cntroutl.rc \ + classfac.c \ + clipbrd.c \ + cntrbase.c \ + cntrline.c \ + debug.c \ + debug2.c \ + dialogs.c \ + dragdrop.c \ + frametls.c \ + heading.c \ + linking.c \ + main.c \ + memmgr.c \ + oleapp.c \ + oledoc.c \ + outlapp.c \ + outldoc.c \ + outlline.c \ + outllist.c \ + outlname.c \ + outlntbl.c \ + outltxtl.c \ + status.c \ + tests.c + +UMTYPE= windows +UMENTRY= winmain +USE_CRTDLL=1 +TARGETLIBS= \ + ..\..\..\ole2ui\daytona\obj\*\ole2u32a.lib \ + ..\..\..\gizmobar\daytona\obj\*\gizmobar.lib \ + ..\..\..\bttncur\daytona\obj\*\bttncur.lib \ + $(BASEDIR)\public\sdk\lib\*\ole32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\gdi32.lib \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\uuid.lib + +NTTARGETFILE0=copyfiles diff --git a/private/oleutest/letest/outline/cntroutl/dirs b/private/oleutest/letest/outline/cntroutl/dirs new file mode 100644 index 000000000..515c134a8 --- /dev/null +++ b/private/oleutest/letest/outline/cntroutl/dirs @@ -0,0 +1,37 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + \ + daytona diff --git a/private/oleutest/letest/outline/cntrrc.h b/private/oleutest/letest/outline/cntrrc.h new file mode 100644 index 000000000..455f9ff4b --- /dev/null +++ b/private/oleutest/letest/outline/cntrrc.h @@ -0,0 +1,30 @@ +/************************************************************************* +** +** OLE 2.0 Container Sample Code +** +** cntrrc.h +** +** This file contains constants used in rc file for CNTROUTL.EXE +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if !defined( _CNTRRC_H_ ) +#define _CNTRRC_H_ + +#ifndef RC_INVOKED +#pragma message ("INCLUDING CNTRRC.H from " __FILE__) +#endif /* RC_INVOKED */ + +#define IDM_E_INSERTOBJECT 2700 +#define IDM_E_EDITLINKS 3300 +#define IDM_E_PASTELINK 2750 +#define IDM_E_CONVERTVERB 9000 +#define IDM_E_OBJECTVERBMIN 10000 + +#define IDM_D_INSIDEOUT 2755 + +#define WM_U_UPDATEOBJECTEXTENT WM_USER+1 + +#endif // _CNTRRC_H_ diff --git a/private/oleutest/letest/outline/debug.c b/private/oleutest/letest/outline/debug.c new file mode 100644 index 000000000..14fc4d2f2 --- /dev/null +++ b/private/oleutest/letest/outline/debug.c @@ -0,0 +1,100 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** debug.c +** +** This file contains some functions for debugging support +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +void SetDebugLevelCommand(void) +{ + char szBuf[80]; + HWND hWndFrame = OutlineApp_GetFrameWindow(g_lpApp); + + wsprintf(szBuf, "%d", OleDbgGetDbgLevel()); + + if (InputTextDlg(hWndFrame, szBuf, "Debug Level [0-4]")) { + switch (szBuf[0]) { + case '0': + OleDbgSetDbgLevel(0); + break; + case '1': + OleDbgSetDbgLevel(1); + break; + case '2': + OleDbgSetDbgLevel(2); + break; + case '3': + OleDbgSetDbgLevel(3); + break; + case '4': + OleDbgSetDbgLevel(4); + break; + default: + OutlineApp_ErrorMessage(g_lpApp, "Valid Debug Level Range: 0-4"); + break; + } + } +} + + +#if defined( OLE_VERSION ) + +/* InstallMessageFilterCommand + * --------------------------- + * + * Handles the "Install Message Filter" menu item. If a message filter is + * already installed, this function de-installs it. If there is not one + * already installed, this function installs one. + * + */ + +void InstallMessageFilterCommand(void) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + + /* + ** Check to see if we've already installed a MessageFilter. + ** If so, uninstall it. + */ + if (lpOleApp->m_lpMsgFilter != NULL) + OleApp_RevokeMessageFilter(lpOleApp); + else + OleApp_RegisterMessageFilter(lpOleApp); +} + + +/* RejectIncomingCommand + * --------------------- + * + * Toggles between rejecting and not-handling in coming LRPC calls + * + */ + +void RejectIncomingCommand(void) +{ + DWORD dwOldStatus; + DWORD dwNewStatus; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + + dwOldStatus = OleStdMsgFilter_GetInComingCallStatus(lpOleApp->m_lpMsgFilter); + + if (dwOldStatus == SERVERCALL_RETRYLATER) + dwNewStatus = SERVERCALL_ISHANDLED; + else + dwNewStatus = SERVERCALL_RETRYLATER; + + OleStdMsgFilter_SetInComingCallStatus(lpOleApp->m_lpMsgFilter, dwNewStatus); +} + +#endif // OLE_VERSION diff --git a/private/oleutest/letest/outline/debug.rc b/private/oleutest/letest/outline/debug.rc new file mode 100644 index 000000000..d7c712c0f --- /dev/null +++ b/private/oleutest/letest/outline/debug.rc @@ -0,0 +1,142 @@ +9999 RCDATA LOADONCALL DISCARDABLE +{ + "\327\324\335\270\252\270\313\371\365\350\364\375\270\333\367\374\375\270\334\375\356\375\364\367\350\365\375\366\354\270\314\375\371\365\0", + "\265\265\270\324\375\374\270\372\341\270\265\265\0", + "\333\266\270\334\367\355\377\364\371\353\270\320\367\374\377\375\353\0", + "\270\0", + "\325\371\352\363\270\332\371\374\375\352\0", + "\323\352\371\361\377\270\332\352\367\373\363\353\373\360\365\361\374\354\0", + "\326\371\354\270\332\352\367\357\366\0", + "\316\361\366\367\367\270\333\360\375\352\361\371\366\0", + "\312\367\372\375\352\354\270\333\367\367\363\0", + "\333\364\371\352\363\270\333\341\352\0", + "\314\375\352\352\375\366\373\375\270\320\355\371\366\377\0", + "\310\375\354\375\352\270\324\361\0", + "\312\361\373\360\371\352\374\270\325\373\334\371\366\361\375\364\0", + "\312\375\372\375\373\373\371\270\326\367\352\364\371\366\374\375\352\0", + "\313\373\367\354\354\270\313\363\367\352\355\350\371\0", + "\313\371\352\371\270\317\361\364\364\361\371\365\353\0", + "\334\371\356\361\374\270\317\367\352\354\375\366\374\341\363\375\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\324\361\372\352\371\352\341\270\334\375\356\375\364\367\350\365\375\366\354\270\314\375\371\365\0", + "\265\265\270\324\375\374\270\372\341\270\265\265\265\0", + "\312\371\367\270\312\375\365\371\364\371\0", + "\270\0", + "\332\371\352\352\341\270\332\367\366\374\0", + "\334\352\375\357\270\332\364\361\353\353\0", + "\321\364\371\366\270\333\371\352\367\366\0", + "\331\364\371\366\270\333\371\352\354\375\352\0", + "\334\367\355\377\270\336\352\371\366\363\364\361\366\0", + "\322\371\353\367\366\270\336\355\364\364\375\352\0", + "\333\364\371\352\375\366\373\375\270\337\364\371\353\353\375\0", + "\310\375\354\375\352\270\337\367\364\374\375\0", + "\331\364\375\340\371\366\374\375\352\270\337\367\355\366\371\352\375\353\0", + "\310\360\361\364\361\350\270\324\371\376\367\352\366\371\352\371\0", + "\332\352\371\374\270\324\367\356\375\352\361\366\377\0", + "\313\371\365\270\323\360\367\0", + "\313\352\361\366\361\270\323\367\350\350\367\364\355\0", + "\312\371\362\361\356\270\323\355\365\371\352\0", + "\332\371\352\352\341\270\325\371\373\323\361\373\360\371\366\0", + "\313\354\375\356\375\366\270\326\367\352\371\364\364\0", + "\337\361\364\371\374\270\327\374\361\366\371\363\0", + "\335\352\361\373\270\327\375\365\361\377\0", + "\325\371\354\354\270\310\375\371\352\353\367\366\0", + "\322\367\360\371\366\366\270\310\367\353\373\360\0", + "\333\355\352\354\270\313\354\375\375\372\0", + "\314\367\365\270\314\375\366\377\0", + "\331\364\375\340\270\314\361\364\364\375\353\0", + "\333\352\371\361\377\270\317\361\354\354\375\366\372\375\352\377\0", + "\325\361\373\360\371\375\364\270\317\367\367\364\376\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\314\375\353\354\361\366\377\270\314\375\371\365\0", + "\265\265\270\324\375\374\270\372\341\270\265\265\0", + "\322\375\376\376\270\310\371\373\363\0", + "\270\0", + "\334\371\366\361\375\364\270\332\367\367\366\375\0", + "\332\352\371\366\374\367\366\270\332\341\366\355\365\0", + "\331\366\377\375\364\371\270\333\360\371\366\0", + "\312\361\373\360\270\335\361\342\375\366\360\367\375\376\375\352\0", + "\312\367\377\375\352\270\337\352\371\365\372\361\360\364\375\352\0", + "\333\360\352\361\353\270\323\371\355\376\376\365\371\366\0", + "\313\371\366\362\371\341\270\323\367\360\364\361\0", + "\334\357\361\377\360\354\270\323\352\355\377\375\352\0", + "\314\367\365\270\324\371\341\353\367\366\0", + "\312\367\366\371\364\374\270\324\367\366\377\0", + "\331\364\364\371\366\270\325\373\334\371\366\361\375\364\0", + "\323\375\366\354\270\325\355\352\374\367\373\360\0", + "\314\352\371\356\361\353\270\310\352\355\361\354\354\0", + "\322\371\365\375\353\270\312\367\374\352\361\377\355\375\353\0", + "\312\367\353\353\270\313\365\361\354\360\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\310\352\367\377\352\371\365\270\325\371\366\371\377\375\365\375\366\354\0", + "\265\265\270\324\375\374\270\372\341\270\265\265\0", + "\320\375\361\363\363\361\270\323\371\366\375\352\356\371\0", + "\270\0", + "\333\341\270\333\375\374\371\352\0", + "\335\374\374\361\375\270\337\361\364\372\375\352\354\0", + "\325\371\352\363\270\321\377\352\371\0", + "\334\371\356\361\374\270\324\371\366\361\366\377\0", + "\322\367\360\366\270\324\375\376\367\352\0", + "\313\373\367\354\354\270\317\361\364\354\371\365\355\354\360\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\334\367\373\355\365\375\366\354\371\354\361\367\366\270\314\375\371\365\0", + "\265\265\270\324\375\374\270\372\341\270\265\265\0", + "\325\361\363\375\270\325\373\337\375\375\0", + "\270\0", + "\322\367\360\366\270\332\355\352\363\375\0", + "\334\361\373\363\270\325\367\353\375\364\375\341\0", + "\332\371\352\352\341\270\310\367\354\354\375\352\0", + "\324\341\366\366\375\270\317\371\353\353\367\366\0", + "\322\375\376\376\270\317\375\372\372\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\334\375\356\375\364\367\350\375\352\270\312\375\364\371\354\361\367\366\353\270\337\352\367\355\350\0", + "\270\0", + "\331\364\361\353\354\371\361\352\270\332\371\366\363\353\0", + "\325\361\363\375\270\336\352\361\354\342\0", + "\316\361\363\354\367\352\270\337\352\371\372\366\375\352\0", + "\312\367\372\375\352\354\270\320\375\353\353\0", + "\314\361\365\270\325\373\333\371\376\376\352\375\341\0", + "\322\367\366\270\326\361\373\350\367\366\353\363\361\0", + "\322\371\365\375\353\270\310\364\371\365\367\366\374\367\366\0", + "\317\361\365\270\316\371\366\270\334\375\270\332\367\353\350\367\367\352\354\0", + "\331\374\371\365\270\317\371\371\364\363\375\353\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\331\352\373\360\361\354\375\373\354\353\0", + "\270\0", + "\332\367\372\270\331\354\363\361\366\353\367\366\0", + "\314\367\366\341\270\317\361\364\364\361\371\365\353\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\310\352\367\374\355\373\354\270\325\371\366\371\377\375\352\0", + "\270\0", + "\334\371\356\375\270\313\375\352\375\353\0", + "\270\0", + "\270\0", + "\327\324\335\270\252\270\337\352\367\355\350\270\325\371\366\371\377\375\352\0", + "\270\0", + "\320\371\352\375\364\270\323\367\374\375\353\360\0", + "\270\0", + "\270\0", + "\313\350\375\373\361\371\364\270\314\360\371\366\363\353\270\314\367\242\0", + "\270\0", + "\313\360\371\355\366\371\270\332\352\371\355\366\0", + "\334\371\366\270\334\375\376\376\375\0", + "\322\361\365\270\334\367\353\373\360\0", + "\332\375\356\375\352\364\375\341\270\336\364\367\357\375\352\0", + "\332\361\364\364\270\337\371\354\375\353\0", + "\322\367\366\361\270\320\371\366\353\367\366\0", + "\324\341\366\366\270\320\361\373\363\353\0", + "\326\367\352\365\371\366\270\320\367\374\366\375\0", + "\333\360\371\352\364\361\375\270\323\361\366\374\375\364\0", + "\331\366\374\341\270\324\375\375\0", + "\326\371\366\373\341\270\313\350\375\375\352\0", + "\310\371\355\364\270\313\354\371\376\376\367\352\374\0", + "\313\354\375\350\360\375\366\270\314\355\352\354\367\366\0", + 0x0000 +} diff --git a/private/oleutest/letest/outline/debug2.c b/private/oleutest/letest/outline/debug2.c new file mode 100644 index 000000000..a0d37b912 --- /dev/null +++ b/private/oleutest/letest/outline/debug2.c @@ -0,0 +1,329 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** debug2.c +** +** This file contains various debug / subclass routines for the +** ABOUT dialog +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" +#include <stdlib.h> +#include <time.h> + +extern LPOUTLINEAPP g_lpApp; + +LONG CALLBACK EXPORT DebugAbout(HWND hWnd, unsigned uMsg, WORD wParam, LONG lParam); +void RandomizeStars(HDC hDC); +BOOL InitStrings(void); +BOOL DrawString(int iCount, HDC hDC, LPRECT rcDrawIn); + +static FARPROC lpRealAboutProc = 0L; +static int width, height; +static RECT rc; +static HANDLE hStrBlock = NULL; +static LPSTR lpStrings = NULL; +static WORD wLineHeight; + + +/* TraceDebug + * ---------- + * + * Called once when our About Box's gets the INITDIALOG message. Subclasses + * dialog. + */ + +void TraceDebug(HWND hDlg, int iControl) +{ + + // Load strings, if the strings aren't there, then don't subclass + // the dialog + if (InitStrings() != TRUE) + return; + + // Subclass the dialog + lpRealAboutProc = (FARPROC)(LONG)GetWindowLong(hDlg, GWL_WNDPROC); + SetWindowLong(hDlg, GWL_WNDPROC, (LONG)(FARPROC)DebugAbout); + + // Get rect of control in screen coords, and translate to our dialog + // box's coordinates + GetWindowRect(GetDlgItem(hDlg, iControl), &rc); + MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2); + + width = rc.right - rc.left; + height = rc.bottom - rc.top; +} + +/* DebugAbout + * ---------- + * + * The subclassed About dialog's main window proc. + */ + +LONG CALLBACK EXPORT DebugAbout(HWND hWnd, unsigned uMsg, WORD wParam, LONG lParam) +{ + RECT rcOut; + static BOOL bTimerStarted = FALSE; + static int iTopLocation; + HDC hDCScr; + static HDC hDCMem; + static HBITMAP hBitmap; + static HBITMAP hBitmapOld; + static RECT rcMem; + static HFONT hFont; + + switch (uMsg) + { + + /* + * If we get a LBUTTONDBLCLICK in the upper left of + * the dialog, fire off the about box effects + */ + + case WM_LBUTTONDBLCLK: + if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT) + && LOWORD(lParam) < 10 && HIWORD(lParam) < 10 && + bTimerStarted == FALSE) + { + if (SetTimer ( hWnd, 1, 10, NULL )) + { + LOGFONT lf; + int i; + + bTimerStarted = TRUE; + + // "Open up" the window + hDCScr = GetDC ( hWnd ); + hDCMem = CreateCompatibleDC ( hDCScr ); + + hBitmap = CreateCompatibleBitmap(hDCScr, width, height); + hBitmapOld = SelectObject(hDCMem, hBitmap); + + // Blt from dialog to memDC + BitBlt(hDCMem, 0, 0, width, height, + hDCScr, rc.left, rc.top, SRCCOPY); + + for (i=0;i<height;i+=1) + { + BitBlt(hDCScr, rc.left, rc.top + i + 1, width, height-i-1, hDCMem, 0, 0, SRCCOPY); + PatBlt(hDCScr, rc.left, rc.top + i, width, 1, BLACKNESS); + } + + SelectObject(hDCMem, hBitmapOld); + DeleteObject(hBitmap); + + // Set up memory DC with default attributes + hBitmap = CreateCompatibleBitmap(hDCScr, width, height); + ReleaseDC(hWnd, hDCScr); + + hBitmapOld = SelectObject(hDCMem, hBitmap); + + SetBkMode(hDCMem, TRANSPARENT); + SetBkColor(hDCMem, RGB(0,0,0)); + + // Create font + memset(&lf, 0, sizeof(LOGFONT)); + lf.lfHeight = -(height / 7); // Fit 7 lines of text in box + lf.lfWeight = FW_BOLD; + strcpy(lf.lfFaceName, "Arial"); + hFont = CreateFontIndirect(&lf); + + // If we can't create the font, revert and use the standard + // system font. + if (!hFont) + GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf); + + wLineHeight = abs(lf.lfHeight) + 5; // 5 pixels between lines + + // Set location of top of banner at bottom of the window + iTopLocation = height + 50; + + SetRect(&rcMem, 0, 0, width, height); + } + } + // Call our real window procedure in case they want to + // handle LBUTTONDOWN messages also + goto Default; + + case WM_TIMER: + { + int iCount; + HFONT hfold; + + /* + * On each timer message, we are going to construct the next image + * in the animation sequence, then bitblt this to our dialog. + */ + + // Clear out old bitmap and place random star image on background + PatBlt(hDCMem, rcMem.left, rcMem.top, rcMem.right, rcMem.bottom, BLACKNESS); + RandomizeStars(hDCMem); + + // Set initial location to draw text + rcOut = rcMem; + rcOut.top = 0 + iTopLocation; + rcOut.bottom = rcOut.top + wLineHeight; + + iCount = 0; + if (hFont) hfold = SelectObject(hDCMem, hFont); + + SetTextColor(hDCMem, RGB(0,255,0)); + while (DrawString(iCount, hDCMem, &rcOut) == TRUE) + { + rcOut.top += wLineHeight; + rcOut.bottom += wLineHeight; + iCount++; + } + if (hFont) SelectObject(hDCMem, hfold); + + // Now blt the memory dc that we have just constructed + // to the screen + hDCScr = GetDC(hWnd); + BitBlt(hDCScr, rc.left, rc.top, rc.right, rc.bottom, + hDCMem, 0, 0, SRCCOPY); + ReleaseDC(hWnd, hDCScr); + + // For the next animation sequence, we want to move the + // whole thing up, so decrement the location of the top + // of the banner + + iTopLocation -= 2; + + // If we've gone through the banner once, reset it + if (iTopLocation < -(int)(wLineHeight * iCount)) + iTopLocation = height + 50; + } + // Goto default + goto Default; + + case WM_NCDESTROY: + { + LONG defReturn; + + /* + * We're being destroyed. Clean up what we created. + */ + + if (bTimerStarted) + { + KillTimer(hWnd, 1); + SelectObject (hDCMem, hBitmapOld); + DeleteObject (hBitmap); + DeleteDC (hDCMem); + if (hFont) DeleteObject(hFont); + bTimerStarted = FALSE; + } + + if (lpStrings) + UnlockResource(hStrBlock), lpStrings = NULL; + if (hStrBlock) + FreeResource(hStrBlock), hStrBlock = NULL; + + // Pass the NCDESTROY on to our real window procedure. Since + // this is the last message that we are going to be getting, + // we can go ahead and free the proc instance here. + + defReturn = CallWindowProc((WNDPROC)lpRealAboutProc, hWnd, + uMsg, wParam, lParam); + return defReturn; + } + + Default: + default: + return CallWindowProc( + (WNDPROC)lpRealAboutProc, hWnd, uMsg, wParam, lParam); + } + return 0L; +} + + +/* RandomizeStars + * -------------- + * + * Paints random stars on the specified hDC + * + */ + +void RandomizeStars(HDC hDC) +{ + int i; + + // Seed the random number generator with current time. This will, + // in effect, only change the seed every second, so our + // starfield will change only every second. + srand((unsigned)time(NULL)); + + // Generate random white stars + for (i=0;i<20;i++) + PatBlt(hDC, getrandom(0,width), getrandom(0,height), 2, 2, WHITENESS); +} + +/* InitStrings + * -------------- + * + * Reads strings from stringtable. Returns TRUE if it worked OK. + * + */ + +BOOL InitStrings() +{ + HRSRC hResStrings; + LPSTR lpWalk; + + // Load the block of strings + if ((hResStrings = FindResource( + g_lpApp->m_hInst, + MAKEINTRESOURCE(9999), + RT_RCDATA)) == NULL) + return FALSE; + if ((hStrBlock = LoadResource(g_lpApp->m_hInst, hResStrings)) == NULL) + return FALSE; + if ((lpStrings = LockResource(hStrBlock)) == NULL) + return FALSE; + + if (lpStrings && *(lpStrings+2)!=0x45) + { + lpWalk = lpStrings; + while (*(LPWORD)lpWalk != (WORD)0x0000) + { + if (*lpWalk != (char)0x00) + *lpWalk ^= 0x98; + lpWalk++; + } + } + return TRUE; +} + +/* DrawString + * ---------- + * + * Draws the next string on the specified hDC using the + * output rectangle. If iCount == 0, reset to start of list. + * + * Returns: TRUE to contine, FALSE if we're done + */ + +BOOL DrawString(int iCount, HDC hDC, LPRECT rcDrawIn) +{ + static LPSTR lpPtr = NULL; + + if (iCount == 0) + // First time, reset pointer + lpPtr = lpStrings; + + if (*lpPtr == '\0') // If we've hit a NULL string, we're done + return FALSE; + + // If we're drawing outside of visible box, don't call DrawText + if ((rcDrawIn->bottom > 0) && (rcDrawIn->top < height)) + DrawText(hDC, lpPtr, -1, rcDrawIn, DT_CENTER); + + // Advance pointer to next string + lpPtr += lstrlen(lpPtr) + 1; + + return TRUE; +} diff --git a/private/oleutest/letest/outline/defguid.h b/private/oleutest/letest/outline/defguid.h new file mode 100644 index 000000000..680323355 --- /dev/null +++ b/private/oleutest/letest/outline/defguid.h @@ -0,0 +1,44 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** clsid.h +** +** This file contains file contains GUID definitions used for the +** OLE versions of OUTLINE. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if defined( OLE_SERVER ) || defined( OLE_CNTR ) +// OLE2NOTE: We need access to these GUIDs in modules other than +// where they are defined (MAIN.C). Even though the values of the +// GUIDs are duplicated here, they are not used. Refer to MAIN.C +// for the definition of these GUIDs. + +/* CLASS ID CONSTANTS (GUID's) +** OLE2NOTE: these class id values are allocated out of a private pool +** of GUID's allocated to the OLE 2.0 development team. GUID's of +** the following range have been allocated to OLE 2.0 sample code: +** 00000400-0000-0000-C000-000000000046 +** 000004FF-0000-0000-C000-000000000046 +** +** values reserved thus far: +** 00000400 -- Ole 2.0 Server Sample Outline +** 00000401 -- Ole 2.0 Container Sample Outline +** 00000402 -- Ole 2.0 In-Place Server Outline +** 00000403 -- Ole 2.0 In-Place Container Outline +** 00000404 : 000004FE -- reserved for OLE Sample code +** 000004FF -- IID_IOleUILinkContainer +*/ + +DEFINE_GUID(CLSID_SvrOutl, 0x00000400, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +DEFINE_GUID(CLSID_CntrOutl, 0x00000401, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +DEFINE_GUID(CLSID_ISvrOtl, 0x00000402, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +DEFINE_GUID(CLSID_ICntrOtl, 0x00000403, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + +#if defined( OLE_CNTR ) +DEFINE_GUID(IID_IOleUILinkContainer, 0x000004FF, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +#endif +#endif diff --git a/private/oleutest/letest/outline/dialogs.c b/private/oleutest/letest/outline/dialogs.c new file mode 100644 index 000000000..bcd16b924 --- /dev/null +++ b/private/oleutest/letest/outline/dialogs.c @@ -0,0 +1,659 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** dialogs.c +** +** This file contains dialog functions and support function +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +static char g_szBuf[MAXSTRLEN+1]; +static LPSTR g_lpszDlgTitle; + +// REVIEW: should use string resource for messages +static char ErrMsgInvalidRange[] = "Invalid Range entered!"; +static char ErrMsgInvalidValue[] = "Invalid Value entered!"; +static char ErrMsgInvalidName[] = "Invalid Name entered!"; +static char ErrMsgNullName[] = "NULL string disallowed!"; +static char ErrMsgNameNotFound[] = "Name doesn't exist!"; + +/* InputTextDlg + * ------------ + * + * Put up a dialog box to allow the user to edit text + */ +BOOL InputTextDlg(HWND hWnd, LPSTR lpszText, LPSTR lpszDlgTitle) +{ + int nResult; + + g_lpszDlgTitle = lpszDlgTitle; + lstrcpy((LPSTR)g_szBuf, lpszText); // preload dialog with input text + + nResult = DialogBox(g_lpApp->m_hInst, (LPSTR)"AddEditLine", hWnd, + (DLGPROC)AddEditDlgProc); + if (nResult) { + lstrcpy(lpszText, (LPSTR)g_szBuf); + return TRUE; + } else { + return FALSE; + } +} + + + +/* AddEditDlgProc + * -------------- + * + * This procedure is associated with the dialog box that is included in + * the function name of the procedure. It provides the service routines + * for the events (messages) that occur because the end user operates + * one of the dialog box's buttons, entry fields, or controls. + */ +BOOL CALLBACK EXPORT AddEditDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) +{ + HWND hEdit; + + switch(Message) { + case WM_INITDIALOG: + /* initialize working variables */ + hEdit=GetDlgItem(hDlg,IDD_EDIT); + SendMessage(hEdit,EM_LIMITTEXT,(WPARAM)MAXSTRLEN,0L); + SetWindowText(hDlg, g_lpszDlgTitle); + SetDlgItemText(hDlg,IDD_EDIT, g_szBuf); + break; /* End of WM_INITDIALOG */ + + case WM_CLOSE: + /* Closing the Dialog behaves the same as Cancel */ + PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L); + break; /* End of WM_CLOSE */ + + case WM_COMMAND: + switch (wParam) { + case IDOK: + /* save data values entered into the controls + ** and dismiss the dialog box returning TRUE + */ + GetDlgItemText(hDlg,IDD_EDIT,(LPSTR)g_szBuf,MAXSTRLEN+1); + EndDialog(hDlg, TRUE); + break; + + case IDCANCEL: + /* ignore data values entered into the controls + ** and dismiss the dialog box returning FALSE + */ + EndDialog(hDlg, FALSE); + break; + } + break; /* End of WM_COMMAND */ + + default: + return FALSE; + } + + return TRUE; +} /* End of AddEditDlgProc */ + + +/* SetLineHeightDlgProc + * -------------------- + * + * Dialog procedure for set line height + */ +BOOL CALLBACK EXPORT SetLineHeightDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) +{ + BOOL fTranslated; + BOOL fEnable; + static LPINT lpint; + int nHeight; + static int nMaxHeight; + + switch (Message) { + case WM_INITDIALOG: + { + char cBuf[80]; + + nMaxHeight = XformHeightInPixelsToHimetric(NULL, + LISTBOX_HEIGHT_LIMIT); + lpint = (LPINT)lParam; + SetDlgItemInt(hDlg, IDD_EDIT, *lpint, FALSE); + wsprintf(cBuf, "Maximum value is %d units", nMaxHeight); + SetDlgItemText(hDlg, IDD_LIMIT, (LPSTR)cBuf); + break; + } + + case WM_COMMAND: + switch (wParam) { + case IDOK: + if (IsDlgButtonChecked(hDlg, IDD_CHECK)) { + *lpint = -1; + } + else { + /* save the value in the edit control */ + nHeight = GetDlgItemInt(hDlg, IDD_EDIT, + (BOOL FAR*)&fTranslated, FALSE); + if (!fTranslated || !nHeight || (nHeight>nMaxHeight)){ + OutlineApp_ErrorMessage(g_lpApp, + ErrMsgInvalidValue); + break; + } + *lpint = nHeight; + } + EndDialog(hDlg, TRUE); + break; + + case IDCANCEL: + *lpint = 0; + EndDialog(hDlg, FALSE); + break; + + + case IDD_CHECK: + fEnable = !IsDlgButtonChecked(hDlg, IDD_CHECK); + EnableWindow(GetDlgItem(hDlg, IDD_EDIT), fEnable); + EnableWindow(GetDlgItem(hDlg, IDD_TEXT), fEnable); + break; + } + break; /* WM_COMMAND */ + + case WM_CLOSE: /* Closing the Dialog behaves the same as Cancel */ + PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L); + break; /* End of WM_CLOSE */ + + default: + return FALSE; + } + + return TRUE; + +} /* end of SetLineHeightProc */ + + + + + +/* DefineNameDlgProc + * ----------------- + * + * Dialog procedure for define name + */ +BOOL CALLBACK EXPORT DefineNameDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) +{ + static HWND hCombo; + static LPOUTLINEDOC lpOutlineDoc = NULL; + static LPOUTLINENAMETABLE lpOutlineNameTable = NULL; + LPOUTLINENAME lpOutlineName = NULL; + UINT nIndex; + LINERANGE lrSel; + BOOL fTranslated; + + switch(Message) { + case WM_INITDIALOG: + /* initialize working variables */ + hCombo=GetDlgItem(hDlg,IDD_COMBO); + lpOutlineDoc = (LPOUTLINEDOC) lParam; + lpOutlineNameTable = OutlineDoc_GetNameTable(lpOutlineDoc); + + SendMessage(hCombo,CB_LIMITTEXT,(WPARAM)MAXNAMESIZE,0L); + NameDlg_LoadComboBox(lpOutlineNameTable, hCombo); + + OutlineDoc_GetSel(lpOutlineDoc, (LPLINERANGE)&lrSel); + lpOutlineName = OutlineNameTable_FindNamedRange( + lpOutlineNameTable, + &lrSel + ); + + /* if current selection already has a name, hilight it */ + if (lpOutlineName) { + nIndex = (int) SendMessage( + hCombo, + CB_FINDSTRINGEXACT, + (WPARAM)0xffff, + (LPARAM)(LPCSTR)lpOutlineName->m_szName + ); + if (nIndex != CB_ERR) { + SendMessage(hCombo, CB_SETCURSEL, (WPARAM)nIndex, 0L); + } + } + + SetDlgItemInt(hDlg, IDD_FROM, (UINT)lrSel.m_nStartLine+1,FALSE); + SetDlgItemInt(hDlg, IDD_TO, (UINT)lrSel.m_nEndLine+1, FALSE); + + break; /* End of WM_INITDIALOG */ + + case WM_CLOSE: + /* Closing the Dialog behaves the same as Cancel */ + PostMessage(hDlg, WM_COMMAND, IDD_CLOSE, 0L); + break; /* End of WM_CLOSE */ + + case WM_COMMAND: + switch(wParam) { + case IDOK: + GetDlgItemText(hDlg,IDD_COMBO,(LPSTR)g_szBuf,MAXNAMESIZE); + if(! SendMessage(hCombo,WM_GETTEXTLENGTH,0,0L)) { + MessageBox( + hDlg, + ErrMsgNullName, + NULL, + MB_ICONEXCLAMATION + ); + break; + } else if(SendMessage(hCombo,CB_GETCURSEL,0,0L)==CB_ERR && + _fstrchr(g_szBuf, ' ')) { + MessageBox( + hDlg, + ErrMsgInvalidName, + NULL, + MB_ICONEXCLAMATION + ); + break; + } else { + nIndex = (int) SendMessage(hCombo,CB_FINDSTRINGEXACT, + (WPARAM)0xffff,(LPARAM)(LPCSTR)g_szBuf); + + /* Line indices are 1 less than the number in + ** the row heading + */ + lrSel.m_nStartLine = GetDlgItemInt(hDlg, IDD_FROM, + (BOOL FAR*)&fTranslated, FALSE) - 1; + if(! fTranslated) { + OutlineApp_ErrorMessage(g_lpApp, + ErrMsgInvalidRange); + break; + } + lrSel.m_nEndLine = GetDlgItemInt(hDlg, IDD_TO, + (BOOL FAR*)&fTranslated, FALSE) - 1; + if (!fTranslated || + (lrSel.m_nStartLine < 0) || + (lrSel.m_nEndLine < lrSel.m_nStartLine) || + (lrSel.m_nEndLine >= OutlineDoc_GetLineCount( + lpOutlineDoc))) { + OutlineApp_ErrorMessage(g_lpApp, + ErrMsgInvalidRange); + break; + } + + if(nIndex != CB_ERR) { + NameDlg_UpdateName( + hCombo, + lpOutlineDoc, + nIndex, + g_szBuf, + &lrSel + ); + } else { + NameDlg_AddName( + hCombo, + lpOutlineDoc, + g_szBuf, + &lrSel + ); + } + } + // fall through + + case IDD_CLOSE: + /* Ignore data values entered into the controls */ + /* and dismiss the dialog window returning FALSE */ + EndDialog(hDlg,0); + break; + + case IDD_DELETE: + GetDlgItemText(hDlg,IDD_COMBO,(LPSTR)g_szBuf,MAXNAMESIZE); + if((nIndex=(int)SendMessage(hCombo,CB_FINDSTRINGEXACT, + (WPARAM)0xffff,(LPARAM)(LPCSTR)g_szBuf))==CB_ERR) + MessageBox(hDlg, ErrMsgNameNotFound, NULL, MB_ICONEXCLAMATION); + else { + NameDlg_DeleteName(hCombo, lpOutlineDoc, nIndex); + } + break; + + case IDD_COMBO: + if(HIWORD(lParam) == CBN_SELCHANGE) { + nIndex=(int)SendMessage(hCombo, CB_GETCURSEL, 0, 0L); + lpOutlineName = (LPOUTLINENAME)SendMessage( + hCombo, + CB_GETITEMDATA, + (WPARAM)nIndex, + 0L + ); + SetDlgItemInt( + hDlg, + IDD_FROM, + (UINT) lpOutlineName->m_nStartLine + 1, + FALSE + ); + SetDlgItemInt( + hDlg, + IDD_TO, + (UINT) lpOutlineName->m_nEndLine + 1, + FALSE + ); + } + } + break; /* End of WM_COMMAND */ + + default: + return FALSE; + } + + return TRUE; +} /* End of DefineNameDlgProc */ + + +/* GotoNameDlgProc + * --------------- + * + * Dialog procedure for goto name + */ +BOOL CALLBACK EXPORT GotoNameDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) +{ + static HWND hLBName; + static LPOUTLINEDOC lpOutlineDoc = NULL; + static LPOUTLINENAMETABLE lpOutlineNameTable = NULL; + UINT nIndex; + LINERANGE lrLineRange; + LPOUTLINENAME lpOutlineName; + + switch(Message) { + case WM_INITDIALOG: + /* initialize working variables */ + lpOutlineDoc = (LPOUTLINEDOC) lParam; + lpOutlineNameTable = OutlineDoc_GetNameTable(lpOutlineDoc); + + hLBName=GetDlgItem(hDlg,IDD_LINELISTBOX); + NameDlg_LoadListBox(lpOutlineNameTable, hLBName); + + // highlight 1st item + SendMessage(hLBName, LB_SETCURSEL, 0, 0L); + // trigger to initialize edit control + SendMessage(hDlg, WM_COMMAND, (WPARAM)IDD_LINELISTBOX, + MAKELONG(hLBName, LBN_SELCHANGE)); + + break; /* End of WM_INITDIALOG */ + + case WM_CLOSE: + /* Closing the Dialog behaves the same as Cancel */ + PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L); + break; /* End of WM_CLOSE */ + + case WM_COMMAND: + switch(wParam) { + case IDD_LINELISTBOX: + if(HIWORD(lParam) == LBN_SELCHANGE) { + // update the line range display + nIndex=(int)SendMessage(hLBName, LB_GETCURSEL, 0, 0L); + lpOutlineName = (LPOUTLINENAME)SendMessage(hLBName, LB_GETITEMDATA, + (WPARAM)nIndex,0L); + if (lpOutlineName) { + SetDlgItemInt( + hDlg, + IDD_FROM, + (UINT) lpOutlineName->m_nStartLine + 1, + FALSE + ); + SetDlgItemInt( + hDlg, + IDD_TO, + (UINT) lpOutlineName->m_nEndLine + 1, + FALSE + ); + } + break; + } + // double click will fall through + else if(HIWORD(lParam) != LBN_DBLCLK) + break; + + case IDOK: + nIndex=(int)SendMessage(hLBName,LB_GETCURSEL,0,0L); + if(nIndex!=LB_ERR) { + lpOutlineName = (LPOUTLINENAME)SendMessage(hLBName, + LB_GETITEMDATA, (WPARAM)nIndex, 0L); + lrLineRange.m_nStartLine=lpOutlineName->m_nStartLine; + lrLineRange.m_nEndLine = lpOutlineName->m_nEndLine; + OutlineDoc_SetSel(lpOutlineDoc, &lrLineRange); + } // fall through + + case IDCANCEL: + /* Ignore data values entered into the controls */ + /* and dismiss the dialog window returning FALSE */ + EndDialog(hDlg,0); + break; + + } + break; /* End of WM_COMMAND */ + + default: + return FALSE; + } + + return TRUE; +} /* End of GotoNameDlgProc */ + + + +/* NameDlg_LoadComboBox + * -------------------- + * + * Load defined names into combo box + */ +void NameDlg_LoadComboBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hCombo) +{ + LPOUTLINENAME lpOutlineName; + int i, nIndex; + int nCount; + + nCount=OutlineNameTable_GetCount((LPOUTLINENAMETABLE)lpOutlineNameTable); + if(!nCount) return; + + SendMessage(hCombo,WM_SETREDRAW,(WPARAM)FALSE,0L); + for(i=0; i<nCount; i++) { + lpOutlineName=OutlineNameTable_GetName((LPOUTLINENAMETABLE)lpOutlineNameTable,i); + nIndex = (int)SendMessage( + hCombo, + CB_ADDSTRING, + 0, + (LPARAM)(LPCSTR)lpOutlineName->m_szName + ); + SendMessage(hCombo,CB_SETITEMDATA,(WPARAM)nIndex,(LPARAM)lpOutlineName); + } + SendMessage(hCombo,WM_SETREDRAW,(WPARAM)TRUE,0L); +} + + +/* NameDlg_LoadListBox + * ------------------- + * + * Load defined names into list box + */ +void NameDlg_LoadListBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hListBox) +{ + int i; + int nCount; + int nIndex; + LPOUTLINENAME lpOutlineName; + + nCount=OutlineNameTable_GetCount((LPOUTLINENAMETABLE)lpOutlineNameTable); + + SendMessage(hListBox,WM_SETREDRAW,(WPARAM)FALSE,0L); + for(i=0; i<nCount; i++) { + lpOutlineName=OutlineNameTable_GetName((LPOUTLINENAMETABLE)lpOutlineNameTable,i); + nIndex = (int)SendMessage( + hListBox, + LB_ADDSTRING, + 0, + (LPARAM)(LPCSTR)lpOutlineName->m_szName + ); + SendMessage(hListBox,LB_SETITEMDATA,(WPARAM)nIndex,(LPARAM)lpOutlineName); + } + SendMessage(hListBox,WM_SETREDRAW,(WPARAM)TRUE,0L); +} + + +/* NameDlg_AddName + * --------------- + * + * Add a name to the name table corresponding to the name dialog + * combo box. + */ +void NameDlg_AddName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, LPSTR lpszName, LPLINERANGE lplrSel) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINENAME lpOutlineName; + + lpOutlineName = OutlineApp_CreateName(lpOutlineApp); + + if (lpOutlineName) { + lstrcpy(lpOutlineName->m_szName, lpszName); + lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; + lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; + OutlineDoc_AddName(lpOutlineDoc, lpOutlineName); + } else { + // REVIEW: do we need error message here? + } +} + + +/* NameDlg_UpdateName + * ------------------ + * + * Update a name in the name table corresponding to a name in + * the name dialog combo box. + */ +void NameDlg_UpdateName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, int nIndex, LPSTR lpszName, LPLINERANGE lplrSel) +{ + LPOUTLINENAME lpOutlineName; + + lpOutlineName = (LPOUTLINENAME)SendMessage( + hCombo, + CB_GETITEMDATA, + (WPARAM)nIndex, + 0L + ); + + OutlineName_SetName(lpOutlineName, lpszName); + OutlineName_SetSel(lpOutlineName, lplrSel, TRUE /* name modified */); + OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE); +} + + +/* NameDlg_DeleteName + * ------------------ + * + * Delete a name from the name dialog combo box and corresponding + * name table. + */ +void NameDlg_DeleteName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, UINT nIndex) +{ + SendMessage(hCombo,CB_DELETESTRING,(WPARAM)nIndex,0L); + OutlineDoc_DeleteName(lpOutlineDoc, nIndex); +} + +/* PlaceBitmap + * ----------- + * + * Places a bitmap centered in the specified control in the dialog on the + * specified DC. + * + */ + +PlaceBitmap(HWND hDlg, int control, HDC hDC, HBITMAP hBitmap) +{ + BITMAP bm; + HDC hdcmem; + HBITMAP hbmOld; + RECT rcControl; // Rect of dialog control + int width, height; + + GetObject(hBitmap, sizeof(BITMAP), &bm); + + hdcmem= CreateCompatibleDC(hDC); + hbmOld = SelectObject(hdcmem, hBitmap); + + // Get rect of control in screen coords, and translate to our dialog + // box's coordinates + GetWindowRect(GetDlgItem(hDlg, control), &rcControl); + MapWindowPoints(NULL, hDlg, (LPPOINT)&rcControl, 2); + + width = rcControl.right - rcControl.left; + height = rcControl.bottom - rcControl.top; + + BitBlt(hDC, rcControl.left + (width - bm.bmWidth) / 2, + rcControl.top + (height - bm.bmHeight) /2, + bm.bmWidth, bm.bmHeight, + hdcmem, 0, 0, SRCCOPY); + + SelectObject(hdcmem, hbmOld); + DeleteDC(hdcmem); + return 1; +} + + + +/* AboutDlgProc + * ------------ + * + * Dialog procedure for the About function + */ +BOOL CALLBACK EXPORT AboutDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) +{ + int narrVersion[2]; + static HBITMAP hbmLogo; + + switch(Message) { + + case WM_INITDIALOG: + // get version number of app + wsprintf(g_szBuf, "About %s", (LPCSTR)APPNAME); + SetWindowText(hDlg, (LPCSTR)g_szBuf); + OutlineApp_GetAppVersionNo(g_lpApp, narrVersion); + wsprintf(g_szBuf, "%s version %d.%d", (LPSTR) APPDESC, + narrVersion[0], narrVersion[1]); + SetDlgItemText(hDlg, IDD_APPTEXT, (LPCSTR)g_szBuf); + + // Load bitmap for displaying later + hbmLogo = LoadBitmap(g_lpApp->m_hInst, "LogoBitmap"); + TraceDebug(hDlg, IDD_BITMAPLOCATION); + ShowWindow(GetDlgItem(hDlg, IDD_BITMAPLOCATION), SW_HIDE); + break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint(hDlg, &ps); + + // Display bitmap in IDD_BITMAPLOCATION control area + PlaceBitmap(hDlg, IDD_BITMAPLOCATION, ps.hdc, hbmLogo); + EndPaint(hDlg, &ps); + } + break; + + case WM_CLOSE : + PostMessage(hDlg, WM_COMMAND, IDOK, 0L); + break; + + case WM_COMMAND : + switch(wParam) { + case IDOK: + case IDCANCEL: + if (hbmLogo) DeleteObject(hbmLogo); + EndDialog(hDlg,0); + break; + } + break; + + default : + return FALSE; + + } + return TRUE; +} diff --git a/private/oleutest/letest/outline/dialogs.dlg b/private/oleutest/letest/outline/dialogs.dlg new file mode 100644 index 000000000..a77bbde65 --- /dev/null +++ b/private/oleutest/letest/outline/dialogs.dlg @@ -0,0 +1,92 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** dialogs.dlg +** +** Resource file for dialogs +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +ADDEDITLINE DIALOG 6, 18, 225, 53 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Shell Dlg" +BEGIN + EDITTEXT IDD_EDIT, 5, 16, 212, 13, ES_AUTOHSCROLL + LTEXT "Enter text for the line", -1, 5, 4, 72, 8 + PUSHBUTTON "Cancel", IDCANCEL, 177, 35, 40, 14 + DEFPUSHBUTTON "OK", IDOK, 5, 35, 40, 14 +END + +DEFINENAME DIALOG 6, 18, 160, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Define Name" +FONT 8, "MS Shell Dlg" +BEGIN + COMBOBOX IDD_COMBO, 5, 17, 98, 49, CBS_SIMPLE | CBS_AUTOHSCROLL | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK", IDOK, 114, 11, 40, 14 + PUSHBUTTON "Close", IDD_CLOSE, 114, 31, 40, 14 + PUSHBUTTON "Delete", IDD_DELETE, 114, 51, 40, 14 + LTEXT "Defined Names", -1, 5, 6, 57, 8 + LTEXT "Line Range : ", -1, 5, 76, 44, 8 + LTEXT "to", -1, 86, 76, 10, 8 + EDITTEXT IDD_FROM, 50, 75, 32, 12, ES_AUTOHSCROLL + EDITTEXT IDD_TO, 99, 75, 32, 12, ES_AUTOHSCROLL +END + +GOTONAME DIALOG 6, 18, 160, 93 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Goto Name" +FONT 8, "MS Shell Dlg" +BEGIN + LISTBOX IDD_LINELISTBOX, 5, 18, 99, 49, LBS_SORT | WS_VSCROLL | + WS_TABSTOP + LTEXT "Goto:", -1, 5, 7, 20, 8 + DEFPUSHBUTTON "OK", IDOK, 115, 18, 40, 14 + PUSHBUTTON "Cancel", IDCANCEL, 115, 38, 40, 14 + LTEXT "Line Range : ", -1, 5, 79, 44, 8 + LTEXT "to", -1, 79, 79, 10, 8 + LTEXT "", IDD_FROM, 55, 79, 19, 8 + LTEXT "", IDD_TO, 93, 79, 20, 8 +END + +PRINT DIALOG 69, 41, 109, 48 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Outline" +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Cancel", IDCANCEL, 34, 28, 40, 14 + LTEXT "Printing...", -1, 17, 8, 72, 10 +END + +SETLINEHEIGHT DIALOG 52, 52, 160, 80 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Set Line Height" +FONT 8, "MS Shell Dlg" +BEGIN + EDITTEXT IDD_EDIT, 34, 42, 50, 12, ES_AUTOHSCROLL + LTEXT "Height:", IDD_TEXT, 6, 43, 28, 12 + CONTROL "Use Standard Height", IDD_CHECK, "Button", + BS_AUTOCHECKBOX | WS_TABSTOP, 6, 64, 80, 10 + LTEXT "Enter Line Height (100 units = 1mm)", -1, 6, 10, 121, + 10 + DEFPUSHBUTTON "OK", IDOK, 110, 40, 40, 14 + PUSHBUTTON "Cancel", IDCANCEL, 110, 62, 40, 14 + LTEXT "", IDD_LIMIT, 6, 24, 89, 8 +END + +ABOUT DIALOG DISCARDABLE 17, 21, 205, 138 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Shell Dlg" +BEGIN + CTEXT "",IDD_APPTEXT,5,90,195,10 + DEFPUSHBUTTON "OK",IDOK,81,117,45,15 + CTEXT "Copyright \2511992 - 1993, Microsoft Corporation", -1, + 25,103,156,8 + CONTROL "",IDD_BITMAPLOCATION,"Static",SS_BLACKFRAME,11,10,184, + 68 + CONTROL "",-1,"Static",SS_BLACKFRAME,6,5,194,78 +END diff --git a/private/oleutest/letest/outline/dirs b/private/oleutest/letest/outline/dirs new file mode 100644 index 000000000..0052409cb --- /dev/null +++ b/private/oleutest/letest/outline/dirs @@ -0,0 +1,32 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Rick Sailor (Ricksa) 15-Mar-1994 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= \ + \ + cntroutl \ + icntrotl \ + isvrotl \ + svroutl diff --git a/private/oleutest/letest/outline/dragcopy.cur b/private/oleutest/letest/outline/dragcopy.cur Binary files differnew file mode 100644 index 000000000..89c7c960d --- /dev/null +++ b/private/oleutest/letest/outline/dragcopy.cur diff --git a/private/oleutest/letest/outline/dragdrop.c b/private/oleutest/letest/outline/dragdrop.c new file mode 100644 index 000000000..ab4b95795 --- /dev/null +++ b/private/oleutest/letest/outline/dragdrop.c @@ -0,0 +1,674 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** dragdrop.c +** +** This file contains the major interfaces, methods and related support +** functions for implementing Drag/Drop. The code contained in this +** file is used by BOTH the Container and Server (Object) versions +** of the Outline sample code. +** The Drag/Drop support includes the following implementation objects: +** +** OleDoc Object +** exposed interfaces: +** IDropSource +** IDropTarget +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + +#if defined( USE_DRAGDROP ) + +/* OleDoc_QueryDrag + * ---------------- + * Check to see if Drag operation should be initiated. A Drag operation + * should be initiated when the mouse in either the top 10 pixels of the + * selected list box entry or in the bottom 10 pixels of the last selected + * item. + */ + +BOOL OleDoc_QueryDrag(LPOLEDOC lpOleDoc, int y) +{ + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + LINERANGE LineRange; + + if ( LineList_GetSel( lpLL, (LPLINERANGE)&LineRange) ) { + RECT rect; + + if (!LineList_GetLineRect(lpLL,LineRange.m_nStartLine,(LPRECT)&rect)) + return FALSE ; + + if ( rect.top <= y && y <= rect.top + DD_SEL_THRESH ) + return TRUE; + + LineList_GetLineRect( lpLL, LineRange.m_nEndLine, (LPRECT)&rect ); + if ( rect.bottom >= y && y >= rect.bottom - DD_SEL_THRESH ) + return TRUE; + + } + + return FALSE; +} + +/* OleDoc_DoDragScroll + * ------------------- + * Check to see if Drag scroll operation should be initiated. A Drag scroll + * operation should be initiated when the mouse has remained in the active + * scroll area (11 pixels frame around border of window) for a specified + * amount of time (50ms). + */ + +BOOL OleDoc_DoDragScroll(LPOLEDOC lpOleDoc, POINTL pointl) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + HWND hWndListBox = LineList_GetWindow(lpLL); + DWORD dwScrollDir = SCROLLDIR_NULL; + DWORD dwTime = GetCurrentTime(); + int nScrollInset = lpOleApp->m_nScrollInset; + int nScrollDelay = lpOleApp->m_nScrollDelay; + int nScrollInterval = lpOleApp->m_nScrollInterval; + POINT point; + RECT rect; + + if ( lpLL->m_nNumLines == 0 ) + return FALSE; + + point.x = (int)pointl.x; + point.y = (int)pointl.y; + + ScreenToClient( hWndListBox, &point); + GetClientRect ( hWndListBox, (LPRECT) &rect ); + + if (rect.top <= point.y && point.y<=(rect.top+nScrollInset)) + dwScrollDir = SCROLLDIR_UP; + else if ((rect.bottom-nScrollInset) <= point.y && point.y <= rect.bottom) + dwScrollDir = SCROLLDIR_DOWN; + + if (lpOleDoc->m_dwTimeEnterScrollArea) { + + /* cursor was already in Scroll Area */ + + if (! dwScrollDir) { + /* cusor moved OUT of scroll area. + ** clear "EnterScrollArea" time. + */ + lpOleDoc->m_dwTimeEnterScrollArea = 0L; + lpOleDoc->m_dwNextScrollTime = 0L; + lpOleDoc->m_dwLastScrollDir = SCROLLDIR_NULL; + } else if (dwScrollDir != lpOleDoc->m_dwLastScrollDir) { + /* cusor moved into a different direction scroll area. + ** reset "EnterScrollArea" time to start a new 50ms delay. + */ + lpOleDoc->m_dwTimeEnterScrollArea = dwTime; + lpOleDoc->m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay; + lpOleDoc->m_dwLastScrollDir = dwScrollDir; + } else if (dwTime && dwTime >= lpOleDoc->m_dwNextScrollTime) { + LineList_Scroll ( lpLL, dwScrollDir ); // Scroll doc NOW + lpOleDoc->m_dwNextScrollTime = dwTime + (DWORD)nScrollInterval; + } + } else { + if (dwScrollDir) { + /* cusor moved INTO a scroll area. + ** reset "EnterScrollArea" time to start a new 50ms delay. + */ + lpOleDoc->m_dwTimeEnterScrollArea = dwTime; + lpOleDoc->m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay; + lpOleDoc->m_dwLastScrollDir = dwScrollDir; + } + } + + return (dwScrollDir ? TRUE : FALSE); +} + + +/* OleDoc_QueryDrop +** ---------------- +** Check if the desired drop operation (identified by the given key +** state) is possible at the current mouse position (pointl). +*/ +BOOL OleDoc_QueryDrop ( + LPOLEDOC lpOleDoc, + DWORD grfKeyState, + POINTL pointl, + BOOL fDragScroll, + LPDWORD lpdwEffect +) +{ + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + LINERANGE linerange; + short nIndex = LineList_GetLineIndexFromPointl( lpLL, pointl ); + DWORD dwScrollEffect = 0L; + DWORD dwOKEffects = *lpdwEffect; + + /* check if the cursor is in the active scroll area, if so need the + ** special scroll cursor. + */ + if (fDragScroll) + dwScrollEffect = DROPEFFECT_SCROLL; + + /* if we have already determined that the source does NOT have any + ** acceptable data for us, the return NO-DROP + */ + if (! lpOleDoc->m_fCanDropCopy && ! lpOleDoc->m_fCanDropLink) + goto dropeffect_none; + + /* if the Drag/Drop is local to our document, we can NOT accept a + ** drop in the middle of the current selection (which is the exact + ** data that is being dragged!). + */ + if (lpOleDoc->m_fLocalDrag) { + LineList_GetSel( lpLL, (LPLINERANGE)&linerange ); + + if (linerange.m_nStartLine <= nIndex && nIndex<linerange.m_nEndLine) + goto dropeffect_none; + } + + /* OLE2NOTE: determine what type of drop should be performed given + ** the current modifier key state. we rely on the standard + ** interpretation of the modifier keys: + ** no modifier -- DROPEFFECT_MOVE or whatever is allowed by src + ** SHIFT -- DROPEFFECT_MOVE + ** CTRL -- DROPEFFECT_COPY + ** CTRL-SHIFT -- DROPEFFECT_LINK + */ + + *lpdwEffect = OleStdGetDropEffect(grfKeyState); + if (*lpdwEffect == 0) { + // No modifier keys given. Try in order MOVE, COPY, LINK. + if ((DROPEFFECT_MOVE & dwOKEffects) && lpOleDoc->m_fCanDropCopy) + *lpdwEffect = DROPEFFECT_MOVE; + else if ((DROPEFFECT_COPY & dwOKEffects) && lpOleDoc->m_fCanDropCopy) + *lpdwEffect = DROPEFFECT_COPY; + else if ((DROPEFFECT_LINK & dwOKEffects) && lpOleDoc->m_fCanDropLink) + *lpdwEffect = DROPEFFECT_LINK; + else + goto dropeffect_none; + } else { + /* OLE2NOTE: we should check if the drag source application allows + ** the desired drop effect. + */ + if (!(*lpdwEffect & dwOKEffects)) + goto dropeffect_none; + + if ((*lpdwEffect == DROPEFFECT_COPY || *lpdwEffect == DROPEFFECT_MOVE) + && ! lpOleDoc->m_fCanDropCopy) + goto dropeffect_none; + + if (*lpdwEffect == DROPEFFECT_LINK && ! lpOleDoc->m_fCanDropLink) + goto dropeffect_none; + } + + *lpdwEffect |= dwScrollEffect; + return TRUE; + +dropeffect_none: + + *lpdwEffect = DROPEFFECT_NONE; + return FALSE; +} + +/* OleDoc_DoDragDrop + * ----------------- + * Actually perform a drag/drop operation with the current selection in + * the source document (lpSrcOleDoc). + * + * returns the result effect of the drag/drop operation: + * DROPEFFECT_NONE, + * DROPEFFECT_COPY, + * DROPEFFECT_MOVE, or + * DROPEFFECT_LINK + */ + +DWORD OleDoc_DoDragDrop (LPOLEDOC lpSrcOleDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc; + LPOLEDOC lpDragDoc; + LPLINELIST lpSrcLL = + (LPLINELIST)&((LPOUTLINEDOC)lpSrcOleDoc)->m_LineList; + DWORD dwEffect = 0; + LPLINE lplineStart, lplineEnd; + LINERANGE linerange; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + HRESULT hrErr; + + OLEDBG_BEGIN3("OleDoc_DoDragDrop\r\n") + + /* squirrel away a copy of the current selection to the ClipboardDoc */ + lpDragDoc = (LPOLEDOC)OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc); + if ( ! lpDragDoc) { + dwEffect = DROPEFFECT_NONE; + goto error; + } + + /* OLE2NOTE: initially the DataTransferDoc is created with a 0 ref + ** count. in order to have a stable Doc object during the drag/ + ** drop operation, we intially AddRef the Doc ref cnt and later + ** Release it. This AddRef is artificial; it is simply + ** done to guarantee that a harmless QueryInterface followed by + ** a Release does not inadvertantly force our object to destroy + ** itself prematurely. + */ + OleDoc_AddRef(lpDragDoc); + + //NOTE: we need to keep the LPLINE pointers + // rather than the indexes because the + // indexes will not be the same after the + // drop occurs -- the drop adds new + // entries to the list thereby shifting + // the whole list. + LineList_GetSel( lpSrcLL, (LPLINERANGE)&linerange ); + lplineStart = LineList_GetLine ( lpSrcLL, linerange.m_nStartLine ); + lplineEnd = LineList_GetLine ( lpSrcLL, linerange.m_nEndLine ); + + if (! lplineStart || ! lplineEnd) { + dwEffect = DROPEFFECT_NONE; + goto error; + } + + lpSrcOleDoc->m_fLocalDrop = FALSE; + lpSrcOleDoc->m_fLocalDrag = TRUE; + + /* OLE2NOTE: it is VERY important to DISABLE the Busy/NotResponding + ** dialogs BEFORE calling DoDragDrop. The DoDragDrop API starts + ** a mouse capture modal loop. if the Busy/NotResponding comes + ** up in the middle of this loop (eg. if one of the remoted + ** calls like IDropTarget::DragOver call takes a long time, then + ** the NotResponding dialog may want to come up), then the mouse + ** capture is lost by OLE and things can get messed up. + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + OLEDBG_BEGIN2("DoDragDrop called\r\n") + hrErr = DoDragDrop ( (LPDATAOBJECT) &lpDragDoc->m_DataObject, + (LPDROPSOURCE) &lpSrcOleDoc->m_DropSource, + DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK, + (LPDWORD) &dwEffect + ); + OLEDBG_END2 + + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); + +#if defined( _DEBUG ) + if (FAILED(hrErr)) + OleDbgOutHResult("DoDragDrop returned", hrErr); +#endif + lpSrcOleDoc->m_fLocalDrag = FALSE; + + /* OLE2NOTE: we need to guard the lifetime of our lpSrcOleDoc + ** object while we are deleting the lines that were drag + ** moved. it is possible that deleting these lines could + ** cause the deletion of a PseudoObj. the deletion of a + ** PseudoObj will cause the Doc to be unlock + ** (CoLockObjectExternal(FALSE,TRUE) called). each PseudoObj + ** holds a strong lock on the Doc. It is always best to have + ** a memory guard around such critical sections of code. in + ** this case, it is particularly important if we were an + ** in-place active server and this drag ended up in a drop + ** in our outer container. this scenario will lead to a + ** crash if we do not hold this memory guard. + */ + OleDoc_Lock(lpSrcOleDoc, TRUE, 0); + + /* if after the Drag/Drop modal (mouse capture) loop is finished + ** and a drag MOVE operation was performed, then we must delete + ** the lines that were dragged. + */ + if ( GetScode(hrErr) == DRAGDROP_S_DROP + && (dwEffect & DROPEFFECT_MOVE) != 0 ) { + + int i,j,iEnd; + LPLINE lplineFocusLine; + + /* disable repainting and sending data changed notifications + ** until after all lines have been deleted. + */ + OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpSrcOleDoc, FALSE ); + + /* if the drop was local to our document, then we must take + ** into account that the line indices of the original source + ** of the drag could have shifted because the dropped lines + ** have been inserted into our document. thus we will + ** re-determine the source line indices. + */ + if (lpSrcOleDoc->m_fLocalDrop) { + i = LineList_GetFocusLineIndex ( lpSrcLL ); + lplineFocusLine = LineList_GetLine ( lpSrcLL, i ); + } + + for ( i = j = LineList_GetLineIndex(lpSrcLL,lplineStart ) , + iEnd = LineList_GetLineIndex(lpSrcLL,lplineEnd ) ; + i <= iEnd ; + i++ + ) OutlineDoc_DeleteLine ((LPOUTLINEDOC)lpSrcOleDoc, j ); + + LineList_RecalcMaxLineWidthInHimetric(lpSrcLL, 0); + + if (lpSrcOleDoc->m_fLocalDrop) { + i = LineList_GetLineIndex ( lpSrcLL, lplineFocusLine ); + LineList_SetFocusLine ( lpSrcLL, (WORD)i ); + } + + OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpSrcOleDoc, TRUE ); + + /* if it is a local Drag/Drop move, we need to balance the + ** SetRedraw(FALSE) call that was made in the implementation + ** of IDropTarget::Drop. + */ + if (lpSrcOleDoc->m_fLocalDrop) + OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpSrcOleDoc, TRUE ); + + LineList_ForceRedraw ( lpSrcLL, FALSE ); + } + + OleDoc_Release(lpDragDoc); // rel artificial AddRef above + OleDoc_Lock(lpSrcOleDoc, FALSE, FALSE); // unlock artificial lock guard + + OLEDBG_END3 + return dwEffect; + +error: + OLEDBG_END3 + return dwEffect; +} + + + +/************************************************************************* +** OleDoc::IDropSource interface implementation +*************************************************************************/ + +STDMETHODIMP OleDoc_DropSource_QueryInterface( + LPDROPSOURCE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropSourceImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) OleDoc_DropSource_AddRef( LPDROPSOURCE lpThis ) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropSourceImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IDropSource"); + + return OleDoc_AddRef(lpOleDoc); +} + + +STDMETHODIMP_(ULONG) OleDoc_DropSource_Release ( LPDROPSOURCE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropSourceImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IDropSource"); + + return OleDoc_Release(lpOleDoc); +} + + +STDMETHODIMP OleDoc_DropSource_QueryContinueDrag ( + LPDROPSOURCE lpThis, + BOOL fEscapePressed, + DWORD grfKeyState +){ + if (fEscapePressed) + return ResultFromScode(DRAGDROP_S_CANCEL); + else if (!(grfKeyState & MK_LBUTTON)) + return ResultFromScode(DRAGDROP_S_DROP); + else + return NOERROR; +} + + +STDMETHODIMP OleDoc_DropSource_GiveFeedback ( + LPDROPSOURCE lpThis, + DWORD dwEffect +) +{ + // Tell OLE to use the standard drag/drop feedback cursors + return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS); + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) + switch (dwEffect) { + + case DROPEFFECT_NONE: + SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragNone ); + break; + + case DROPEFFECT_COPY: + SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragCopy ); + break; + + case DROPEFFECT_MOVE: + SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragMove ); + break; + + case DROPEFFECT_LINK: + SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragLink ); + break; + + } + + return NOERROR; +#endif + +} + +/************************************************************************* +** OleDoc::IDropTarget interface implementation +*************************************************************************/ + +STDMETHODIMP OleDoc_DropTarget_QueryInterface( + LPDROPTARGET lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) OleDoc_DropTarget_AddRef(LPDROPTARGET lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IDropTarget"); + + return OleDoc_AddRef(lpOleDoc); +} + + +STDMETHODIMP_(ULONG) OleDoc_DropTarget_Release ( LPDROPTARGET lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IDropTarget"); + + return OleDoc_Release(lpOleDoc); +} + + +STDMETHODIMP OleDoc_DropTarget_DragEnter ( + LPDROPTARGET lpThis, + LPDATAOBJECT lpDataObj, + DWORD grfKeyState, + POINTL pointl, + LPDWORD lpdwEffect +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + BOOL fDragScroll; + + OLEDBG_BEGIN2("OleDoc_DropTarget_DragEnter\r\n") + + lpOleDoc->m_fDragLeave = FALSE; + lpOleDoc->m_dwTimeEnterScrollArea = 0; + lpOleDoc->m_dwLastScrollDir = SCROLLDIR_NULL; + + + /* Determine if the drag source data object offers a data format + ** that we can copy and/or link to. + */ + + lpOleDoc->m_fCanDropCopy = OleDoc_QueryPasteFromData( + lpOleDoc, + lpDataObj, + FALSE /* fLink */ + ); + + lpOleDoc->m_fCanDropLink = OleDoc_QueryPasteFromData( + lpOleDoc, + lpDataObj, + TRUE /* fLink */ + ); + + fDragScroll = OleDoc_DoDragScroll ( lpOleDoc, pointl ); + + if (OleDoc_QueryDrop(lpOleDoc,grfKeyState,pointl,fDragScroll,lpdwEffect)) + LineList_SetDragOverLineFromPointl( lpLL, pointl ); + + OLEDBG_END2 + return NOERROR; + +} + +STDMETHODIMP OleDoc_DropTarget_DragOver ( + LPDROPTARGET lpThis, + DWORD grfKeyState, + POINTL pointl, + LPDWORD lpdwEffect +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + BOOL fDragScroll; + + fDragScroll = OleDoc_DoDragScroll ( lpOleDoc, pointl ); + + if (OleDoc_QueryDrop(lpOleDoc,grfKeyState, pointl,fDragScroll,lpdwEffect)) + LineList_SetDragOverLineFromPointl( lpLL, pointl ); + else + LineList_RestoreDragFeedback( lpLL ); + + return NOERROR; +} + + +STDMETHODIMP OleDoc_DropTarget_DragLeave ( LPDROPTARGET lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + + OLEDBG_BEGIN2("OleDoc_DropTarget_DragLeave\r\n") + + lpOleDoc->m_fDragLeave = TRUE; + + LineList_RestoreDragFeedback( lpLL ); + + OLEDBG_END2 + return NOERROR; + +} + +STDMETHODIMP OleDoc_DropTarget_Drop ( + LPDROPTARGET lpThis, + LPDATAOBJECT lpDataObj, + DWORD grfKeyState, + POINTL pointl, + LPDWORD lpdwEffect +) +{ + LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + + OLEDBG_BEGIN2("OleDoc_DropTarget_Drop\r\n") + + lpOleDoc->m_fDragLeave = TRUE; + lpOleDoc->m_fLocalDrop = TRUE; + + LineList_RestoreDragFeedback( lpLL ); + SetFocus( LineList_GetWindow( lpLL) ); + + if (OleDoc_QueryDrop(lpOleDoc, grfKeyState, pointl, FALSE, lpdwEffect)) { + BOOL fLink = (*lpdwEffect == DROPEFFECT_LINK); + int iFocusLine = LineList_GetFocusLineIndex( lpLL ); + BOOL fStatus; + + OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpOleDoc, FALSE ); + LineList_SetFocusLineFromPointl ( lpLL, pointl ); + + fStatus = OleDoc_PasteFromData( + lpOleDoc, + lpDataObj, + lpOleDoc->m_fLocalDrag, /* data source is local to app */ + fLink + ); + + // if drop was unsuccessfull, restore the original focus line + if (! fStatus) + LineList_SetFocusLine( lpLL, (WORD)iFocusLine ); + +#if defined( INPLACE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; + + /* OLE2NOTE: if there is currently a UIActive OLE object, + ** then we must tell it to UIDeactivate after + ** the drop has completed. + */ + if (lpContainerDoc->m_lpLastUIActiveLine) { + ContainerLine_UIDeactivate( + lpContainerDoc->m_lpLastUIActiveLine); + } + } +#endif + +#if defined( INPLACE_SVR ) + { + /* OLE2NOTE: if the drop was into a in-place visible + ** (in-place active but NOT UIActive object), then we + ** want to UIActivate the object after the drop is + ** complete. + */ + ServerDoc_UIActivate((LPSERVERDOC) lpOleDoc); + } +#endif + + + /* if it is a local Drag/Drop move, don't enable redraw. + ** after the source is done deleting the moved lines, it + ** will re-enable redraw + */ + if (! (lpOleDoc->m_fLocalDrag + && (*lpdwEffect & DROPEFFECT_MOVE) != 0 )) + OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpOleDoc, TRUE ); + } + + OLEDBG_END2 + return NOERROR; +} + + +#endif // USE_DRAGDROP diff --git a/private/oleutest/letest/outline/draglink.cur b/private/oleutest/letest/outline/draglink.cur Binary files differnew file mode 100644 index 000000000..fca1fc090 --- /dev/null +++ b/private/oleutest/letest/outline/draglink.cur diff --git a/private/oleutest/letest/outline/dragmove.cur b/private/oleutest/letest/outline/dragmove.cur Binary files differnew file mode 100644 index 000000000..a9a9bd636 --- /dev/null +++ b/private/oleutest/letest/outline/dragmove.cur diff --git a/private/oleutest/letest/outline/dragnone.cur b/private/oleutest/letest/outline/dragnone.cur Binary files differnew file mode 100644 index 000000000..b002e96b3 --- /dev/null +++ b/private/oleutest/letest/outline/dragnone.cur diff --git a/private/oleutest/letest/outline/frametls.c b/private/oleutest/letest/outline/frametls.c new file mode 100644 index 000000000..cb28d17ee --- /dev/null +++ b/private/oleutest/letest/outline/frametls.c @@ -0,0 +1,1075 @@ +/************************************************************************* +** +** OLE 2 Server Sample Code +** +** frametls.c +** +** This file contains all FrameTools methods and related support +** functions. The FrameTools object is an encapsulation of the apps +** formula bar and button bar. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +/* private function prototype */ +static void Bar_Move(LPBAR lpbar, LPRECT lprcClient, LPRECT lprcPopup); +static void FB_ResizeEdit(LPBAR lpbar); + +extern LPOUTLINEAPP g_lpApp; +extern RECT g_rectNull; + +/* + * FrameToolsRegisterClass + * + * Purpose: + * Register the popup toolbar window class + * + * Parameters: + * hInst Process instance + * + * Return Value: + * TRUE if successful + * FALSE if failed + * + */ +BOOL FrameToolsRegisterClass(HINSTANCE hInst) +{ + WNDCLASS wc; + + // Register Tool Palette Class + wc.style = CS_BYTEALIGNWINDOW; + wc.lpfnWndProc = FrameToolsWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = hInst; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = CLASS_PALETTE; + + if (!RegisterClass(&wc)) + return FALSE; + else + return TRUE; +} + + +static BOOL FrameTools_CreatePopupPalette(LPFRAMETOOLS lpft, HWND hWndFrame) +{ + if (lpft->m_hWndPopupPalette) + DestroyWindow(lpft->m_hWndPopupPalette); + + lpft->m_hWndPopupPalette = CreateWindow( + CLASS_PALETTE, + "Tool Palette", + WS_POPUP | WS_CAPTION | WS_CLIPCHILDREN, + CW_USEDEFAULT, 0, 0, 0, + hWndFrame, + (HMENU)NULL, + g_lpApp->m_hInst, + 0L + ); + + if (!lpft->m_hWndPopupPalette) + return FALSE; + + SetWindowLong(lpft->m_hWndPopupPalette, 0, (LONG)lpft); + return TRUE; +} + + +/* + * FrameTools_Init + * + * Purpose: + * Init and create the toolbar + * + * Parameters: + * lpft FrameTools object + * hWndParent The window which owns the toolbar + * hInst Process instance + * + * Return Value: + * TRUE if successful + * FALSE if failed + * + */ +BOOL FrameTools_Init(LPFRAMETOOLS lpft, HWND hWndParent, HINSTANCE hInst) +{ + RECT rc; + UINT uPos; + UINT dx; + UINT dy; + + if (!lpft || !hWndParent || !hInst) + return FALSE; + + //Get BTTNCUR's display information + UIToolConfigureForDisplay(&lpft->m_tdd); + + dx=lpft->m_tdd.cxButton; + dy=lpft->m_tdd.cyButton; + + // 15 is calculated from the total number of buttons and separators + lpft->m_uPopupWidth = dx * 15; + + lpft->m_hWndApp = hWndParent; + lpft->m_ButtonBar.m_nState = BARSTATE_TOP; + lpft->m_FormulaBar.m_nState = BARSTATE_TOP; + lpft->m_fInFormulaBar = FALSE; + + lpft->m_fToolsDisabled = FALSE; + + lpft->m_ButtonBar.m_uHeight = lpft->m_tdd.cyBar; + lpft->m_FormulaBar.m_uHeight = lpft->m_tdd.cyBar; + + + //Get our image bitmaps for the display type we're on + if (72 == lpft->m_tdd.uDPI) + lpft->m_hBmp = LoadBitmap(hInst, (LPCSTR)"Image72"); + if (96 == lpft->m_tdd.uDPI) + lpft->m_hBmp = LoadBitmap(hInst, (LPCSTR)"Image96"); + if (120 == lpft->m_tdd.uDPI) + lpft->m_hBmp = LoadBitmap(hInst, (LPCSTR)"Image120"); + + if (!lpft->m_hBmp) + return FALSE; + + /* Create Popup Tool Palette window */ + lpft->m_hWndPopupPalette = NULL; + if (! FrameTools_CreatePopupPalette(lpft, hWndParent)) + return FALSE; + + uPos = 0; + //Create the GizmoBar and the client area window + GetClientRect(hWndParent, &rc); + lpft->m_ButtonBar.m_hWnd = CreateWindow( + CLASS_GIZMOBAR, + "ButtonBar", + WS_CHILD | WS_VISIBLE, + 0, 0, rc.right-rc.left, lpft->m_tdd.cyBar, + hWndParent, + (HMENU)IDC_GIZMOBAR, + hInst, + 0L + ); + + if (!lpft->m_ButtonBar.m_hWnd) + return FALSE; + + + SendMessage(lpft->m_ButtonBar.m_hWnd, WM_SETREDRAW, FALSE, 0L); + + //File new, open, save, print + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_NEW, dx, dy, NULL, NULL, TOOLIMAGE_FILENEW, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_OPEN, dx, dy, NULL, NULL, TOOLIMAGE_FILEOPEN, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_SAVE, dx, dy, NULL, NULL, TOOLIMAGE_FILESAVE, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_PRINT, dx, dy, NULL, NULL, TOOLIMAGE_FILEPRINT, GIZMO_NORMAL); + + // separator + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL); + + // Edit cut, copy, paste + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_E_CUT, dx, dy, NULL, NULL, TOOLIMAGE_EDITCUT, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_E_COPY, dx, dy, NULL, NULL, TOOLIMAGE_EDITCOPY, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_E_PASTE, dx, dy, NULL, NULL, TOOLIMAGE_EDITPASTE, GIZMO_NORMAL); + + // separator + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL); + + // Line indent, unindent + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_UNINDENTLINE, dx, dy, NULL, lpft->m_hBmp, IDB_UNINDENTLINE, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_INDENTLINE, dx, dy, NULL, lpft->m_hBmp, IDB_INDENTLINE, GIZMO_NORMAL); + + // separator + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL); + + // Help + GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_H_ABOUT, dx, dy, NULL, NULL, TOOLIMAGE_HELP, GIZMO_NORMAL); + + SendMessage(lpft->m_ButtonBar.m_hWnd, WM_SETREDRAW, TRUE, 0L); + + + uPos = 0; + lpft->m_FormulaBar.m_hWnd = CreateWindow( + CLASS_GIZMOBAR, + "FormulaBar", + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, + 0, lpft->m_tdd.cyBar, rc.right-rc.left, lpft->m_tdd.cyBar, + hWndParent, + (HMENU)IDC_FORMULABAR, + hInst, + 0L + ); + + if (!lpft->m_FormulaBar.m_hWnd) + return FALSE; + + SendMessage(lpft->m_FormulaBar.m_hWnd, WM_SETREDRAW, FALSE, 0L); + + // Line add line + GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_ADDLINE, dx, dy, NULL, lpft->m_hBmp, IDB_ADDLINE, GIZMO_NORMAL); + + // separator + GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL); + + // Line edit line, Cancel + GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_EDITLINE, dx, dy, NULL, lpft->m_hBmp, IDB_EDITLINE, GIZMO_NORMAL); + GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_FB_CANCEL, dx, dy, NULL, lpft->m_hBmp, IDB_CANCEL, GIZMO_NORMAL); + + // separator + GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL); + + // Edit control for line input + GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_EDIT, uPos++, IDM_FB_EDIT, dx*10, lpft->m_tdd.cyBar-5, NULL, NULL, 0, GIZMO_NORMAL); + + + SendMessage(lpft->m_FormulaBar.m_hWnd, WM_SETREDRAW, TRUE, 0L); + + // Limit the text lenght of edit control + GBGizmoSendMessage(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, EM_LIMITTEXT, + (WPARAM)MAXSTRLEN, 0L); + + //Set the GizmoBar's associate to be this client window + GBHwndAssociateSet(lpft->m_ButtonBar.m_hWnd, hWndParent); + + //Set the FormulaBar's associate to be this client window + GBHwndAssociateSet(lpft->m_FormulaBar.m_hWnd, hWndParent); + + return TRUE; +} + + +void FrameTools_AttachToFrame(LPFRAMETOOLS lpft, HWND hWndFrame) +{ + if (! lpft) + return; + + if (hWndFrame == NULL) + hWndFrame = OutlineApp_GetFrameWindow((LPOUTLINEAPP)g_lpApp); + + if (lpft->m_hWndApp == hWndFrame) + return; // already have this parent frame + + lpft->m_hWndApp = hWndFrame; + + /* parent the tool bars to the frame so we can safely + ** destroy/recreate the palette window. + */ + SetParent(lpft->m_ButtonBar.m_hWnd, hWndFrame); + SetParent(lpft->m_FormulaBar.m_hWnd, hWndFrame); + + // recreate popup palette so that it is owned by the hWndFrame + FrameTools_CreatePopupPalette(lpft, hWndFrame); + + // restore the correct parent for the tool bars + FrameTools_BB_SetState(lpft, lpft->m_ButtonBar.m_nState); + FrameTools_FB_SetState(lpft, lpft->m_FormulaBar.m_nState); +} + + +void FrameTools_AssociateDoc(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc) +{ + HWND hWnd = OutlineDoc_GetWindow(lpOutlineDoc); + + if (! lpft) + return; + + // if no Doc is given, then associate with the App's frame window. + if (lpOutlineDoc) + hWnd = OutlineDoc_GetWindow(lpOutlineDoc); + else + hWnd = OutlineApp_GetWindow((LPOUTLINEAPP)g_lpApp); + + //Set the GizmoBar's associate to be this client window + GBHwndAssociateSet(lpft->m_ButtonBar.m_hWnd, hWnd); + + //Set the FormulaBar's associate to be this client window + GBHwndAssociateSet(lpft->m_FormulaBar.m_hWnd, hWnd); +} + + +/* + * FrameTools_Destroy + * + * Purpose: + * Destroy the toolbar + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nil + */ +void FrameTools_Destroy(LPFRAMETOOLS lpft) +{ + if (!lpft) + return; + + if (IsWindow(lpft->m_ButtonBar.m_hWnd)) + DestroyWindow(lpft->m_ButtonBar.m_hWnd); + if (IsWindow(lpft->m_FormulaBar.m_hWnd)) + DestroyWindow(lpft->m_FormulaBar.m_hWnd); + if (IsWindow(lpft->m_hWndPopupPalette)) + DestroyWindow(lpft->m_hWndPopupPalette); + + if (lpft->m_hBmp) + DeleteObject(lpft->m_hBmp); +} + + +/* + * FrameTools_Move + * + * Purpose: + * Move and resize the toolbar + * + * Parameters: + * lpft FrameTools object + * lprc Pointer to client rectangle + * + * Return Value: + * nil + */ +void FrameTools_Move(LPFRAMETOOLS lpft, LPRECT lprcClient) +{ + RECT rcPopup; + LPRECT lprcPopup = (LPRECT)&rcPopup; + int nCmdShow = SW_HIDE; + + if (!lpft || lpft->m_fToolsDisabled) + return; + + lprcPopup->left = 0; + lprcPopup->top = 0; + lprcPopup->right = lpft->m_uPopupWidth; + lprcPopup->bottom = lpft->m_ButtonBar.m_uHeight + + lpft->m_FormulaBar.m_uHeight; + + switch (lpft->m_ButtonBar.m_nState) { + case BARSTATE_HIDE: + case BARSTATE_POPUP: + case BARSTATE_TOP: + Bar_Move(&lpft->m_ButtonBar, lprcClient, lprcPopup); + Bar_Move(&lpft->m_FormulaBar, lprcClient, lprcPopup); + break; + + case BARSTATE_BOTTOM: + Bar_Move(&lpft->m_FormulaBar, lprcClient, lprcPopup); + Bar_Move(&lpft->m_ButtonBar, lprcClient, lprcPopup); + break; + } + + if (lprcPopup->top) { + SetWindowPos(lpft->m_hWndPopupPalette, NULL, 0, 0, lprcPopup->right, + lprcPopup->top + GetSystemMetrics(SM_CYCAPTION), + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW); + } + else + ShowWindow(lpft->m_hWndPopupPalette, SW_HIDE); + + FB_ResizeEdit(&lpft->m_FormulaBar); + + InvalidateRect(lpft->m_ButtonBar.m_hWnd, NULL, TRUE); + InvalidateRect(lpft->m_FormulaBar.m_hWnd, NULL, TRUE); +} + + +/* + * FrameTools_PopupTools + * + * Purpose: + * Put both formula bar and button bar in Popup Window. + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nil + */ +void FrameTools_PopupTools(LPFRAMETOOLS lpft) +{ + if (! lpft) + return; + + FrameTools_BB_SetState(lpft, BARSTATE_POPUP); + FrameTools_FB_SetState(lpft, BARSTATE_POPUP); + FrameTools_Move(lpft, NULL); +} + + +/* + * FrameTools_Enable + * + * Purpose: + * Enable/Disable(hide) all the tools of the toolbar. + * this will hide both the buttonbar and the + * formulabar independent of whether they are floating or anchored. + * + * Parameters: + * lpft FrameTools object + * fEnable + * + * Return Value: + * nil + */ +void FrameTools_Enable(LPFRAMETOOLS lpft, BOOL fEnable) +{ + lpft->m_fToolsDisabled = !fEnable; + if (lpft->m_fToolsDisabled) { + ShowWindow(lpft->m_hWndPopupPalette, SW_HIDE); + ShowWindow(lpft->m_ButtonBar.m_hWnd, SW_HIDE); + ShowWindow(lpft->m_FormulaBar.m_hWnd, SW_HIDE); + } +} + + +/* + * FrameTools_EnableWindow + * + * Purpose: + * EnableWindow for all the tools of the toolbar. + * this enables/disables mouse and keyboard input to the tools. + * while a modal dialog is up, it is inportant to disable the + * floating tool windows. + * this will NOT hide any windows; it will only call EnableWindow. + * + * Parameters: + * lpft FrameTools object + * fEnable + * + * Return Value: + * nil + */ +void FrameTools_EnableWindow(LPFRAMETOOLS lpft, BOOL fEnable) +{ + EnableWindow(lpft->m_hWndPopupPalette, fEnable); + EnableWindow(lpft->m_ButtonBar.m_hWnd, fEnable); + EnableWindow(lpft->m_FormulaBar.m_hWnd, fEnable); +} + + +#if defined( INPLACE_CNTR ) || defined( INPLACE_SVR ) + +/* + * FrameTools_NegotiateForSpaceAndShow + * + * Purpose: + * Negotiate for space for the toolbar tools with the given frame window. + * and make them visible. + * Negotiation steps: + * 1. try to get enough space at top/bottom of window + * 2. float the tools as a palette if space not available + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * none + */ +void FrameTools_NegotiateForSpaceAndShow( + LPFRAMETOOLS lpft, + LPRECT lprcFrameRect, + LPOLEINPLACEFRAME lpTopIPFrame +) +{ + BORDERWIDTHS borderwidths; + RECT rectBorder; + HRESULT hrErr; + + if (lprcFrameRect) + rectBorder = *lprcFrameRect; + else { + /* OLE2NOTE: by calling GetBorder, the server can find out the + ** size of the frame window. it can use this information to + ** make decisions about how to orient/organize it tools (eg. + ** if window is taller than wide put tools vertically at + ** left edge). + */ + OLEDBG_BEGIN2("IOleInPlaceFrame::GetBorder called\r\n") + hrErr = lpTopIPFrame->lpVtbl->GetBorder( + lpTopIPFrame, + (LPRECT)&rectBorder + ); + OLEDBG_END2 + } + + /* Try SetBorderSpace() with the space that you need. If it fails then + ** you can negotiate for space and then do the SetBorderSpace(). + */ + FrameTools_GetRequiredBorderSpace(lpft,(LPBORDERWIDTHS)&borderwidths); + OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace called\r\n") + hrErr = lpTopIPFrame->lpVtbl->SetBorderSpace( + lpTopIPFrame, + (LPCBORDERWIDTHS)&borderwidths + ); + OLEDBG_END2 + +#if defined( LATER ) + if (hrErr != NOERROR) { + /* Frame did not give the toolsspace that we want. So negotiate */ + + // REVIEW: try a different placement of the tools here + + OLEDBG_BEGIN2("IOleInPlaceFrame::RequestBorderSpace called\r\n") + hrErr = lpTopIPFrame->lpVtbl->RequestBorderSpace( + lpTopIPFrame, + (LPCBORDERWIDTHS)&borderwidths + ); + OLEDBG_END2 + + if (hrErr == NOERROR) { + OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace called\r\n") + hrErr = lpTopIPFrame->lpVtbl->SetBorderSpace( + lpTopIPFrame, + (LPCBORDERWIDTHS)&borderwidths + ); + OLEDBG_END2 + } + } +#endif + + if (hrErr == NOERROR) { + FrameTools_Move(lpft, (LPRECT)&rectBorder); // we got what we wanted + } else { + /* We did not get tool space, so POP them up. + /* OLE2NOTE: since we are poping up our tools, we MUST inform + ** the top in-place frame window that we need NO tool space + ** BUT that it should NOT put its own tools up. if we were + ** to pass NULL instead of (0,0,0,0), then the container + ** would have the option to leave its own tools up. + */ + OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(NULL) called\r\n") + hrErr = lpTopIPFrame->lpVtbl->SetBorderSpace( + lpTopIPFrame, + (LPCBORDERWIDTHS)&g_rectNull + ); + OLEDBG_END2 + FrameTools_PopupTools(lpft); + } +} + +#endif // INPLACE_CNTR || INPLACE_SVR + + +/* + * FrameTools_GetRequiredBorderSpace + * + * Purpose: + * Calculate the desired space for the toolbar tools. + * + * Parameters: + * lpft FrameTools object + * lpBorderWidths Widths required at top,bottom,left,right + * + * Return Value: + * nil + */ +void FrameTools_GetRequiredBorderSpace(LPFRAMETOOLS lpft, LPBORDERWIDTHS lpBorderWidths) +{ + *lpBorderWidths = g_rectNull; + + switch (lpft->m_ButtonBar.m_nState) { + case BARSTATE_TOP: + lpBorderWidths->top += lpft->m_ButtonBar.m_uHeight; + break; + + case BARSTATE_BOTTOM: + lpBorderWidths->bottom += lpft->m_ButtonBar.m_uHeight; + break; + } + + switch (lpft->m_FormulaBar.m_nState) { + case BARSTATE_TOP: + lpBorderWidths->top += lpft->m_FormulaBar.m_uHeight; + break; + + case BARSTATE_BOTTOM: + lpBorderWidths->bottom += lpft->m_FormulaBar.m_uHeight; + break; + } +} + + + +/* + * FrameTools_UpdateButtons + * + * Purpose: + * Enable/disable individual buttons of the toolbar according to the + * state of the app + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nil + */ +void FrameTools_UpdateButtons(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc) +{ + BOOL fEnable; + +#if defined( OLE_VERSION ) + LPDATAOBJECT lpClipboardDataObj; + HRESULT hrErr; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + BOOL fPrevEnable1; + BOOL fPrevEnable2; +#endif + + if (!lpft) + return; + +#if defined( INPLACE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + if (lpContainerDoc->m_lpLastUIActiveLine && + lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive) { + + /* if there is a UIActive object, then we should disable + ** all of our "active editor" commands. we should enable + ** only those commands that are "workspace" commands. + */ + if (lpft->m_FormulaBar.m_nState != BARSTATE_HIDE) { + + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_L_EDITLINE,FALSE); + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_L_ADDLINE,FALSE); + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_FB_CANCEL,FALSE); + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_L_EDITLINE,FALSE); + } + + if (lpft->m_ButtonBar.m_nState != BARSTATE_HIDE) + { + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_CUT, FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_COPY, FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd,IDM_L_INDENTLINE,FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_L_UNINDENTLINE, FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_H_ABOUT, FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_FB_EDIT, FALSE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_NEW, TRUE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_OPEN, TRUE); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_SAVE, TRUE); + } + return; + } + } +#endif // INPLACE_CNTR + + fEnable = (BOOL)OutlineDoc_GetLineCount(lpOutlineDoc); + + if (lpft->m_FormulaBar.m_nState != BARSTATE_HIDE) { + + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_EDITLINE, fEnable); + + if (! lpft->m_fInFormulaBar) { + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_ADDLINE, FALSE); + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_FB_CANCEL, FALSE); + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_EDITLINE, FALSE); + if (!fEnable) { + GBGizmoTextSet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, ""); + } + } else { + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_ADDLINE, TRUE); + GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_FB_CANCEL, TRUE); + } + } + + if (lpft->m_ButtonBar.m_nState != BARSTATE_HIDE) + { + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_CUT, fEnable); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_COPY, fEnable); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_L_INDENTLINE, fEnable); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_L_UNINDENTLINE, fEnable); + +#if defined( OLE_SERVER ) + + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + +#if defined( INPLACE_SVR ) + fEnable = ((lpServerDoc->m_fUIActive) ? FALSE : TRUE); +#else + fEnable = (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED); +#endif // INPLACE_SVR + + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_NEW, fEnable); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_OPEN, fEnable); + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_SAVE, fEnable); + } + +#endif // OLE_SERVER + +#if defined( OLE_VERSION ) + + /* OLE2NOTE: we do not want to ever give the busy dialog when we + ** are trying to enable or disable our tool bar buttons eg. + ** even if the source of data on the clipboard is busy, we do + ** not want put up the busy dialog. thus we will disable the + ** dialog and at the end re-enable it. + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + /* OLE2NOTE: perform OLE specific menu initialization. + ** the OLE versions use the OleGetClipboard mechanism for + ** clipboard handling. thus, they determine if the Paste + ** command should be enabled in an OLE specific manner. + */ + fEnable = FALSE; + hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj); + + if (hrErr == NOERROR) { + int nFmtEtc; + + nFmtEtc = OleStdGetPriorityClipboardFormat( + lpClipboardDataObj, + lpOleApp->m_arrPasteEntries, + lpOleApp->m_nPasteEntries + ); + + fEnable = (nFmtEtc >= 0); // there IS a format we like + + OleStdRelease((LPUNKNOWN)lpClipboardDataObj); + } + + // re-enable the busy dialog + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); + + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, fEnable); + +#else + + // Base Outline version uses standard Windows clipboard handling + if(IsClipboardFormatAvailable(g_lpApp->m_cfOutline) || + IsClipboardFormatAvailable(CF_TEXT)) + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, TRUE); + else + GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, FALSE); + +#endif // OLE_VERSION + + } +} + +/* + * FrameTools_FB_SetEditText + * + * Purpose: + * Set text in the edit control in FormulaBar + * + * Parameters: + * lpft FrameTools object + * lpsz pointer to string to be set + * + * Return Value: + * nil + */ +void FrameTools_FB_SetEditText(LPFRAMETOOLS lpft, LPSTR lpsz) +{ + GBGizmoTextSet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, lpsz); +} + + +/* + * FrameTools_FB_GetEditText + * + * Purpose: + * Get text from the edit control in FormulaBar + * + * Parameters: + * lpft FrameTools object + * lpsz pointer to buffer to receive the text + * cch buffer size + * + * Return Value: + * nil + */ +void FrameTools_FB_GetEditText(LPFRAMETOOLS lpft, LPSTR lpsz, UINT cch) +{ + GBGizmoTextGet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, lpsz, cch); +} + + +/* + * FrameTools_FB_FocusEdit + * + * Purpose: + * Set the focus in the edit control of FormulaBar + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nil + */ +void FrameTools_FB_FocusEdit(LPFRAMETOOLS lpft) +{ + GBGizmoFocusSet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT); + + // select the whole text in the edit control + GBGizmoSendMessage(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, EM_SETSEL, + (WPARAM)TRUE, MAKELPARAM(0, -1)); +} + + +/* + * FrameTools_FB_SendMessage + * + * Purpose: + * Send a message to the FormulaBar window gizmo + * + * Parameters: + * lpft FrameTools object + * uID gizmo ID + * msg + * wParam + * lParam + * + * Return Value: + * nil + */ +void FrameTools_FB_SendMessage(LPFRAMETOOLS lpft, UINT uID, UINT msg, WPARAM wParam, LPARAM lParam) +{ + GBGizmoSendMessage(lpft->m_FormulaBar.m_hWnd, uID, msg, wParam, lParam); +} + + +/* + * FrameTools_FB_ForceRedraw + * + * Purpose: + * Force the toolbar to draw itself + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nil + */ +void FrameTools_ForceRedraw(LPFRAMETOOLS lpft) +{ + InvalidateRect(lpft->m_ButtonBar.m_hWnd, NULL, TRUE); + InvalidateRect(lpft->m_FormulaBar.m_hWnd, NULL, TRUE); + InvalidateRect(lpft->m_hWndPopupPalette, NULL, TRUE); +} + + +/* + * FrameTools_BB_SetState + * + * Purpose: + * Set display state of ButtonBar + * + * Parameters: + * lpft FrameTools object + * nState new display state + * + * Return Value: + * nil + */ +void FrameTools_BB_SetState(LPFRAMETOOLS lpft, int nState) +{ + if (!lpft) { + return; + } + + lpft->m_ButtonBar.m_nState = nState; + + if (nState == BARSTATE_POPUP) + SetParent(lpft->m_ButtonBar.m_hWnd, lpft->m_hWndPopupPalette); + else + SetParent(lpft->m_ButtonBar.m_hWnd, lpft->m_hWndApp); +} + + +/* + * FrameTools_BB_GetState + * + * Purpose: + * Get display state of ButtonBar + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nState current display state + */ +int FrameTools_BB_GetState(LPFRAMETOOLS lpft) +{ + return lpft->m_ButtonBar.m_nState; +} + + +/* + * FrameTools_FB_SetState + * + * Purpose: + * Set display state of FormulaBar + * + * Parameters: + * lpft FrameTools object + * nState new display state + * + * Return Value: +4 * nil + */ +void FrameTools_FB_SetState(LPFRAMETOOLS lpft, int nState) +{ + if (!lpft) { + return; + } + + lpft->m_FormulaBar.m_nState = nState; + + if (nState == BARSTATE_POPUP) + SetParent(lpft->m_FormulaBar.m_hWnd, lpft->m_hWndPopupPalette); + +#if defined( INPLACE_SVR ) + /* OLE2NOTE: it is dangerous for an in-place server to hide its + ** toolbar window and leave it parented to the hWndFrame of the + ** in-place container. if the in-place container call + ** ShowOwnedPopups, then it could inadvertantly be made visible. + ** to avoid this we will parent the toolbar window back to our + ** own application main window. if we are not in-place active + ** then this is the same as lpft->m_hWndApp. + */ + else if (nState == BARSTATE_HIDE) + SetParent(lpft->m_FormulaBar.m_hWnd, g_lpApp->m_hWndApp); +#endif + + else + SetParent(lpft->m_FormulaBar.m_hWnd, lpft->m_hWndApp); +} + + +/* + * FrameTools_FB_GetState + * + * Purpose: + * Get display state of FormulaBar + * + * Parameters: + * lpft FrameTools object + * + * Return Value: + * nState current display state + */ +int FrameTools_FB_GetState(LPFRAMETOOLS lpft) +{ + return lpft->m_FormulaBar.m_nState; +} + + +/* + * FrameToolsWndProc + * + * Purpose: + * WndProc for toolbar window + * + * Parameters: + * hWnd + * Message + * wParam + * lParam + * + * Return Value: + * message dependent + */ +LRESULT FAR PASCAL FrameToolsWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) +{ + LPFRAMETOOLS lpft = (LPFRAMETOOLS)GetWindowLong(hWnd, 0); + + switch (Message) { + + case WM_MOUSEACTIVATE: + return MA_NOACTIVATE; + + default: + return DefWindowProc(hWnd, Message, wParam, lParam); + } + + return 0L; +} + + +/* + * Bar_Move + * + * Purpose: + * Resize and reposition a bar + * + * Parameters: + * lpbar Bar object + * lprcClient pointer to Client rect + * lprcPopup pointer to Popup rect + * + * Return Value: + * nil + */ +static void Bar_Move(LPBAR lpbar, LPRECT lprcClient, LPRECT lprcPopup) +{ + if (lpbar->m_nState == BARSTATE_HIDE) { + ShowWindow(lpbar->m_hWnd, SW_HIDE); + } + else { + ShowWindow(lpbar->m_hWnd, SW_SHOW); + switch (lpbar->m_nState) { + case BARSTATE_POPUP: + MoveWindow(lpbar->m_hWnd, lprcPopup->left, lprcPopup->top, + lprcPopup->right - lprcPopup->left, lpbar->m_uHeight, + TRUE); + lprcPopup->top += lpbar->m_uHeight; + break; + + case BARSTATE_TOP: + MoveWindow(lpbar->m_hWnd, lprcClient->left, lprcClient->top, + lprcClient->right - lprcClient->left, + lpbar->m_uHeight, TRUE); + lprcClient->top += lpbar->m_uHeight; + break; + + case BARSTATE_BOTTOM: + MoveWindow(lpbar->m_hWnd, lprcClient->left, + lprcClient->bottom - lpbar->m_uHeight, + lprcClient->right - lprcClient->left, + lpbar->m_uHeight, TRUE); + lprcClient->bottom -= lpbar->m_uHeight; + break; + } + } +} + + +/* + * FB_ResizeEdit + * + * Purpose: + * Resize the edit control in FormulaBar + * + * Parameters: + * lpft Bar object + * + * Return Value: + * nil + */ +static void FB_ResizeEdit(LPBAR lpbar) +{ + RECT rcClient; + RECT rcEdit; + HWND hwndEdit; + + GetClientRect(lpbar->m_hWnd, (LPRECT)&rcClient); + hwndEdit = GetDlgItem(lpbar->m_hWnd, IDM_FB_EDIT); + GetWindowRect(hwndEdit, (LPRECT)&rcEdit); + ScreenToClient(lpbar->m_hWnd, (LPPOINT)&rcEdit.left); + ScreenToClient(lpbar->m_hWnd, (LPPOINT)&rcEdit.right); + + SetWindowPos(hwndEdit, NULL, 0, 0, rcClient.right - rcEdit.left - SPACE, + rcEdit.bottom - rcEdit.top, SWP_NOMOVE | SWP_NOZORDER); +} diff --git a/private/oleutest/letest/outline/frametls.h b/private/oleutest/letest/outline/frametls.h new file mode 100644 index 000000000..c235c5567 --- /dev/null +++ b/private/oleutest/letest/outline/frametls.h @@ -0,0 +1,102 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** frametls.h +** +** This file contains file contains data structure defintions, +** function prototypes, constants, etc. used by the frame level +** tools used by the Outline series of sample applications. The +** frame level tools include a formula bar and a button bar (toolbar) +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if !defined( _FRAMETLS_H_ ) +#define _FRAMETLS_H_ + +#ifndef RC_INVOKED +#pragma message ("INCLUDING FRAMETLS.H from " __FILE__) +#endif /* RC_INVOKED */ + +#include "bttncur.h" +#include "gizmobar.h" + +#define SPACE 5 +#define POPUPSTUB_HEIGHT 5 + + +/* forward type references */ +typedef struct tagOUTLINEDOC FAR* LPOUTLINEDOC; + +#define IDC_GIZMOBAR 1000 +#define IDC_FORMULABAR 1001 + +#define IDB_CANCEL 0 +#define IDB_EDITLINE 1 +#define IDB_ADDLINE 2 +#define IDB_UNINDENTLINE 3 +#define IDB_INDENTLINE 4 + +#define BARSTATE_TOP 1 +#define BARSTATE_BOTTOM 2 +#define BARSTATE_POPUP 3 +#define BARSTATE_HIDE 4 + +#define CLASS_PALETTE "Tool Palette" + +typedef struct tagBAR{ + UINT m_uHeight; + HWND m_hWnd; + int m_nState; +} BAR, FAR* LPBAR; + +typedef struct tagFRAMETOOLS { + HWND m_hWndPopupPalette; // Popup Tool Palette window + HWND m_hWndApp; // App Frame window + UINT m_uPopupWidth; // Width of the popup palette + HBITMAP m_hBmp; // Image bitmaps + BOOL m_fInFormulaBar; // does formula bar have edit focus + BOOL m_fToolsDisabled; // when TRUE all tools are hidden + + BAR m_ButtonBar; // Button Bar + BAR m_FormulaBar; // Formula Bar + + TOOLDISPLAYDATA m_tdd; // from UIToolConfigureForDisplay +} FRAMETOOLS, FAR* LPFRAMETOOLS; + + +BOOL FrameToolsRegisterClass(HINSTANCE hInst); +BOOL FrameTools_Init(LPFRAMETOOLS lpft, HWND hWndParent, HINSTANCE hInst); +void FrameTools_AttachToFrame(LPFRAMETOOLS lpft, HWND hWndFrame); +void FrameTools_AssociateDoc(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc); +void FrameTools_Destroy(LPFRAMETOOLS lpft); +void FrameTools_Move(LPFRAMETOOLS lpft, LPRECT lprcClient); +void FrameTools_PopupTools(LPFRAMETOOLS lpft); +void FrameTools_Enable(LPFRAMETOOLS lpft, BOOL fEnable); +void FrameTools_EnableWindow(LPFRAMETOOLS lpft, BOOL fEnable); + +#if defined( INPLACE_CNTR ) || defined( INPLACE_SVR ) +void FrameTools_NegotiateForSpaceAndShow( + LPFRAMETOOLS lpft, + LPRECT lprcFrameRect, + LPOLEINPLACEFRAME lpTopIPFrame +); +#endif // INPLACE_CNTR || INPLACE_SVR + +void FrameTools_GetRequiredBorderSpace(LPFRAMETOOLS lpft, LPBORDERWIDTHS lpBorderWidths); + +void FrameTools_UpdateButtons(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc); +void FrameTools_FB_SetEditText(LPFRAMETOOLS lpft, LPSTR lpsz); +void FrameTools_FB_GetEditText(LPFRAMETOOLS lpft, LPSTR lpsz, UINT cch); +void FrameTools_FB_FocusEdit(LPFRAMETOOLS lpft); +void FrameTools_FB_SendMessage(LPFRAMETOOLS lpft, UINT uID, UINT msg, WPARAM wParam, LPARAM lParam); +void FrameTools_ForceRedraw(LPFRAMETOOLS lpft); +void FrameTools_BB_SetState(LPFRAMETOOLS lpft, int nState); +void FrameTools_FB_SetState(LPFRAMETOOLS lpft, int nState); +int FrameTools_BB_GetState(LPFRAMETOOLS lpft); +int FrameTools_FB_GetState(LPFRAMETOOLS lpft); +LRESULT FAR PASCAL FrameToolsWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); + +#endif // _FRAMETLS_H_ diff --git a/private/oleutest/letest/outline/heading.c b/private/oleutest/letest/outline/heading.c new file mode 100644 index 000000000..d8cefde58 --- /dev/null +++ b/private/oleutest/letest/outline/heading.c @@ -0,0 +1,451 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** heading.c +** +** This file contains functions and support for OutlineDoc's row and +** column headings. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +extern LPOUTLINEAPP g_lpApp; + + +BOOL Heading_Create(LPHEADING lphead, HWND hWndParent, HINSTANCE hInst) +{ + HDC hDC; + TEXTMETRIC tm; + + if (!lphead || !hWndParent || !hInst) + return FALSE; + + hDC = GetDC(hWndParent); + if (!hDC) + return FALSE; + + if (!GetTextMetrics(hDC, (TEXTMETRIC FAR*)&tm)) + return FALSE; + lphead->m_colhead.m_uHeight = tm.tmHeight; + lphead->m_rowhead.m_uWidth = 4 * tm.tmAveCharWidth; + lphead->m_fShow = TRUE; + + ReleaseDC(hWndParent, hDC); + + lphead->m_hfont = CreateFont( + tm.tmHeight, + 0,0,0,0,0,0,0,0, + OUT_TT_PRECIS, // use TrueType + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH | FF_DONTCARE, + HEADING_FONT + ); + + if (!lphead->m_hfont) + return FALSE; + + lphead->m_colhead.m_hWnd = CreateWindow( + "listbox", + "Column Heading", + WS_VISIBLE | WS_CHILD | WS_DISABLED | LBS_OWNERDRAWVARIABLE | + LBS_NOINTEGRALHEIGHT, + 0,0,0,0, // any values + hWndParent, + (HMENU)IDC_COLHEADING, + hInst, + NULL); + + if (!lphead->m_colhead.m_hWnd) + return FALSE; + + // add a dummy line to get WM_DRAWITEM message + SendMessage(lphead->m_colhead.m_hWnd, LB_ADDSTRING, 0, + MAKELPARAM(lphead->m_colhead.m_uHeight,0)); + + lphead->m_rowhead.m_hWnd = CreateWindow( + "listbox", + "Row Heading", + WS_VISIBLE | WS_CHILD | WS_DISABLED | LBS_OWNERDRAWVARIABLE, + 0,0,0,0, // any values + hWndParent, + (HMENU)IDC_ROWHEADING, + hInst, + NULL); + + if (!lphead->m_rowhead.m_hWnd) + return FALSE; + + SendMessage(lphead->m_rowhead.m_hWnd, LB_ADDSTRING, 0, + MAKELPARAM(lphead->m_colhead.m_uHeight,0)); + + lphead->m_rowhead.m_WndProc = + (FARPROC) GetWindowLong(lphead->m_rowhead.m_hWnd, GWL_WNDPROC ); + SetWindowLong(lphead->m_rowhead.m_hWnd, GWL_WNDPROC, + (LONG) RowHeadWndProc); + + lphead->m_hwndButton = CreateWindow( + "button", + NULL, + WS_VISIBLE | WS_CHILD, + 0,0,0,0, // any values + hWndParent, + (HMENU)IDC_BUTTON, + hInst, + NULL); + + if (!lphead->m_hwndButton) + return FALSE; + + return TRUE; +} + + +void Heading_Destroy(LPHEADING lphead) +{ + if (!lphead) + return; + + if (IsWindow(lphead->m_colhead.m_hWnd)) { + DestroyWindow(lphead->m_colhead.m_hWnd); + lphead->m_colhead.m_hWnd = NULL; + } + if (IsWindow(lphead->m_rowhead.m_hWnd)) { + DestroyWindow(lphead->m_rowhead.m_hWnd); + lphead->m_rowhead.m_hWnd = NULL; + } + if (IsWindow(lphead->m_hwndButton)) { + DestroyWindow(lphead->m_hwndButton); + lphead->m_hwndButton = NULL; + } +#ifdef WIN32 + if (GetObjectType(lphead->m_hfont)) { +#else + if (IsGDIObject(lphead->m_hfont)) { +#endif + DeleteObject(lphead->m_hfont); + lphead->m_hfont = NULL; + } + +} + + +void Heading_Move(LPHEADING lphead, HWND hwndDoc, LPSCALEFACTOR lpscale) +{ + int nOffsetX; + int nOffsetY; + RECT rcDoc; + + if (!lphead || !hwndDoc || !lpscale) + return; + + if (!lphead->m_fShow) + return; + + nOffsetX = (int) Heading_RH_GetWidth(lphead, lpscale); + nOffsetY = (int) Heading_CH_GetHeight(lphead, lpscale); + GetClientRect(hwndDoc, (LPRECT)&rcDoc); + + MoveWindow(lphead->m_hwndButton, 0, 0, nOffsetX, nOffsetY, TRUE); + + MoveWindow( + lphead->m_colhead.m_hWnd, + nOffsetX, 0, + rcDoc.right-rcDoc.left-nOffsetX, nOffsetY, + TRUE + ); + + MoveWindow(lphead->m_rowhead.m_hWnd, 0, nOffsetY, nOffsetX, + rcDoc.bottom-rcDoc.top-nOffsetY, TRUE); +} + + +void Heading_Show(LPHEADING lphead, BOOL fShow) +{ + int nCmdShow; + + if (!lphead) + return; + + lphead->m_fShow = fShow; + nCmdShow = fShow ? SW_SHOW : SW_HIDE; + + ShowWindow(lphead->m_hwndButton, nCmdShow); + ShowWindow(lphead->m_colhead.m_hWnd, nCmdShow); + ShowWindow(lphead->m_rowhead.m_hWnd, nCmdShow); +} + + +void Heading_ReScale(LPHEADING lphead, LPSCALEFACTOR lpscale) +{ + UINT uHeight; + + if (!lphead || !lpscale) + return; + + // Row heading is scaled with the LineList_Rescale. So, only + // Column heading needed to be scaled here. + uHeight = (UINT)(lphead->m_colhead.m_uHeight * lpscale->dwSyN / + lpscale->dwSyD); + SendMessage(lphead->m_colhead.m_hWnd, LB_SETITEMHEIGHT, 0, + MAKELPARAM(uHeight, 0)); +} + + +void Heading_CH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis, LPRECT lprcScreen, LPRECT lprcObject) +{ + HPEN hpenOld; + HPEN hpen; + HBRUSH hbr; + HFONT hfOld; + int nTabInPix; + char letter; + int i; + int nOldMapMode; + RECT rcWindowOld; + RECT rcViewportOld; + POINT point; + + if (!lpdis || !lphead) + return; + + hbr = GetStockObject(LTGRAY_BRUSH); + FillRect(lpdis->hDC, (LPRECT)&lpdis->rcItem, hbr); + + nOldMapMode = SetDCToAnisotropic(lpdis->hDC, lprcScreen, lprcObject, + (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld); + + hfOld = SelectObject(lpdis->hDC, lphead->m_hfont); + hpen = GetStockObject(BLACK_PEN); + hpenOld = SelectObject(lpdis->hDC, hpen); + + nTabInPix = XformWidthInHimetricToPixels(lpdis->hDC, TABWIDTH); + SetBkMode(lpdis->hDC, TRANSPARENT); + + letter = COLUMN_LETTER; + MoveToEx(lpdis->hDC, lprcObject->left, lprcObject->bottom,&point); + LineTo(lpdis->hDC, lprcObject->left, lprcObject->top); + + for (i = 0; i < COLUMN; i++) { + lprcObject->right = lprcObject->left + nTabInPix; + DrawText(lpdis->hDC, (LPCSTR)&letter, 1, lprcObject, + DT_SINGLELINE | DT_CENTER | DT_VCENTER); + MoveToEx(lpdis->hDC, lprcObject->right, lprcObject->bottom, &point); + LineTo(lpdis->hDC, lprcObject->right, lprcObject->top); + + letter++; + lprcObject->left += nTabInPix; + } + + SelectObject(lpdis->hDC, hpenOld); + SelectObject(lpdis->hDC, hfOld); + + ResetOrigDC(lpdis->hDC, nOldMapMode, (LPRECT)&rcWindowOld, + (LPRECT)&rcViewportOld); +} + + +void Heading_CH_SetHorizontalExtent(LPHEADING lphead, HWND hwndListBox) +{ + RECT rcLL; + RECT rcCH; + int nLLWidth; + int nCHWidth; + int nHorizExtent; + + if (!lphead || !hwndListBox) + return; + + nHorizExtent=(int)SendMessage(hwndListBox, LB_GETHORIZONTALEXTENT, 0, 0L); + GetClientRect(hwndListBox, (LPRECT)&rcLL); + GetClientRect(lphead->m_colhead.m_hWnd, (LPRECT)&rcCH); + + nLLWidth = rcLL.right - rcLL.left; + nCHWidth = rcCH.right - rcCH.left; + nHorizExtent += nCHWidth - nLLWidth; + + SendMessage(lphead->m_colhead.m_hWnd, LB_SETHORIZONTALEXTENT, + nHorizExtent, 0L); +} + + +UINT Heading_CH_GetHeight(LPHEADING lphead, LPSCALEFACTOR lpscale) +{ + if (!lphead || !lpscale) + return 0; + + if (lphead->m_fShow) + return (UINT)(lphead->m_colhead.m_uHeight * lpscale->dwSyN / + lpscale->dwSyD); + else + return 0; +} + + +LRESULT Heading_CH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (!lphead) + return 0; + + if (lphead->m_colhead.m_hWnd) + return SendMessage(lphead->m_colhead.m_hWnd, msg, wParam, lParam); +} + + +void Heading_CH_ForceRedraw(LPHEADING lphead, BOOL fErase) +{ + if (!lphead) + return; + + InvalidateRect(lphead->m_colhead.m_hWnd, NULL, fErase); +} + +void Heading_RH_ForceRedraw(LPHEADING lphead, BOOL fErase) +{ + if (!lphead) + return; + + InvalidateRect(lphead->m_rowhead.m_hWnd, NULL, fErase); +} + +void Heading_RH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis) +{ + char cBuf[5]; + HPEN hpenOld; + HPEN hpen; + HBRUSH hbrOld; + HBRUSH hbr; + HFONT hfOld; + RECT rc; + RECT rcWindowOld; + RECT rcViewportOld; + int nMapModeOld; + + if (!lpdis || !lphead) + return; + + lpdis->rcItem; + + rc.left = 0; + rc.bottom = 0; + rc.top = (int)lpdis->itemData; + rc.right = lphead->m_rowhead.m_uWidth; + + nMapModeOld = SetDCToAnisotropic(lpdis->hDC, &lpdis->rcItem, &rc, + (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld); + + hpen = GetStockObject(BLACK_PEN); + hpenOld = SelectObject(lpdis->hDC, hpen); + hbr = GetStockObject(LTGRAY_BRUSH); + hbrOld = SelectObject(lpdis->hDC, hbr); + + Rectangle(lpdis->hDC, rc.left, rc.top, rc.right, + rc.bottom); + + hfOld = SelectObject(lpdis->hDC, lphead->m_hfont); + + SetBkMode(lpdis->hDC, TRANSPARENT); + + wsprintf(cBuf, "%d", lpdis->itemID + 1); + + DrawText(lpdis->hDC, (LPSTR)cBuf, lstrlen(cBuf), (LPRECT)&rc, + DT_SINGLELINE | DT_CENTER | DT_VCENTER); + + SelectObject(lpdis->hDC, hfOld); + + SelectObject(lpdis->hDC, hpenOld); + SelectObject(lpdis->hDC, hbrOld); + + ResetOrigDC(lpdis->hDC, nMapModeOld, (LPRECT)&rcWindowOld, + (LPRECT)&rcViewportOld); +} + +LRESULT Heading_RH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (!lphead) + return 0; + + if (lphead->m_rowhead.m_hWnd) + return SendMessage(lphead->m_rowhead.m_hWnd, msg, wParam, lParam); +} + + +UINT Heading_RH_GetWidth(LPHEADING lphead, LPSCALEFACTOR lpscale) +{ + if (!lphead || !lpscale) + return 0; + + if (lphead->m_fShow) + return (UINT)(lphead->m_rowhead.m_uWidth * lpscale->dwSxN / + lpscale->dwSxD); + else + return 0; +} + + +void Heading_RH_Scroll(LPHEADING lphead, HWND hwndListBox) +{ + int nTopLL; + int nTopRH; + + if (!lphead || !hwndListBox) + return; + + nTopLL = (int)SendMessage(hwndListBox, LB_GETTOPINDEX, 0, 0L); + nTopRH = (int)SendMessage( + lphead->m_rowhead.m_hWnd, LB_GETTOPINDEX, 0, 0L); + + if (nTopLL != nTopRH) + SendMessage( + lphead->m_rowhead.m_hWnd,LB_SETTOPINDEX,(WPARAM)nTopLL,0L); +} + + +LRESULT FAR PASCAL RowHeadWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) +{ + HWND hwndParent = GetParent (hWnd); + LPOUTLINEDOC lpDoc = (LPOUTLINEDOC)GetWindowLong(hwndParent, 0); + LPHEADING lphead = OutlineDoc_GetHeading(lpDoc); + + switch (Message) { + case WM_PAINT: + { + LPLINELIST lpLL = OutlineDoc_GetLineList(lpDoc); + PAINTSTRUCT ps; + + // If there is no line in listbox, trap the message and draw the + // background gray. Without this, the background will be painted + // as default color. + if (!LineList_GetCount(lpLL)) { + BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + return 0; + } + + break; + } + + case WM_ERASEBKGND: + { + HDC hDC = (HDC)wParam; + RECT rc; + + GetClientRect(hWnd, (LPRECT)&rc); + FillRect(hDC, (LPRECT)&rc, GetStockObject(GRAY_BRUSH)); + + return 1; + } + } + + return CallWindowProc( + (WNDPROC)lphead->m_rowhead.m_WndProc, + hWnd, + Message, + wParam, + lParam + ); +} diff --git a/private/oleutest/letest/outline/heading.h b/private/oleutest/letest/outline/heading.h new file mode 100644 index 000000000..b88f5ccff --- /dev/null +++ b/private/oleutest/letest/outline/heading.h @@ -0,0 +1,59 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** heading.c +** +** This file contains definitions used by OutlineDoc's row and +** column headings. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#define COLUMN 10 + +#define IDC_ROWHEADING 2000 +#define IDC_COLHEADING 2001 +#define IDC_BUTTON 2002 + +#define HEADING_FONT "Arial" + +#define COLUMN_LETTER 'A' + + +typedef struct tagCOLHEADING { + HWND m_hWnd; + UINT m_uHeight; +} COLHEADING, FAR* LPCOLHEADING; + +typedef struct tagROWHEADING { + HWND m_hWnd; + UINT m_uWidth; + FARPROC m_WndProc; +} ROWHEADING, FAR* LPROWHEADING; + +typedef struct tagHEADING { + COLHEADING m_colhead; + ROWHEADING m_rowhead; + HWND m_hwndButton; + BOOL m_fShow; + HFONT m_hfont; +} HEADING, FAR* LPHEADING; + +BOOL Heading_Create(LPHEADING lphead, HWND hWndParent, HINSTANCE hInst); +void Heading_Destroy(LPHEADING lphead); +void Heading_Move(LPHEADING lphead, HWND hwndListBox, LPSCALEFACTOR lpscale); +void Heading_Show(LPHEADING lphead, BOOL fShow); +void Heading_ReScale(LPHEADING lphead, LPSCALEFACTOR lpscale); +void Heading_CH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis, LPRECT lprcScreen, LPRECT lprcObject); +void Heading_CH_SetHorizontalExtent(LPHEADING lphead, HWND hwndListBox); +UINT Heading_CH_GetHeight(LPHEADING lphead, LPSCALEFACTOR lpscale); +LRESULT Heading_CH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam); +void Heading_CH_ForceRedraw(LPHEADING lphead, BOOL fErase); +void Heading_RH_ForceRedraw(LPHEADING lphead, BOOL fErase); +void Heading_RH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis); +LRESULT Heading_RH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam); +UINT Heading_RH_GetWidth(LPHEADING lphead, LPSCALEFACTOR lpscale); +void Heading_RH_Scroll(LPHEADING lphead, HWND hwndListBox); +LRESULT FAR PASCAL RowHeadWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); diff --git a/private/oleutest/letest/outline/icntrotl.ico b/private/oleutest/letest/outline/icntrotl.ico Binary files differnew file mode 100644 index 000000000..7bd2931c5 --- /dev/null +++ b/private/oleutest/letest/outline/icntrotl.ico diff --git a/private/oleutest/letest/outline/icntrotl/daytona/makefile b/private/oleutest/letest/outline/icntrotl/daytona/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/oleutest/letest/outline/icntrotl/daytona/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/oleutest/letest/outline/icntrotl/daytona/makefile.inc b/private/oleutest/letest/outline/icntrotl/daytona/makefile.inc new file mode 100644 index 000000000..462f38133 --- /dev/null +++ b/private/oleutest/letest/outline/icntrotl/daytona/makefile.inc @@ -0,0 +1,2 @@ +copyfiles: + xcopy ..\..\*.c . /D diff --git a/private/oleutest/letest/outline/icntrotl/daytona/sources b/private/oleutest/letest/outline/icntrotl/daytona/sources new file mode 100644 index 000000000..c80247671 --- /dev/null +++ b/private/oleutest/letest/outline/icntrotl/daytona/sources @@ -0,0 +1,108 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Kenneth MacLeod (Kennethm) 9-Mar-1994 + +!ENDIF + +MAJORCOMP = oleutest +MINORCOMP = letest + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= icntrotl + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= PROGRAM + +INCLUDES= ..\..\..\ole2ui; \ + ..\..\..\bttncur; \ + ..\..\..\gizmobar; \ + ..\..\..\..\inc; \ + ..\.. + +C_DEFINES= \ + $(C_DEFINES) \ + -DFLAT \ + -DWIN32=100 \ + -D_NT1X_=100 \ + -DNOEXCEPTIONS \ + -DOLE_CNTR \ + -DINPLACE_CNTR + +SOURCES= \ + ..\icntrotl.rc \ + classfac.c \ + clipbrd.c \ + cntrbase.c \ + cntrinpl.c \ + cntrline.c \ + debug.c \ + debug2.c \ + dialogs.c \ + dragdrop.c \ + frametls.c \ + heading.c \ + linking.c \ + main.c \ + memmgr.c \ + oleapp.c \ + oledoc.c \ + outlapp.c \ + outldoc.c \ + outlline.c \ + outllist.c \ + outlname.c \ + outlntbl.c \ + outltxtl.c \ + status.c \ + tests.c + +UMTYPE= windows +UMENTRY= winmain + +USE_CRTDLL=1 +TARGETLIBS= \ + ..\..\..\ole2ui\daytona\obj\*\ole2u32a.lib \ + ..\..\..\gizmobar\daytona\obj\*\gizmobar.lib \ + ..\..\..\bttncur\daytona\obj\*\bttncur.lib \ + $(BASEDIR)\public\sdk\lib\*\ole32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\gdi32.lib \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\uuid.lib + +NTTARGETFILE0=copyfiles diff --git a/private/oleutest/letest/outline/icntrotl/dirs b/private/oleutest/letest/outline/icntrotl/dirs new file mode 100644 index 000000000..515c134a8 --- /dev/null +++ b/private/oleutest/letest/outline/icntrotl/dirs @@ -0,0 +1,37 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + \ + daytona diff --git a/private/oleutest/letest/outline/icntrotl/icntrotl.rc b/private/oleutest/letest/outline/icntrotl/icntrotl.rc new file mode 100644 index 000000000..160d51dfa --- /dev/null +++ b/private/oleutest/letest/outline/icntrotl/icntrotl.rc @@ -0,0 +1,210 @@ +/************************************************************************* +** +** OLE 2.0 Container Sample Code +** +** icntrotl.rc +** +** Resource file for icntrotl.exe +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "windows.h" +#include "outlrc.h" +#include "cntrrc.h" + +SelCur CURSOR selcross.cur +DragMoveCur CURSOR dragmove.cur + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) +DragNoneCur CURSOR dragnone.cur +DragCopyCur CURSOR dragcopy.cur +DragLinkCur CURSOR draglink.cur +#endif // IF_SPECIAL_DD_CURSORS_NEEDED + +CntrOutlMenu MENU + BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", IDM_F_NEW + MENUITEM "&Open...\t Ctrl+F12", IDM_F_OPEN + MENUITEM "&Save\t Shift+F12", IDM_F_SAVE + MENUITEM "Save &As...\t F12", IDM_F_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print...\t Ctrl+Shift+F12", IDM_F_PRINT + MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP + MENUITEM SEPARATOR + MENUITEM "E&xit\t Alt+F4", IDM_F_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", IDM_E_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\t Ctrl+X", IDM_E_CUT + MENUITEM "&Copy\t Ctrl+C", IDM_E_COPY + MENUITEM "&Paste\t Ctrl+V", IDM_E_PASTE + MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL + MENUITEM "Paste &Link", IDM_E_PASTELINK + MENUITEM "Cl&ear\t Del", IDM_E_CLEAR + MENUITEM SEPARATOR + MENUITEM "&Insert Object...", IDM_E_INSERTOBJECT + MENUITEM "Li&nks...", IDM_E_EDITLINKS + MENUITEM "&Object", IDM_E_OBJECTVERBMIN + MENUITEM SEPARATOR + MENUITEM "Select &All\t Ctrl+A", IDM_E_SELECTALL + END + POPUP "O&utline" + BEGIN + POPUP "&Zoom" + BEGIN + MENUITEM "&100%\t Ctrl+1", IDM_V_ZOOM_100 + MENUITEM "&75%\t Ctrl+2", IDM_V_ZOOM_75 + MENUITEM "&50%\t Ctrl+3", IDM_V_ZOOM_50 + MENUITEM "&25%\t Ctrl+4", IDM_V_ZOOM_25 + END + POPUP "&Left and Right margins" + BEGIN + MENUITEM "&nil", IDM_V_SETMARGIN_0 + MENUITEM "&1 cm", IDM_V_SETMARGIN_1 + MENUITEM "&2 cm", IDM_V_SETMARGIN_2 + MENUITEM "&3 cm", IDM_V_SETMARGIN_3 + MENUITEM "&4 cm", IDM_V_SETMARGIN_4 + END + POPUP "Add &Top Line" + BEGIN + MENUITEM "&1 cm", IDM_V_ADDTOP_1 + MENUITEM "&2 cm", IDM_V_ADDTOP_2 + MENUITEM "&3 cm", IDM_V_ADDTOP_3 + MENUITEM "&4 cm", IDM_V_ADDTOP_4 + END + END + POPUP "&Line" + BEGIN + MENUITEM "&Add Line\t Enter", IDM_L_ADDLINE + MENUITEM "E&dit Line\t Alt+Enter", IDM_L_EDITLINE + MENUITEM SEPARATOR + MENUITEM "&Indent Line\t Tab", IDM_L_INDENTLINE + MENUITEM "U&nindent Line\t Shift+Tab", IDM_L_UNINDENTLINE + MENUITEM SEPARATOR + MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT + END + POPUP "&Name" + BEGIN + MENUITEM "&Define Name...", IDM_N_DEFINENAME + MENUITEM "&Goto Name...", IDM_N_GOTONAME + END + POPUP "&Options" + BEGIN + POPUP "&Button Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_BB_TOP + MENUITEM "At &Bottom", IDM_O_BB_BOTTOM + MENUITEM "&Popup", IDM_O_BB_POPUP + MENUITEM "&Hide", IDM_O_BB_HIDE + END + POPUP "&Formula Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_FB_TOP + MENUITEM "At &Bottom", IDM_O_FB_BOTTOM + MENUITEM "&Popup", IDM_O_FB_POPUP + END + POPUP "&Row and Column Heading" + BEGIN + MENUITEM "&Show", IDM_O_HEAD_SHOW + MENUITEM "&Hide", IDM_O_HEAD_HIDE + END + MENUITEM "&Show Object", IDM_O_SHOWOBJECT + END + POPUP "DbgI&Cntr" + BEGIN + MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL + MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER + MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING + MENUITEM "&Inside-out Activation", IDM_D_INSIDEOUT + END + POPUP "&Help" + BEGIN + MENUITEM "&About...", IDM_H_ABOUT + END + END + +CntrOutlAccel ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CLEAR, VIRTKEY + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + + VK_F2, IDM_F2, VIRTKEY + VK_ESCAPE, IDM_ESCAPE, VIRTKEY + + "1", IDM_V_ZOOM_100, VIRTKEY, CONTROL + "2", IDM_V_ZOOM_75, VIRTKEY, CONTROL + "3", IDM_V_ZOOM_50, VIRTKEY, CONTROL + "4", IDM_V_ZOOM_25, VIRTKEY, CONTROL + END + +; Same as CntrOutlAccel but without Delete and Backspace +; used when edit control of Formula Bar in focus +; +CntrOutlAccelFocusEdit ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + VK_ESCAPE, IDM_ESCAPE, VIRTKEY + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + END + +InPlaceCntrOutlAccel ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + VK_ESCAPE, IDM_ESCAPE, VIRTKEY + "1", IDM_V_ZOOM_100, VIRTKEY, CONTROL + "2", IDM_V_ZOOM_75, VIRTKEY, CONTROL + "3", IDM_V_ZOOM_50, VIRTKEY, CONTROL + "4", IDM_V_ZOOM_25, VIRTKEY, CONTROL + END + +CntrOutlIcon ICON icntrotl.ico + +Image72 BITMAP image72.bmp +Image96 BITMAP image96.bmp +Image120 BITMAP image120.bmp +LogoBitmap BITMAP ole2.bmp + +#include "DIALOGS.DLG" diff --git a/private/oleutest/letest/outline/image120.bmp b/private/oleutest/letest/outline/image120.bmp Binary files differnew file mode 100644 index 000000000..663f5234c --- /dev/null +++ b/private/oleutest/letest/outline/image120.bmp diff --git a/private/oleutest/letest/outline/image72.bmp b/private/oleutest/letest/outline/image72.bmp Binary files differnew file mode 100644 index 000000000..dd096bb2c --- /dev/null +++ b/private/oleutest/letest/outline/image72.bmp diff --git a/private/oleutest/letest/outline/image96.bmp b/private/oleutest/letest/outline/image96.bmp Binary files differnew file mode 100644 index 000000000..34af2948e --- /dev/null +++ b/private/oleutest/letest/outline/image96.bmp diff --git a/private/oleutest/letest/outline/install.bat b/private/oleutest/letest/outline/install.bat new file mode 100644 index 000000000..c06d27747 --- /dev/null +++ b/private/oleutest/letest/outline/install.bat @@ -0,0 +1,7 @@ +if "%OLEROOT%" == "" set OLEROOT=c:\ntole2 +copy cntroutl\cntroutl.exe %OLEROOT%\release\bin +copy svroutl\svroutl.exe %OLEROOT%\release\bin +copy icntrotl\icntrotl.exe %OLEROOT%\release\bin +copy isvrotl\isvrotl.exe %OLEROOT%\release\bin +@REM copy outline\outline.exe %OLEROOT%\release\bin +copy outline.reg %OLEROOT%\release\bin diff --git a/private/oleutest/letest/outline/isvrotl.ico b/private/oleutest/letest/outline/isvrotl.ico Binary files differnew file mode 100644 index 000000000..406bab9d8 --- /dev/null +++ b/private/oleutest/letest/outline/isvrotl.ico diff --git a/private/oleutest/letest/outline/isvrotl/daytona/makefile b/private/oleutest/letest/outline/isvrotl/daytona/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/oleutest/letest/outline/isvrotl/daytona/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/oleutest/letest/outline/isvrotl/daytona/makefile.inc b/private/oleutest/letest/outline/isvrotl/daytona/makefile.inc new file mode 100644 index 000000000..462f38133 --- /dev/null +++ b/private/oleutest/letest/outline/isvrotl/daytona/makefile.inc @@ -0,0 +1,2 @@ +copyfiles: + xcopy ..\..\*.c . /D diff --git a/private/oleutest/letest/outline/isvrotl/daytona/sources b/private/oleutest/letest/outline/isvrotl/daytona/sources new file mode 100644 index 000000000..d07604c50 --- /dev/null +++ b/private/oleutest/letest/outline/isvrotl/daytona/sources @@ -0,0 +1,108 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Kenneth MacLeod (Kennethm) 9-Mar-1994 + +!ENDIF + +MAJORCOMP = oleutest +MINORCOMP = letest + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= isvrotl + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= PROGRAM + +INCLUDES= ..\..\..\ole2ui; \ + ..\..\..\bttncur; \ + ..\..\..\gizmobar; \ + ..\..\..\..\inc; \ + ..\.. + +C_DEFINES= \ + $(C_DEFINES) \ + -DFLAT \ + -DWIN32=100 \ + -D_NT1X_=100 \ + -DNOEXCEPTIONS \ + -DOLE_SERVER \ + -DINPLACE_SVR + +SOURCES= \ + ..\isvrotl.rc \ + classfac.c \ + clipbrd.c \ + debug.c \ + debug2.c \ + dialogs.c \ + dragdrop.c \ + frametls.c \ + heading.c \ + linking.c \ + main.c \ + memmgr.c \ + oleapp.c \ + oledoc.c \ + outlapp.c \ + outldoc.c \ + outlline.c \ + outllist.c \ + outlname.c \ + outlntbl.c \ + outltxtl.c \ + svrbase.c \ + svrinpl.c \ + svrpsobj.c \ + status.c \ + tests.c + +UMTYPE= windows +UMENTRY= winmain + +USE_CRTDLL=1 +TARGETLIBS= \ + ..\..\..\ole2ui\daytona\obj\*\ole2u32a.lib \ + ..\..\..\gizmobar\daytona\obj\*\gizmobar.lib \ + ..\..\..\bttncur\daytona\obj\*\bttncur.lib \ + $(BASEDIR)\public\sdk\lib\*\ole32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\gdi32.lib \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\uuid.lib + +NTTARGETFILE0=copyfiles diff --git a/private/oleutest/letest/outline/isvrotl/dirs b/private/oleutest/letest/outline/isvrotl/dirs new file mode 100644 index 000000000..515c134a8 --- /dev/null +++ b/private/oleutest/letest/outline/isvrotl/dirs @@ -0,0 +1,37 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + \ + daytona diff --git a/private/oleutest/letest/outline/isvrotl/isvrotl.rc b/private/oleutest/letest/outline/isvrotl/isvrotl.rc new file mode 100644 index 000000000..2334521ec --- /dev/null +++ b/private/oleutest/letest/outline/isvrotl/isvrotl.rc @@ -0,0 +1,211 @@ +/************************************************************************* +** +** OLE 2.0 Server Sample Code +** +** isvrotl.rc +** +** Resource file for isvrotl.exe +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "windows.h" +#include "outlrc.h" + +SelCur CURSOR selcross.cur +DragMoveCur CURSOR dragmove.cur + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) +DragNoneCur CURSOR dragnone.cur +DragCopyCur CURSOR dragcopy.cur +DragLinkCur CURSOR draglink.cur +#endif // IF_SPECIAL_DD_CURSORS_NEEDED + +SvrOutlMenu MENU + BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", IDM_F_NEW + MENUITEM "&Open...\t Ctrl+F12", IDM_F_OPEN + MENUITEM "&Save\t Shift+F12", IDM_F_SAVE + MENUITEM "Save &As...\t F12", IDM_F_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print...\t Ctrl+Shift+F12", IDM_F_PRINT + MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP + MENUITEM SEPARATOR + MENUITEM "E&xit\t Alt+F4", IDM_F_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", IDM_E_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\t Ctrl+X", IDM_E_CUT + MENUITEM "&Copy\t Ctrl+C", IDM_E_COPY + MENUITEM "&Paste\t Ctrl+V", IDM_E_PASTE + MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL + MENUITEM "Cl&ear\t Del", IDM_E_CLEAR + MENUITEM SEPARATOR + MENUITEM "Select A&ll\t Ctrl+A", IDM_E_SELECTALL + END + POPUP "O&utline" + BEGIN + POPUP "&Zoom" + BEGIN + MENUITEM "&400%", IDM_V_ZOOM_400 + MENUITEM "&300%", IDM_V_ZOOM_300 + MENUITEM "&200%", IDM_V_ZOOM_200 + MENUITEM "&100%", IDM_V_ZOOM_100 + MENUITEM "&75%", IDM_V_ZOOM_75 + MENUITEM "&50%", IDM_V_ZOOM_50 + MENUITEM "&25%", IDM_V_ZOOM_25 + END + POPUP "&Left and Right margins" + BEGIN + MENUITEM "&nil", IDM_V_SETMARGIN_0 + MENUITEM "&1 cm", IDM_V_SETMARGIN_1 + MENUITEM "&2 cm", IDM_V_SETMARGIN_2 + MENUITEM "&3 cm", IDM_V_SETMARGIN_3 + MENUITEM "&4 cm", IDM_V_SETMARGIN_4 + END + POPUP "Add &Top Line" + BEGIN + MENUITEM "&1 cm", IDM_V_ADDTOP_1 + MENUITEM "&2 cm", IDM_V_ADDTOP_2 + MENUITEM "&3 cm", IDM_V_ADDTOP_3 + MENUITEM "&4 cm", IDM_V_ADDTOP_4 + END + END + POPUP "&Line" + BEGIN + MENUITEM "&Add Line\t Enter", IDM_L_ADDLINE + MENUITEM "E&dit Line\t Alt+Enter", IDM_L_EDITLINE + MENUITEM SEPARATOR + MENUITEM "&Indent Line\t Tab", IDM_L_INDENTLINE + MENUITEM "U&nindent Line\t Shift+Tab", IDM_L_UNINDENTLINE + MENUITEM SEPARATOR + MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT + END + POPUP "&Name" + BEGIN + MENUITEM "&Define Name...", IDM_N_DEFINENAME + MENUITEM "&Goto Name...", IDM_N_GOTONAME + END + POPUP "&Options" + BEGIN + POPUP "&Button Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_BB_TOP + MENUITEM "At &Bottom", IDM_O_BB_BOTTOM + MENUITEM "&Popup", IDM_O_BB_POPUP + MENUITEM "&Hide", IDM_O_BB_HIDE + END + POPUP "&Formula Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_FB_TOP + MENUITEM "At &Bottom", IDM_O_FB_BOTTOM + MENUITEM "&Popup", IDM_O_FB_POPUP + END + POPUP "&Row and Column Heading" + BEGIN + MENUITEM "&Show", IDM_O_HEAD_SHOW + MENUITEM "&Hide", IDM_O_HEAD_HIDE + END + END + POPUP "DbgI&Svr" + BEGIN + MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL + MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER + MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING + END + POPUP "&Help" + BEGIN + MENUITEM "&About...", IDM_H_ABOUT + END + END + +SvrOutlAccel ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CLEAR, VIRTKEY + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + + VK_F2, IDM_F2, VIRTKEY + END + +; used when edit control of Formula Bar in focus +; +SvrOutlAccelFocusEdit ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + + VK_ESCAPE, IDM_ESCAPE, VIRTKEY + END + + +InPlaceSvrOutlAccel ACCELERATORS + BEGIN + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CLEAR, VIRTKEY + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + + VK_F2, IDM_F2, VIRTKEY + VK_ESCAPE, IDM_ESCAPE, VIRTKEY + END + +; used when edit control of Formula Bar in focus +; REVIEW: currently not properly used +InPlaceSvrOutlAccelFocusEdit ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + + VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY + END + +SvrOutlIcon ICON isvrotl.ico + +Image72 BITMAP image72.bmp +Image96 BITMAP image96.bmp +Image120 BITMAP image120.bmp +LogoBitmap BITMAP ole2.bmp + +#include "DIALOGS.DLG" diff --git a/private/oleutest/letest/outline/linking.c b/private/oleutest/letest/outline/linking.c new file mode 100644 index 000000000..cc0e91d72 --- /dev/null +++ b/private/oleutest/letest/outline/linking.c @@ -0,0 +1,2157 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** linking.c +** +** This file contains the major interfaces, methods and related support +** functions for implementing linking to items. The code +** contained in this file is used by BOTH the Container and Server +** (Object) versions of the Outline sample code. +** +** As a server SVROUTL supports linking to the whole document object +** (either a file-based document or as an embedded object). It also +** supports linking to ranges (or PseudoObjects). +** +** As a container CNTROUTL supports linking to embedded objects. +** (see file svrpsobj.c for Pseudo Object implementation) +** +** OleDoc Object +** exposed interfaces: +** IPersistFile +** IOleItemContainer +** IExternalConnection +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + + +STDMETHODIMP OleDoc_ItemCont_GetObjectA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR*lplpvObject +); + +STDMETHODIMP OleDoc_ItemCont_GetObjectStorageA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR*lplpvStorage +); + +#if defined(OLE_CNTR) + +STDMETHODIMP OleDoc_ItemCont_IsRunningA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem +); + +HRESULT ContainerDoc_IsRunningA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem); + +HRESULT ContainerDoc_GetObjectA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR*lplpvObject +); + +HRESULT ContainerDoc_GetObjectStorageA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + LPSTORAGE FAR*lplpStg); + +#endif // OLE_CNTR + +#if defined(OLE_SERVER) + +HRESULT ServerDoc_IsRunningA(LPSERVERDOC lpServerDoc, LPSTR lpszItem); + +HRESULT ServerDoc_GetObjectA( + LPSERVERDOC lpServerDoc, + LPSTR lpszItem, + REFIID riid, + LPVOID FAR*lplpvObject); + +#endif // OLE_SERVER + + + + + + +/************************************************************************* +** OleDoc::IPersistFile interface implementation +*************************************************************************/ + +// IPersistFile::QueryInterface +STDMETHODIMP OleDoc_PFile_QueryInterface( + LPPERSISTFILE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +// IPersistFile::AddRef +STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IPersistFile"); + + return OleDoc_AddRef(lpOleDoc); +} + + +// IPersistFile::Release +STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IPersistFile"); + + return OleDoc_Release(lpOleDoc); +} + + +// IPersistFile::GetClassID +STDMETHODIMP OleDoc_PFile_GetClassID ( + LPPERSISTFILE lpThis, + CLSID FAR* lpclsid +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + OleDbgOut2("OleDoc_PFile_GetClassID\r\n"); + +#if defined( OLE_SERVER ) && defined( SVR_TREATAS ) + + /* OLE2NOTE: we must be carefull to return the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the class of the object + ** written in the storage of the object. otherwise we would + ** return our own class id. + */ + return ServerDoc_GetClassID((LPSERVERDOC)lpOleDoc, lpclsid); +#else + *lpclsid = CLSID_APP; +#endif + return NOERROR; +} + + +// IPersistFile::IsDirty +STDMETHODIMP OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + OleDbgOut2("OleDoc_PFile_IsDirty\r\n"); + + if (OutlineDoc_IsModified((LPOUTLINEDOC)lpOleDoc)) + return NOERROR; + else + return ResultFromScode(S_FALSE); +} + + +// IPersistFile::Load +STDMETHODIMP OleDoc_PFile_LoadA( + LPPERSISTFILE lpThis, + LPCSTR lpszFileName, + DWORD grfMode +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_PFile_Load\r\n") + + /* OLE2NOTE: grfMode passed from the caller indicates if the caller + ** needs Read or ReadWrite permissions. if appropriate the + ** callee should open the file with the requested permissions. + ** the caller will normally not impose sharing permissions. + ** + ** the sample code currently always opens its file ReadWrite. + */ + + if (OutlineDoc_LoadFromFile((LPOUTLINEDOC)lpOleDoc, (LPSTR)lpszFileName)) + sc = S_OK; + else + sc = E_FAIL; + + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +// IPersistFile::Load +STDMETHODIMP OleDoc_PFile_Load ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName, + DWORD grfMode +) +{ + CREATESTR(lpsz, lpszFileName) + + HRESULT hr = OleDoc_PFile_LoadA(lpThis, lpsz, grfMode); + + FREESTR(lpsz) + + return hr; +} + + + +// IPersistFile::Save +STDMETHODIMP OleDoc_PFile_SaveA ( + LPPERSISTFILE lpThis, + LPCSTR lpszFileName, + BOOL fRemember +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_PFile_Save\r\n") + + /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation + ** on a file-based document. if the document is an embedded + ** object then we can not be changed to a file-base object. + ** + ** fRemember lpszFileName Type of Save + ** ---------------------------------------------- + ** TRUE NULL SAVE + ** TRUE ! NULL SAVE AS + ** FALSE ! NULL SAVE COPY AS + ** FALSE NULL ***error*** + */ + if ( (lpszFileName==NULL || (lpszFileName != NULL && fRemember)) + && ((lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE + && lpOutlineDoc->m_docInitType != DOCTYPE_NEW)) ) { + OLEDBG_END2 + return ResultFromScode(E_INVALIDARG); + } + + if (OutlineDoc_SaveToFile( + (LPOUTLINEDOC)lpOleDoc, + lpszFileName, + lpOutlineDoc->m_cfSaveFormat, + fRemember)) { + sc = S_OK; + } else + sc = E_FAIL; + + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +// IPersistFile::Save +STDMETHODIMP OleDoc_PFile_Save( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName, + BOOL fRemember +) +{ + CREATESTR(lpsz, lpszFileName) + + HRESULT hr = OleDoc_PFile_SaveA(lpThis, lpsz, fRemember); + + FREESTR(lpsz) + + return hr; +} + + + + +// IPersistFile::SaveCompleted +STDMETHODIMP OleDoc_PFile_SaveCompletedA ( + LPPERSISTFILE lpThis, + LPCSTR lpszFileName +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + OleDbgOut2("OleDoc_PFile_SaveCompleted\r\n"); + + /* This method is called after IPersistFile::Save is called. during + ** the period between Save and SaveCompleted the object must + ** consider itself in NOSCRIBBLE mode (ie. it is NOT allowed to + ** write to its file. here the object can clear its NOSCRIBBLE + ** mode flag. the outline app never scribbles to its storage, so + ** we have nothing to do. + */ + return NOERROR; +} + + + +STDMETHODIMP OleDoc_PFile_SaveCompleted ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName +) +{ + CREATESTR(lpsz, lpszFileName) + + HRESULT hr = OleDoc_PFile_SaveCompletedA(lpThis, lpsz); + + FREESTR(lpsz) + + return hr; +} + + + +// IPersistFile::GetCurFile +STDMETHODIMP OleDoc_PFile_GetCurFileA ( + LPPERSISTFILE lpThis, + LPSTR FAR* lplpszFileName +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPMALLOC lpMalloc; + LPSTR lpsz; + SCODE sc; + OleDbgOut2("OleDoc_PFile_GetCurFile\r\n"); + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpszFileName = NULL; + + /********************************************************************* + ** OLE2NOTE: memory returned for the lplpszFileName must be + ** allocated appropriately using the current registered IMalloc + ** interface. the allows the ownership of the memory to be + ** passed to the caller (even if in another process). + *********************************************************************/ + + CoGetMalloc(MEMCTX_TASK, &lpMalloc); + if (! lpMalloc) { + return ResultFromScode(E_FAIL); + } + + if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) { + /* valid filename associated; return file name */ + lpsz = (LPSTR)lpMalloc->lpVtbl->Alloc( + lpMalloc, + lstrlen((LPSTR)lpOutlineDoc->m_szFileName)+1 + ); + if (! lpsz) { + sc = E_OUTOFMEMORY; + goto error; + } + + lstrcpy(lpsz, (LPSTR)lpOutlineDoc->m_szFileName); + sc = S_OK; + } else { + /* no file associated; return default file name prompt */ + lpsz=(LPSTR)lpMalloc->lpVtbl->Alloc(lpMalloc, sizeof(DEFEXTENSION)+3); + wsprintf(lpsz, "*.%s", DEFEXTENSION); + sc = S_FALSE; + } + +error: + OleStdRelease((LPUNKNOWN)lpMalloc); + *lplpszFileName = lpsz; + return ResultFromScode(sc); +} + +STDMETHODIMP OleDoc_PFile_GetCurFile ( + LPPERSISTFILE lpThis, + LPOLESTR FAR* lplpszFileName +) +{ + LPSTR lpsz; + + HRESULT hr = OleDoc_PFile_GetCurFileA(lpThis, &lpsz); + + CopyAndFreeSTR(lpsz, lplpszFileName); + + return hr; +} + +/************************************************************************* +** OleDoc::IOleItemContainer interface implementation +*************************************************************************/ + +// IOleItemContainer::QueryInterface +STDMETHODIMP OleDoc_ItemCont_QueryInterface( + LPOLEITEMCONTAINER lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +// IOleItemContainer::AddRef +STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IOleItemContainer"); + + return OleDoc_AddRef((LPOLEDOC)lpOleDoc); +} + + +// IOleItemContainer::Release +STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IOleItemContainer"); + + return OleDoc_Release((LPOLEDOC)lpOleDoc); +} + + +// IOleItemContainer::ParseDisplayName +STDMETHODIMP OleDoc_ItemCont_ParseDisplayNameA( + LPOLEITEMCONTAINER lpThis, + LPBC lpbc, + LPSTR lpszDisplayName, + ULONG FAR* lpchEaten, + LPMONIKER FAR* lplpmkOut +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + char szItemName[MAXNAMESIZE]; + LPUNKNOWN lpUnk; + HRESULT hrErr; + OleDbgOut2("OleDoc_ItemCont_ParseDisplayName\r\n"); + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpmkOut = NULL; + + *lpchEaten = OleStdGetItemToken( + lpszDisplayName, + szItemName, + sizeof(szItemName) + ); + + /* OLE2NOTE: get a pointer to a running instance of the object. we + ** should force the object to go running if necessary (even if + ** this means launching its server EXE). this is the meaining of + ** BINDSPEED_INDEFINITE. Parsing a Moniker is known to be an + ** "EXPENSIVE" operation. + */ + hrErr = OleDoc_ItemCont_GetObjectA( + lpThis, + szItemName, + BINDSPEED_INDEFINITE, + lpbc, + &IID_IUnknown, + (LPVOID FAR*)&lpUnk + ); + + if (hrErr == NOERROR) { + OleStdRelease(lpUnk); // item name FOUND; don't need obj ptr. + + CreateItemMonikerA(OLESTDDELIM, szItemName, lplpmkOut); + + } else + *lpchEaten = 0; // item name is NOT valid + + return hrErr; +} + +STDMETHODIMP OleDoc_ItemCont_ParseDisplayName( + LPOLEITEMCONTAINER lpThis, + LPBC lpbc, + LPOLESTR lpszDisplayName, + ULONG FAR* lpchEaten, + LPMONIKER FAR* lplpmkOut +) +{ + CREATESTR(lpsz, lpszDisplayName) + + HRESULT hr = OleDoc_ItemCont_ParseDisplayNameA(lpThis, lpbc, + lpsz, lpchEaten, lplpmkOut); + + FREESTR(lpsz); + + return hr; +} + + +// IOleItemContainer::EnumObjects +STDMETHODIMP OleDoc_ItemCont_EnumObjects( + LPOLEITEMCONTAINER lpThis, + DWORD grfFlags, + LPENUMUNKNOWN FAR* lplpenumUnknown +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + OLEDBG_BEGIN2("OleDoc_ItemCont_EnumObjects\r\n") + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpenumUnknown = NULL; + + /* OLE2NOTE: this method should be implemented to allow programatic + ** clients the ability to what elements the container holds. + ** this method is NOT called in the standard linking scenarios. + ** + ** grfFlags can be one of the following: + ** OLECONTF_EMBEDDINGS -- enumerate embedded objects + ** OLECONTF_LINKS -- enumerate linked objects + ** OLECONTF_OTHERS -- enumerate non-OLE compound doc objs + ** OLECONTF_ONLYUSER -- enumerate only objs named by user + ** OLECONTF_ONLYIFRUNNING-- enumerate only objs in running state + */ + + OleDbgAssertSz(0, "NOT YET IMPLEMENTED!"); + + OLEDBG_END2 + return ResultFromScode(E_NOTIMPL); +} + + +// IOleItemContainer::LockContainer +STDMETHODIMP OleDoc_ItemCont_LockContainer( + LPOLEITEMCONTAINER lpThis, + BOOL fLock +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + OLEDBG_BEGIN2("OleDoc_ItemCont_LockContainer\r\n") + +#if defined( _DEBUG ) + if (fLock) { + ++lpOleDoc->m_cCntrLock; + OleDbgOutRefCnt3( + "OleDoc_ItemCont_LockContainer: cLock++\r\n", + lpOleDoc, + lpOleDoc->m_cCntrLock + ); + } else { + /* OLE2NOTE: when there are no open documents and the app is not + ** under the control of the user and there are no outstanding + ** locks on the app, then revoke our ClassFactory to enable the + ** app to shut down. + */ + --lpOleDoc->m_cCntrLock; + OleDbgAssertSz ( + lpOleDoc->m_cCntrLock >= 0, + "OleDoc_ItemCont_LockContainer(FALSE) called with cLock == 0" + ); + + if (lpOleDoc->m_cCntrLock == 0) { + OleDbgOutRefCnt2( + "OleDoc_ItemCont_LockContainer: UNLOCKED\r\n", + lpOleDoc, lpOleDoc->m_cCntrLock); + } else { + OleDbgOutRefCnt3( + "OleDoc_ItemCont_LockContainer: cLock--\r\n", + lpOleDoc, lpOleDoc->m_cCntrLock); + } + } +#endif // _DEBUG + + /* OLE2NOTE: in order to hold the document alive we call + ** CoLockObjectExternal to add a strong reference to our Doc + ** object. this will keep the Doc alive when all other external + ** references release us. whenever an embedded object goes + ** running a LockContainer(TRUE) is called. when the embedded + ** object shuts down (ie. transitions from running to loaded) + ** LockContainer(FALSE) is called. if the user issues File.Close + ** the document will shut down in any case ignoring any + ** outstanding LockContainer locks because CoDisconnectObject is + ** called in OleDoc_Close. this will forceably break any + ** existing strong reference counts including counts that we add + ** ourselves by calling CoLockObjectExternal and guarantee that + ** the Doc object gets its final release (ie. cRefs goes to 0). + */ + hrErr = OleDoc_Lock(lpOleDoc, fLock, TRUE /* fLastUnlockReleases */); + + OLEDBG_END2 + return hrErr; +} + + +// IOleItemContainer::GetObject +STDMETHODIMP OleDoc_ItemCont_GetObjectA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_ItemCont_GetObject\r\n") + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObject = NULL; + +#if defined( OLE_SERVER ) + + /* OLE2NOTE: SERVER ONLY version should return PseudoObjects with + ** BINDSPEED_IMMEDIATE, thus the dwSpeedNeeded is not important + ** in the case of a pure server. + */ + hrErr = ServerDoc_GetObjectA( + (LPSERVERDOC)lpOleDoc, lpszItem,riid,lplpvObject); +#endif +#if defined( OLE_CNTR ) + + /* OLE2NOTE: dwSpeedNeeded indicates how long the caller is willing + ** to wait for us to get the object: + ** BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning + ** BINDSPEED_MODERATE -- load obj if necessary && if IsRunning + ** BINDSPEED_INDEFINITE-- force obj to load and run if necessary + */ + hrErr = ContainerDoc_GetObjectA( + (LPCONTAINERDOC)lpOleDoc,lpszItem,dwSpeedNeeded,riid,lplpvObject); +#endif + + OLEDBG_END2 + return hrErr; +} + + + + +STDMETHODIMP OleDoc_ItemCont_GetObject( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = OleDoc_ItemCont_GetObjectA(lpThis, lpsz, dwSpeedNeeded, lpbc, + riid, lplpvObject); + + FREESTR(lpsz) + + return hr; +} + + +// IOleItemContainer::GetObjectStorage +STDMETHODIMP OleDoc_ItemCont_GetObjectStorageA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvStorage +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + OleDbgOut2("OleDoc_ItemCont_GetObjectStorage\r\n"); + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvStorage = NULL; + +#if defined( OLE_SERVER ) + /* OLE2NOTE: in the SERVER ONLY version, item names identify pseudo + ** objects. pseudo objects, do NOT have identifiable storage. + */ + return ResultFromScode(E_FAIL); +#endif +#if defined( OLE_CNTR ) + // We can only return an IStorage* type pointer + if (! IsEqualIID(riid, &IID_IStorage)) + return ResultFromScode(E_FAIL); + + return ContainerDoc_GetObjectStorageA( + (LPCONTAINERDOC)lpOleDoc, + lpszItem, + (LPSTORAGE FAR*)lplpvStorage + ); +#endif +} + +STDMETHODIMP OleDoc_ItemCont_GetObjectStorage( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvStorage +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = OleDoc_ItemCont_GetObjectStorageA(lpThis, lpsz, lpbc, + riid, lplpvStorage); + + FREESTR(lpsz) + + return hr; +} + +// IOleItemContainer::IsRunning +STDMETHODIMP OleDoc_ItemCont_IsRunningA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_ItemCont_IsRunning\r\n") + + /* OLE2NOTE: Check if item name is valid. if so then return if + ** Object is running. PseudoObjects in the Server version are + ** always considered running. Ole objects in the container must + ** be checked if they are running. + */ + +#if defined( OLE_SERVER ) + hrErr = ServerDoc_IsRunningA((LPSERVERDOC)lpOleDoc, lpszItem); +#endif +#if defined( OLE_CNTR ) + hrErr = ContainerDoc_IsRunningA((LPCONTAINERDOC)lpOleDoc, lpszItem); +#endif + + OLEDBG_END2 + return hrErr; +} + +STDMETHODIMP OleDoc_ItemCont_IsRunning( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = OleDoc_ItemCont_IsRunningA(lpThis,lpsz); + + FREESTR(lpsz) + + return hr; +} + +/************************************************************************* +** OleDoc::IExternalConnection interface implementation +*************************************************************************/ + +// IExternalConnection::QueryInterface +STDMETHODIMP OleDoc_ExtConn_QueryInterface( + LPEXTERNALCONNECTION lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +// IExternalConnection::AddRef +STDMETHODIMP_(ULONG) OleDoc_ExtConn_AddRef(LPEXTERNALCONNECTION lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IExternalConnection"); + + return OleDoc_AddRef(lpOleDoc); +} + + +// IExternalConnection::Release +STDMETHODIMP_(ULONG) OleDoc_ExtConn_Release (LPEXTERNALCONNECTION lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IExternalConnection"); + + return OleDoc_Release(lpOleDoc); +} + + +// IExternalConnection::AddConnection +STDMETHODIMP_(DWORD) OleDoc_ExtConn_AddConnection( + LPEXTERNALCONNECTION lpThis, + DWORD extconn, + DWORD reserved +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + if( extconn & EXTCONN_STRONG ) { + +#if defined( _DEBUG ) + OleDbgOutRefCnt3( + "OleDoc_ExtConn_AddConnection: dwStrongExtConn++\r\n", + lpOleDoc, + lpOleDoc->m_dwStrongExtConn + 1 + ); +#endif + return ++(lpOleDoc->m_dwStrongExtConn); + } else + return 0; +} + + +// IExternalConnection::ReleaseConnection +STDMETHODIMP_(DWORD) OleDoc_ExtConn_ReleaseConnection( + LPEXTERNALCONNECTION lpThis, + DWORD extconn, + DWORD reserved, + BOOL fLastReleaseCloses +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + if( extconn & EXTCONN_STRONG ){ + DWORD dwSave = --(lpOleDoc->m_dwStrongExtConn); +#if defined( _DEBUG ) + OLEDBG_BEGIN2( (fLastReleaseCloses ? + "OleDoc_ExtConn_ReleaseConnection(TRUE)\r\n" : + "OleDoc_ExtConn_ReleaseConnection(FALSE)\r\n") ) + OleDbgOutRefCnt3( + "OleDoc_ExtConn_ReleaseConnection: dwStrongExtConn--\r\n", + lpOleDoc, + lpOleDoc->m_dwStrongExtConn + ); + OleDbgAssertSz ( + lpOleDoc->m_dwStrongExtConn >= 0, + "OleDoc_ExtConn_ReleaseConnection called with dwStrong == 0" + ); +#endif // _DEBUG + + if( lpOleDoc->m_dwStrongExtConn == 0 && fLastReleaseCloses ) + OleDoc_Close(lpOleDoc, OLECLOSE_SAVEIFDIRTY); + + OLEDBG_END2 + return dwSave; + } else + return 0; +} + + +/************************************************************************* +** OleDoc Common Support Functions +*************************************************************************/ + + +/* OleDoc_GetFullMoniker +** --------------------- +** Return the full, absolute moniker of the document. +** +** NOTE: the caller must release the pointer returned when done. +*/ +LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign) +{ + LPMONIKER lpMoniker = NULL; + + OLEDBG_BEGIN3("OleDoc_GetFullMoniker\r\n") + + if (lpOleDoc->m_lpSrcDocOfCopy) { + /* CASE I: this document was created for a copy or drag/drop + ** operation. generate the moniker which identifies the + ** source document of the original copy. + */ + if (! lpOleDoc->m_fLinkSourceAvail) + goto done; // we already know a moniker is not available + + lpMoniker=OleDoc_GetFullMoniker(lpOleDoc->m_lpSrcDocOfCopy, dwAssign); + } + else if (lpOleDoc->m_lpFileMoniker) { + + /* CASE II: this document is a top-level user document (either + ** file-based or untitled). return the FileMoniker stored + ** with the document; it uniquely identifies the document. + */ + // we must AddRef the moniker to pass out a ptr + lpOleDoc->m_lpFileMoniker->lpVtbl->AddRef(lpOleDoc->m_lpFileMoniker); + + lpMoniker = lpOleDoc->m_lpFileMoniker; + } + +#if defined( OLE_SERVER ) + + else if (((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite) { + + /* CASE III: this document is an embedded object, ask our + ** container for our moniker. + */ + OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n"); + ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite->lpVtbl->GetMoniker( + ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite, + dwAssign, + OLEWHICHMK_OBJFULL, + &lpMoniker + ); + OLEDBG_END2 + } + +#endif + + else { + lpMoniker = NULL; + } + +done: + OLEDBG_END3 + return lpMoniker; +} + + +/* OleDoc_DocRenamedUpdate +** ----------------------- +** Update the documents registration in the running object table (ROT). +** Also inform all embedded OLE objects (container only) and/or psedudo +** objects (server only) that the name of the document has changed. +*/ +void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc) +{ + OLEDBG_BEGIN3("OleDoc_DocRenamedUpdate\r\n") + + OleDoc_AddRef(lpOleDoc); + + /* OLE2NOTE: we must re-register ourselves as running when we + ** get a new moniker assigned (ie. when we are renamed). + */ + OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n") + OleStdRegisterAsRunning( + (LPUNKNOWN)&lpOleDoc->m_Unknown, + lpmkDoc, + &lpOleDoc->m_dwRegROT + ); + OLEDBG_END3 + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + /* OLE2NOTE: inform any linking clients that the document has been + ** renamed. + */ + ServerDoc_SendAdvise ( + lpServerDoc, + OLE_ONRENAME, + lpmkDoc, + 0 /* advf -- not relevant here */ + ); + + /* OLE2NOTE: inform any clients of pseudo objects + ** within our document, that our document's + ** Moniker has changed. + */ + ServerNameTable_InformAllPseudoObjectsDocRenamed( + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, lpmkDoc); + } +#endif +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; + + /* OLE2NOTE: must tell all OLE objects that our container + ** moniker changed. + */ + ContainerDoc_InformAllOleObjectsDocRenamed( + lpContainerDoc, + lpmkDoc + ); + } +#endif + + OleDoc_Release(lpOleDoc); // release artificial AddRef above + OLEDBG_END3 +} + + + +#if defined( OLE_SERVER ) + +/************************************************************************* +** ServerDoc Supprt Functions Used by Server versions +*************************************************************************/ + + +/* ServerDoc_PseudoObjLockDoc +** -------------------------- +** Add a lock on the Doc on behalf of the PseudoObject. the Doc may not +** close while the Doc exists. +** +** when a pseudo object is first created, it calls this method to +** guarantee that the document stays alive (PseudoObj_Init). +** when a pseudo object is destroyed, it call +** ServerDoc_PseudoObjUnlockDoc to release this hold on the document. +*/ +void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + ULONG cPseudoObj; + + cPseudoObj = ++lpServerDoc->m_cPseudoObj; + +#if defined( _DEBUG ) + OleDbgOutRefCnt3( + "ServerDoc_PseudoObjLockDoc: cPseudoObj++\r\n", + lpServerDoc, + cPseudoObj + ); +#endif + OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */); + return; +} + + +/* ServerDoc_PseudoObjUnlockDoc +** ---------------------------- +** Release the lock on the Doc on behalf of the PseudoObject. if this was +** the last lock on the Doc, then it will shutdown. +*/ +void ServerDoc_PseudoObjUnlockDoc( + LPSERVERDOC lpServerDoc, + LPPSEUDOOBJ lpPseudoObj +) +{ + ULONG cPseudoObj; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + OLEDBG_BEGIN3("ServerDoc_PseudoObjUnlockDoc\r\n") + + /* OLE2NOTE: when there are no active pseudo objects in the Doc and + ** the Doc is not visible, and if there are no outstanding locks + ** on the Doc, then this is a "silent update" + ** situation. our Doc is being used programatically by some + ** client; it is NOT accessible to the user because it is + ** NOT visible. thus since all Locks have been released, we + ** will close the document. if the app is only running due + ** to the presence of this document, then the app will now + ** also shut down. + */ + cPseudoObj = --lpServerDoc->m_cPseudoObj; + +#if defined( _DEBUG ) + OleDbgAssertSz ( + lpServerDoc->m_cPseudoObj >= 0, + "PseudoObjUnlockDoc called with cPseudoObj == 0" + ); + + OleDbgOutRefCnt3( + "ServerDoc_PseudoObjUnlockDoc: cPseudoObj--\r\n", + lpServerDoc, + cPseudoObj + ); +#endif + OleDoc_Lock(lpOleDoc, FALSE /* fLock */, TRUE /* fLastUnlockReleases */); + + OLEDBG_END3 + return; +} + + +/* ServerDoc_GetObject +** ------------------- +** +** Return a pointer to an object identified by an item string +** (lpszItem). For a server-only app, the object returned will be a +** pseudo object. +*/ +HRESULT ServerDoc_GetObjectA( + LPSERVERDOC lpServerDoc, + LPSTR lpszItem, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + LPPSEUDOOBJ lpPseudoObj; + LPSERVERNAMETABLE lpServerNameTable = + (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable; + + *lplpvObject = NULL; + + /* Get the PseudoObj which corresponds to an item name. if the item + ** name does NOT exist in the name table then NO object is + ** returned. the ServerNameTable_GetPseudoObj routine finds a + ** name entry corresponding to the item name, it then checks if + ** a PseudoObj has already been allocated. if so, it returns the + ** existing object, otherwise it allocates a new PseudoObj. + */ + lpPseudoObj = ServerNameTable_GetPseudoObj( + lpServerNameTable, + lpszItem, + lpServerDoc + ); + + if (! lpPseudoObj) { + *lplpvObject = NULL; + return ResultFromScode(MK_E_NOOBJECT); + } + + // return the desired interface pointer of the pseudo object. + return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObject); +} + + + +HRESULT ServerDoc_GetObject( + LPSERVERDOC lpServerDoc, + LPOLESTR lpszItem, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + CREATESTR(pstr, lpszItem) + + HRESULT hr = ServerDoc_GetObjectA(lpServerDoc, pstr, riid, lplpvObject); + + FREESTR(pstr) + + return hr; +} + + + +/* ServerDoc_IsRunning +** ------------------- +** +** Check if the object identified by an item string (lpszItem) is in +** the running state. For a server-only app, if the item name exists in +** in the NameTable then the item name is considered running. +** IOleItemContainer::GetObject would succeed. +*/ + +HRESULT ServerDoc_IsRunningA(LPSERVERDOC lpServerDoc, LPSTR lpszItem) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + ((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable; + LPSERVERNAME lpServerName; + + lpServerName = (LPSERVERNAME)OutlineNameTable_FindName( + lpOutlineNameTable, + lpszItem + ); + + if (lpServerName) + return NOERROR; + else + return ResultFromScode(MK_E_NOOBJECT); +} + + +/* ServerDoc_GetSelRelMoniker +** -------------------------- +** Retrieve the relative item moniker which identifies the given +** selection (lplrSel). +** +** Returns NULL if a moniker can NOT be created. +*/ + +LPMONIKER ServerDoc_GetSelRelMoniker( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel, + DWORD dwAssign +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERNAMETABLE lpServerNameTable = + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable; + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LPMONIKER lpmk; + + lpOutlineName=OutlineNameTable_FindNamedRange(lpOutlineNameTable,lplrSel); + + if (lpOutlineName) { + /* the selection range already has a name assigned */ + CreateItemMonikerA(OLESTDDELIM, lpOutlineName->m_szName, &lpmk); + } else { + char szbuf[MAXNAMESIZE]; + + switch (dwAssign) { + + case GETMONIKER_FORCEASSIGN: + + /* Force the assignment of the name. This is called when a + ** Paste Link actually occurs. At this point we want to + ** create a Name and add it to the NameTable in order to + ** track the source of the link. This name (as all + ** names) will be updated upon editing of the document. + */ + wsprintf( + szbuf, + "%s %ld", + (LPSTR)DEFRANGENAMEPREFIX, + ++(lpServerDoc->m_nNextRangeNo) + ); + + lpOutlineName = OutlineApp_CreateName(lpOutlineApp); + + if (lpOutlineName) { + lstrcpy(lpOutlineName->m_szName, szbuf); + lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; + lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; + OutlineDoc_AddName(lpOutlineDoc, lpOutlineName); + } else { + // REVIEW: do we need "Out-of-Memory" error message here? + } + break; + + case GETMONIKER_TEMPFORUSER: + + /* Create a name to show to the user in the Paste + ** Special dialog but do NOT yet incur the overhead + ** of adding a Name to the NameTable. The Moniker + ** generated should be useful to display to the user + ** to indicate the source of the copy, but will NOT + ** be used to create a link directly (the caller + ** should ask again for a moniker specifying FORCEASSIGN). + ** we will generate the name that would be the next + ** auto-generated range name, BUT will NOT actually + ** increment the range counter. + */ + wsprintf( + szbuf, + "%s %ld", + (LPSTR)DEFRANGENAMEPREFIX, + (lpServerDoc->m_nNextRangeNo)+1 + ); + break; + + case GETMONIKER_ONLYIFTHERE: + + /* the caller only wants a name if one has already been + ** assigned. we have already above checked if the + ** current selection has a name, so we will simply + ** return NULL here. + */ + return NULL; // no moniker is assigned + + default: + return NULL; // unknown flag given + } + + CreateItemMonikerA(OLESTDDELIM, szbuf, &lpmk); + } + return lpmk; +} + + +/* ServerDoc_GetSelFullMoniker +** --------------------------- +** Retrieve the full absolute moniker which identifies the given +** selection (lplrSel). +** this moniker is created as a composite of the absolute moniker for +** the entire document appended with an item moniker which identifies +** the selection relative to the document. +** Returns NULL if a moniker can NOT be created. +*/ +LPMONIKER ServerDoc_GetSelFullMoniker( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel, + DWORD dwAssign +) +{ + LPMONIKER lpmkDoc = NULL; + LPMONIKER lpmkItem = NULL; + LPMONIKER lpmkFull = NULL; + + lpmkDoc = OleDoc_GetFullMoniker( + (LPOLEDOC)lpServerDoc, + dwAssign + ); + if (! lpmkDoc) return NULL; + + lpmkItem = ServerDoc_GetSelRelMoniker( + lpServerDoc, + lplrSel, + dwAssign + ); + if (lpmkItem) { + CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull); + OleStdRelease((LPUNKNOWN)lpmkItem); + } + + if (lpmkDoc) + OleStdRelease((LPUNKNOWN)lpmkDoc); + + return lpmkFull; +} + + +/* ServerNameTable_EditLineUpdate + * ------------------------------- + * + * Update the table when a line at nEditIndex is edited. + */ +void ServerNameTable_EditLineUpdate( + LPSERVERNAMETABLE lpServerNameTable, + int nEditIndex +) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LINERANGE lrSel; + LPPSEUDOOBJ lpPseudoObj; + int i; + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + + lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; + + /* if there is a pseudo object associated with this name, then + ** check if the line that was modified is included within + ** the named range. + */ + if (lpPseudoObj) { + OutlineName_GetSel(lpOutlineName, &lrSel); + + if(((int)lrSel.m_nStartLine <= nEditIndex) && + ((int)lrSel.m_nEndLine >= nEditIndex)) { + + // inform linking clients data has changed + PseudoObj_SendAdvise( + lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); + } + + } + } +} + + +/* ServerNameTable_InformAllPseudoObjectsDocRenamed + * ------------------------------------------------ + * + * Inform all pseudo object clients that the name of the pseudo + * object has changed. + */ +void ServerNameTable_InformAllPseudoObjectsDocRenamed( + LPSERVERNAMETABLE lpServerNameTable, + LPMONIKER lpmkDoc +) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LPPSEUDOOBJ lpPseudoObj; + LPMONIKER lpmkObj; + int i; + + OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocRenamed\r\n"); + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + + lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; + + /* if there is a pseudo object associated with this name, then + ** send OnRename advise to its linking clients. + */ + if (lpPseudoObj && + ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) { + + // inform the clients that the name has changed + PseudoObj_SendAdvise ( + lpPseudoObj, + OLE_ONRENAME, + lpmkObj, + 0 /* advf -- not relevant here */ + ); + } + } + OLEDBG_END2 +} + + +/* ServerNameTable_InformAllPseudoObjectsDocSaved + * ------------------------------------------------ + * + * Inform all pseudo object clients that the name of the pseudo + * object has changed. + */ +void ServerNameTable_InformAllPseudoObjectsDocSaved( + LPSERVERNAMETABLE lpServerNameTable, + LPMONIKER lpmkDoc +) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LPPSEUDOOBJ lpPseudoObj; + LPMONIKER lpmkObj; + int i; + + OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocSaved\r\n"); + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + + lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; + + /* if there is a pseudo object associated with this name, then + ** send OnSave advise to its linking clients. + */ + if (lpPseudoObj && + ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) { + + // inform the clients that the name has been saved + PseudoObj_SendAdvise ( + lpPseudoObj, + OLE_ONSAVE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- not relevant here */ + ); + } + } + OLEDBG_END2 +} + + +/* ServerNameTable_SendPendingAdvises + * ---------------------------------- + * + * Send any pending change notifications for pseudo objects. + * while ReDraw is diabled on the ServerDoc, then change advise + * notifications are not sent to pseudo object clients. + */ +void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPSERVERNAME lpServerName; + int i; + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpServerName = (LPSERVERNAME)OutlineNameTable_GetName( + lpOutlineNameTable, + i + ); + ServerName_SendPendingAdvises(lpServerName); + } +} + + +/* ServerNameTable_GetPseudoObj +** ---------------------------- +** +** Return a pointer to a pseudo object identified by an item string +** (lpszItem). if the pseudo object already exists, then return the +** existing object, otherwise allocate a new pseudo object. +*/ +LPPSEUDOOBJ ServerNameTable_GetPseudoObj( + LPSERVERNAMETABLE lpServerNameTable, + LPSTR lpszItem, + LPSERVERDOC lpServerDoc +) +{ + LPSERVERNAME lpServerName; + + lpServerName = (LPSERVERNAME)OutlineNameTable_FindName( + (LPOUTLINENAMETABLE)lpServerNameTable, + lpszItem + ); + + if (lpServerName) + return ServerName_GetPseudoObj(lpServerName, lpServerDoc); + else + return NULL; +} + + +/* ServerNameTable_CloseAllPseudoObjs + * ---------------------------------- + * + * Force all pseudo objects to close. this results in sending OnClose + * notification to each pseudo object's linking clients. + */ +void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPSERVERNAME lpServerName; + int i; + + OLEDBG_BEGIN3("ServerNameTable_CloseAllPseudoObjs\r\n") + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpServerName = (LPSERVERNAME)OutlineNameTable_GetName( + lpOutlineNameTable, + i + ); + ServerName_ClosePseudoObj(lpServerName); + } + + OLEDBG_END3 +} + + + +/* ServerName_SetSel + * ----------------- + * + * Change the line range of a name. + */ +void ServerName_SetSel( + LPSERVERNAME lpServerName, + LPLINERANGE lplrSel, + BOOL fRangeModified +) +{ + LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpServerName; + BOOL fPseudoObjChanged = fRangeModified; + + if (lpOutlineName->m_nStartLine != lplrSel->m_nStartLine) { + lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; + fPseudoObjChanged = TRUE; + } + + if (lpOutlineName->m_nEndLine != lplrSel->m_nEndLine) { + lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; + fPseudoObjChanged = TRUE; + } + + /* OLE2NOTE: if the range of an active pseudo object has + ** changed, then inform any linking clients that the object + ** has changed. + */ + if (lpServerName->m_lpPseudoObj && fPseudoObjChanged) { + PseudoObj_SendAdvise( + lpServerName->m_lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); + } +} + + +/* ServerName_SendPendingAdvises + * ----------------------------- + * + * Send any pending change notifications for the associated + * pseudo objects for this name (if one exists). + * while ReDraw is diabled on the ServerDoc, then change advise + * notifications are not sent to pseudo object clients. + */ +void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName) +{ + if (! lpServerName->m_lpPseudoObj) + return; // no associated pseudo object + + if (lpServerName->m_lpPseudoObj->m_fDataChanged) + PseudoObj_SendAdvise( + lpServerName->m_lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); +} + + +/* ServerName_GetPseudoObj +** ----------------------- +** +** Return a pointer to a pseudo object associated to a ServerName. +** if the pseudo object already exists, then return the +** existing object, otherwise allocate a new pseudo object. +** +** NOTE: the PseudoObj is returned with a 0 refcnt if first created, +** else the existing refcnt is unchanged. +*/ +LPPSEUDOOBJ ServerName_GetPseudoObj( + LPSERVERNAME lpServerName, + LPSERVERDOC lpServerDoc +) +{ + // Check if a PseudoObj already exists + if (lpServerName->m_lpPseudoObj) + return lpServerName->m_lpPseudoObj; + + // A PseudoObj does NOT already exist, allocate a new one. + lpServerName->m_lpPseudoObj=(LPPSEUDOOBJ) New((DWORD)sizeof(PSEUDOOBJ)); + if (lpServerName->m_lpPseudoObj == NULL) { + OleDbgAssertSz(lpServerName->m_lpPseudoObj != NULL, "Error allocating PseudoObj"); + return NULL; + } + + PseudoObj_Init(lpServerName->m_lpPseudoObj, lpServerName, lpServerDoc); + return lpServerName->m_lpPseudoObj; +} + + +/* ServerName_ClosePseudoObj + * ------------------------- + * + * if there is an associated pseudo objects for this name (if one + * exists), then close it. this results in sending OnClose + * notification to the pseudo object's linking clients. + */ +void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName) +{ + if (!lpServerName || !lpServerName->m_lpPseudoObj) + return; // no associated pseudo object + + PseudoObj_Close(lpServerName->m_lpPseudoObj); +} + + +#endif // OLE_SERVER + + +#if defined( OLE_CNTR ) + + +/************************************************************************* +** ContainerDoc Supprt Functions Used by Container versions +*************************************************************************/ + + +/* ContainerLine_GetRelMoniker +** --------------------------- +** Retrieve the relative item moniker which identifies the OLE object +** relative to the container document. +** +** Returns NULL if a moniker can NOT be created. +*/ +LPMONIKER ContainerLine_GetRelMoniker( + LPCONTAINERLINE lpContainerLine, + DWORD dwAssign +) +{ + LPMONIKER lpmk = NULL; + + /* OLE2NOTE: we should only give out a moniker for the OLE object + ** if the object is allowed to be linked to from the inside. if + ** so we are allowed to give out a moniker which binds to the + ** running OLE object). if the object is an OLE 2.0 embedded + ** object then it is allowed to be linked to from the inside. if + ** the object is either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we could offer linking + ** to the outside of the object (ie. a pseudo object within our + ** document). we are a container only app that does not support + ** linking to ranges of its data. + */ + + switch (dwAssign) { + + case GETMONIKER_FORCEASSIGN: + + /* Force the assignment of the name. This is called when a + ** Paste Link actually occurs. From now on we want + ** to inform the OLE object that its moniker is + ** assigned and is thus necessary to register itself + ** in the RunningObjectTable. + */ + CreateItemMonikerA( + OLESTDDELIM, lpContainerLine->m_szStgName, &lpmk); + + /* OLE2NOTE: if the OLE object is already loaded and it + ** is being assigned a moniker for the first time, + ** then we need to inform it that it now has a moniker + ** assigned by calling IOleObject::SetMoniker. this + ** will force the OLE object to register in the + ** RunningObjectTable when it enters the running + ** state. if the object is not currently loaded, + ** SetMoniker will be called automatically later when + ** the object is loaded by the function + ** ContainerLine_LoadOleObject. + */ + if (! lpContainerLine->m_fMonikerAssigned) { + + /* we must remember forever more that this object has a + ** moniker assigned. + */ + lpContainerLine->m_fMonikerAssigned = TRUE; + + // we are now dirty and must be saved + OutlineDoc_SetModified( + (LPOUTLINEDOC)lpContainerLine->m_lpDoc, + TRUE, /* fModified */ + FALSE, /* fDataChanged--N/A for container ver. */ + FALSE /* fSizeChanged--N/A for container ver. */ + ); + + if (lpContainerLine->m_lpOleObj) { + OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( + lpContainerLine->m_lpOleObj, + OLEWHICHMK_OBJREL, + lpmk + ); + OLEDBG_END2 + } + } + break; + + case GETMONIKER_ONLYIFTHERE: + + /* If the OLE object currently has a moniker assigned, + ** then return it. + */ + if (lpContainerLine->m_fMonikerAssigned) { + + CreateItemMonikerA( + OLESTDDELIM, + lpContainerLine->m_szStgName, + &lpmk + ); + + } + break; + + case GETMONIKER_TEMPFORUSER: + + /* Return the moniker that would be used for the OLE + ** object but do NOT force moniker assignment at + ** this point. Since our strategy is to use the + ** storage name of the object as its item name, we + ** can simply create the corresponding ItemMoniker + ** (indepenedent of whether the moniker is currently + ** assigned or not). + */ + CreateItemMonikerA( + OLESTDDELIM, + lpContainerLine->m_szStgName, + &lpmk + ); + + break; + + case GETMONIKER_UNASSIGN: + + lpContainerLine->m_fMonikerAssigned = FALSE; + break; + + } + + return lpmk; +} + + +/* ContainerLine_GetFullMoniker +** ---------------------------- +** Retrieve the full absolute moniker which identifies the OLE object +** in the container document. +** this moniker is created as a composite of the absolute moniker for +** the entire document appended with an item moniker which identifies +** the OLE object relative to the document. +** Returns NULL if a moniker can NOT be created. +*/ +LPMONIKER ContainerLine_GetFullMoniker( + LPCONTAINERLINE lpContainerLine, + DWORD dwAssign +) +{ + LPMONIKER lpmkDoc = NULL; + LPMONIKER lpmkItem = NULL; + LPMONIKER lpmkFull = NULL; + + lpmkDoc = OleDoc_GetFullMoniker( + (LPOLEDOC)lpContainerLine->m_lpDoc, + dwAssign + ); + if (! lpmkDoc) return NULL; + + lpmkItem = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign); + + if (lpmkItem) { + CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull); + OleStdRelease((LPUNKNOWN)lpmkItem); + } + + if (lpmkDoc) + OleStdRelease((LPUNKNOWN)lpmkDoc); + + return lpmkFull; +} + + +/* ContainerDoc_InformAllOleObjectsDocRenamed +** ------------------------------------------ +** Inform all OLE objects that the name of the ContainerDoc has changed. +*/ +void ContainerDoc_InformAllOleObjectsDocRenamed( + LPCONTAINERDOC lpContainerDoc, + LPMONIKER lpmkDoc +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + /* OLE2NOTE: if the OLE object is already loaded AND the + ** object already has a moniker assigned, then we need + ** to inform it that the moniker of the ContainerDoc has + ** changed. of course, this means the full moniker of + ** the object has changed. to do this we call + ** IOleObject::SetMoniker. this will force the OLE + ** object to re-register in the RunningObjectTable if it + ** is currently in the running state. it is not in the + ** running state, the object handler can make not that + ** the object has a new moniker. if the object is not + ** currently loaded, SetMoniker will be called + ** automatically later when the object is loaded by the + ** function ContainerLine_LoadOleObject. + ** also if the object is a linked object, we always want + ** to call SetMoniker on the link so that in case the + ** link source is contained within our same container, + ** the link source will be tracked. the link rebuilds + ** its absolute moniker if it has a relative moniker. + */ + if (lpContainerLine->m_lpOleObj) { + if (lpContainerLine->m_fMonikerAssigned || + lpContainerLine->m_dwLinkType != 0) { + OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( + lpContainerLine->m_lpOleObj, + OLEWHICHMK_CONTAINER, + lpmkDoc + ); + OLEDBG_END2 + } + + /* OLE2NOTE: we must call IOleObject::SetHostNames so + ** any open objects can update their window titles. + */ + OLEDBG_BEGIN2("IOleObject::SetHostNames called\r\n") + + CallIOleObjectSetHostNamesA( + lpContainerLine->m_lpOleObj, + APPNAME, + ((LPOUTLINEDOC)lpContainerDoc)->m_lpszDocTitle + ); + + OLEDBG_END2 + } + } + } +} + + +/* ContainerDoc_GetObject +** ---------------------- +** Return a pointer to the desired interface of an object identified +** by an item string (lpszItem). the object returned will be an OLE +** object (either link or embedding). +** +** OLE2NOTE: we must force the object to run because we are +** REQUIRED to return a pointer the OLE object in the +** RUNNING state. +** +** dwSpeedNeeded indicates how long the caller is willing +** to wait for us to get the object: +** BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning +** BINDSPEED_MODERATE -- load obj if necessary && if IsRunning +** BINDSPEED_INDEFINITE-- force obj to load and run if necessary +*/ +HRESULT ContainerDoc_GetObjectA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + BOOL fMatchFound = FALSE; + DWORD dwStatus; + HRESULT hrErr; + + *lplpvObject = NULL; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { + + fMatchFound = TRUE; // valid item name + + // check if object is loaded. + if (lpContainerLine->m_lpOleObj == NULL) { + + // if BINDSPEED_IMMEDIATE is requested, object must + // ALREADY be loadded. + if (dwSpeedNeeded == BINDSPEED_IMMEDIATE) + return ResultFromScode(MK_E_EXCEEDEDDEADLINE); + + ContainerLine_LoadOleObject(lpContainerLine); + if (! lpContainerLine->m_lpOleObj) + return ResultFromScode(E_OUTOFMEMORY); + } + + /* OLE2NOTE: check if the object is allowed to be linked + ** to from the inside (ie. we are allowed to + ** give out a moniker which binds to the running + ** OLE object). if the object is an OLE + ** 2.0 embedded object then it is allowed to be + ** linked to from the inside. if the object is + ** either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we + ** could offer linking to the outside of the + ** object (ie. a pseudo object within our + ** document). we are a container only app that + ** does not support linking to ranges of its data. + */ + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n"); + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, /* aspect is not important */ + (LPDWORD)&dwStatus + ); + OLEDBG_END2 + if (dwStatus & OLEMISC_CANTLINKINSIDE) + return ResultFromScode(MK_E_NOOBJECT); + + // check if object is running. + if (! OleIsRunning(lpContainerLine->m_lpOleObj)) { + + // if BINDSPEED_MODERATE is requested, object must + // ALREADY be running. + if (dwSpeedNeeded == BINDSPEED_MODERATE) + return ResultFromScode(MK_E_EXCEEDEDDEADLINE); + + /* OLE2NOTE: we have found a match for the item name. + ** now we must return a pointer to the desired + ** interface on the RUNNING object. we must + ** carefully load the object and initially ask for + ** an interface that we are sure the loaded form of + ** the object supports. if we immediately ask the + ** loaded object for the desired interface, the + ** QueryInterface call might fail if it is an + ** interface that is supported only when the object + ** is running. thus we force the object to load and + ** return its IUnknown*. then we force the object to + ** run, and then finally, we can ask for the + ** actually requested interface. + */ + hrErr = ContainerLine_RunOleObject(lpContainerLine); + if (hrErr != NOERROR) { + return hrErr; + } + } + + // Retrieve the requested interface + *lplpvObject = OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, riid); + + break; // Match FOUND! + } + } + } + + if (*lplpvObject != NULL) { + return NOERROR; + } else + return (fMatchFound ? ResultFromScode(E_NOINTERFACE) + : ResultFromScode(MK_E_NOOBJECT)); +} + + +HRESULT ContainerDoc_GetObject( + LPCONTAINERDOC lpContainerDoc, + LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = ContainerDoc_GetObjectA(lpContainerDoc, lpsz, dwSpeedNeeded, + riid, lplpvObject); + + FREESTR(lpsz) + + return hr; +} + +/* ContainerDoc_GetObjectStorage +** ----------------------------- +** Return a pointer to the IStorage* used by the object identified +** by an item string (lpszItem). the object identified could be either +** an OLE object (either link or embedding). +*/ +HRESULT ContainerDoc_GetObjectStorageA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + LPSTORAGE FAR* lplpStg +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + + *lplpStg = NULL; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { + + *lplpStg = lpContainerLine->m_lpStg; + break; // Match FOUND! + } + } + } + + if (*lplpStg != NULL) { + return NOERROR; + } else + return ResultFromScode(MK_E_NOOBJECT); +} + +HRESULT ContainerDoc_GetObjectStorage( + LPCONTAINERDOC lpContainerDoc, + LPOLESTR lpszItem, + LPSTORAGE FAR* lplpStg +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = ContainerDoc_GetObjectStorageA(lpContainerDoc, lpsz, lplpStg); + + FREESTR(lpsz) + + return hr; +} + +/* ContainerDoc_IsRunning +** ---------------------- +** Check if the object identified by an item string (lpszItem) is in +** the running state. +** For a container-only app, a check is made if the OLE object +** associated with the item name is running. +*/ +HRESULT ContainerDoc_IsRunningA(LPCONTAINERDOC lpContainerDoc, LPSTR lpszItem) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + DWORD dwStatus; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { + + /* OLE2NOTE: we have found a match for the item name. + ** now we must check if the OLE object is running. + ** we will load the object if not already loaded. + */ + if (! lpContainerLine->m_lpOleObj) { + ContainerLine_LoadOleObject(lpContainerLine); + if (! lpContainerLine->m_lpOleObj) + return ResultFromScode(E_OUTOFMEMORY); + } + + /* OLE2NOTE: check if the object is allowed to be linked + ** to from the inside (ie. we are allowed to + ** give out a moniker which binds to the running + ** OLE object). if the object is an OLE + ** 2.0 embedded object then it is allowed to be + ** linked to from the inside. if the object is + ** either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we + ** could offer linking to the outside of the + ** object (ie. a pseudo object within our + ** document). we are a container only app that + ** does not support linking to ranges of its data. + */ + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, /* aspect is not important */ + (LPDWORD)&dwStatus + ); + OLEDBG_END2 + if (dwStatus & OLEMISC_CANTLINKINSIDE) + return ResultFromScode(MK_E_NOOBJECT); + + if (OleIsRunning(lpContainerLine->m_lpOleObj)) + return NOERROR; + else + return ResultFromScode(S_FALSE); + } + } + } + + // no object was found corresponding to the item name + return ResultFromScode(MK_E_NOOBJECT); +} + +HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC lpContainerDoc, LPOLESTR lpszItem) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = ContainerDoc_IsRunningA(lpContainerDoc, lpsz); + + FREESTR(lpsz) + + return hr; +} + +#endif // OLE_CNTR diff --git a/private/oleutest/letest/outline/main.c b/private/oleutest/letest/outline/main.c new file mode 100644 index 000000000..58ba4b773 --- /dev/null +++ b/private/oleutest/letest/outline/main.c @@ -0,0 +1,2488 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** main.c +** +** This file contains initialization functions which are WinMain, +** WndProc, and OutlineApp_InitalizeMenu. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" +#if defined( USE_STATUSBAR ) +#include "status.h" +#endif + +#if !defined( WIN32 ) +#if defined( USE_CTL3D ) +#include "ctl3d.h" +#endif // USE_CTL3D +#endif // !WIN32 + +#include "initguid.h" // forces our GUIDs to be initialized +#include "defguid.h" + +// OLETEST driver window handler +HWND g_hwndDriver; + +#if defined( OLE_CNTR ) +//************************************************************************* + +#if defined( INPLACE_CNTR ) +OLEDBGDATA_MAIN("ICNTR") +#else +OLEDBGDATA_MAIN("CNTR") +#endif + + +CONTAINERAPP g_OutlineApp; // Global App object maintains app instance state + +/* Global interface Vtbl's + * OLE2NOTE: we only need one copy of each Vtbl. When an object which + * exposes an interface is instantiated, its lpVtbl is intialized + * to point to one of these global Vtbl's. + */ +IUnknownVtbl g_OleApp_UnknownVtbl; +IClassFactoryVtbl g_OleApp_ClassFactoryVtbl; +IMessageFilterVtbl g_OleApp_MessageFilterVtbl; + +IUnknownVtbl g_OleDoc_UnknownVtbl; +IPersistFileVtbl g_OleDoc_PersistFileVtbl; +IOleItemContainerVtbl g_OleDoc_OleItemContainerVtbl; +IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl; +IDataObjectVtbl g_OleDoc_DataObjectVtbl; + +#if defined( USE_DRAGDROP ) +IDropSourceVtbl g_OleDoc_DropSourceVtbl; +IDropTargetVtbl g_OleDoc_DropTargetVtbl; +#endif // USE_DRAGDROP + +IOleUILinkContainerVtbl g_CntrDoc_OleUILinkContainerVtbl; + +IOleClientSiteVtbl g_CntrLine_UnknownVtbl; +IOleClientSiteVtbl g_CntrLine_OleClientSiteVtbl; +IAdviseSinkVtbl g_CntrLine_AdviseSinkVtbl; + +#if defined( INPLACE_CNTR ) +IOleInPlaceSiteVtbl g_CntrLine_OleInPlaceSiteVtbl; +IOleInPlaceFrameVtbl g_CntrApp_OleInPlaceFrameVtbl; +BOOL g_fInsideOutContainer = FALSE; // default to outside-in activation +#endif // INPLACE_CNTR + +//************************************************************************* +#endif // OLE_CNTR + +#if defined( OLE_SERVER ) +//************************************************************************* + +#if defined( INPLACE_SVR ) +OLEDBGDATA_MAIN("ISVR") +#else +OLEDBGDATA_MAIN("SVR") +#endif + +SERVERAPP g_OutlineApp; // Global App object maintains app instance state + +/* Global interface Vtbl's + * OLE2NOTE: we only need one copy of each Vtbl. When an object which + * exposes an interface is instantiated, its lpVtbl is intialized + * to point to one of these global Vtbl's. + */ +IUnknownVtbl g_OleApp_UnknownVtbl; +IClassFactoryVtbl g_OleApp_ClassFactoryVtbl; +IMessageFilterVtbl g_OleApp_MessageFilterVtbl; + +IUnknownVtbl g_OleDoc_UnknownVtbl; +IPersistFileVtbl g_OleDoc_PersistFileVtbl; +IOleItemContainerVtbl g_OleDoc_OleItemContainerVtbl; +IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl; +IDataObjectVtbl g_OleDoc_DataObjectVtbl; + +#if defined( USE_DRAGDROP ) +IDropSourceVtbl g_OleDoc_DropSourceVtbl; +IDropTargetVtbl g_OleDoc_DropTargetVtbl; +#endif // USE_DRAGDROP + +IOleObjectVtbl g_SvrDoc_OleObjectVtbl; +IPersistStorageVtbl g_SvrDoc_PersistStorageVtbl; + +#if defined( SVR_TREATAS ) +IStdMarshalInfoVtbl g_SvrDoc_StdMarshalInfoVtbl; +#endif // SVR_TREATAS + +#if defined( INPLACE_SVR ) +IOleInPlaceObjectVtbl g_SvrDoc_OleInPlaceObjectVtbl; +IOleInPlaceActiveObjectVtbl g_SvrDoc_OleInPlaceActiveObjectVtbl; +#endif // INPLACE_SVR + +IUnknownVtbl g_PseudoObj_UnknownVtbl; +IOleObjectVtbl g_PseudoObj_OleObjectVtbl; +IDataObjectVtbl g_PseudoObj_DataObjectVtbl; + +//************************************************************************* +#endif // OLE_SVR + +#if !defined( OLE_VERSION ) +OLEDBGDATA_MAIN("OUTL") +OUTLINEAPP g_OutlineApp; // Global App object maintains app instance state +#endif + +LPOUTLINEAPP g_lpApp=(LPOUTLINEAPP)&g_OutlineApp; // ptr to global app obj +RECT g_rectNull = {0, 0, 0, 0}; +UINT g_uMsgHelp = 0; // help msg from ole2ui dialogs +BOOL g_fAppActive = FALSE; + +/* WinMain +** ------- +** Main routine for the Windows application. +*/ +int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + MSG msg; /* MSG structure to store your messages */ + LPSTR pszTemp; + +#if defined( OLE_VERSION ) + /* OLE2NOTE: it is recommended that all OLE applications to set + ** their message queue size to 96. this improves the capacity + ** and performance of OLE's LRPC mechanism. + */ + int cMsg = 96; // recommend msg queue size for OLE + while (cMsg && ! SetMessageQueue(cMsg)) // take largest size we can get. + cMsg -= 8; + if (! cMsg) + return -1; // ERROR: we got no message queue +#endif + +#if defined( USE_CTL3D ) + Ctl3dRegister(hInstance); + Ctl3dAutoSubclass(hInstance); +#endif + + if(! hPrevInstance) { + /* register window classes if first instance of application */ + if(! OutlineApp_InitApplication(lpOutlineApp, hInstance)) + return 0; + } + + /* Create App Frame window */ + if (! OutlineApp_InitInstance(lpOutlineApp, hInstance, nCmdShow)) + return 0; + + if( (pszTemp = strstr(lpszCmdLine, "-driver")) ) + { + //we were launched by the test driver + g_hwndDriver = (HWND)strtoul(pszTemp+8, &lpszCmdLine, 10); + } + else + { + g_hwndDriver = NULL; + } + + if (! OutlineApp_ParseCmdLine(lpOutlineApp, lpszCmdLine, nCmdShow)) + return 0; + + lpOutlineApp->m_hAccelApp = LoadAccelerators(hInstance, APPACCEL); + lpOutlineApp->m_hAccelFocusEdit = LoadAccelerators(hInstance, + FB_EDIT_ACCEL); + lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelApp; + lpOutlineApp->m_hWndAccelTarget = lpOutlineApp->m_hWndApp; + + if( g_hwndDriver ) + { + PostMessage(g_hwndDriver, WM_TESTREG, + (WPARAM)lpOutlineApp->m_hWndApp, 0); + } + + // Main message loop + while(GetMessage(&msg, NULL, 0, 0)) { /* Until WM_QUIT message */ + if(!MyTranslateAccelerator(&msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + +#if defined( OLE_VERSION ) + OleApp_TerminateApplication((LPOLEAPP)lpOutlineApp); +#else + /* OLE2NOTE: CoInitialize() is called in OutlineApp_InitInstance + ** and therefore we need to uninitialize it when exit. + */ + CoUninitialize(); +#endif + +#if defined( USE_CTL3D ) + Ctl3dUnregister(hInstance); +#endif + + return msg.wParam; + +} /* End of WinMain */ + +BOOL MyTranslateAccelerator(LPMSG lpmsg) +{ + // if it's not a keystroke it can not be an accelerator + if (lpmsg->message < WM_KEYFIRST || lpmsg->message > WM_KEYLAST) + return FALSE; + + if (g_lpApp->m_hWndAccelTarget && + TranslateAccelerator(g_lpApp->m_hWndAccelTarget, + g_lpApp->m_hAccel,lpmsg)) + return TRUE; + +#if defined( INPLACE_SVR ) + /* OLE2NOTE: if we are in-place active and we did not translate the + ** accelerator, we need to give the top-level (frame) in-place + ** container a chance to translate the accelerator. + ** we ONLY need to call OleTranslateAccelerator API if the + ** message is a keyboard message. otherwise it is harmless but + ** unnecessary. + ** + ** NOTE: even a in-place server that does NOT have any + ** Accelerators must still call OleTranslateAccelerator for all + ** keyboard messages so that the server's OWN menu mneumonics + ** (eg. &Edit -- Alt-e) function properly. + ** + ** NOTE: an in-place server MUST check that the accelerator is + ** NOT one of its own accelerators BEFORE calling + ** OleTranslateAccelerator which tries to see if it is a + ** container accelerator. if this is a server accelerator that + ** was not translateed because the associated menu command was + ** disabled, we MUST NOT call OleTranslateAccelerator. The + ** IsAccelerator helper API has been added to assist with this + ** check. + */ + if (g_OutlineApp.m_lpIPData && + !IsAccelerator(g_lpApp->m_hAccel, + GetAccelItemCount(g_lpApp->m_hAccel), lpmsg,NULL) && + OleTranslateAccelerator(g_OutlineApp.m_lpIPData->lpFrame, + (LPOLEINPLACEFRAMEINFO)&g_OutlineApp.m_lpIPData->frameInfo, + lpmsg) == NOERROR) { + return TRUE; + } +#endif + + return FALSE; +} + + +/************************************************************************/ +/* */ +/* Main Window Procedure */ +/* */ +/* This procedure provides service routines for the Windows events */ +/* (messages) that Windows sends to the window, as well as the user */ +/* initiated events (messages) that are generated when the user selects */ +/* the action bar and pulldown menu controls or the corresponding */ +/* keyboard accelerators. */ +/* */ +/************************************************************************/ + +LRESULT FAR PASCAL AppWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)GetWindowLong(hWnd, 0); + LPOUTLINEDOC lpOutlineDoc = NULL; +#if defined( OLE_VERSION ) + LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp; +#endif +#if defined( OLE_CNTR ) + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOutlineApp; +#endif + HWND hWndDoc = NULL; + +#if defined( USE_FRAMETOOLS ) + LPFRAMETOOLS lptb = OutlineApp_GetFrameTools(lpOutlineApp); +#endif + + if (lpOutlineApp) { + lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp); + + if (lpOutlineDoc) + hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc); + } + + switch (Message) { + case WM_TEST1: + StartClipboardTest1(lpOutlineApp); + break; + case WM_TEST2: + ContinueClipboardTest1(lpOutlineApp); + break; + case WM_COMMAND: + { +#ifdef WIN32 + WORD wID = LOWORD(wParam); +#else + WORD wID = wParam; +#endif + +#if defined( INPLACE_CNTR ) + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** m_fMenuHelpMode flag is set when F1 is pressed when a + ** menu item is selected. this flag is set in + ** IOleInPlaceFrame::ContextSensitveHelp method. + ** m_fCSHelpMode flag is set when SHIFT-F1 context + ** sensitive help is entered. this flag is set in + ** IOleInPlaceSite::ContextSensitiveHelp method. + ** if either of these flags are set then the WM_COMMAND + ** message is received then, the corresponding command + ** should NOT executed; help can be given (if desired). + ** also the context sensitve help mode should be exited. + ** the two different cases have their own way to exit + ** the mode (please refer to the technote). + */ + if (lpOleDoc && + (lpContainerApp->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) && + (wID > IDM_FILE) /* min wID for app command */ && + (wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) { + + if ((lpContainerApp->m_fMenuHelpMode)) { + LPOLEINPLACEACTIVEOBJECT lpIPActiveObj = + lpContainerApp->m_lpIPActiveObj; + + lpContainerApp->m_fMenuHelpMode = FALSE; + + // inform the in-place active object that we handled the + // menu help mode (F1) selection. + if (lpIPActiveObj) { + OLEDBG_BEGIN2("IOleInPlaceActiveObject::ContextSensitiveHelp(FALSE) called\r\n") + lpIPActiveObj->lpVtbl->ContextSensitiveHelp( + lpIPActiveObj, FALSE); + OLEDBG_END2 + } + } + + if ((lpOleDoc->m_fCSHelpMode)) { + LPOLEINPLACEOBJECT lpIPObj; + LPCONTAINERLINE lpLastIpActiveLine = + lpContainerDoc->m_lpLastIpActiveLine; + + lpOleDoc->m_fCSHelpMode = FALSE; + + /* inform immediate in-place container parent and, + ** if we were a container/server, immediate + ** in-place object children that we handled the + ** context sensitive help mode. + */ + if (lpLastIpActiveLine && + (lpIPObj=lpLastIpActiveLine->m_lpOleIPObj)!=NULL){ + OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp(FALSE) called\r\n") + lpIPObj->lpVtbl->ContextSensitiveHelp(lpIPObj, FALSE); + OLEDBG_END2 + } + } + + // if we provided help, we would do it here... + + // remove context sensitive help cursor + SetCursor(LoadCursor(NULL,IDC_ARROW)); + return 0L; + } +#endif // INPLACE_CNTR + + switch (wID) { + + case IDM_F_NEW: + OleDbgIndent(-2); // Reset debug output indent level + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_NewCommand\r\n") + OutlineApp_NewCommand(lpOutlineApp); + OLEDBG_END3 + +#if defined( OLE_CNTR ) + /* OLE2NOTE: this call will attempt to recover + ** resources by unloading DLL's that were loaded + ** by OLE and are no longer being used. it is a + ** good idea to call this API now and then if + ** your app tends to run for a long time. + ** otherwise these DLL's will be unloaded when + ** the app exits. some apps may want to call + ** this as part of idle-time processing. this + ** call is optional. + */ + OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n") + CoFreeUnusedLibraries(); + OLEDBG_END2 +#endif + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons( + OutlineApp_GetActiveDoc(lpOutlineApp)); +#endif + break; + + case IDM_F_OPEN: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_OpenCommand\r\n") + OutlineApp_OpenCommand(lpOutlineApp); + OLEDBG_END3 + +#if defined( OLE_CNTR ) + /* OLE2NOTE: this call will attempt to recover + ** resources by unloading DLL's that were loaded + ** by OLE and are no longer being used. it is a + ** good idea to call this API now and then if + ** your app tends to run for a long time. + ** otherwise these DLL's will be unloaded when + ** the app exits. some apps may want to call + ** this as part of idle-time processing. this + ** call is optional. + */ + OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n") + CoFreeUnusedLibraries(); + OLEDBG_END2 +#endif + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons( + OutlineApp_GetActiveDoc(lpOutlineApp)); +#endif + break; + + case IDM_F_SAVE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_SaveCommand\r\n") + OutlineApp_SaveCommand(lpOutlineApp); + OLEDBG_END3 + break; + + case IDM_F_SAVEAS: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_SaveAsCommand\r\n") + OutlineApp_SaveAsCommand(lpOutlineApp); + OLEDBG_END3 + break; + + case IDM_F_PRINT: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_PrintCommand\r\n") + OutlineApp_PrintCommand(lpOutlineApp); + OLEDBG_END3 + break; + + case IDM_F_PRINTERSETUP: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_PrinterSetupCommand\r\n") + OutlineApp_PrinterSetupCommand(lpOutlineApp); + OLEDBG_END3 + break; + + case IDM_F_EXIT: + SendMessage(hWnd, WM_CLOSE, 0, 0L); + break; + + case IDM_H_ABOUT: + OutlineApp_AboutCommand(lpOutlineApp); + break; + +#if defined( INPLACE_CNTR ) + case IDM_ESCAPE: + { + /* ESCAPE key pressed */ + LPCONTAINERDOC lpContainerDoc = + (LPCONTAINERDOC)lpOutlineDoc; + + /* OLE2NOTE: The standard OLE 2.0 UI convention + ** is to have ESCAPE key exit in-place + ** activation (ie. UIDeactivate). If + ** possible it is recommended for both + ** in-place servers AND in-place containers + ** to take responsibility to handle the + ** ESCAPE key accelerator. The server has + ** the first crack at handling accelerator + ** keys and normally the server should do + ** the UIDeactivation. It is a good idea for + ** in-place containers, in order to + ** guarantee consistent behavior, to also + ** handle the ESCAPE key and UIDeactivate + ** the object in case the object does not do + ** it itself. normally this should be + ** unnecessary. + */ + if (lpContainerDoc->m_lpLastUIActiveLine && + lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive) + { + ContainerLine_UIDeactivate( + lpContainerDoc->m_lpLastUIActiveLine); + } + break; + } +#endif // INPLACE_CNTR + + + default: + // forward message to document window + if (hWndDoc) { + return DocWndProc(hWndDoc, Message,wParam,lParam); + } + } + + break; /* End of WM_COMMAND */ + } + + case WM_INITMENU: + OutlineApp_InitMenu(lpOutlineApp, lpOutlineDoc, (HMENU)wParam); + break; + +#if defined( OLE_VERSION ) + + /* OLE2NOTE: WM_INITMENUPOPUP is trapped primarily for the Edit + ** menu. We didn't update the Edit menu until it is popped + ** up to avoid the overheads of the OLE calls which are + ** required to initialize some Edit menu items. + */ + case WM_INITMENUPOPUP: + { + HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1); +#if defined( INPLACE_CNTR ) + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + + /* OLE2NOTE: we must check if there is an object currently + ** in-place UIActive. if so, then our edit menu is not + ** on the menu; we do not want to bother updating the + ** edit menu when it is not even there. + */ + if (lpContainerDoc && lpContainerDoc->m_lpLastUIActiveLine && + lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive) + break; // an object is in-place UI active +#endif + if ((HMENU)wParam == hMenuEdit && + (LOWORD(lParam) == POS_EDITMENU) && + OleDoc_GetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc)) { + OleApp_UpdateEditMenu(lpOleApp, lpOutlineDoc, hMenuEdit); + } + break; + } +#endif // OLE_VERSION + + case WM_SIZE: + if (wParam != SIZE_MINIMIZED) + OutlineApp_ResizeWindows(lpOutlineApp); + break; + + + case WM_ACTIVATEAPP: +#if defined (OLE_CNTR) + if (g_fAppActive = (BOOL) wParam) + OleApp_QueryNewPalette(lpOleApp); +#endif + +#if defined( INPLACE_CNTR ) + { + BOOL fActivate = (BOOL)wParam; + LPOLEINPLACEACTIVEOBJECT lpIPActiveObj = + lpContainerApp->m_lpIPActiveObj; + + /* OLE2NOTE: the in-place container MUST inform the + ** inner most in-place active object (this is NOT + ** necessarily our immediate child if there are + ** nested levels of embedding) of the WM_ACTIVATEAPP + ** status. + */ + if (lpIPActiveObj) { +#if defined( _DEBUG ) + OLEDBG_BEGIN2((fActivate ? + "IOleInPlaceActiveObject::OnFrameWindowActivate(TRUE) called\r\n" : + "IOleInPlaceActiveObject::OnFrameWindowActivate(FALSE) called\r\n")) +#endif // _DEUBG + lpIPActiveObj->lpVtbl->OnFrameWindowActivate( + lpIPActiveObj, fActivate); + OLEDBG_END2 + } + } + +#endif // INPLACE_CNTR + + // OLE2NOTE: We can't call OutlineDoc_UpdateFrameToolButtons + // right away which + // would generate some OLE calls and eventually + // WM_ACTIVATEAPP and a loop was formed. Therefore, we + // should delay the frame tool initialization until + // WM_ACTIVATEAPP is finished by posting a message + // to ourselves. + // we want to ignore the WM_ACTIVATEAPP that comes + // as we bring up a modal dialog. + + /* Update enable/disable state of buttons in toolbar */ + if (wParam +#if defined( OLE_VERSION ) + && lpOleApp->m_cModalDlgActive == 0 +#endif + ) { + PostMessage(hWnd, WM_U_INITFRAMETOOLS, 0, 0L); + } + return 0L; + + case WM_SETFOCUS: + SetFocus(hWndDoc); + break; + + +#if defined( OLE_CNTR ) + case WM_QUERYNEWPALETTE: + if (!g_fAppActive) + return 0L; + + return OleApp_QueryNewPalette(lpOleApp); + + case WM_PALETTECHANGED: + { + HWND hWndPalChg = (HWND) wParam; + static BOOL fInPaletteChanged = FALSE; + + if (fInPaletteChanged) // Guard against recursion + return 0L; + + fInPaletteChanged = TRUE; + + if (hWnd != hWndPalChg) + wSelectPalette(hWnd, lpOleApp->m_hStdPal,TRUE/*fBackground*/); + +#if defined( INPLACE_CNTR ) + /* OLE2NOTE: always forward the WM_PALETTECHANGED message (via + ** SendMessage) to any in-place objects that currently have + ** their window visible. this gives these objects the chance + ** to select their palettes. this is + ** REQUIRED by all in-place containers independent of + ** whether they use color palettes themselves--their objects + ** may use color palettes. + ** (see ContainerDoc_ForwardPaletteChangedMsg for more info) + */ + if (lpOutlineDoc){ + ContainerDoc_ForwardPaletteChangedMsg( + (LPCONTAINERDOC)lpOutlineDoc, hWndPalChg); + } +#endif // INPLACE_CNTR + + fInPaletteChanged = FALSE; + return 0L; + } +#endif // OLE_CNTR + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_CLOSE: /* close the window */ + + /* Close all active documents. if successful, then exit */ + OleDbgOutNoPrefix2("\r\n"); + + OutlineApp_CloseAllDocsAndExitCommand(lpOutlineApp, FALSE); + break; + + case WM_QUERYENDSESSION: + { +#if defined( OLE_CNTR ) + /* OLE2NOTE: we are not able to make OLE LRPC calls when + ** WM_QUERYENDSESSION is recieved (this is a + ** SendMessage). this means, for example, that we are + ** NOT able to ask objects to save. thus the most we can + ** do is ask the user if he wants to exit with + ** discarding changes or else abort shutting down. + */ + + int nResponse = MessageBox( + hWnd, + "Discard changes?", + APPNAME, + MB_ICONQUESTION | MB_OKCANCEL + ); + if(nResponse == IDOK) + return 1L; /* can terminate */ + +#endif +#if defined( OLE_SERVER ) + /* OLE2NOTE: an embedded object should never prompt whether + ** it should be saved (according the OLE 2.0 User + ** Model). therefore, an embedded object will never + ** complain that it needs to be saved. it will always + ** allow the QueryEndSession to proceed. + */ + if (lpOutlineApp->m_lpDoc->m_docInitType == DOCTYPE_EMBEDDED) + return 1L; /* can terminate */ + else +#endif + { + /* this is not an embedded object; it is a user + ** document. we will prompt if the user wants to + ** save the document now in WM_QUERYENDSESSION. if + ** the user cancels then that would abort the + ** shutdown. if the user does not abort, then later + ** in WM_ENDSESSION the document will be actually + ** closed. + ** + ** Because this is an SDI app, there is only one + ** document. An MDI would need to loop through all + ** open documents. + */ + DWORD dwSaveOption = OLECLOSE_PROMPTSAVE; + if (OutlineDoc_CheckSaveChanges( + lpOutlineApp->m_lpDoc, &dwSaveOption)) + return 1L; /* can terminate */ + } + + /* else: can't terminate now */ + + break; + } + +#if defined( OLE_VERSION) + case WM_ENDSESSION: + { + BOOL fEndSession = (BOOL)wParam; + + if (fEndSession) { + OutlineApp_CloseAllDocsAndExitCommand(lpOutlineApp, TRUE); + return 0L; + } + } + break; +#endif // OLE_VERSION + + +#if defined( USE_STATUSBAR ) + case WM_MENUSELECT: + { + LPSTR lpszMessage; +#ifdef WIN32 + UINT fuFlags = (UINT)HIWORD(wParam); + UINT uItem = (UINT)LOWORD(wParam); +#else + UINT fuFlags = (UINT)LOWORD(lParam); + UINT uItem = (UINT)wParam; +#endif + + if (uItem == 0 && fuFlags == (UINT)-1) { + GetControlMessage(STATUS_READY, &lpszMessage); + OutlineApp_SetStatusText(lpOutlineApp, lpszMessage); + } + else if (fuFlags & MF_POPUP) { +#ifdef WIN32 + HMENU hMainMenu = (HMENU)lParam; + HMENU hPopupMenu = GetSubMenu(hMainMenu,uItem); +#else + HMENU hPopupMenu = (HMENU)wParam; +#endif + GetPopupMessage(hPopupMenu, &lpszMessage); + OutlineApp_SetStatusText(lpOutlineApp, lpszMessage); + } + else if (fuFlags & MF_SYSMENU) { + GetSysMenuMessage(uItem, &lpszMessage); + OutlineApp_SetStatusText(lpOutlineApp, lpszMessage); + } + else if (uItem != 0) { // Command Item + GetItemMessage(uItem, &lpszMessage); + OutlineApp_SetStatusText(lpOutlineApp, lpszMessage); + } + else { + GetControlMessage(STATUS_BLANK, &lpszMessage); + OutlineApp_SetStatusText(lpOutlineApp, lpszMessage); + } + break; + } +#endif // USE_STATUSBAR + + +#if defined( USE_FRAMETOOLS ) + case WM_U_INITFRAMETOOLS: + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); + break; +#endif + + default: + /* For any message for which you don't specifically provide a */ + /* service routine, you should return the message to Windows */ + /* for default message processing. */ + + return DefWindowProc(hWnd, Message, wParam, lParam); + } + + return (LRESULT)0; +} /* End of AppWndProc */ + + +/************************************************************************/ +/* */ +/* Document Window Procedure */ +/* */ +/* The Document Window is the parent of the OwnerDraw Listbox which */ +/* maintains the list of lines in the current document. This window */ +/* receives the ownerdraw callback messages from the list box. */ +/************************************************************************/ + +LRESULT FAR PASCAL DocWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)GetWindowLong(hWnd, 0); + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + LPSCALEFACTOR lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc); + +#if defined( OLE_VERSION ) + LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; +#if defined( OLE_CNTR ) + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; +#endif +#if defined( OLE_SERVER ) + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; +#endif +#if defined( INPLACE_CNTR ) + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOutlineApp; +#endif +#endif // OLE_VERSION + + switch(Message) { + +#if defined( INPLACE_SVR ) + + /* OLE2NOTE: ISVROTL doesn't use color palettes. The inplace objects + ** that use color palettes must implement the following + ** lines of code. + ** + case WM_QUERYNEWPALETTE: + return wSelectPalette(hWnd, hPal, FALSE); // foreground + + case WM_PALETTECHANGED: + if (hWnd != (HWND) wParam) + wSelectPalette(hWnd, hPal, TRUE); // background + break; + ** + ** + ** + */ +#endif + + case WM_MEASUREITEM: + { + LPMEASUREITEMSTRUCT lpmis = ((LPMEASUREITEMSTRUCT)lParam); + + switch (wParam) { + case IDC_LINELIST: + { + HDC hDC = LineList_GetDC(lpLL); + UINT uHeight; + + uHeight=Line_GetHeightInHimetric((LPLINE)lpmis->itemData); + uHeight = XformHeightInHimetricToPixels(hDC, uHeight); + uHeight = (UINT) (uHeight * lpscale->dwSyN / + lpscale->dwSyD); + + if (uHeight >LISTBOX_HEIGHT_LIMIT) + uHeight = LISTBOX_HEIGHT_LIMIT; + + lpmis->itemHeight = uHeight; + LineList_ReleaseDC(lpLL, hDC); + break; + } + + case IDC_NAMETABLE: + { + // NOTE: NameTable is never made visible. do nothing. + break; + } + +#if defined( USE_HEADING ) + case IDC_ROWHEADING: + { + UINT uHeight; + + uHeight = LOWORD(lpmis->itemData); + uHeight = (UINT) (uHeight * lpscale->dwSyN / + lpscale->dwSyD); + if (uHeight >LISTBOX_HEIGHT_LIMIT) + uHeight = LISTBOX_HEIGHT_LIMIT; + lpmis->itemHeight = uHeight; + break; + } + + case IDC_COLHEADING: + { + UINT uHeight; + + uHeight = LOWORD(lpmis->itemData); + uHeight = (UINT) (uHeight * lpscale->dwSyN / + lpscale->dwSyD); + if (uHeight > LISTBOX_HEIGHT_LIMIT) + uHeight = LISTBOX_HEIGHT_LIMIT; + lpmis->itemHeight = uHeight; + break; + } +#endif // USE_HEADING + + } + return (LRESULT)TRUE; + } + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT lpdis = ((LPDRAWITEMSTRUCT)lParam); + + switch (lpdis->CtlID) { + + case IDC_LINELIST: + { + RECT rcClient; + RECT rcDevice; + HWND hWndLL = LineList_GetWindow(lpLL); + LPLINE lpLine = (LPLINE)lpdis->itemData; + + // NOTE: When itemID == -1, the listbox is empty. + // We are supposed to draw focus rect only + // But it is not done in this app. If this line is + // removed, the app will crash in Line_DrawToScreen + // because of invalid lpLine. + if (lpdis->itemID == -1) + break; + + GetClientRect(hWndLL, &rcClient); + + rcDevice = lpdis->rcItem; + + // shift the item rect to account for horizontal scrolling + + rcDevice.left += rcClient.right - lpdis->rcItem.right; + +#if defined( OLE_CNTR ) + /* we need to remember the horizontal scroll offset + ** needed for the in-place object's window. + ** (this is specific to ICNTROTL) + */ + if(lpdis->itemAction & ODA_DRAWENTIRE) { + if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) + ((LPCONTAINERLINE)lpLine)->m_nHorizScrollShift = + rcDevice.left; + } +#endif // OLE_CNTR + + // shift rect for left margin + rcDevice.left += (int)(XformWidthInHimetricToPixels(NULL, + LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) * + lpscale->dwSxN / lpscale->dwSxD); + + rcDevice.right = rcDevice.left + + (int)(XformWidthInHimetricToPixels(lpdis->hDC, + Line_GetWidthInHimetric(lpLine)) * + lpscale->dwSxN / lpscale->dwSxD); + + Line_DrawToScreen( + lpLine, + lpdis->hDC, + &lpdis->rcItem, + lpdis->itemAction, + lpdis->itemState, + &rcDevice + ); + +#if defined( USE_FRAMETOOLS ) + if (lpdis->itemState & ODS_FOCUS) + OutlineDoc_SetFormulaBarEditText(lpOutlineDoc,lpLine); +#endif + break; + } + case IDC_NAMETABLE: + { + // NOTE: NameTable is never made visible. do nothing + break; + } + +#if defined( USE_HEADING ) + case IDC_ROWHEADING: + { + LPHEADING lphead; + + // Last dummy item shouldn't be drawn + if (lpdis->itemID == (UINT)LineList_GetCount(lpLL)) + break; + + // only DrawEntire need be trapped as window is disabled + if (lpdis->itemAction == ODA_DRAWENTIRE) { + lphead = OutlineDoc_GetHeading(lpOutlineDoc); + Heading_RH_Draw(lphead, lpdis); + } + break; + } + + case IDC_COLHEADING: + { + RECT rect; + RECT rcDevice; + RECT rcLogical; + LPHEADING lphead; + + // only DrawEntire need be trapped as window is disabled + if (lpdis->itemAction == ODA_DRAWENTIRE) { + lphead = OutlineDoc_GetHeading(lpOutlineDoc); + GetClientRect(lpdis->hwndItem, &rect); + + rcDevice = lpdis->rcItem; + + // shift the item rect to account for + // horizontal scrolling + rcDevice.left = -(rcDevice.right - rect.right); + + // shift rect for left margin + rcDevice.left += (int)(XformWidthInHimetricToPixels( + NULL, + LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) * + lpscale->dwSxN / lpscale->dwSxD); + + rcDevice.right = rcDevice.left + (int)lpscale->dwSxN; + rcLogical.left = 0; + rcLogical.bottom = 0; + rcLogical.right = (int)lpscale->dwSxD; + rcLogical.top = LOWORD(lpdis->itemData); + + Heading_CH_Draw(lphead, lpdis, &rcDevice, &rcLogical); + } + break; + } +#endif // USE_HEADING + + } + return (LRESULT)TRUE; + } + + case WM_SETFOCUS: + if (lpLL) + SetFocus(LineList_GetWindow(lpLL)); + break; + +#if !defined( OLE_VERSION ) + case WM_RENDERFORMAT: + { + LPOUTLINEDOC lpClipboardDoc = lpOutlineApp->m_lpClipboardDoc; + if (lpClipboardDoc) + OutlineDoc_RenderFormat(lpClipboardDoc, wParam); + + break; + } + case WM_RENDERALLFORMATS: + { + LPOUTLINEDOC lpClipboardDoc = lpOutlineApp->m_lpClipboardDoc; + if (lpClipboardDoc) + OutlineDoc_RenderAllFormats(lpClipboardDoc); + + break; + } + case WM_DESTROYCLIPBOARD: + if (g_lpApp->m_lpClipboardDoc) { + OutlineDoc_Destroy(g_lpApp->m_lpClipboardDoc); + g_lpApp->m_lpClipboardDoc = NULL; + } + break; + +#endif // OLE_VERSION + +#if defined( OLE_CNTR ) + case WM_U_UPDATEOBJECTEXTENT: + { + /* Update the extents of any OLE object that is marked that + ** its size may have changed. when an + ** IAdviseSink::OnViewChange notification is received, + ** the corresponding ContainerLine is marked + ** (m_fDoGetExtent==TRUE) and a message + ** (WM_U_UPDATEOBJECTEXTENT) is posted to the document + ** indicating that there are dirty objects. + */ + ContainerDoc_UpdateExtentOfAllOleObjects(lpContainerDoc); + break; + } +#endif // OLE_CNTR + +#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR ) + /* OLE2NOTE: Any window that is used during in-place activation + ** must handle the WM_SETCURSOR message or else the cursor + ** of the in-place parent will be used. if WM_SETCURSOR is + ** not handled, then DefWindowProc sends the message to the + ** window's parent. + ** + ** see context sensitive help technote (CSHELP.DOC). + ** m_fCSHelpMode flag is set when SHIFT-F1 context + ** sensitive help is entered. + ** if this flag is set then the context sensitive help + ** cursor should be shown. + */ + case WM_SETCURSOR: + if (lpOleDoc->m_fCSHelpMode) + SetCursor(UICursorLoad(IDC_CONTEXTHELP)); + else + SetCursor(LoadCursor(NULL, IDC_ARROW) ); + return (LRESULT)TRUE; +#endif // INPLACE_SVR || INPLACE_CNTR + +#if defined( INPLACE_SVR ) + /* OLE2NOTE: when the in-place active, our in-place server + ** document window (passed to IOleInPlaceFrame::SetMenu) + ** will receive the WM_INITMENU and WM_INITMENUPOPUP messages. + */ + case WM_INITMENU: + OutlineApp_InitMenu(lpOutlineApp, lpOutlineDoc, (HMENU)wParam); + break; + + /* OLE2NOTE: WM_INITMENUPOPUP is trapped primarily for the Edit + ** menu. We didn't update the Edit menu until it is popped + ** up to avoid the overheads of the OLE calls which are + ** required to initialize some Edit menu items. + */ + case WM_INITMENUPOPUP: + { + HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1); + if ((HMENU)wParam == hMenuEdit && + (LOWORD(lParam) == POS_EDITMENU) && + OleDoc_GetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc)) { + OleApp_UpdateEditMenu( + (LPOLEAPP)lpOutlineApp, lpOutlineDoc, hMenuEdit); + } + break; + } +#endif // INPLACE_SVR + +#if defined( INPLACE_SVR ) && defined( USE_STATUSBAR ) + /* OLE2NOTE: when the server is in-place active the + ** WM_MENUSELECT message is sent to the object's window and + ** not the server app's frame window. processing this + ** message allows there in-place server to give status bar + ** help text for menu commands. + */ + case WM_MENUSELECT: + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + LPSTR lpszMessage; +#ifdef WIN32 + UINT fuFlags = (UINT)HIWORD(wParam); + UINT uItem = (UINT)LOWORD(wParam); +#else + UINT fuFlags = (UINT)LOWORD(lParam); + UINT uItem = (UINT)wParam; +#endif + + if (uItem == 0 && fuFlags == (UINT)-1) { + GetControlMessage(STATUS_READY, &lpszMessage); + ServerDoc_SetStatusText(lpServerDoc, lpszMessage); + } + else if (fuFlags & MF_POPUP) { +#ifdef WIN32 + HMENU hMainMenu = (HMENU)lParam; + HMENU hPopupMenu = GetSubMenu(hMainMenu,uItem); +#else + HMENU hPopupMenu = (HMENU)wParam; +#endif + GetPopupMessage(hPopupMenu, &lpszMessage); + ServerDoc_SetStatusText(lpServerDoc, lpszMessage); + } + else if (uItem != 0) { // Command Item + GetItemMessage(uItem, &lpszMessage); + ServerDoc_SetStatusText(lpServerDoc, lpszMessage); + } + else { + GetControlMessage(STATUS_BLANK, &lpszMessage); + ServerDoc_SetStatusText(lpServerDoc, lpszMessage); + } + break; + } +#endif // INPLACE_SVR && USE_STATUSBAR +#if defined( INPLACE_SVR ) && defined( USE_FRAMETOOLS ) + + case WM_U_INITFRAMETOOLS: + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); + break; +#endif // INPLACE_SVR && USE_FRAMETOOLS + + + case WM_COMMAND: + { +#ifdef WIN32 + WORD wNotifyCode = HIWORD(wParam); + WORD wID = LOWORD(wParam); + HWND hwndCtl = (HWND) lParam; +#else + WORD wNotifyCode = HIWORD(lParam); + WORD wID = wParam; + HWND hwndCtl = (HWND) LOWORD(lParam); +#endif + +#if defined( INPLACE_SVR ) + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** m_fMenuHelpMode flag is set when F1 is pressed when a + ** menu item is selected. this flag is set in + ** IOleInPlaceActiveObject::ContextSensitveHelp method. + ** m_fCSHelpMode flag is set when SHIFT-F1 context + ** sensitive help is entered. this flag is set in + ** IOleInPlaceObject::ContextSensitiveHelp method. + ** if either of these flags are set then the WM_COMMAND + ** message is received then, the corresponding command + ** should NOT executed; help can be given (if desired). + ** also the context sensitve help mode should be exited. + ** the two different cases have their own way to exit + ** the mode (please refer to the technote). + */ + if (lpOleDoc && + (lpServerDoc->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) && + (wID > IDM_FILE) /* min wID for app command */ && + (wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) { + + if ((lpServerDoc->m_fMenuHelpMode)) { + LPOLEINPLACEFRAME lpFrame; + + lpServerDoc->m_fMenuHelpMode = FALSE; + + // inform top-level frame that we handled the + // menu help mode (F1) selection. + if (lpServerDoc->m_lpIPData && + (lpFrame=lpServerDoc->m_lpIPData->lpFrame)!=NULL){ + OLEDBG_BEGIN2("IOleInPlaceFrame::ContextSensitiveHelp(FALSE) called\r\n") + lpFrame->lpVtbl->ContextSensitiveHelp(lpFrame, FALSE); + OLEDBG_END2 + } + } + + if ((lpOleDoc->m_fCSHelpMode)) { + LPOLEINPLACESITE lpSite; + + lpOleDoc->m_fCSHelpMode = FALSE; + + /* inform immediate in-place container parent and, + ** if we were a container/server, immediate + ** in-place object children that we handled the + ** context sensitive help mode. + */ + if (lpServerDoc->m_lpIPData && + (lpSite=lpServerDoc->m_lpIPData->lpSite) !=NULL) { + OLEDBG_BEGIN2("IOleInPlaceSite::ContextSensitiveHelp(FALSE) called\r\n") + lpSite->lpVtbl->ContextSensitiveHelp(lpSite, FALSE); + OLEDBG_END2 + } + } + + // if we provided help, we would do it here... + + // remove context sensitive help cursor + SetCursor(LoadCursor(NULL,IDC_ARROW)); + return 0L; + } +#endif // INPLACE_SVR +#if defined( INPLACE_CNTR ) + + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** m_fMenuHelpMode flag is set when F1 is pressed when a + ** menu item is selected. this flag is set in + ** IOleInPlaceFrame::ContextSensitveHelp method. + ** m_fCSHelpMode flag is set when SHIFT-F1 context + ** sensitive help is entered. this flag is set in + ** IOleInPlaceSite::ContextSensitiveHelp method. + ** if either of these flags are set then the WM_COMMAND + ** message is received then, the corresponding command + ** should NOT executed; help can be given (if desired). + ** also the context sensitve help mode should be exited. + ** the two different cases have their own way to exit + ** the mode (please refer to the technote). + */ + if (lpOleDoc && + (lpContainerApp->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) && + (wID > IDM_FILE) /* min wID for app command */ && + (wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) { + + if ((lpContainerApp->m_fMenuHelpMode)) { + LPOLEINPLACEACTIVEOBJECT lpIPActiveObj = + lpContainerApp->m_lpIPActiveObj; + + lpContainerApp->m_fMenuHelpMode = FALSE; + + // inform the in-place active object that we handled the + // menu help mode (F1) selection. + if (lpIPActiveObj) { + OLEDBG_BEGIN2("IOleInPlaceActiveObject::ContextSensitiveHelp(FALSE) called\r\n") + lpIPActiveObj->lpVtbl->ContextSensitiveHelp( + lpIPActiveObj, FALSE); + OLEDBG_END2 + } + } + + if ((lpOleDoc->m_fCSHelpMode)) { + LPOLEINPLACEOBJECT lpIPObj; + LPCONTAINERLINE lpLastIpActiveLine = + lpContainerDoc->m_lpLastIpActiveLine; + + lpOleDoc->m_fCSHelpMode = FALSE; + + /* inform immediate in-place container parent and, + ** if we were a container/server, immediate + ** in-place object children that we handled the + ** context sensitive help mode. + */ + if (lpLastIpActiveLine && + (lpIPObj=lpLastIpActiveLine->m_lpOleIPObj)!=NULL){ + OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp(FALSE) called\r\n") + lpIPObj->lpVtbl->ContextSensitiveHelp(lpIPObj, FALSE); + OLEDBG_END2 + } + } + + // if we provided help, we would do it here... + + // remove context sensitive help cursor + SetCursor(LoadCursor(NULL,IDC_ARROW)); + return 0L; + } +#endif // INPLACE_CNTR + + switch (wID) { + + /********************************************************* + ** File new, open, save and print as well as Help about + ** are duplicated in this switch statement and they are + ** used to trap the message from the toolbar + ** + *********************************************************/ + + case IDM_F_NEW: + OleDbgIndent(-2); // Reset debug output indent level + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_NewCommand\r\n") + OutlineApp_NewCommand(lpOutlineApp); + OLEDBG_END3 + +#if defined( OLE_CNTR ) + /* OLE2NOTE: this call will attempt to recover + ** resources by unloading DLL's that were loaded + ** by OLE and are no longer being used. it is a + ** good idea to call this API now and then if + ** your app tends to run for a long time. + ** otherwise these DLL's will be unloaded when + ** the app exits. some apps may want to call + ** this as part of idle-time processing. this + ** call is optional. + */ + OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n") + CoFreeUnusedLibraries(); + OLEDBG_END2 +#endif + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons( + OutlineApp_GetActiveDoc(lpOutlineApp)); +#endif + break; + + case IDM_F_OPEN: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_OpenCommand\r\n") + OutlineApp_OpenCommand(lpOutlineApp); + OLEDBG_END3 + +#if defined( OLE_CNTR ) + /* OLE2NOTE: this call will attempt to recover + ** resources by unloading DLL's that were loaded + ** by OLE and are no longer being used. it is a + ** good idea to call this API now and then if + ** your app tends to run for a long time. + ** otherwise these DLL's will be unloaded when + ** the app exits. some apps may want to call + ** this as part of idle-time processing. this + ** call is optional. + */ + OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n") + CoFreeUnusedLibraries(); + OLEDBG_END2 +#endif + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons( + OutlineApp_GetActiveDoc(lpOutlineApp)); +#endif + break; + + case IDM_F_SAVE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_SaveCommand\r\n") + OutlineApp_SaveCommand(lpOutlineApp); + OLEDBG_END3 + break; + + case IDM_F_PRINT: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineApp_PrintCommand\r\n") + OutlineApp_PrintCommand(lpOutlineApp); + OLEDBG_END3 + break; + + + case IDM_E_UNDO: + // SORRY. NOT IMPLEMENTED + break; + + case IDM_E_CUT: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_CutCommand\r\n") + OutlineDoc_CutCommand(lpOutlineDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + + case IDM_E_COPY: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_CopyCommand\r\n") + OutlineDoc_CopyCommand(lpOutlineDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + + case IDM_E_PASTE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_PasteCommand\r\n") + OutlineDoc_PasteCommand(lpOutlineDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + +#if defined( OLE_VERSION ) + case IDM_E_PASTESPECIAL: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OleDoc_PasteSpecialCommand\r\n") + OleDoc_PasteSpecialCommand((LPOLEDOC)lpOutlineDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + +#endif // OLE_VERSION + + case IDM_E_CLEAR: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_ClearCommand\r\n") + OutlineDoc_ClearCommand(lpOutlineDoc); + OLEDBG_END3 + +#if defined( OLE_CNTR ) + /* OLE2NOTE: this call will attempt to recover + ** resources by unloading DLL's that were loaded + ** by OLE and are no longer being used. it is a + ** good idea to call this API now and then if + ** your app tends to run for a long time. + ** otherwise these DLL's will be unloaded when + ** the app exits. some apps may want to call + ** this as part of idle-time processing. this + ** call is optional. + */ + OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n") + CoFreeUnusedLibraries(); + OLEDBG_END2 +#endif + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + + case IDM_L_ADDLINE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_AddTextLineCommand\r\n") + OutlineDoc_AddTextLineCommand(lpOutlineDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); + SetFocus(LineList_GetWindow(lpLL)); +#endif + break; + + case IDM_L_EDITLINE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_EditLineCommand\r\n") + OutlineDoc_EditLineCommand(lpOutlineDoc); + OLEDBG_END3 + SetFocus(LineList_GetWindow(lpLL)); + break; + + case IDM_L_INDENTLINE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_IndentCommand\r\n") + OutlineDoc_IndentCommand(lpOutlineDoc); + OLEDBG_END3 + break; + + case IDM_L_UNINDENTLINE: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_UnindentCommand\r\n") + OutlineDoc_UnindentCommand(lpOutlineDoc); + OLEDBG_END3 + break; + + case IDM_L_SETLINEHEIGHT: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_SetLineHeight\r\n") + OutlineDoc_SetLineHeightCommand(lpOutlineDoc); + OLEDBG_END3 + break; + + case IDM_E_SELECTALL: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_SelectAllCommand\r\n") + OutlineDoc_SelectAllCommand(lpOutlineDoc); + OLEDBG_END3 + break; + +#if defined( OLE_CNTR ) + case IDM_E_INSERTOBJECT: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("ContainerDoc_InsertOleObjectCommand\r\n") + ContainerDoc_InsertOleObjectCommand(lpContainerDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + + case IDM_E_EDITLINKS: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("ContainerDoc_EditLinksCommand\r\n") + ContainerDoc_EditLinksCommand(lpContainerDoc); + OLEDBG_END3 + break; + + case IDM_E_CONVERTVERB: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("ContainerDoc_ConvertCommand\r\n") + ContainerDoc_ConvertCommand( + lpContainerDoc, FALSE /*fMustActivate*/); + OLEDBG_END3 + break; + + + case IDM_E_PASTELINK: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("ContainerDoc_PasteLinkCommand\r\n") + ContainerDoc_PasteLinkCommand(lpContainerDoc); + OLEDBG_END3 + +#if defined( USE_FRAMETOOLS ) + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif + break; + +#endif // OLE_CNTR + + case IDM_N_DEFINENAME: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_DefineNameCommand\r\n") + OutlineDoc_DefineNameCommand(lpOutlineDoc); + OLEDBG_END3 + break; + + case IDM_N_GOTONAME: + OleDbgOutNoPrefix2("\r\n"); + + OLEDBG_BEGIN3("OutlineDoc_GotoNameCommand\r\n") + OutlineDoc_GotoNameCommand(lpOutlineDoc); + OLEDBG_END3 + break; + +#if defined( USE_FRAMETOOLS ) + case IDM_O_BB_TOP: + FrameTools_BB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_TOP); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_O_BB_BOTTOM: + FrameTools_BB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_BOTTOM); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_O_BB_POPUP: + FrameTools_BB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_POPUP); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_O_BB_HIDE: + FrameTools_BB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_HIDE); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_O_FB_TOP: + FrameTools_FB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_TOP); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_O_FB_BOTTOM: + FrameTools_FB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_BOTTOM); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_O_FB_POPUP: + FrameTools_FB_SetState( + lpOutlineDoc->m_lpFrameTools, BARSTATE_POPUP); + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + break; + + case IDM_FB_EDIT: + + switch (wNotifyCode) { + case EN_SETFOCUS: + OutlineDoc_SetFormulaBarEditFocus( + lpOutlineDoc, TRUE); + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); + break; + + case EN_KILLFOCUS: + OutlineDoc_SetFormulaBarEditFocus( + lpOutlineDoc, FALSE); + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); + break; + } + break; + + case IDM_FB_CANCEL: + + SetFocus(hWnd); + break; + + + case IDM_F2: + SendMessage(hWnd, WM_COMMAND, (WPARAM)IDM_FB_EDIT, + MAKELONG(0, EN_SETFOCUS)); + break; +#endif // USE_FRAMETOOLS + + case IDM_ESCAPE: + /* ESCAPE key pressed */ + +#if defined( USE_FRAMETOOLS ) + if (OutlineDoc_IsEditFocusInFormulaBar(lpOutlineDoc)) + SendMessage( + hWnd, WM_COMMAND,(WPARAM)IDM_FB_CANCEL,(LPARAM)0); +#endif // USE_FRAMETOOLS + +#if defined( INPLACE_SVR ) + else { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + + /* OLE2NOTE: The standard OLE 2.0 UI convention + ** is to have ESCAPE key exit in-place + ** activation (ie. UIDeactivate). If + ** possible it is recommended for both + ** in-place servers AND in-place containers + ** to take responsibility to handle the + ** ESCAPE key accelerator. The server has + ** the first crack at handling accelerator + ** keys and normally the server should do + ** the UIDeactivation. + */ + if (lpServerDoc->m_fUIActive) { + SvrDoc_IPObj_UIDeactivate( (LPOLEINPLACEOBJECT)& + lpServerDoc->m_OleInPlaceObject); + } + } +#endif // INPLACE_SVR + + break; + + +#if defined( USE_HEADING ) + case IDC_BUTTON: + if (wNotifyCode == BN_CLICKED) { + SendMessage(hWnd, WM_COMMAND, IDM_E_SELECTALL, 0L); + SetFocus(hWnd); + } + break; + + case IDM_O_HEAD_SHOW: + OutlineDoc_ShowHeading(lpOutlineDoc, TRUE); + break; + + case IDM_O_HEAD_HIDE: + OutlineDoc_ShowHeading(lpOutlineDoc, FALSE); + break; +#endif // USE_HEADING + + +#if defined( OLE_CNTR ) + case IDM_O_SHOWOBJECT: + { + LPCONTAINERDOC lpContainerDoc = + (LPCONTAINERDOC)lpOutlineDoc; + BOOL fShowObject; + + fShowObject = !ContainerDoc_GetShowObjectFlag( + lpContainerDoc); + ContainerDoc_SetShowObjectFlag( + lpContainerDoc, fShowObject); + LineList_ForceRedraw(lpLL, TRUE); + + break; + } +#endif // OLE_CNTR + +#if !defined( OLE_CNTR ) + // Container does not allow zoom factors > 100% + case IDM_V_ZOOM_400: + case IDM_V_ZOOM_300: + case IDM_V_ZOOM_200: +#endif // !OLE_CNTR + + case IDM_V_ZOOM_100: + case IDM_V_ZOOM_75: + case IDM_V_ZOOM_50: + case IDM_V_ZOOM_25: + OutlineDoc_SetCurrentZoomCommand(lpOutlineDoc, wID); + break; + + case IDM_V_SETMARGIN_0: + case IDM_V_SETMARGIN_1: + case IDM_V_SETMARGIN_2: + case IDM_V_SETMARGIN_3: + case IDM_V_SETMARGIN_4: + OutlineDoc_SetCurrentMarginCommand(lpOutlineDoc, wID); + break; + + case IDM_V_ADDTOP_1: + case IDM_V_ADDTOP_2: + case IDM_V_ADDTOP_3: + case IDM_V_ADDTOP_4: + { + UINT nHeightInHimetric; + + switch (wID) { + case IDM_V_ADDTOP_1: + nHeightInHimetric = 1000; + break; + + case IDM_V_ADDTOP_2: + nHeightInHimetric = 2000; + break; + + case IDM_V_ADDTOP_3: + nHeightInHimetric = 3000; + break; + + case IDM_V_ADDTOP_4: + nHeightInHimetric = 4000; + break; + } + + OutlineDoc_AddTopLineCommand( + lpOutlineDoc, nHeightInHimetric); + break; + } + + + case IDM_H_ABOUT: + OutlineApp_AboutCommand(lpOutlineApp); + break; + + case IDM_D_DEBUGLEVEL: + SetDebugLevelCommand(); + break; + +#if defined( OLE_VERSION ) + case IDM_D_INSTALLMSGFILTER: + InstallMessageFilterCommand(); + break; + + case IDM_D_REJECTINCOMING: + RejectIncomingCommand(); + break; +#endif // OLE_VERSION + +#if defined( INPLACE_CNTR ) + case IDM_D_INSIDEOUT: + g_fInsideOutContainer = !g_fInsideOutContainer; + + // force all object to unload so they can start new + // activation behavior. + ContainerDoc_UnloadAllOleObjectsOfClass( + (LPCONTAINERDOC)lpOutlineDoc, + &CLSID_NULL, + OLECLOSE_SAVEIFDIRTY + ); + OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE); + break; +#endif // INPLACE_CNTR + + +#if defined( OLE_CNTR ) + case IDC_LINELIST: { + + if (wNotifyCode == LBN_DBLCLK) { + + /* OLE2NOTE: a container should execute the + ** OLEIVERB_PRIMARY verb on an OLE object + ** when the user DBLCLK's the object. + */ + int nIndex = LineList_GetFocusLineIndex(lpLL); + LPLINE lpLine = LineList_GetLine(lpLL, nIndex); + + if (lpLine && + Line_GetLineType(lpLine)==CONTAINERLINETYPE) { + MSG msg; + + _fmemset((LPMSG)&msg,0,sizeof(msg)); + msg.hwnd = hWnd; + msg.message = Message; + msg.wParam = wParam; + msg.lParam = lParam; + + ContainerLine_DoVerb( + (LPCONTAINERLINE)lpLine, + OLEIVERB_PRIMARY, + (LPMSG)&msg, + TRUE, + TRUE + ); + } + +#if defined( INPLACE_CNTR ) + { // BEGIN BLOCK + LPCONTAINERDOC lpContainerDoc = + (LPCONTAINERDOC) lpOutlineDoc; + if (lpContainerDoc->m_fAddMyUI) { + /* OLE2NOTE: fAddMyUI is TRUE when + ** there was previously an in-place + ** active object which got + ** UIDeactivated as a result of this + ** DBLCLK AND the DBLCLK did NOT + ** result in in-place activating + ** another object. + ** (see IOleInPlaceSite::OnUIActivate and + ** IOleInPlaceSite::OnUIDeactivate + ** methods). + */ + + /* OLE2NOTE: You need to generate + ** QueryNewPalette only if you own + ** the top level frame (ie. you are + ** a top-level inplace container). + */ + + + OleApp_QueryNewPalette((LPOLEAPP)g_lpApp); + +#if defined( USE_DOCTOOLS ) + ContainerDoc_AddDocLevelTools(lpContainerDoc); +#endif + +#if defined( USE_FRAMETOOLS ) + ContainerDoc_AddFrameLevelUI(lpContainerDoc); +#endif + lpContainerDoc->m_fAddMyUI = FALSE; + } + } // END BLOCK +#endif // INPLACE_CNTR + } + break; + } +#endif // OLE_CNTR + + + default: + +#if defined( OLE_CNTR ) + if (wID >= IDM_E_OBJECTVERBMIN) { + + OleDbgOutNoPrefix2("\r\n"); + OLEDBG_BEGIN3("ContainerDoc_ContainerLineDoVerbCommand\r\n") + ContainerDoc_ContainerLineDoVerbCommand( + (LPCONTAINERDOC)lpOutlineDoc, + (LONG)(wID-IDM_E_OBJECTVERBMIN) + ); + OLEDBG_END3 + break; + } +#endif // OLE_CNTR + return DefWindowProc(hWnd, Message, wParam, lParam); + } + + break; /* End of WM_COMMAND */ + } + default: + + if (Message == g_uMsgHelp) { + /* Handle OLE2UI dialog's help messages. + ** We get the hDlg of the dialog that called us in the wParam + ** and the dialog type in the LOWORD of the lParam, + ** so we pass this along to our help function. + */ + OutlineDoc_DialogHelp((HWND)wParam, LOWORD(lParam)); + break; + } + + /* For any message for which you don't specifically provide a */ + /* service routine, you should return the message to Windows */ + /* for default message processing. */ + return DefWindowProc(hWnd, Message, wParam, lParam); + } + + return (LRESULT)0; + +} /* End of DocWndProc */ + + + +//*********************************************************************** +//* +//* LineListWndProc() Drag and Drop Listbox Window Proc Sub-Class +//* +//* Sub Class the Ownerdraw list box in order to activate the drag drop. +//*********************************************************************** + +LRESULT FAR PASCAL LineListWndProc( + HWND hWnd, + UINT Message, + WPARAM wParam, + LPARAM lParam +) +{ + HWND hwndParent = GetParent ( hWnd ); + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC) GetWindowLong( hwndParent, 0 ); + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + +#if defined( OLE_VERSION ) + LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; +#endif // OLE_VERSION + +#if defined( INPLACE_SVR ) + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + static BOOL fUIActivateClick = FALSE; + static BOOL fInWinPosChged = FALSE; +#endif // INPLACE_SVR + +#if defined( INPLACE_CNTR ) + LPCONTAINERAPP lpContainerApp=(LPCONTAINERAPP)lpOutlineApp; + LPCONTAINERDOC lpContainerDoc=(LPCONTAINERDOC)lpOutlineDoc; +#endif // INPLACE_CNTR + + switch (Message) { + + case WM_KILLFOCUS: + /* OLE2NOTE: when our window looses focus we + ** should not display any active selection + */ +#if defined( INPLACE_CNTR ) + if (! lpContainerApp->m_fPendingUIDeactivate) +#endif // INPLACE_CNTR + LineList_RemoveSel(lpLL); + break; + + case WM_SETFOCUS: + +#if defined( INPLACE_CNTR ) + { + HWND hWndObj=ContainerDoc_GetUIActiveWindow(lpContainerDoc); + + /* OLE2NOTE: if there is a UIActive in-place object, we must + ** forward focus to its window as long as there is + ** not a pending UIDeactivate. if the mouse is + ** clicked outside of the object and the object is + ** about to be deactivated then we do NOT want to + ** forward focus to the object. we do NOT want it to + ** restore its selection feedback. + */ + if (lpContainerApp->m_fPendingUIDeactivate) + break; + else if (hWndObj) { + SetFocus(hWndObj); + break; // do not restore containers selection state + } + } +#endif // INPLACE_CNTR + + /* OLE2NOTE: when our window gains focus we + ** should restore the previous selection + */ + LineList_RestoreSel(lpLL); + + break; + +#if defined( INPLACE_SVR ) + case WM_MOUSEACTIVATE: + { + if (lpServerDoc->m_fInPlaceActive && !lpServerDoc->m_fUIActive) { + fUIActivateClick = TRUE; + }; + break; + } + +#endif // INPLACE_SVR + + +#if defined( USE_FRAMETOOLS ) + case WM_CHAR: + { + OutlineDoc_SetFormulaBarEditFocus(lpOutlineDoc, TRUE); + FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, NULL); + FrameTools_FB_SendMessage( + lpOutlineDoc->m_lpFrameTools, + IDM_FB_EDIT, + Message, + wParam, + lParam + ); + + return (LRESULT)0; // don't do default listbox processing + } +#endif // USE_FRAMETOOLS + +#if defined( INPLACE_CNTR ) + case WM_VSCROLL: + { + if (wParam == SB_ENDSCROLL) { + /* OLE2NOTE: after scrolling finishes, update position of + ** in-place visible windows. + ** (ICNTROTL specific) we first let the ListBox + ** perform it normal processing with the EndScroll + ** message. also we let the ListBox handle all other + ** scroll messages. + */ + LRESULT lResult = CallWindowProc( + (WNDPROC)lpOutlineApp->m_ListBoxWndProc, + hWnd, + Message, + wParam, + lParam + ); + ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, 0); + return lResult; + } + + break; + } +#endif // INPLACR_CNTR + +#if defined( USE_HEADING ) + case WM_HSCROLL: + { + LPHEADING lphead = OutlineDoc_GetHeading(lpOutlineDoc); + + Heading_CH_SendMessage(lphead, Message, wParam, lParam); + + break; + } + + /* NOTE: WM_PAINT trapped in order to track vertical scrolling + ** that has taken place so the row headings can be + ** coordinated with the LineList. we wanted to trap instead + ** but it is not generated from scrolling without using + ** scroll bar (e.g. use keyboard). + */ + case WM_PAINT: + { + Heading_RH_Scroll(OutlineDoc_GetHeading(lpOutlineDoc), hWnd); + break; + } + +#endif // USE_HEADING + + case WM_LBUTTONUP: + { + +#if defined( USE_DRAGDROP ) + if (lpOleDoc->m_fPendingDrag) { + /* ButtonUP came BEFORE distance/time threshholds were + ** exceeded. clear fPendingDrag state. + */ + ReleaseCapture(); + KillTimer(hWnd, 1); + lpOleDoc->m_fPendingDrag = FALSE; + } +#endif // USE_DRAGDROP + +#if defined( INPLACE_SVR ) + if (fUIActivateClick) { + fUIActivateClick = FALSE; + ServerDoc_UIActivate((LPSERVERDOC) lpOleDoc); + } +#endif // INPLACE_SVR + +#if defined( INPLACE_CNTR ) + { + /* check if a UIDeactivate is pending. + ** (see comment in WM_LBUTTONDOWN) + */ + if ( lpContainerApp->m_fPendingUIDeactivate ) { + ContainerLine_UIDeactivate( + lpContainerDoc->m_lpLastUIActiveLine); + + lpContainerApp->m_fPendingUIDeactivate = FALSE; + } + } +#endif // INPLACE_CNTR + + break; + } + + case WM_LBUTTONDOWN: + { + POINT pt; + + pt.x = (int)(short)LOWORD (lParam ); + pt.y = (int)(short)HIWORD (lParam ); + +#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR ) + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** m_fCSHelpMode flag is set when SHIFT-F1 context + ** sensitive help is entered. + ** if this flag is set then the button click should not + ** cause any action. if the application implements a + ** help system, then context sensitive help should be + ** given for the location clicked by the user. + */ + if (lpOleDoc->m_fCSHelpMode) { + return (LRESULT)0; // eat the button click because we do + // not give any help. + } +#endif // INPLACE_SVR || INPLACE_CNTR + +#if defined( INPLACE_CNTR ) + { + /* OLE2NOTE: both inside-out and outside-in style + ** containers must check if the mouse click is + ** outside of the current UIActive object (if + ** any). If so, then set the flag indicating that + ** there is a pending UIDeactivate needed. We do NOT + ** want to do it now, + ** because that would result in un-wanted movement of + ** the data on the screen as frame adornments (eg. + ** toolbar) and/or object adornments (eg. ruler) would + ** be removed from the screen. we want to defer the + ** UIDeactivate till the mouse up event. The listbox's + ** default processing captures the mouse on button down + ** so that it is sure to get the button up message. + ** + ** SPECIAL NOTE: there is potential interaction here + ** with Drag/Drop. if this button down event actually + ** starts a Drag/Drop operation, then OLE does the mouse + ** capture. in this situation we will NOT get our button + ** up event. we must instead perform the UIDeactivate + ** when the drop operation finishes + */ + lpContainerApp->m_fPendingUIDeactivate = + ContainerDoc_IsUIDeactivateNeeded(lpContainerDoc, pt); + } +#endif // INPLACE_CNTR + +#if defined( USE_DRAGDROP ) + + /* OLE2NOTE: check if this is a button down on the region + ** that is a handle to start a drag operation. for us, + ** this this the top/bottom border of the selection. + ** do NOT want to start a drag immediately; we want to + ** wait until the mouse moves a certain threshold. if + ** LButtonUp comes before mouse move to start drag, then + ** the fPendingDrag state is cleared. we must capture + ** the mouse to ensure the modal state is handled + ** properly. + */ + if ( OleDoc_QueryDrag(lpOleDoc, pt.y) ) { + lpOleDoc->m_fPendingDrag = TRUE; + lpOleDoc->m_ptButDown = pt; + SetTimer(hWnd, 1, lpOleApp->m_nDragDelay, NULL); + SetCapture(hWnd); + + /* We do NOT want to do the listbox's default + ** processing which would be to capture the mouse + ** and enter a modal multiple selection state until + ** a mouse up occurs. we have just finished a modal + ** drag/drop operation where OLE has captured the + ** mouse. thus by now the mouse up has already occured. + */ + + return (LRESULT)0; // don't do default listbox processing + } +#endif // USE_DRAGDROP + + break; + } + + + case WM_MOUSEMOVE: { + +#if defined( USE_DRAGDROP ) + + int x = (int)(short)LOWORD (lParam ); + int y = (int)(short)HIWORD (lParam ); + POINT pt = lpOleDoc->m_ptButDown; + int nDragMinDist = lpOleApp->m_nDragMinDist; + + if (lpOleDoc->m_fPendingDrag) { + + if (! ( ((pt.x - nDragMinDist) <= x) + && (x <= (pt.x + nDragMinDist)) + && ((pt.y - nDragMinDist) <= y) + && (y <= (pt.y + nDragMinDist)) ) ) { + + DWORD dwEffect; + + // mouse moved beyond threshhold to start drag + ReleaseCapture(); + KillTimer(hWnd, 1); + lpOleDoc->m_fPendingDrag = FALSE; + + // perform the modal drag/drop operation. + dwEffect = OleDoc_DoDragDrop( lpOleDoc ); + +#if defined( INPLACE_CNTR ) + { + /* if necessary UIDeactive the in-place object. + ** this applies to outside-in style + ** container only. + ** (see comment above) + */ + if (lpContainerApp->m_fPendingUIDeactivate) { + lpContainerApp->m_fPendingUIDeactivate = FALSE; + + // do not UIDeactivate if drag/drop was canceled + if (dwEffect != DROPEFFECT_NONE) + ContainerLine_UIDeactivate( + lpContainerDoc->m_lpLastUIActiveLine + ); + } + } +#endif // INPLACE_CNTR + + return (LRESULT)0; // don't do default listbox process + } + else { + /* cursor did not move from initial mouse down + ** (pending drag) point. + */ + return (LRESULT)0; // don't do default listbox process + } + } + +#endif // USE_DRAGDROP + +#if defined( INPLACE_CNTR ) + { // BEGIN BLOCK + if (lpContainerDoc->m_fAddMyUI) { + /* OLE2NOTE: fAddMyUI is TRUE when + ** there was previously an in-place + ** active object which got + ** UIDeactivated as a result of a + ** DBLCLK AND the DBLCLK did NOT + ** result in in-place activating + ** another object. + ** (see IOleInPlaceSite::OnUIActivate and + ** IOleInPlaceSite::OnUIDeactivate + ** methods). + */ +#if defined( USE_DOCTOOLS ) + ContainerDoc_AddDocLevelTools(lpContainerDoc); +#endif + +#if defined( USE_FRAMETOOLS ) + ContainerDoc_AddFrameLevelUI(lpContainerDoc); +#endif + lpContainerDoc->m_fAddMyUI = FALSE; + } + } // END BLOCK +#endif // INPLACE_CNTR + + break; + } + + +#if defined( USE_DRAGDROP ) + case WM_TIMER: + { + DWORD dwEffect; + + // drag time delay threshhold exceeded -- start drag + ReleaseCapture(); + KillTimer(hWnd, 1); + lpOleDoc->m_fPendingDrag = FALSE; + + // perform the modal drag/drop operation. + dwEffect = OleDoc_DoDragDrop( lpOleDoc ); + +#if defined( INPLACE_CNTR ) + /* if necessary UIDeactive the in-place object. + ** this applies to outside-in style + ** container only. + ** (see comment above) + */ + if (lpContainerApp->m_fPendingUIDeactivate) { + lpContainerApp->m_fPendingUIDeactivate = FALSE; + + // do not UIDeactivate if drag/drop was canceled + if (dwEffect != DROPEFFECT_NONE) + ContainerLine_UIDeactivate( + lpContainerDoc->m_lpLastUIActiveLine); + } +#endif // INPLACE_CNTR + break; + } +#endif // USE_DRAGDROP + + case WM_SETCURSOR: + { + RECT rc; + POINT ptCursor; +#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR ) + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** m_fCSHelpMode flag is set when SHIFT-F1 context + ** sensitive help is entered. + ** if this flag is set then the context sensitive help + ** cursor should be shown. + */ + if (lpOleDoc->m_fCSHelpMode) { + SetCursor(UICursorLoad(IDC_CONTEXTHELP)); + return (LRESULT)TRUE; + } +#endif // INPLACE_SVR || INPLACE_CNTR + + GetCursorPos((POINT FAR*)&ptCursor); + ScreenToClient(hWnd, (POINT FAR*)&ptCursor); + GetClientRect(hWnd, (LPRECT)&rc); + + // use arrow cursor if in scroll bar + if (! PtInRect((LPRECT)&rc, ptCursor) ) + SetCursor(LoadCursor(NULL, IDC_ARROW) ); + +#if defined( USE_DRAGDROP ) + // use arrow cursor if on drag handle (top/bottom of selection) + else if ( OleDoc_QueryDrag ( lpOleDoc, ptCursor.y) ) + SetCursor(LoadCursor(NULL, IDC_ARROW) ); +#endif // USE_DRAGDROP + + else + SetCursor(lpOutlineApp->m_hcursorSelCur); + + return (LRESULT)TRUE; + } + +#if defined( INPLACE_SVR ) + + /* The handling of WM_WINDOWPOSCHANGED message is ISVROTL + ** application specific. The nature of the owner-draw list + ** box used by the ISVROTL application causes a recursive + ** call to this message in some situations when in-place + ** active. in order not to crash this recursive call must be + ** guarded. + */ + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS FAR* lpWinPos = (WINDOWPOS FAR*) lParam; + LRESULT lResult; + + // guard against recursive call + if (fInWinPosChged) + return (LRESULT)0; + + fInWinPosChged = TRUE; + lResult = CallWindowProc( + (WNDPROC)lpOutlineApp->m_ListBoxWndProc, + hWnd, + Message, + wParam, + lParam + ); + fInWinPosChged = FALSE; + + return lResult; + } +#endif // INPLACE_SVR + + } + + return CallWindowProc( + (WNDPROC)lpOutlineApp->m_ListBoxWndProc, + hWnd, + Message, + wParam, + lParam + ); + +} + +// Utility function to count the number of accelerator items in an +// accelerator table. A number of OLE APIs need this count, so +// this can be quite handy. +// (code shamelessly stolen from the Microsoft Foundation Classes) + +int GetAccelItemCount(HACCEL hAccel) +{ +#if defined( WIN32 ) + return CopyAcceleratorTable(hAccel, NULL, 0); +#else + #pragma pack(1) + typedef struct tagACCELERATOR + { + BYTE fFlags; + WORD wEvent; + WORD wID; + } ACCELERATOR; + #pragma pack() + + // attempt to lock down the accelerator resource + ACCELERATOR FAR* pAccel; + int cAccelItems = 1; + if (hAccel == NULL || + (pAccel = (ACCELERATOR FAR*)LockResource((HGLOBAL)hAccel)) == NULL) + { + // NULL accerator table or LockResource failed on the HACCEL, + // no accelerators + return 0; + } + // otherwise, count them -- last entry in accel table has 0x80 bit set + while ((pAccel->fFlags & 0x80) == 0) + { + ++cAccelItems; + ++pAccel; + } + UnlockResource((HGLOBAL)hAccel); + return cAccelItems; +#endif +} diff --git a/private/oleutest/letest/outline/memmgr.c b/private/oleutest/letest/outline/memmgr.c new file mode 100644 index 000000000..0f9b4cc68 --- /dev/null +++ b/private/oleutest/letest/outline/memmgr.c @@ -0,0 +1,38 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** memmgr.c +** +** This file contains memory management functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + + +/* New + * --- + * + * Allocate memory for a new structure + */ +LPVOID New(DWORD lSize) +{ + LPVOID lp = OleStdMalloc((ULONG)lSize); + + return lp; +} + + +/* Delete + * ------ + * + * Free memory allocated for a structure + */ +void Delete(LPVOID lp) +{ + OleStdFree(lp); +} diff --git a/private/oleutest/letest/outline/message.h b/private/oleutest/letest/outline/message.h new file mode 100644 index 000000000..f8aa7f580 --- /dev/null +++ b/private/oleutest/letest/outline/message.h @@ -0,0 +1,109 @@ +/************************************************************************* +** +** OLE 2.0 Server Sample Code +** +** message.h +** +** This file is a user customizable list of status messages associated +** with menu items. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +// Status bar messages and associated data. + +// Message type for status bar messages. +typedef struct { + UINT wIDItem; + char *string; +} STATMESG; + +/* + * CUSTOMIZATION NOTE: Be sure to change NUM_POPUP if you + * change the number of popup messages. + */ + +// REVIEW: these messages should be loaded from a string resource + +// List of all menu item messages. +STATMESG MesgList[] = +{ + { IDM_F_NEW, "Creates a new outline" }, + { IDM_F_OPEN, "Opens an existing outline file" }, + { IDM_F_SAVE, "Saves the outline" }, + { IDM_F_SAVEAS, "Saves the outline with a new name" }, + { IDM_F_PRINT, "Prints the outline" }, + { IDM_F_PRINTERSETUP, "Changes the printer and the printing options" }, + { IDM_F_EXIT, "Quits the application, prompting to save changes" }, + + { IDM_E_UNDO, "Undo not yet implemented" }, + { IDM_E_CUT, "Cuts the selection and puts it on the Clipboard" }, + { IDM_E_COPY, "Copies the selection and puts it on the Clipboard" }, + { IDM_E_PASTE, "Inserts the Clipboard contents after current line" }, + { IDM_E_PASTESPECIAL,"Allows pasting Clipboard data using a special format" }, + { IDM_E_CLEAR, "Clears the selection" }, + { IDM_E_SELECTALL, "Selects the entire outline" }, +#if defined( OLE_CNTR ) + { IDM_E_INSERTOBJECT, "Inserts new object after current line" }, + { IDM_E_EDITLINKS, "Edit and view links contained in the document" }, + { IDM_E_CONVERTVERB, "Converts or activates an object as another type" }, + { IDM_E_OBJECTVERBMIN, "Opens, edits or interacts with an object" }, + { IDM_E_OBJECTVERBMIN+1, "Opens, edits or interacts with an object1" }, + { IDM_E_OBJECTVERBMIN+2, "Opens, edits or interacts with an object2" }, + { IDM_E_OBJECTVERBMIN+3, "Opens, edits or interacts with an object3" }, + { IDM_E_OBJECTVERBMIN+4, "Opens, edits or interacts with an object4" }, + { IDM_E_OBJECTVERBMIN+5, "Opens, edits or interacts with an object5" }, +#endif + + { IDM_L_ADDLINE, "Adds a new line after current line" }, + { IDM_L_EDITLINE, "Edits the current line" }, + { IDM_L_INDENTLINE, "Indents the selection" }, + { IDM_L_UNINDENTLINE, "Unindents the selection" }, + { IDM_L_SETLINEHEIGHT, "Modify the height of a line" }, + + { IDM_N_DEFINENAME, "Assigns a name to the selection" }, + { IDM_N_GOTONAME, "Jumps to a specified place in the outline" }, + + { IDM_H_ABOUT, "Displays program info, version no., and copyright" }, + + { IDM_D_DEBUGLEVEL, "Set debug level (0-4)" }, + { IDM_D_INSTALLMSGFILTER,"Install/deinstall the IMessageFilter" }, + { IDM_D_REJECTINCOMING, "Return RETRYLATER to incoming method calls" }, + + { IDM_O_BB_TOP, "Position ButtonBar at top of window" }, + { IDM_O_BB_BOTTOM, "Position ButtonBar at botttom of window" }, + { IDM_O_BB_POPUP, "Put ButtonBar in popup pallet" }, + { IDM_O_BB_HIDE, "Hide ButtonBar" }, + + { IDM_O_FB_TOP, "Position FormulaBar at top of window" }, + { IDM_O_FB_BOTTOM, "Position FormulaBar at botttom of window" }, + { IDM_O_FB_POPUP, "Put FormulaBar in popup pallet" }, + + { IDM_O_HEAD_SHOW, "Show row/column headings" }, + { IDM_O_HEAD_HIDE, "Hide row/column headings" }, + { IDM_O_SHOWOBJECT, "Show border around objects/links" }, + + { IDM_V_ZOOM_400, "Set document zoom level" }, + { IDM_V_ZOOM_300, "Set document zoom level" }, + { IDM_V_ZOOM_200, "Set document zoom level" }, + { IDM_V_ZOOM_100, "Set document zoom level" }, + { IDM_V_ZOOM_75, "Set document zoom level" }, + { IDM_V_ZOOM_50, "Set document zoom level" }, + { IDM_V_ZOOM_25, "Set document zoom level" }, + + { IDM_V_SETMARGIN_0, "Remove left/right document margins" }, + { IDM_V_SETMARGIN_1, "Set left/right document margins" }, + { IDM_V_SETMARGIN_2, "Set left/right document margins" }, + { IDM_V_SETMARGIN_3, "Set left/right document margins" }, + { IDM_V_SETMARGIN_4, "Set left/right document margins" }, + + { IDM_V_ADDTOP_1, "Add top line" }, + { IDM_V_ADDTOP_2, "Add top line" }, + { IDM_V_ADDTOP_3, "Add top line" }, + { IDM_V_ADDTOP_4, "Add top line" } +}; + +#define NUM_STATS sizeof(MesgList)/sizeof(MesgList[0]) +#define NUM_POPUP 10 // Maximum number of popup messages. +#define MAX_MESSAGE 100 // Maximum characters in a popup message. diff --git a/private/oleutest/letest/outline/ole2.bmp b/private/oleutest/letest/outline/ole2.bmp Binary files differnew file mode 100644 index 000000000..f1d0cbbf7 --- /dev/null +++ b/private/oleutest/letest/outline/ole2.bmp diff --git a/private/oleutest/letest/outline/oleapp.c b/private/oleutest/letest/outline/oleapp.c new file mode 100644 index 000000000..0f355307b --- /dev/null +++ b/private/oleutest/letest/outline/oleapp.c @@ -0,0 +1,2989 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** oleapp.c +** +** This file contains functions and methods that are common to +** server and the client version of the app. This includes the class +** factory methods and all OleApp functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" +#include <ole2ver.h> + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +extern IUnknownVtbl g_OleApp_UnknownVtbl; + +extern IUnknownVtbl g_OleDoc_UnknownVtbl; +extern IPersistFileVtbl g_OleDoc_PersistFileVtbl; +extern IOleItemContainerVtbl g_OleDoc_OleItemContainerVtbl; +extern IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl; +extern IDataObjectVtbl g_OleDoc_DataObjectVtbl; + +#if defined( USE_DRAGDROP ) +extern IDropTargetVtbl g_OleDoc_DropTargetVtbl; +extern IDropSourceVtbl g_OleDoc_DropSourceVtbl; +#endif // USE_DRAGDROP + +#if defined( OLE_SERVER ) +extern IOleObjectVtbl g_SvrDoc_OleObjectVtbl; +extern IPersistStorageVtbl g_SvrDoc_PersistStorageVtbl; + +#if defined( SVR_TREATAS ) +extern IStdMarshalInfoVtbl g_SvrDoc_StdMarshalInfoVtbl; +#endif // SVR_TREATAS + +extern IUnknownVtbl g_PseudoObj_UnknownVtbl; +extern IOleObjectVtbl g_PseudoObj_OleObjectVtbl; +extern IDataObjectVtbl g_PseudoObj_DataObjectVtbl; + +#if defined( INPLACE_SVR ) +extern IOleInPlaceObjectVtbl g_SvrDoc_OleInPlaceObjectVtbl; +extern IOleInPlaceActiveObjectVtbl g_SvrDoc_OleInPlaceActiveObjectVtbl; +#endif // INPLACE_SVR + +#endif // OLE_SERVER + +#if defined( OLE_CNTR ) + +extern IOleUILinkContainerVtbl g_CntrDoc_OleUILinkContainerVtbl; +extern IUnknownVtbl g_CntrLine_UnknownVtbl; +extern IOleClientSiteVtbl g_CntrLine_OleClientSiteVtbl; +extern IAdviseSinkVtbl g_CntrLine_AdviseSinkVtbl; + +#if defined( INPLACE_CNTR ) +extern IOleInPlaceSiteVtbl g_CntrLine_OleInPlaceSiteVtbl; +extern IOleInPlaceFrameVtbl g_CntrApp_OleInPlaceFrameVtbl; +extern BOOL g_fInsideOutContainer; +#endif // INPLACE_CNTR + +#endif // OLE_CNTR + +// REVIEW: these are NOT useful end-user messages +static char ErrMsgCreateCF[] = "Can't create Class Factory!"; +static char ErrMsgRegCF[] = "Can't register Class Factory!"; +static char ErrMsgRegMF[] = "Can't register Message Filter!"; + +extern UINT g_uMsgHelp; + + +/* OleApp_InitInstance + * ------------------- + * + * Initialize the app instance by creating the main frame window and + * performing app instance specific initializations + * (eg. initializing interface Vtbls). + * + * RETURNS: TRUE if the memory could be allocated, and the server app + * was properly initialized. + * FALSE otherwise + * + */ +BOOL OleApp_InitInstance(LPOLEAPP lpOleApp, HINSTANCE hInst, int nCmdShow) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + HRESULT hrErr; + DWORD dwBuildVersion = OleBuildVersion(); + LPMALLOC lpMalloc = NULL; + + OLEDBG_BEGIN3("OleApp_InitInstance\r\n") + + lpOleApp->m_fOleInitialized = FALSE; + + /* OLE2NOTE: check if the build version of the OLE2 DLL's match + ** what our application is expecting. + */ + if (HIWORD(dwBuildVersion) != rmm || LOWORD(dwBuildVersion) < rup) { + OleDbgAssertSz(0, "ERROR: OLE 2.0 DLL's are NOT compatible!"); + +#if !defined( _DEBUG ) + return FALSE; // Wrong version of DLL's +#endif + } + +#if defined( _DEBUG ) + /* OLE2NOTE: Use a special debug allocator to help track down + ** memory leaks. + */ + OleStdCreateDbAlloc(0, &lpMalloc); +#endif + /* OLE2NOTE: the OLE libraries must be properly initialized before + ** making any calls. OleInitialize automatically calls + ** CoInitialize. we will use the default task memory allocator + ** therefore we pass NULL to OleInitialize. + */ + OLEDBG_BEGIN2("OleInitialize called\r\n") + hrErr = OleInitialize(lpMalloc); + + if (FAILED(hrErr)) + { + // Replacing the allocator may not be legal - try initializing + // without overriding the allocator + hrErr = OleInitialize(NULL); + } + + OLEDBG_END2 + +#if defined( _DEBUG ) + /* OLE2NOTE: release the special debug allocator so that only OLE is + ** holding on to it. later when OleUninitialize is called, then + ** the debug allocator object will be destroyed. when the debug + ** allocator object is destoyed, it will report (to the Output + ** Debug Terminal) whether there are any memory leaks. + */ + if (lpMalloc) lpMalloc->lpVtbl->Release(lpMalloc); +#endif + + if (hrErr != NOERROR) { + OutlineApp_ErrorMessage(lpOutlineApp,"OLE initialization failed!"); + goto error; + } + + /***************************************************************** + ** OLE2NOTE: we must remember the fact that OleInitialize has + ** been call successfully. the very last thing an app must + ** be do is properly shut down OLE by calling + ** OleUninitialize. This call MUST be guarded! it is only + ** allowable to call OleUninitialize if OleInitialize has + ** been called SUCCESSFULLY. + *****************************************************************/ + + lpOleApp->m_fOleInitialized = TRUE; + + // Initialize the OLE 2.0 interface method tables. + if (! OleApp_InitVtbls(lpOleApp)) + goto error; + + // Register OLE 2.0 clipboard formats. + lpOleApp->m_cfEmbedSource = RegisterClipboardFormat(CF_EMBEDSOURCE); + lpOleApp->m_cfEmbeddedObject = RegisterClipboardFormat( + CF_EMBEDDEDOBJECT + ); + lpOleApp->m_cfLinkSource = RegisterClipboardFormat(CF_LINKSOURCE); + lpOleApp->m_cfFileName = RegisterClipboardFormat(CF_FILENAME); + lpOleApp->m_cfObjectDescriptor = + RegisterClipboardFormat(CF_OBJECTDESCRIPTOR); + lpOleApp->m_cfLinkSrcDescriptor = + RegisterClipboardFormat(CF_LINKSRCDESCRIPTOR); + + lpOleApp->m_cRef = 0; + lpOleApp->m_cDoc = 0; + lpOleApp->m_fUserCtrl = FALSE; + lpOleApp->m_dwRegClassFac = 0; + lpOleApp->m_lpClassFactory = NULL; + lpOleApp->m_cModalDlgActive = 0; + + INIT_INTERFACEIMPL( + &lpOleApp->m_Unknown, + &g_OleApp_UnknownVtbl, + lpOleApp + ); + +#if defined( USE_DRAGDROP ) + + // delay before dragging should start, in milliseconds + lpOleApp->m_nDragDelay = GetProfileInt( + "windows", + "DragDelay", + DD_DEFDRAGDELAY + ); + + // minimum distance (radius) before drag should start, in pixels + lpOleApp->m_nDragMinDist = GetProfileInt( + "windows", + "DragMinDist", + DD_DEFDRAGMINDIST + ); + + // delay before scrolling, in milliseconds + lpOleApp->m_nScrollDelay = GetProfileInt( + "windows", + "DragScrollDelay", + DD_DEFSCROLLDELAY + ); + + // inset-width of the hot zone, in pixels + lpOleApp->m_nScrollInset = GetProfileInt( + "windows", + "DragScrollInset", + DD_DEFSCROLLINSET + ); + + // scroll interval, in milliseconds + lpOleApp->m_nScrollInterval = GetProfileInt( + "windows", + "DragScrollInterval", + DD_DEFSCROLLINTERVAL + ); + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) + // This would be used if the app wanted to have custom drag/drop cursors + lpOleApp->m_hcursorDragNone = LoadCursor ( hInst, "DragNoneCur" ); + lpOleApp->m_hcursorDragCopy = LoadCursor ( hInst, "DragCopyCur" ); + lpOleApp->m_hcursorDragMove = LoadCursor ( hInst, "DragMoveCur" ); + lpOleApp->m_hcursorDragLink = LoadCursor ( hInst, "DragLinkCur" ); +#endif // IF_SPECIAL_DD_CURSORS_NEEDED + +#endif // USE_DRAGDROP + + lpOleApp->m_lpMsgFilter = NULL; + +#if defined( USE_MSGFILTER ) + /* OLE2NOTE: Register our message filter upon app startup. the + ** message filter is used to handle concurrency. + ** we will use a standard implementation of IMessageFilter that + ** is included as part of the OLE2UI library. + */ + lpOleApp->m_lpMsgFilter = NULL; + if (! OleApp_RegisterMessageFilter(lpOleApp)) + goto error; + + /* OLE2NOTE: because our app is initially INVISIBLE, we must + ** DISABLE the busy dialog. we should NOT put up any dialogs if + ** our app is invisible. when our app window is made visible, + ** then the busy dialog will be enabled. + */ + OleStdMsgFilter_EnableBusyDialog(lpOleApp->m_lpMsgFilter, FALSE); +#endif // USE_MSGFILTER + +#if defined( OLE_SERVER ) + /* OLE2NOTE: perform initialization specific for an OLE server */ + if (! ServerApp_InitInstance((LPSERVERAPP)lpOutlineApp, hInst, nCmdShow)) + goto error; +#endif +#if defined( OLE_CNTR ) + /* OLE2NOTE: perform initialization specific for an OLE container */ + + // Register help message + g_uMsgHelp = RegisterWindowMessage(SZOLEUI_MSG_HELP); + + if (! ContainerApp_InitInstance((LPCONTAINERAPP)lpOutlineApp, hInst, nCmdShow)) + goto error; +#endif + +#if defined( OLE_CNTR ) + lpOleApp->m_hStdPal = OleStdCreateStandardPalette(); +#endif + + OLEDBG_END3 + return TRUE; + +error: + OLEDBG_END3 + return FALSE; +} + + +/* + * OleApp_TerminateApplication + * --------------------------- + * Perform proper OLE application cleanup before shutting down + */ +void OleApp_TerminateApplication(LPOLEAPP lpOleApp) +{ + OLEDBG_BEGIN3("OleApp_TerminateApplication\r\n") + + /* OLE2NOTE: perform a clean shut down for OLE. at this point our + ** App refcnt should be 0, or else we should never have reached + ** this point! + */ + OleDbgAssertSz(lpOleApp->m_cRef == 0, "App NOT shut down properly"); + + if(lpOleApp->m_fOleInitialized) { + OLEDBG_BEGIN2("OleUninitialize called\r\n") + OleUninitialize(); + OLEDBG_END2 + } + OLEDBG_END3 +} + + +/* OleApp_ParseCmdLine + * ------------------- + * + * Parse the command line for any execution flags/arguments. + * OLE2NOTE: check if "-Embedding" switch is given. + */ +BOOL OleApp_ParseCmdLine(LPOLEAPP lpOleApp, LPSTR lpszCmdLine, int nCmdShow) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + char szFileName[256]; /* buffer for filename in command line */ + BOOL fStatus = TRUE; + BOOL fEmbedding = FALSE; + + OLEDBG_BEGIN3("OleApp_ParseCmdLine\r\n") + + szFileName[0] = '\0'; + ParseCmdLine(lpszCmdLine, &fEmbedding, (LPSTR)szFileName); + +#if defined( MDI_VERSION ) + /* OLE2NOTE: an MDI app would ALWAYS register its ClassFactory. it + ** can handle multiple objects at the same time, while an SDI + ** application can only handle a single embedded or file-based + ** object at a time. + */ + fStatus = OleApp_RegisterClassFactory(lpOleApp); +#endif + + if(fEmbedding) { + + if (szFileName[0] == '\0') { + + /***************************************************************** + ** App was launched with /Embedding. + ** We must register our ClassFactory with OLE, remain hidden + ** (the app window is initially created not visible), and + ** wait for OLE to call IClassFactory::CreateInstance + ** method. We do not automatically create a document as we + ** do when the app is launched by the user from the + ** FileManager. We must NOT make our app window visible + ** until told to do so by our container. + ** + ** OLE2NOTE: Because we are an SDI app, we only register our + ** ClassFactory if we are launched with the /Embedding + ** flag WITHOUT a filename. an MDI app would ALWAYS + ** register its ClassFactory. it can handle multiple + ** objects at the same time, while an SDI application + ** can only handle a single embedded or file-based + ** object at a time. + *****************************************************************/ + +#if defined( SDI_VERSION ) + fStatus = OleApp_RegisterClassFactory(lpOleApp); +#endif + } else { + + /***************************************************************** + ** App was launched with /Embedding <Filename>. + ** We must create a document and load the file and + ** register it in the RunningObjectTable BEFORE we + ** enter our GetMessage loop (ie. before we yield). + ** One way to perform these tasks is to call the same + ** interface methods that OLE 2.0 calls for linking to a + ** file: + ** IClassFactory::CreateInstance + ** IPersistFile::Load + ** + ** We must NOT make our app window visible until told to + ** do so by our container. An application will be + ** launched in this manner by an OLE 1.0 application + ** link situation (eg. double clicking a linked object + ** or OleCreateLinkFromFile called). + ** + ** OLE2NOTE: Because we are an SDI app, we should NOT + ** register our ClassFactory when we are launched with the + ** /Embedding <Filename> flag. our SDI instance can only + ** handle a single embedded or file-based object. + ** an MDI app WOULD register its ClassFactory at all + ** times because it can handle multiple objects. + *****************************************************************/ + + // allocate a new document object + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) { + OLEDBG_END3 + return FALSE; + } + + /* OLE2NOTE: initially the Doc object is created with a 0 ref + ** count. in order to have a stable Doc object during the + ** process of initializing the new Doc instance, + ** we intially AddRef the Doc ref cnt and later + ** Release it. This initial AddRef is artificial; it is simply + ** done to guarantee that a harmless QueryInterface followed by + ** a Release does not inadvertantly force our object to destroy + ** itself prematurely. + */ + OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc); + + /* OLE2NOTE: OutlineDoc_LoadFromFile will register our document + ** in the RunningObjectTable. this registration will + ** AddRef our document. therefore our document will not + ** be destroyed when we release the artificial AddRef + */ + fStatus = OutlineDoc_LoadFromFile( + lpOutlineApp->m_lpDoc, (LPSTR)szFileName); + + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); // rel AddRef + + OLEDBG_END3 + return fStatus; + } + } else { + + /***************************************************************** + ** App was launched by the user (without /Embedding) and + ** therefore is marked to be under user control. + ** In this case, because we are an SDI app, we do NOT + ** register our ClassFactory with OLE. This app instance can + ** only manage one document at a time (either a user + ** document or an embedded object document). An MDI app + ** would register its ClassFactory here. + ** + ** We must create a document for the user (either + ** initialized from a file given on the command line or + ** initialized as an untitled document. We must also make + ** our app window visible to the user. + *****************************************************************/ + + // allocate a new document object + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + /* OLE2NOTE: initially the Doc object is created with a 0 ref + ** count. in order to have a stable Doc object during the + ** process of initializing the new Doc instance, + ** we intially AddRef the Doc ref cnt and later + ** Release it. This initial AddRef is artificial; it is simply + ** done to guarantee that a harmless QueryInterface followed by + ** a Release does not inadvertantly force our object to destroy + ** itself prematurely. + */ + OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc); + + if(*szFileName) { + // initialize the document from the specified file + if (! OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, szFileName)) + goto error; + } else { + // set the doc to an (Untitled) doc. + if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc)) + goto error; + } + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); // calls OleDoc_Lock + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);// rel AddRef above + + // show main app window + ShowWindow(lpOutlineApp->m_hWndApp, nCmdShow); + UpdateWindow(lpOutlineApp->m_hWndApp); + +#if defined( OLE_CNTR ) + ContainerDoc_UpdateLinks((LPCONTAINERDOC)lpOutlineApp->m_lpDoc); +#endif + + } + + OLEDBG_END3 + return fStatus; + +error: + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage( + lpOutlineApp, + "Could not create document--Out of Memory" + ); + if (lpOutlineApp->m_lpDoc) // rel artificial AddRef above + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); + + OLEDBG_END3 + return FALSE; +} + + +/* OleApp_CloseAllDocsAndExitCommand + * --------------------------------- + * + * Close all active documents and exit the app. + * Because this is an SDI, there is only one document + * If the doc was modified, prompt the user if he wants to save it. + * + * Returns: + * TRUE if the app is successfully closed + * FALSE if failed or aborted + * + * OLE2NOTE: in the OLE version, we can NOT directly + * destroy the App object. we can only take all + * necessary actions to ensure that our object receives + * all of its Releases from clients holding onto + * pointers (eg. closing all docs and flushing the + * clipboard) and then we must hide our window and wait + * actually for our refcnt to reach 0. when it reaches 0, + * our destructor (OutlineApp_Destroy) will be called. + * each document addref's the app object in order to + * guarentee that the app does not shut down while the doc + * is still open. closing all docs, will release these + * refcnt's. if there are now more open documents AND the + * app is not under the control of the user (ie. launched by + * OLE) then the app will now shut down. the OleApp_Release + * function executes this shut down procedure. after closing + * all docs, then releasing the user refcnt will force the + * app to shut down. + */ +BOOL OleApp_CloseAllDocsAndExitCommand( + LPOLEAPP lpOleApp, + BOOL fForceEndSession +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + DWORD dwSaveOption = (fForceEndSession ? + OLECLOSE_NOSAVE : OLECLOSE_PROMPTSAVE); + + /* OLE2NOTE: in order to have a stable App object during the + ** process of closing, we intially AddRef the App ref cnt and + ** later Release it. This initial AddRef is artificial; it is + ** simply done to guarantee that our App object does not + ** destroy itself until the end of this routine. + */ + OleApp_AddRef(lpOleApp); + + /* Because this is an SDI app, there is only one document. + ** Close the doc. if it is successfully closed and the app will + ** not automatically exit, then also exit the app. + ** if this were an MDI app, we would loop through and close all + ** open MDI child documents. + */ + +#if defined( OLE_SERVER ) + if (!fForceEndSession && + lpOutlineApp->m_lpDoc->m_docInitType == DOCTYPE_EMBEDDED) + dwSaveOption = OLECLOSE_SAVEIFDIRTY; +#endif + + if (! OutlineDoc_Close(lpOutlineApp->m_lpDoc, dwSaveOption)) { + OleApp_Release(lpOleApp); + return FALSE; // User Aborted shutdown + } +#if defined( _DEBUG ) + OleDbgAssertSz( + lpOutlineApp->m_lpDoc==NULL, + "Closed doc NOT properly destroyed" + ); +#endif + +#if defined( OLE_CNTR ) + /* if we currently have data on the clipboard then we must tell + ** the clipboard to release our clipboard data object + ** (document) + */ + if (lpOutlineApp->m_lpClipboardDoc) + OleApp_FlushClipboard(lpOleApp); +#endif + + OleApp_HideWindow(lpOleApp); + + /* OLE2NOTE: this call forces all external connections to our + ** object to close down and therefore guarantees that we receive + ** all releases associated with those external connections. + */ + OLEDBG_BEGIN2("CoDisconnectObject(lpApp) called\r\n") + CoDisconnectObject((LPUNKNOWN)&lpOleApp->m_Unknown, 0); + OLEDBG_END2 + + OleApp_Release(lpOleApp); // release artificial AddRef above + + return TRUE; +} + + +/* OleApp_ShowWindow + * ----------------- + * + * Show the window of the app to the user. + * make sure app window is visible and bring the app to the top. + * IF fGiveUserCtrl == TRUE + * THEN give the user the control over the life-time of the app. + */ +void OleApp_ShowWindow(LPOLEAPP lpOleApp, BOOL fGiveUserCtrl) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + + OLEDBG_BEGIN3("OleApp_ShowWindow\r\n") + + /* OLE2NOTE: while the application is visible and under user + ** control, we do NOT want it to be prematurely destroyed when + ** the user closes a document. thus we must inform OLE to hold + ** an external lock on our application on behalf of the user. + ** this arranges that OLE holds at least 1 reference to our + ** application that will NOT be released until we release this + ** external lock. later, when the application window is hidden, we + ** will release this external lock. + */ + if (fGiveUserCtrl && ! lpOleApp->m_fUserCtrl) { + lpOleApp->m_fUserCtrl = TRUE; + OleApp_Lock(lpOleApp, TRUE /* fLock */, 0 /* not applicable */); + } + + // we must show our App window and force it to have input focus + ShowWindow(lpOutlineApp->m_hWndApp, SW_SHOWNORMAL); + SetFocus(lpOutlineApp->m_hWndApp); + + /* OLE2NOTE: because our app is now visible, we can enable the busy + ** dialog. we should NOT put up any dialogs if our app is + ** invisible. + */ + OleApp_EnableBusyDialogs(lpOleApp, TRUE, TRUE); + + OLEDBG_END3 +} + + +/* OleApp_HideWindow + * ----------------- + * + * Hide the window of the app from the user. + * take away the control of the app by the user. + */ +void OleApp_HideWindow(LPOLEAPP lpOleApp) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + + OLEDBG_BEGIN3("OleApp_HideWindow\r\n") + + /* OLE2NOTE: the application is now being hidden, so we must release + ** the external lock that was made on behalf of the user. + ** if this is that last external lock on our application, thus + ** enabling our application to complete its shutdown operation. + */ + if (lpOleApp->m_fUserCtrl) { + lpOleApp->m_fUserCtrl = FALSE; + OleApp_Lock(lpOleApp, FALSE /*fLock*/, TRUE /*fLastUnlockReleases*/); + } + + ShowWindow(lpOutlineApp->m_hWndApp, SW_HIDE); + + /* OLE2NOTE: because our app is now INVISIBLE, we must DISABLE the busy + ** dialog. we should NOT put up any dialogs if our app is + ** invisible. + */ + OleApp_EnableBusyDialogs(lpOleApp, FALSE, FALSE); + OLEDBG_END3 +} + + +/* OleApp_Lock +** ----------- +** Lock/Unlock the App object. if the last lock is unlocked and +** fLastUnlockReleases == TRUE, then the app object will shut down +** (ie. it will recieve its final release and its refcnt will go to 0). +*/ +HRESULT OleApp_Lock(LPOLEAPP lpOleApp, BOOL fLock, BOOL fLastUnlockReleases) +{ + HRESULT hrErr; + +#if defined( _DEBUG ) + if (fLock) { + OLEDBG_BEGIN2("CoLockObjectExternal(lpApp,TRUE) called\r\n") + } else { + if (fLastUnlockReleases) + OLEDBG_BEGIN2("CoLockObjectExternal(lpApp,FALSE,TRUE) called\r\n") + else + OLEDBG_BEGIN2("CoLockObjectExternal(lpApp,FALSE,FALSE) called\r\n") + } +#endif // _DEBUG + + OleApp_AddRef(lpOleApp); // artificial AddRef to make object stable + + hrErr = CoLockObjectExternal( + (LPUNKNOWN)&lpOleApp->m_Unknown, fLock, fLastUnlockReleases); + + OleApp_Release(lpOleApp); // release artificial AddRef above + + OLEDBG_END2 + return hrErr; +} + + +/* OleApp_Destroy + * -------------- + * + * Free all OLE related resources that had been allocated for the app. + */ +void OleApp_Destroy(LPOLEAPP lpOleApp) +{ + // OLE2NOTE: Revoke our message filter upon app shutdown. + OleApp_RevokeMessageFilter(lpOleApp); + + // OLE2NOTE: Revoke our ClassFactory upon app shutdown. + OleApp_RevokeClassFactory(lpOleApp); + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) + // This would be used if the app wanted to have custom drag/drop cursors + DestroyCursor(lpOleApp->m_hcursorDragNone); + DestroyCursor(lpOleApp->m_hcursorDragCopy); + DestroyCursor(lpOleApp->m_hcursorDragLink); + DestroyCursor(lpOleApp->m_hcursorDragMove); +#endif // IF_SPECIAL_DD_CURSORS_NEEDED + +#if defined( OLE_CNTR ) + if (lpOleApp->m_hStdPal) { + DeleteObject(lpOleApp->m_hStdPal); + lpOleApp->m_hStdPal = NULL; + } +#endif +} + + +/* OleApp_DocLockApp +** ----------------- +** Add a lock on the App on behalf of the Doc. the App may not close +** while the Doc exists. +** +** when a document is first created, it calls this method to +** guarantee that the application stays alive (OleDoc_Init). +** when a document is destroyed, it calls +** OleApp_DocUnlockApp to release this hold on the app. +*/ +void OleApp_DocLockApp(LPOLEAPP lpOleApp) +{ + ULONG cDoc; + + OLEDBG_BEGIN3("OleApp_DocLockApp\r\n") + + cDoc = ++lpOleApp->m_cDoc; + + OleDbgOutRefCnt3("OleApp_DocLockApp: cDoc++\r\n", lpOleApp, cDoc); + + OleApp_Lock(lpOleApp, TRUE /* fLock */, 0 /* not applicable */); + + OLEDBG_END3 + return; +} + + +/* OleApp_DocUnlockApp +** ------------------- +** Forget all references to a closed document. +** Release the lock on the App on behalf of the Doc. if this was the +** last lock on the app, then it will shutdown. +*/ +void OleApp_DocUnlockApp(LPOLEAPP lpOleApp, LPOUTLINEDOC lpOutlineDoc) +{ + ULONG cDoc; + + OLEDBG_BEGIN3("OleApp_DocUnlockApp\r\n") + + /* OLE2NOTE: when there are no open documents and the app is not + ** under the control of the user then revoke our ClassFactory to + ** enable the app to shut down. + */ + cDoc = --lpOleApp->m_cDoc; + +#if defined( _DEBUG ) + OleDbgAssertSz ( + lpOleApp->m_cDoc >= 0, "DocUnlockApp called with cDoc == 0"); + + OleDbgOutRefCnt3( + "OleApp_DocUnlockApp: cDoc--\r\n", lpOleApp, cDoc); +#endif + + OleApp_Lock(lpOleApp, FALSE /* fLock */, TRUE /* fLastUnlockReleases */); + + OLEDBG_END3 + return; +} + + +/* OleApp_HideIfNoReasonToStayVisible +** ---------------------------------- +** +** if there are no more documents visible to the user and the app +** itself is not under user control, then it has no reason to stay +** visible. we thus should hide the app. we can not directly destroy +** the app, because it may be validly being used programatically by +** another client application and should remain running. the app +** should simply be hidden from the user. +*/ +void OleApp_HideIfNoReasonToStayVisible(LPOLEAPP lpOleApp) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + LPOUTLINEDOC lpOutlineDoc; + + OLEDBG_BEGIN3("OleApp_HideIfNoReasonToStayVisible\r\n") + + if (lpOleApp->m_fUserCtrl) { + OLEDBG_END3 + return; // remain visible; user in control of app + } + + /* Because this is an SDI app, there is only one user document. + ** check if it is visible to the user. an MDI app would loop over + ** all open MDI child documents to see if any are visible. + */ + lpOutlineDoc = (LPOUTLINEDOC)lpOutlineApp->m_lpDoc; + if (lpOutlineDoc && IsWindowVisible(lpOutlineDoc->m_hWndDoc)) + return; // remain visible; the doc is visible to the user + + // if we reached here, the app should be hidden + OleApp_HideWindow(lpOleApp); + + OLEDBG_END3 +} + + +/* OleApp_AddRef +** ------------- +** +** increment the ref count of the App object. +** +** Returns the new ref count on the object +*/ +ULONG OleApp_AddRef(LPOLEAPP lpOleApp) +{ + ++lpOleApp->m_cRef; + +#if defined( _DEBUG ) + OleDbgOutRefCnt4( + "OleApp_AddRef: cRef++\r\n", + lpOleApp, + lpOleApp->m_cRef + ); +#endif + return lpOleApp->m_cRef; +} + + +/* OleApp_Release +** -------------- +** +** decrement the ref count of the App object. +** if the ref count goes to 0, then the app object is destroyed. +** +** Returns the remaining ref count on the object +*/ +ULONG OleApp_Release (LPOLEAPP lpOleApp) +{ + ULONG cRef; + + cRef = --lpOleApp->m_cRef; + +#if defined( _DEBUG ) + OleDbgAssertSz (lpOleApp->m_cRef >= 0, "Release called with cRef == 0"); + + OleDbgOutRefCnt4( + "OleApp_AddRef: cRef--\r\n", lpOleApp, cRef); +#endif // _DEBUG + /********************************************************************* + ** OLE2NOTE: when the ClassFactory refcnt == 0, then destroy it. ** + ** otherwise the ClassFactory is still in use. ** + *********************************************************************/ + + if(cRef == 0) + OutlineApp_Destroy((LPOUTLINEAPP)lpOleApp); + + return cRef; +} + + + +/* OleApp_QueryInterface +** --------------------- +** +** Retrieve a pointer to an interface on the app object. +** +** OLE2NOTE: this function will AddRef the ref cnt of the object. +** +** Returns NOERROR if interface is successfully retrieved. +** E_NOINTERFACE if the interface is not supported +*/ +HRESULT OleApp_QueryInterface ( + LPOLEAPP lpOleApp, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + SCODE sc; + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) { + OleDbgOut4("OleApp_QueryInterface: IUnknown* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleApp->m_Unknown; + OleApp_AddRef(lpOleApp); + sc = S_OK; + } + else { + sc = E_NOINTERFACE; + } + + OleDbgQueryInterfaceMethod(*lplpvObj); + return ResultFromScode(sc); +} + + +/* OleApp_RejectInComingCalls +** ------------------------- +** Reject/Handle in coming OLE (LRPC) calls. +** +** OLE2NOTE: if the app is in a state when it can NOT handle in +** coming OLE method calls from an external process (eg. the app has +** an application modal dialog up), then it should call +** OleApp_RejectInComingCalls(TRUE). in this state the +** IMessageFilter::HandleInComingCall method will return +** SERVERCALL_RETRYLATER. this tells the caller to try again in a +** little while. normally the calling app will put up a dialog (see +** OleUIBusy dialog) in this situation informing the user of the +** situation. the user then is normally given the option to +** "Switch To..." the busy application, retry, or cancel the +** operation. when the app is ready to continue processing such +** calls, it should call OleApp_RejectInComingCalls(FALSE). in this +** state, SERVERCALL_ISHANDLED is returned by +** IMessageFilter::HandleInComingCall. +*/ +void OleApp_RejectInComingCalls(LPOLEAPP lpOleApp, BOOL fReject) +{ +#if defined( _DEBUG ) + if (fReject) + OleDbgOut3("OleApp_RejectInComingCalls(TRUE)\r\n"); + else + OleDbgOut3("OleApp_RejectInComingCalls(FALSE)\r\n"); +#endif // _DEBUG + + OleDbgAssert(lpOleApp->m_lpMsgFilter != NULL); + if (! lpOleApp->m_lpMsgFilter) + return; + + OleStdMsgFilter_SetInComingCallStatus( + lpOleApp->m_lpMsgFilter, + (fReject ? SERVERCALL_RETRYLATER : SERVERCALL_ISHANDLED) + ); +} + + +/* OleApp_DisableBusyDialogs +** ------------------------- +** Disable the Busy and NotResponding dialogs. +** +** Returns previous enable state so that it can be restored by +** calling OleApp_ReEnableBusyDialogs. +*/ +void OleApp_DisableBusyDialogs( + LPOLEAPP lpOleApp, + BOOL FAR* lpfPrevBusyEnable, + BOOL FAR* lpfPrevNREnable +) +{ + if (lpOleApp->m_lpMsgFilter) { + *lpfPrevNREnable = OleStdMsgFilter_EnableNotRespondingDialog( + lpOleApp->m_lpMsgFilter, FALSE); + *lpfPrevBusyEnable = OleStdMsgFilter_EnableBusyDialog( + lpOleApp->m_lpMsgFilter, FALSE); + } +} + + +/* OleApp_EnableBusyDialogs +** ------------------------ +** Set the enable state of the Busy and NotResponding dialogs. +** +** This function is typically used after a call to +** OleApp_DisableBusyDialogs in order to restore the previous enable +** state of the dialogs. +*/ +void OleApp_EnableBusyDialogs( + LPOLEAPP lpOleApp, + BOOL fPrevBusyEnable, + BOOL fPrevNREnable +) +{ + if (lpOleApp->m_lpMsgFilter) { + OleStdMsgFilter_EnableNotRespondingDialog( + lpOleApp->m_lpMsgFilter, fPrevNREnable); + OleStdMsgFilter_EnableBusyDialog( + lpOleApp->m_lpMsgFilter, fPrevBusyEnable); + } +} + + +/* OleApp_PreModalDialog +** --------------------- +** Keep track that a modal dialog is about to be brought up. +** +** while a modal dialog is up we need to take special actions: +** 1. we do NOT want to initialize our tool bar buttons on +** WM_ACTIVATEAPP. the tool bar is not accessible. +** 2. we want to reject new top-level, incoming LRPC calls +** (return SERVERCALL_RETRYLATER from IMessageFilter:: +** HandleInComingCall). +** 3. (IN-PLACE SERVER) tell our in-place container to disable +** modeless dialogs by calling IOleInPlaceFrame:: +** EnableModeless(FALSE). +** 4. (IN-PLACE CONTAINER) tell our UIActive in-place object to +** disable modeless dialogs by calling IOleInPlaceActiveObject:: +** EnableModeless(FALSE). +*/ +void OleApp_PreModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpOleDoc) +{ + if (lpOleApp->m_cModalDlgActive == 0) { + // top-level modal dialog is being brought up + +#if defined( USE_FRAMETOOLS ) + LPFRAMETOOLS lptb; + + if (lpOleDoc) + lptb = ((LPOUTLINEDOC)lpOleDoc)->m_lpFrameTools; + else + lptb = OutlineApp_GetFrameTools((LPOUTLINEAPP)lpOleApp); + if (lptb) + FrameTools_EnableWindow(lptb, FALSE); +#endif // USE_FRAMETOOLS + + OleApp_RejectInComingCalls(lpOleApp, TRUE); + +#if defined( INPLACE_SVR ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + + /* if the document bringing up the modal dialog is + ** currently a UIActive in-place object, then tell the + ** top-level in-place frame to disable its modeless + ** dialogs. + */ + if (lpServerDoc && lpServerDoc->m_fUIActive && + lpServerDoc->m_lpIPData && + lpServerDoc->m_lpIPData->lpFrame) { + OLEDBG_BEGIN2("IOleInPlaceFrame::EnableModless(FALSE) called\r\n"); + lpServerDoc->m_lpIPData->lpFrame->lpVtbl->EnableModeless( + lpServerDoc->m_lpIPData->lpFrame, FALSE); + OLEDBG_END2 + } + } +#endif // INPLACE_SVR +#if defined( INPLACE_CNTR ) + { + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp; + + /* if the document bringing up the modal dialog is an + ** in-place container that has a UIActive object, then + ** tell the UIActive object to disable its modeless + ** dialogs. + */ + if (lpContainerApp->m_lpIPActiveObj) { + OLEDBG_BEGIN2("IOleInPlaceActiveObject::EnableModless(FALSE) called\r\n"); + lpContainerApp->m_lpIPActiveObj->lpVtbl->EnableModeless( + lpContainerApp->m_lpIPActiveObj, FALSE); + OLEDBG_END2 + } + } +#endif // INPLACE_CNTR + } + + lpOleApp->m_cModalDlgActive++; +} + + +/* OleApp_PostModalDialog +** ---------------------- +** Keep track that a modal dialog is being brought down. this call +** balances the OleApp_PreModalDialog call. +*/ +void OleApp_PostModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpOleDoc) +{ + lpOleApp->m_cModalDlgActive--; + + if (lpOleApp->m_cModalDlgActive == 0) { + // last modal dialog is being brought down + +#if defined( USE_FRAMETOOLS ) + LPFRAMETOOLS lptb; + + if (lpOleDoc) + lptb = ((LPOUTLINEDOC)lpOleDoc)->m_lpFrameTools; + else + lptb = OutlineApp_GetFrameTools((LPOUTLINEAPP)lpOleApp); + if (lptb) { + FrameTools_EnableWindow(lptb, TRUE); + FrameTools_UpdateButtons(lptb, (LPOUTLINEDOC)lpOleDoc); + } +#endif // USE_FRAMETOOLS + + OleApp_RejectInComingCalls(lpOleApp, FALSE); + +#if defined( INPLACE_SVR ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + + /* if the document bringing down the modal dialog is + ** currently a UIActive in-place object, then tell the + ** top-level in-place frame it can re-enable its + ** modeless dialogs. + */ + if (lpServerDoc && lpServerDoc->m_fUIActive && + lpServerDoc->m_lpIPData && + lpServerDoc->m_lpIPData->lpFrame) { + OLEDBG_BEGIN2("IOleInPlaceFrame::EnableModless(TRUE) called\r\n"); + lpServerDoc->m_lpIPData->lpFrame->lpVtbl->EnableModeless( + lpServerDoc->m_lpIPData->lpFrame, TRUE); + OLEDBG_END2 + } + } +#endif // INPLACE_SVR +#if defined( INPLACE_CNTR ) + { + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp; + + /* if the document bringing down the modal dialog is an + ** in-place container that has a UIActive object, then + ** tell the UIActive object it can re-enable its + ** modeless dialogs. + */ + if (lpContainerApp->m_lpIPActiveObj) { + OLEDBG_BEGIN2("IOleInPlaceActiveObject::EnableModless(TRUE) called\r\n"); + lpContainerApp->m_lpIPActiveObj->lpVtbl->EnableModeless( + lpContainerApp->m_lpIPActiveObj, TRUE); + OLEDBG_END2 + } + } +#endif // INPLACE_CNTR + } +} + + +/* OleApp_InitVtbls + * ---------------- + * + * initialize the methods in all of the interface Vtbl's + * + * OLE2NOTE: we only need one copy of each Vtbl. When an object which + * exposes an interface is instantiated, its lpVtbl is intialized + * to point to the single copy of the Vtbl. + * + */ +BOOL OleApp_InitVtbls (LPOLEAPP lpOleApp) +{ + BOOL fStatus; + + // OleApp::IUnknown method table + OleStdInitVtbl(&g_OleApp_UnknownVtbl, sizeof(IUnknownVtbl)); + g_OleApp_UnknownVtbl.QueryInterface = OleApp_Unk_QueryInterface; + g_OleApp_UnknownVtbl.AddRef = OleApp_Unk_AddRef; + g_OleApp_UnknownVtbl.Release = OleApp_Unk_Release; + fStatus = OleStdCheckVtbl( + &g_OleApp_UnknownVtbl, + sizeof(IUnknownVtbl), + "IUnknown" + ); + if (! fStatus) return FALSE; + + // OleDoc::IUnknown method table + OleStdInitVtbl(&g_OleDoc_UnknownVtbl, sizeof(IUnknownVtbl)); + g_OleDoc_UnknownVtbl.QueryInterface = OleDoc_Unk_QueryInterface; + g_OleDoc_UnknownVtbl.AddRef = OleDoc_Unk_AddRef; + g_OleDoc_UnknownVtbl.Release = OleDoc_Unk_Release; + fStatus = OleStdCheckVtbl( + &g_OleDoc_UnknownVtbl, + sizeof(IUnknownVtbl), + "IUnknown" + ); + if (! fStatus) return FALSE; + + // OleDoc::IPersistFile method table + OleStdInitVtbl(&g_OleDoc_PersistFileVtbl, sizeof(IPersistFileVtbl)); + g_OleDoc_PersistFileVtbl.QueryInterface = OleDoc_PFile_QueryInterface; + g_OleDoc_PersistFileVtbl.AddRef = OleDoc_PFile_AddRef; + g_OleDoc_PersistFileVtbl.Release = OleDoc_PFile_Release; + g_OleDoc_PersistFileVtbl.GetClassID = OleDoc_PFile_GetClassID; + g_OleDoc_PersistFileVtbl.IsDirty = OleDoc_PFile_IsDirty; + g_OleDoc_PersistFileVtbl.Load = OleDoc_PFile_Load; + g_OleDoc_PersistFileVtbl.Save = OleDoc_PFile_Save; + g_OleDoc_PersistFileVtbl.SaveCompleted = OleDoc_PFile_SaveCompleted; + g_OleDoc_PersistFileVtbl.GetCurFile = OleDoc_PFile_GetCurFile; + fStatus = OleStdCheckVtbl( + &g_OleDoc_PersistFileVtbl, + sizeof(IPersistFileVtbl), + "IPersistFile" + ); + if (! fStatus) return FALSE; + + // OleDoc::IOleItemContainer method table + OleStdInitVtbl(&g_OleDoc_OleItemContainerVtbl, sizeof(IOleItemContainerVtbl)); + g_OleDoc_OleItemContainerVtbl.QueryInterface = + OleDoc_ItemCont_QueryInterface; + g_OleDoc_OleItemContainerVtbl.AddRef = OleDoc_ItemCont_AddRef; + g_OleDoc_OleItemContainerVtbl.Release = OleDoc_ItemCont_Release; + g_OleDoc_OleItemContainerVtbl.ParseDisplayName = + OleDoc_ItemCont_ParseDisplayName; + g_OleDoc_OleItemContainerVtbl.EnumObjects= OleDoc_ItemCont_EnumObjects; + g_OleDoc_OleItemContainerVtbl.LockContainer = + OleDoc_ItemCont_LockContainer; + g_OleDoc_OleItemContainerVtbl.GetObject = OleDoc_ItemCont_GetObject; + g_OleDoc_OleItemContainerVtbl.GetObjectStorage = + OleDoc_ItemCont_GetObjectStorage; + g_OleDoc_OleItemContainerVtbl.IsRunning = OleDoc_ItemCont_IsRunning; + fStatus = OleStdCheckVtbl( + &g_OleDoc_OleItemContainerVtbl, + sizeof(IOleItemContainerVtbl), + "IOleItemContainer" + ); + if (! fStatus) return FALSE; + + // OleDoc::IExternalConnection method table + OleStdInitVtbl( + &g_OleDoc_ExternalConnectionVtbl,sizeof(IExternalConnectionVtbl)); + g_OleDoc_ExternalConnectionVtbl.QueryInterface = + OleDoc_ExtConn_QueryInterface; + g_OleDoc_ExternalConnectionVtbl.AddRef = OleDoc_ExtConn_AddRef; + g_OleDoc_ExternalConnectionVtbl.Release = OleDoc_ExtConn_Release; + g_OleDoc_ExternalConnectionVtbl.AddConnection = + OleDoc_ExtConn_AddConnection; + g_OleDoc_ExternalConnectionVtbl.ReleaseConnection = + OleDoc_ExtConn_ReleaseConnection; + fStatus = OleStdCheckVtbl( + &g_OleDoc_ExternalConnectionVtbl, + sizeof(IExternalConnectionVtbl), + "IExternalConnection" + ); + if (! fStatus) return FALSE; + + // OleDoc::IDataObject method table + OleStdInitVtbl(&g_OleDoc_DataObjectVtbl, sizeof(IDataObjectVtbl)); + g_OleDoc_DataObjectVtbl.QueryInterface = OleDoc_DataObj_QueryInterface; + g_OleDoc_DataObjectVtbl.AddRef = OleDoc_DataObj_AddRef; + g_OleDoc_DataObjectVtbl.Release = OleDoc_DataObj_Release; + g_OleDoc_DataObjectVtbl.GetData = OleDoc_DataObj_GetData; + g_OleDoc_DataObjectVtbl.GetDataHere = OleDoc_DataObj_GetDataHere; + g_OleDoc_DataObjectVtbl.QueryGetData = OleDoc_DataObj_QueryGetData; + g_OleDoc_DataObjectVtbl.GetCanonicalFormatEtc = + OleDoc_DataObj_GetCanonicalFormatEtc; + g_OleDoc_DataObjectVtbl.SetData = OleDoc_DataObj_SetData; + g_OleDoc_DataObjectVtbl.EnumFormatEtc = OleDoc_DataObj_EnumFormatEtc; + g_OleDoc_DataObjectVtbl.DAdvise = OleDoc_DataObj_DAdvise; + g_OleDoc_DataObjectVtbl.DUnadvise = OleDoc_DataObj_DUnadvise; + g_OleDoc_DataObjectVtbl.EnumDAdvise = OleDoc_DataObj_EnumDAdvise; + + fStatus = OleStdCheckVtbl( + &g_OleDoc_DataObjectVtbl, + sizeof(IDataObjectVtbl), + "IDataObject" + ); + if (! fStatus) return FALSE; + +#if defined( USE_DRAGDROP ) + + // OleDoc::IDropTarget method table + OleStdInitVtbl(&g_OleDoc_DropTargetVtbl, sizeof(IDropTargetVtbl)); + g_OleDoc_DropTargetVtbl.QueryInterface= OleDoc_DropTarget_QueryInterface; + g_OleDoc_DropTargetVtbl.AddRef = OleDoc_DropTarget_AddRef; + g_OleDoc_DropTargetVtbl.Release = OleDoc_DropTarget_Release; + + g_OleDoc_DropTargetVtbl.DragEnter = OleDoc_DropTarget_DragEnter; + g_OleDoc_DropTargetVtbl.DragOver = OleDoc_DropTarget_DragOver; + g_OleDoc_DropTargetVtbl.DragLeave = OleDoc_DropTarget_DragLeave; + g_OleDoc_DropTargetVtbl.Drop = OleDoc_DropTarget_Drop; + + fStatus = OleStdCheckVtbl( + &g_OleDoc_DropTargetVtbl, + sizeof(IDropTargetVtbl), + "IDropTarget" + ); + if (! fStatus) + return FALSE; + + // OleDoc::IDropSource method table + OleStdInitVtbl(&g_OleDoc_DropSourceVtbl, sizeof(IDropSourceVtbl)); + g_OleDoc_DropSourceVtbl.QueryInterface = + OleDoc_DropSource_QueryInterface; + g_OleDoc_DropSourceVtbl.AddRef = OleDoc_DropSource_AddRef; + g_OleDoc_DropSourceVtbl.Release = OleDoc_DropSource_Release; + + g_OleDoc_DropSourceVtbl.QueryContinueDrag = + OleDoc_DropSource_QueryContinueDrag; + g_OleDoc_DropSourceVtbl.GiveFeedback = OleDoc_DropSource_GiveFeedback; + + fStatus = OleStdCheckVtbl( + &g_OleDoc_DropSourceVtbl, + sizeof(IDropSourceVtbl), + "IDropSource" + ); + if (! fStatus) return FALSE; +#endif // USE_DRAGDROP + +#if defined( OLE_SERVER ) + + // Initialize the server specific interface method tables. + if (! ServerApp_InitVtbls((LPSERVERAPP)lpOleApp)) + return FALSE; +#endif +#if defined( OLE_CNTR ) + + // Initialize the container specific interface method tables. + if (! ContainerApp_InitVtbls((LPCONTAINERAPP)lpOleApp)) + return FALSE; +#endif + return TRUE; +}; + + + +/* OleApp_InitMenu + * --------------- + * + * Enable or Disable menu items depending on the state of + * the appliation. + * The OLE versions of the Outline sample app add a PasteSpecial command. + * Also, the container version add InsertObject and ObjectVerb menu items. + */ +void OleApp_InitMenu( + LPOLEAPP lpOleApp, + LPOLEDOC lpOleDoc, + HMENU hMenu +) +{ + BOOL bMsgFilterInstalled = FALSE; + BOOL bRejecting = FALSE; + + if (!lpOleApp || !hMenu) + return; + + OLEDBG_BEGIN3("OleApp_InitMenu\r\n") + + /* + ** Enable/disable menu items for Message Filter + */ + bMsgFilterInstalled = (lpOleApp->m_lpMsgFilter != NULL); + bRejecting = bMsgFilterInstalled && + OleStdMsgFilter_GetInComingCallStatus(lpOleApp->m_lpMsgFilter) != SERVERCALL_ISHANDLED; + + CheckMenuItem(hMenu, + IDM_D_INSTALLMSGFILTER, + bMsgFilterInstalled ? MF_CHECKED : MF_UNCHECKED); + + EnableMenuItem(hMenu, + IDM_D_REJECTINCOMING, + bMsgFilterInstalled ? MF_ENABLED : MF_GRAYED); + + CheckMenuItem(hMenu, + IDM_D_REJECTINCOMING, + bRejecting ? MF_CHECKED : MF_UNCHECKED); + +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; + BOOL fShowObject; + + fShowObject = ContainerDoc_GetShowObjectFlag(lpContainerDoc); + CheckMenuItem( + hMenu, + IDM_O_SHOWOBJECT, + (fShowObject ? MF_CHECKED : MF_UNCHECKED) + ); + +#if defined( INPLACE_CNTR ) && defined( _DEBUG ) + CheckMenuItem( + hMenu, + IDM_D_INSIDEOUT, + g_fInsideOutContainer ? MF_CHECKED:MF_UNCHECKED); +#endif // INPLACE_CNTR && _DEBUG + + } +#endif // OLE_CNTR + + OLEDBG_END3 +} + + + +/* OleApp_UpdateEditMenu + * --------------------- + * + * Purpose: + * Update the Edit menuitems of the App according to the state of + * OutlineDoc + * + * Parameter: + * lpOutlineDoc pointer to the document + * hMenuEdit edit menu handle + */ +void OleApp_UpdateEditMenu( + LPOLEAPP lpOleApp, + LPOUTLINEDOC lpOutlineDoc, + HMENU hMenuEdit +) +{ + int nFmtEtc; + UINT uEnablePaste = MF_GRAYED; + UINT uEnablePasteLink = MF_GRAYED; + LPDATAOBJECT lpClipboardDataObj; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + HRESULT hrErr; + BOOL fPrevEnable1; + BOOL fPrevEnable2; + + if (!lpOleApp || !lpOutlineDoc || !hMenuEdit) + return; + + if (!OleDoc_GetUpdateEditMenuFlag(lpOleDoc)) + /* OLE2NOTE: if the flag is not set, we don't have to update + ** the edit menu again. This blocks repetitive updating when + ** the user move the mouse across Edit menu while holding + ** down the button + */ + return; + + OLEDBG_BEGIN3("OleApp_InitEditMenu\r\n") + + /* OLE2NOTE: we do not want to ever give the busy dialog when we + ** are trying to put up our menus. eg. even if the source of + ** data on the clipboard is busy, we do not want put up the busy + ** dialog. thus we will disable the dialog and at the end + ** re-enable it. + */ + OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2); + + // check if there is data on the clipboard that we can paste/paste link + + OLEDBG_BEGIN2("OleGetClipboard called\r\n") + hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj); + OLEDBG_END2 + + if (hrErr == NOERROR) { + nFmtEtc = OleStdGetPriorityClipboardFormat( + lpClipboardDataObj, + lpOleApp->m_arrPasteEntries, + lpOleApp->m_nPasteEntries + ); + + if (nFmtEtc >= 0) + uEnablePaste = MF_ENABLED; // there IS a format we like + + OLEDBG_BEGIN2("OleQueryLinkFromData called\r\n") + hrErr = OleQueryLinkFromData(lpClipboardDataObj); + OLEDBG_END2 + + if(hrErr == NOERROR) + uEnablePasteLink = MF_ENABLED; + + OleStdRelease((LPUNKNOWN)lpClipboardDataObj); + } + + EnableMenuItem(hMenuEdit, IDM_E_PASTE, uEnablePaste); + EnableMenuItem(hMenuEdit, IDM_E_PASTESPECIAL, uEnablePaste); + + +#if defined( OLE_CNTR ) + if (ContainerDoc_GetNextLink((LPCONTAINERDOC)lpOutlineDoc, NULL)) + EnableMenuItem(hMenuEdit, IDM_E_EDITLINKS, MF_ENABLED); + else + EnableMenuItem(hMenuEdit, IDM_E_EDITLINKS, MF_GRAYED); + + + { + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp; + HMENU hMenuVerb = NULL; + LPOLEOBJECT lpOleObj = NULL; + LPCONTAINERLINE lpContainerLine = NULL; + BOOL fSelIsOleObject; + + EnableMenuItem(hMenuEdit, IDM_E_PASTELINK, uEnablePasteLink); + + /* check if selection is a single line that contains an OleObject */ + + fSelIsOleObject = ContainerDoc_IsSelAnOleObject( + (LPCONTAINERDOC)lpOutlineDoc, + &IID_IOleObject, + (LPUNKNOWN FAR*)&lpOleObj, + NULL, /* we don't need the line index */ + (LPCONTAINERLINE FAR*)&lpContainerLine + ); + + if (hMenuEdit != NULL) { + + /* If the current line is an ContainerLine, add the object + ** verb sub menu to the Edit menu. if the line is not an + ** ContainerLine, (lpOleObj==NULL) then disable the + ** Edit.Object command. this helper API takes care of + ** building the verb menu as appropriate. + */ + OleUIAddVerbMenu( + (LPOLEOBJECT)lpOleObj, + (lpContainerLine ? lpContainerLine->m_lpszShortType:NULL), + hMenuEdit, + POS_OBJECT, + IDM_E_OBJECTVERBMIN, + 0, // no uIDVerbMax enforced + TRUE, // Add Convert menu item + IDM_E_CONVERTVERB, // ID for Convert menu item + (HMENU FAR*) &hMenuVerb + ); + +#if defined( USE_STATUSBAR_LATER ) + /* setup status messages for the object verb menu */ + if (hMenuVerb) { + // REVIEW: this string should come from a string resource. + // REVIEW: this doesn't work for dynamically created menus + AssignPopupMessage( + hMenuVerb, + "Open, edit or interact with an object" + ); + } +#endif // USE_STATUSBAR_LATER + } + + if (lpOleObj) + OleStdRelease((LPUNKNOWN)lpOleObj); + } + +#endif // OLE_CNTR + + // re-enable the Busy/NotResponding dialogs + OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2); + + OleDoc_SetUpdateEditMenuFlag(lpOleDoc, FALSE); + + OLEDBG_END3 +} + + +/* OleApp_RegisterClassFactory + * --------------------------- + * + * Register our app's ClassFactory with OLE. + * + */ +BOOL OleApp_RegisterClassFactory(LPOLEAPP lpOleApp) +{ + HRESULT hrErr; + + if (lpOleApp->m_lpClassFactory) + return TRUE; // already registered + + OLEDBG_BEGIN3("OleApp_RegisterClassFactory\r\n") + + /****************************************************************** + ** An SDI app must register its ClassFactory if it is launched + ** for embedding (/Embedding command line option specified). + ** An MDI app must register its ClassFactory in all cases, + ******************************************************************/ + + lpOleApp->m_lpClassFactory = AppClassFactory_Create(); + if (! lpOleApp->m_lpClassFactory) { + OutlineApp_ErrorMessage(g_lpApp, ErrMsgCreateCF); + goto error; + } + + OLEDBG_BEGIN2("CoRegisterClassObject called\r\n") + hrErr = CoRegisterClassObject( + &CLSID_APP, + (LPUNKNOWN)lpOleApp->m_lpClassFactory, + CLSCTX_LOCAL_SERVER, + REGCLS_SINGLEUSE, + &lpOleApp->m_dwRegClassFac + ); + OLEDBG_END2 + + if(hrErr != NOERROR) { + OleDbgOutHResult("CoRegisterClassObject returned", hrErr); + OutlineApp_ErrorMessage(g_lpApp, ErrMsgRegCF); + goto error; + } + + OLEDBG_END3 + return TRUE; + +error: + + if (lpOleApp->m_lpClassFactory) { + OleStdRelease((LPUNKNOWN)lpOleApp->m_lpClassFactory); + lpOleApp->m_lpClassFactory = NULL; + } + OLEDBG_END3 + return FALSE; +} + + +/* OleApp_RevokeClassFactory + * ------------------------- + * + * Revoke our app's ClassFactory. + * + */ +void OleApp_RevokeClassFactory(LPOLEAPP lpOleApp) +{ + HRESULT hrErr; + + if (lpOleApp->m_lpClassFactory) { + + OLEDBG_BEGIN2("CoRevokeClassObject called\r\n") + hrErr = CoRevokeClassObject(lpOleApp->m_dwRegClassFac); + OLEDBG_END2 + +#if defined( _DEBUG ) + if (hrErr != NOERROR) { + OleDbgOutHResult("CoRevokeClassObject returned", hrErr); + } +#endif + + // we just release here; other folks may still have + // a pointer to our class factory, so we can't + // do any checks on the reference count. + OleStdRelease((LPUNKNOWN)lpOleApp->m_lpClassFactory); + lpOleApp->m_lpClassFactory = NULL; + } +} + + +#if defined( USE_MSGFILTER ) + +/* OleApp_RegisterMessageFilter + * ---------------------------- + * Register our IMessageFilter*. the message filter is used to handle + * concurrency. we will use a standard implementation of IMessageFilter + * that is included as part of the OLE2UI library. + */ +BOOL OleApp_RegisterMessageFilter(LPOLEAPP lpOleApp) +{ + HRESULT hrErr; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + + if (lpOleApp->m_lpMsgFilter == NULL) { + // Register our message filter. + lpOleApp->m_lpfnMsgPending = (MSGPENDINGPROC)MessagePendingProc; + lpOleApp->m_lpMsgFilter = OleStdMsgFilter_Create( + g_lpApp->m_hWndApp, + (LPSTR)APPNAME, + lpOleApp->m_lpfnMsgPending, + NULL /* Busy dialog callback hook function */ + ); + + OLEDBG_BEGIN2("CoRegisterMessageFilter called\r\n") + hrErr = CoRegisterMessageFilter( + lpOleApp->m_lpMsgFilter, + NULL /* don't need previous message filter */ + ); + OLEDBG_END2 + + if(hrErr != NOERROR) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgRegMF); + return FALSE; + } + } + return TRUE; +} + + +/* OleApp_RevokeMessageFilter + * -------------------------- + * Revoke our IMessageFilter*. the message filter is used to handle + * concurrency. we will use a standard implementation of IMessageFilter + * that is included as part of the OLE2UI library. + */ +void OleApp_RevokeMessageFilter(LPOLEAPP lpOleApp) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + + if (lpOleApp->m_lpMsgFilter != NULL) { + // Revoke our message filter + OLEDBG_BEGIN2("CoRegisterMessageFilter(NULL) called\r\n") + CoRegisterMessageFilter(NULL, NULL); + OLEDBG_END2 + + if (lpOleApp->m_lpfnMsgPending) { + lpOleApp->m_lpfnMsgPending = NULL; + } + + OleStdVerifyRelease( + (LPUNKNOWN)lpOleApp->m_lpMsgFilter, + "Release MessageFilter FAILED!" + ); + lpOleApp->m_lpMsgFilter = NULL; + } +} + + +/* MessagePendingProc + * ------------------ + * + * Callback function for the IMessageFilter::MessagePending procedure. This + * function is called when a message is received by our application while + * we are waiting for an OLE call to complete. We are essentially + * blocked at this point, waiting for a response from the other OLE application. + * We should not process any messages which might cause another OLE call + * to become blocked, or any other call which might cause re-entrancy problems. + * + * For this application, only process WM_PAINT messages. A more sophisticated + * application might allow certain menu messages and menu items to be processed + * also. + * + * RETURNS: TRUE if we processed the message, FALSE if we did not. + */ + +BOOL FAR PASCAL EXPORT MessagePendingProc(MSG FAR *lpMsg) +{ + // Our application is only handling WM_PAINT messages when we are blocked + switch (lpMsg->message) { + case WM_PAINT: + OleDbgOut2("WM_PAINT dispatched while blocked\r\n"); + + DispatchMessage(lpMsg); + break; + } + + return FALSE; // return PENDINGMSG_WAITDEFPROCESS from MessagePending +} +#endif // USE_MSGFILTER + + +/* OleApp_FlushClipboard + * --------------------- + * + * Force the Windows clipboard to release our clipboard DataObject. + */ +void OleApp_FlushClipboard(LPOLEAPP lpOleApp) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + LPOLEDOC lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc; + OLEDBG_BEGIN3("OleApp_FlushClipboard\r\n") + + /* OLE2NOTE: if for some reason our clipboard data transfer + ** document is still held on to by an external client, we want + ** to forceably break all external connections. + */ + OLEDBG_BEGIN2("CoDisconnectObject called\r\n") + CoDisconnectObject((LPUNKNOWN)&lpClipboardDoc->m_Unknown, 0); + OLEDBG_END2 + + OLEDBG_BEGIN2("OleFlushClipboard called\r\n") + OleFlushClipboard(); + OLEDBG_END2 + + lpOutlineApp->m_lpClipboardDoc = NULL; + + OLEDBG_END3 +} + + +/* OleApp_NewCommand + * ----------------- + * + * Start a new untitled document (File.New command). + */ +void OleApp_NewCommand(LPOLEAPP lpOleApp) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc; + + if (! OutlineDoc_Close(lpOutlineDoc, OLECLOSE_PROMPTSAVE)) + return; + + OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed"); + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + /* OLE2NOTE: initially the Doc object is created with a 0 ref + ** count. in order to have a stable Doc object during the + ** process of initializing the new Doc instance, + ** we intially AddRef the Doc ref cnt and later + ** Release it. This initial AddRef is artificial; it is simply + ** done to guarantee that a harmless QueryInterface followed by + ** a Release does not inadvertantly force our object to destroy + ** itself prematurely. + */ + OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc); + + // set the doc to an (Untitled) doc. + if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc)) + goto error; + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); // calls OleDoc_Lock + + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); // rel artificial AddRef + + return; + +error: + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Could not create new document"); + + if (lpOutlineApp->m_lpDoc) { + // releasing the artificial AddRef above will destroy the document + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); + lpOutlineApp->m_lpDoc = NULL; + } + + return; +} + + +/* OleApp_OpenCommand + * ------------------ + * + * Load a document from file (File.Open command). + */ +void OleApp_OpenCommand(LPOLEAPP lpOleApp) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp; + LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc; + OPENFILENAME ofn; + char szFilter[]=APPFILENAMEFILTER; + char szFileName[256]; + UINT i; + DWORD dwSaveOption = OLECLOSE_PROMPTSAVE; + BOOL fStatus = TRUE; + + if (! OutlineDoc_CheckSaveChanges(lpOutlineDoc, &dwSaveOption)) + return; // abort opening new doc + + for(i=0; szFilter[i]; i++) + if(szFilter[i]=='|') szFilter[i]='\0'; + + _fmemset((LPOPENFILENAME)&ofn,0,sizeof(OPENFILENAME)); + + szFileName[0]='\0'; + + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.hwndOwner=lpOutlineApp->m_hWndApp; + ofn.lpstrFilter=(LPSTR)szFilter; + ofn.lpstrFile=(LPSTR)szFileName; + ofn.nMaxFile=sizeof(szFileName); + ofn.Flags=OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt=DEFEXTENSION; + + OleApp_PreModalDialog(lpOleApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); + + fStatus = GetOpenFileName((LPOPENFILENAME)&ofn); + + OleApp_PostModalDialog(lpOleApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); + + if(! fStatus) + return; // user canceled file open dialog + + OutlineDoc_Close(lpOutlineDoc, OLECLOSE_NOSAVE); + OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed"); + + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + /* OLE2NOTE: initially the Doc object is created with a 0 ref + ** count. in order to have a stable Doc object during the + ** process of initializing the new Doc instance, + ** we intially AddRef the Doc ref cnt and later + ** Release it. This initial AddRef is artificial; it is simply + ** done to guarantee that a harmless QueryInterface followed by + ** a Release does not inadvertantly force our object to destroy + ** itself prematurely. + */ + OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc); + + fStatus=OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, (LPSTR)szFileName); + + if (! fStatus) { + // loading the doc failed; create an untitled instead + + // releasing the artificial AddRef above will destroy the document + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); + + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc); + + if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc)) + goto error; + } + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); + +#if defined( OLE_CNTR ) + UpdateWindow(lpOutlineApp->m_hWndApp); + ContainerDoc_UpdateLinks((LPCONTAINERDOC)lpOutlineApp->m_lpDoc); +#endif + + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); // rel artificial AddRef + + return; + +error: + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Could not create new document"); + + if (lpOutlineApp->m_lpDoc) { + // releasing the artificial AddRef above will destroy the document + OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); + lpOutlineApp->m_lpDoc = NULL; + } + + return; +} + + + +#if defined( OLE_CNTR ) + +/* OLE2NOTE: forward the WM_QUERYNEWPALETTE message (via +** SendMessage) to UIActive in-place object if there is one. +** this gives the UIActive object the opportunity to select +** and realize its color palette as the FOREGROUND palette. +** this is optional for in-place containers. if a container +** prefers to force its color palette as the foreground +** palette then it should NOT forward the this message. or +** the container can give the UIActive object priority; if +** the UIActive object returns 0 from the WM_QUERYNEWPALETTE +** message (ie. it did not realize its own palette), then +** the container can realize its palette. +** (see ContainerDoc_ForwardPaletteChangedMsg for more info) +** +** (It is a good idea for containers to use the standard +** palette even if they do not use colors themselves. this +** will allow embedded object to get a good distribution of +** colors when they are being drawn by the container) +** +*/ + +LRESULT OleApp_QueryNewPalette(LPOLEAPP lpOleApp) +{ +#if defined( INPLACE_CNTR ) + LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp; + + if (lpContainerApp && lpContainerApp->m_hWndUIActiveObj) { + if (SendMessage(lpContainerApp->m_hWndUIActiveObj, WM_QUERYNEWPALETTE, + (WPARAM)0, (LPARAM)0)) { + /* Object selected its palette as foreground palette */ + return (LRESULT)1; + } + } +#endif // INPLACE_CNTR + + + return wSelectPalette(((LPOUTLINEAPP)lpOleApp)->m_hWndApp, + lpOleApp->m_hStdPal, FALSE/*fBackground*/); +} + +#endif // OLE_CNTR + + + +/* This is just a helper routine */ + +LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground) +{ + HDC hdc; + HPALETTE hOldPal; + UINT iPalChg = 0; + + if (hPal == 0) + return (LRESULT)0; + + hdc = GetDC(hWnd); + hOldPal = SelectPalette(hdc, hPal, fBackground); + iPalChg = RealizePalette(hdc); + SelectPalette(hdc, hOldPal, TRUE /*fBackground*/); + ReleaseDC(hWnd, hdc); + + if (iPalChg > 0) + InvalidateRect(hWnd, NULL, TRUE); + + return (LRESULT)1; +} + + + + +/************************************************************************* +** OleApp::IUnknown interface implementation +*************************************************************************/ + +STDMETHODIMP OleApp_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEAPP lpOleApp = ((struct CAppUnknownImpl FAR*)lpThis)->lpOleApp; + + return OleApp_QueryInterface(lpOleApp, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) OleApp_Unk_AddRef(LPUNKNOWN lpThis) +{ + LPOLEAPP lpOleApp = ((struct CAppUnknownImpl FAR*)lpThis)->lpOleApp; + + OleDbgAddRefMethod(lpThis, "IUnknown"); + + return OleApp_AddRef(lpOleApp); +} + + +STDMETHODIMP_(ULONG) OleApp_Unk_Release (LPUNKNOWN lpThis) +{ + LPOLEAPP lpOleApp = ((struct CAppUnknownImpl FAR*)lpThis)->lpOleApp; + + OleDbgReleaseMethod(lpThis, "IUnknown"); + + return OleApp_Release(lpOleApp); +} + + + + +#if defined( OLE_SERVER ) + +/************************************************************************* +** ServerDoc Supprt Functions Used by Server versions +*************************************************************************/ + +/* ServerApp_InitInstance + * ---------------------- + * + * Initialize the app instance by creating the main frame window and + * performing app instance specific initializations + * (eg. initializing interface Vtbls). + * + * RETURNS: TRUE if the memory could be allocated, and the server app + * was properly initialized. + * FALSE otherwise + * + */ + +BOOL ServerApp_InitInstance( + LPSERVERAPP lpServerApp, + HINSTANCE hInst, + int nCmdShow +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + + /* Setup arrays used by IDataObject::EnumFormatEtc. + ** + ** OLE2NOTE: The order that the formats are listed for GetData is very + ** significant. It should be listed in order of highest fidelity + ** formats to least fidelity formats. A common ordering will be: + ** 1. private app formats + ** 2. EmbedSource + ** 3. lower fidelity interchange formats + ** 4. pictures (metafile, dib, etc.) + ** (graphic-related apps offer pictures 1st!) + ** 5. LinkSource + */ + + /* m_arrDocGetFmts array enumerates the formats that a ServerDoc + ** DataTransferDoc object can offer (give) through a + ** IDataObject::GetData call. a ServerDoc DataTransferDoc offers + ** data formats in the following order: + ** 1. CF_OUTLINE + ** 2. CF_EMBEDSOURCE + ** 3. CF_OBJECTDESCRIPTOR + ** 4. CF_TEXT + ** 5. CF_METAFILEPICT + ** 6. CF_LINKSOURCE * + ** 7. CF_LINKSRCDESCRIPTOR * + ** + ** * NOTE: CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR is only + ** offered if the doc is able to give + ** a Moniker which references the data. CF_LINKSOURCE is + ** deliberately listed last in this array of possible formats. + ** if the doc does not have a Moniker then the last element of + ** this array is not used. (see SvrDoc_DataObj_EnumFormatEtc). + ** + ** NOTE: The list of formats that a USER ServerDoc document can + ** offer is a static list and is registered in the registration + ** database for the SVROUTL class. The + ** IDataObject::EnumFormatEtc method returns OLE_S_USEREG in the + ** case the document is a user docuemt (ie. created via + ** File.New, File.Open, InsertObject in a container, or + ** IPersistFile::Load during binding a link source). this tells + ** OLE to enumerate the formats automatically using the data the + ** the REGDB. + */ + + lpOleApp->m_arrDocGetFmts[0].cfFormat = lpOutlineApp->m_cfOutline; + lpOleApp->m_arrDocGetFmts[0].ptd = NULL; + lpOleApp->m_arrDocGetFmts[0].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[0].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[0].lindex = -1; + + lpOleApp->m_arrDocGetFmts[1].cfFormat = lpOleApp->m_cfEmbedSource; + lpOleApp->m_arrDocGetFmts[1].ptd = NULL; + lpOleApp->m_arrDocGetFmts[1].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[1].tymed = TYMED_ISTORAGE; + lpOleApp->m_arrDocGetFmts[1].lindex = -1; + + lpOleApp->m_arrDocGetFmts[2].cfFormat = CF_TEXT; + lpOleApp->m_arrDocGetFmts[2].ptd = NULL; + lpOleApp->m_arrDocGetFmts[2].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[2].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[2].lindex = -1; + + lpOleApp->m_arrDocGetFmts[3].cfFormat = CF_METAFILEPICT; + lpOleApp->m_arrDocGetFmts[3].ptd = NULL; + lpOleApp->m_arrDocGetFmts[3].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[3].tymed = TYMED_MFPICT; + lpOleApp->m_arrDocGetFmts[3].lindex = -1; + + lpOleApp->m_arrDocGetFmts[4].cfFormat = lpOleApp->m_cfObjectDescriptor; + lpOleApp->m_arrDocGetFmts[4].ptd = NULL; + lpOleApp->m_arrDocGetFmts[4].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[4].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[4].lindex = -1; + + lpOleApp->m_arrDocGetFmts[5].cfFormat = lpOleApp->m_cfLinkSource; + lpOleApp->m_arrDocGetFmts[5].ptd = NULL; + lpOleApp->m_arrDocGetFmts[5].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[5].tymed = TYMED_ISTREAM; + lpOleApp->m_arrDocGetFmts[5].lindex = -1; + + lpOleApp->m_arrDocGetFmts[6].cfFormat = lpOleApp->m_cfLinkSrcDescriptor; + lpOleApp->m_arrDocGetFmts[6].ptd = NULL; + lpOleApp->m_arrDocGetFmts[6].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[6].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[6].lindex = -1; + + lpOleApp->m_nDocGetFmts = 7; + + /* m_arrPasteEntries array enumerates the formats that a ServerDoc + ** object can accept (get) from the clipboard. + ** The formats are listed in priority order. + ** ServerDoc accept data formats in the following order: + ** 1. CF_OUTLINE + ** 2. CF_TEXT + */ + // REVIEW: strings should be loaded from string resource + lpOleApp->m_arrPasteEntries[0].fmtetc.cfFormat =lpOutlineApp->m_cfOutline; + lpOleApp->m_arrPasteEntries[0].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[0].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[0].fmtetc.tymed = TYMED_HGLOBAL; + lpOleApp->m_arrPasteEntries[0].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[0].lpstrFormatName = "Outline Data"; + lpOleApp->m_arrPasteEntries[0].lpstrResultText = "Outline Data"; + lpOleApp->m_arrPasteEntries[0].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[1].fmtetc.cfFormat = CF_TEXT; + lpOleApp->m_arrPasteEntries[1].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[1].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[1].fmtetc.tymed = TYMED_HGLOBAL; + lpOleApp->m_arrPasteEntries[1].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[1].lpstrFormatName = "Text"; + lpOleApp->m_arrPasteEntries[1].lpstrResultText = "text"; + lpOleApp->m_arrPasteEntries[1].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_nPasteEntries = 2; + + /** m_arrLinkTypes array enumerates the link types that a ServerDoc + ** object can accept from the clipboard. ServerDoc does NOT + ** accept any type of link from the clipboard. ServerDoc can + ** only be the source of a link. it can not contain links. + */ + + lpOleApp->m_nLinkTypes = 0; + +#if defined( INPLACE_SVR ) + + lpServerApp->m_hAccelBaseApp = NULL; + lpServerApp->m_hAccelIPSvr = LoadAccelerators( + hInst, + "InPlaceSvrOutlAccel" + ); + + lpServerApp->m_lpIPData = NULL; + + lpServerApp->m_hMenuEdit = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_EDITMENU + ); + lpServerApp->m_hMenuLine = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_LINEMENU + ); + lpServerApp->m_hMenuName = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_NAMEMENU + ); + lpServerApp->m_hMenuOptions = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_OPTIONSMENU + ); + lpServerApp->m_hMenuDebug = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_DEBUGMENU + ); + lpServerApp->m_hMenuHelp = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_HELPMENU + ); + +#endif // INPLACE_SVR + + return TRUE; +} + + +/* ServerApp_InitVtbls + * ------------------- + * + * initialize the methods in all of the interface Vtbl's + * + * OLE2NOTE: we only need one copy of each Vtbl. When an object which + * exposes an interface is instantiated, its lpVtbl is intialized + * to point to the single copy of the Vtbl. + * + */ +BOOL ServerApp_InitVtbls (LPSERVERAPP lpServerApp) +{ + BOOL fStatus; + + // ServerDoc::IOleObject method table + OleStdInitVtbl(&g_SvrDoc_OleObjectVtbl, sizeof(IOleObjectVtbl)); + g_SvrDoc_OleObjectVtbl.QueryInterface = SvrDoc_OleObj_QueryInterface; + g_SvrDoc_OleObjectVtbl.AddRef = SvrDoc_OleObj_AddRef; + g_SvrDoc_OleObjectVtbl.Release = SvrDoc_OleObj_Release; + g_SvrDoc_OleObjectVtbl.SetClientSite = SvrDoc_OleObj_SetClientSite; + g_SvrDoc_OleObjectVtbl.GetClientSite = SvrDoc_OleObj_GetClientSite; + g_SvrDoc_OleObjectVtbl.SetHostNames = SvrDoc_OleObj_SetHostNames; + g_SvrDoc_OleObjectVtbl.Close = SvrDoc_OleObj_Close; + g_SvrDoc_OleObjectVtbl.SetMoniker = SvrDoc_OleObj_SetMoniker; + g_SvrDoc_OleObjectVtbl.GetMoniker = SvrDoc_OleObj_GetMoniker; + g_SvrDoc_OleObjectVtbl.InitFromData = SvrDoc_OleObj_InitFromData; + g_SvrDoc_OleObjectVtbl.GetClipboardData = SvrDoc_OleObj_GetClipboardData; + g_SvrDoc_OleObjectVtbl.DoVerb = SvrDoc_OleObj_DoVerb; + g_SvrDoc_OleObjectVtbl.EnumVerbs = SvrDoc_OleObj_EnumVerbs; + g_SvrDoc_OleObjectVtbl.Update = SvrDoc_OleObj_Update; + g_SvrDoc_OleObjectVtbl.IsUpToDate = SvrDoc_OleObj_IsUpToDate; + g_SvrDoc_OleObjectVtbl.GetUserClassID = SvrDoc_OleObj_GetUserClassID; + g_SvrDoc_OleObjectVtbl.GetUserType = SvrDoc_OleObj_GetUserType; + g_SvrDoc_OleObjectVtbl.SetExtent = SvrDoc_OleObj_SetExtent; + g_SvrDoc_OleObjectVtbl.GetExtent = SvrDoc_OleObj_GetExtent; + g_SvrDoc_OleObjectVtbl.Advise = SvrDoc_OleObj_Advise; + g_SvrDoc_OleObjectVtbl.Unadvise = SvrDoc_OleObj_Unadvise; + g_SvrDoc_OleObjectVtbl.EnumAdvise = SvrDoc_OleObj_EnumAdvise; + g_SvrDoc_OleObjectVtbl.GetMiscStatus = SvrDoc_OleObj_GetMiscStatus; + g_SvrDoc_OleObjectVtbl.SetColorScheme = SvrDoc_OleObj_SetColorScheme; + fStatus = OleStdCheckVtbl( + &g_SvrDoc_OleObjectVtbl, + sizeof(IOleObjectVtbl), + "IOleObject" + ); + if (! fStatus) return FALSE; + + // ServerDoc::IPersistStorage method table + OleStdInitVtbl(&g_SvrDoc_PersistStorageVtbl, sizeof(IPersistStorageVtbl)); + g_SvrDoc_PersistStorageVtbl.QueryInterface = SvrDoc_PStg_QueryInterface; + g_SvrDoc_PersistStorageVtbl.AddRef = SvrDoc_PStg_AddRef; + g_SvrDoc_PersistStorageVtbl.Release = SvrDoc_PStg_Release; + g_SvrDoc_PersistStorageVtbl.GetClassID = SvrDoc_PStg_GetClassID; + g_SvrDoc_PersistStorageVtbl.IsDirty = SvrDoc_PStg_IsDirty; + g_SvrDoc_PersistStorageVtbl.InitNew = SvrDoc_PStg_InitNew; + g_SvrDoc_PersistStorageVtbl.Load = SvrDoc_PStg_Load; + g_SvrDoc_PersistStorageVtbl.Save = SvrDoc_PStg_Save; + g_SvrDoc_PersistStorageVtbl.SaveCompleted = SvrDoc_PStg_SaveCompleted; + g_SvrDoc_PersistStorageVtbl.HandsOffStorage = SvrDoc_PStg_HandsOffStorage; + fStatus = OleStdCheckVtbl( + &g_SvrDoc_PersistStorageVtbl, + sizeof(IPersistStorageVtbl), + "IPersistStorage" + ); + if (! fStatus) return FALSE; + +#if defined( SVR_TREATAS ) + // ServerDoc::IStdMarshalInfo method table + OleStdInitVtbl( + &g_SvrDoc_StdMarshalInfoVtbl, sizeof(IStdMarshalInfoVtbl)); + g_SvrDoc_StdMarshalInfoVtbl.QueryInterface = + SvrDoc_StdMshl_QueryInterface; + g_SvrDoc_StdMarshalInfoVtbl.AddRef = SvrDoc_StdMshl_AddRef; + g_SvrDoc_StdMarshalInfoVtbl.Release = SvrDoc_StdMshl_Release; + g_SvrDoc_StdMarshalInfoVtbl.GetClassForHandler = + SvrDoc_StdMshl_GetClassForHandler; + fStatus = OleStdCheckVtbl( + &g_SvrDoc_StdMarshalInfoVtbl, + sizeof(IStdMarshalInfoVtbl), + "IStdMarshalInfo" + ); + if (! fStatus) return FALSE; +#endif // SVR_TREATAS + +#if defined( INPLACE_SVR ) + // ServerDoc::IOleInPlaceObject method table + OleStdInitVtbl( + &g_SvrDoc_OleInPlaceObjectVtbl, + sizeof(IOleInPlaceObjectVtbl) + ); + g_SvrDoc_OleInPlaceObjectVtbl.QueryInterface + = SvrDoc_IPObj_QueryInterface; + g_SvrDoc_OleInPlaceObjectVtbl.AddRef + = SvrDoc_IPObj_AddRef; + g_SvrDoc_OleInPlaceObjectVtbl.Release + = SvrDoc_IPObj_Release; + g_SvrDoc_OleInPlaceObjectVtbl.GetWindow + = SvrDoc_IPObj_GetWindow; + g_SvrDoc_OleInPlaceObjectVtbl.ContextSensitiveHelp + = SvrDoc_IPObj_ContextSensitiveHelp; + g_SvrDoc_OleInPlaceObjectVtbl.InPlaceDeactivate + = SvrDoc_IPObj_InPlaceDeactivate; + g_SvrDoc_OleInPlaceObjectVtbl.UIDeactivate + = SvrDoc_IPObj_UIDeactivate; + g_SvrDoc_OleInPlaceObjectVtbl.SetObjectRects + = SvrDoc_IPObj_SetObjectRects; + g_SvrDoc_OleInPlaceObjectVtbl.ReactivateAndUndo + = SvrDoc_IPObj_ReactivateAndUndo; + fStatus = OleStdCheckVtbl( + &g_SvrDoc_OleInPlaceObjectVtbl, + sizeof(IOleInPlaceObjectVtbl), + "IOleInPlaceObject" + ); + if (! fStatus) return FALSE; + + // ServerDoc::IOleInPlaceActiveObject method table + OleStdInitVtbl( + &g_SvrDoc_OleInPlaceActiveObjectVtbl, + sizeof(IOleInPlaceActiveObjectVtbl) + ); + g_SvrDoc_OleInPlaceActiveObjectVtbl.QueryInterface + = SvrDoc_IPActiveObj_QueryInterface; + g_SvrDoc_OleInPlaceActiveObjectVtbl.AddRef + = SvrDoc_IPActiveObj_AddRef; + g_SvrDoc_OleInPlaceActiveObjectVtbl.Release + = SvrDoc_IPActiveObj_Release; + g_SvrDoc_OleInPlaceActiveObjectVtbl.GetWindow + = SvrDoc_IPActiveObj_GetWindow; + g_SvrDoc_OleInPlaceActiveObjectVtbl.ContextSensitiveHelp + = SvrDoc_IPActiveObj_ContextSensitiveHelp; + g_SvrDoc_OleInPlaceActiveObjectVtbl.TranslateAccelerator + = SvrDoc_IPActiveObj_TranslateAccelerator; + g_SvrDoc_OleInPlaceActiveObjectVtbl.OnFrameWindowActivate + = SvrDoc_IPActiveObj_OnFrameWindowActivate; + g_SvrDoc_OleInPlaceActiveObjectVtbl.OnDocWindowActivate + = SvrDoc_IPActiveObj_OnDocWindowActivate; + g_SvrDoc_OleInPlaceActiveObjectVtbl.ResizeBorder + = SvrDoc_IPActiveObj_ResizeBorder; + g_SvrDoc_OleInPlaceActiveObjectVtbl.EnableModeless + = SvrDoc_IPActiveObj_EnableModeless; + fStatus = OleStdCheckVtbl( + &g_SvrDoc_OleInPlaceActiveObjectVtbl, + sizeof(IOleInPlaceActiveObjectVtbl), + "IOleInPlaceActiveObject" + ); + if (! fStatus) return FALSE; + +#endif + + + // PseudoObj::IUnknown method table + OleStdInitVtbl(&g_PseudoObj_UnknownVtbl, sizeof(IUnknownVtbl)); + g_PseudoObj_UnknownVtbl.QueryInterface = PseudoObj_Unk_QueryInterface; + g_PseudoObj_UnknownVtbl.AddRef = PseudoObj_Unk_AddRef; + g_PseudoObj_UnknownVtbl.Release = PseudoObj_Unk_Release; + fStatus = OleStdCheckVtbl( + &g_PseudoObj_UnknownVtbl, + sizeof(IUnknownVtbl), + "IUnknown" + ); + if (! fStatus) return FALSE; + + // PseudoObj::IOleObject method table + OleStdInitVtbl(&g_PseudoObj_OleObjectVtbl, sizeof(IOleObjectVtbl)); + g_PseudoObj_OleObjectVtbl.QueryInterface= PseudoObj_OleObj_QueryInterface; + g_PseudoObj_OleObjectVtbl.AddRef = PseudoObj_OleObj_AddRef; + g_PseudoObj_OleObjectVtbl.Release = PseudoObj_OleObj_Release; + g_PseudoObj_OleObjectVtbl.SetClientSite = PseudoObj_OleObj_SetClientSite; + g_PseudoObj_OleObjectVtbl.GetClientSite = PseudoObj_OleObj_GetClientSite; + g_PseudoObj_OleObjectVtbl.SetHostNames = PseudoObj_OleObj_SetHostNames; + g_PseudoObj_OleObjectVtbl.Close = PseudoObj_OleObj_Close; + g_PseudoObj_OleObjectVtbl.SetMoniker = PseudoObj_OleObj_SetMoniker; + g_PseudoObj_OleObjectVtbl.GetMoniker = PseudoObj_OleObj_GetMoniker; + g_PseudoObj_OleObjectVtbl.InitFromData = PseudoObj_OleObj_InitFromData; + g_PseudoObj_OleObjectVtbl.GetClipboardData = + PseudoObj_OleObj_GetClipboardData; + g_PseudoObj_OleObjectVtbl.DoVerb = PseudoObj_OleObj_DoVerb; + g_PseudoObj_OleObjectVtbl.EnumVerbs = PseudoObj_OleObj_EnumVerbs; + g_PseudoObj_OleObjectVtbl.Update = PseudoObj_OleObj_Update; + g_PseudoObj_OleObjectVtbl.IsUpToDate = PseudoObj_OleObj_IsUpToDate; + g_PseudoObj_OleObjectVtbl.GetUserType = PseudoObj_OleObj_GetUserType; + g_PseudoObj_OleObjectVtbl.GetUserClassID= PseudoObj_OleObj_GetUserClassID; + g_PseudoObj_OleObjectVtbl.SetExtent = PseudoObj_OleObj_SetExtent; + g_PseudoObj_OleObjectVtbl.GetExtent = PseudoObj_OleObj_GetExtent; + g_PseudoObj_OleObjectVtbl.Advise = PseudoObj_OleObj_Advise; + g_PseudoObj_OleObjectVtbl.Unadvise = PseudoObj_OleObj_Unadvise; + g_PseudoObj_OleObjectVtbl.EnumAdvise = PseudoObj_OleObj_EnumAdvise; + g_PseudoObj_OleObjectVtbl.GetMiscStatus = PseudoObj_OleObj_GetMiscStatus; + g_PseudoObj_OleObjectVtbl.SetColorScheme= PseudoObj_OleObj_SetColorScheme; + fStatus = OleStdCheckVtbl( + &g_PseudoObj_OleObjectVtbl, + sizeof(IOleObjectVtbl), + "IOleObject" + ); + if (! fStatus) return FALSE; + + // ServerDoc::IDataObject method table + OleStdInitVtbl(&g_PseudoObj_DataObjectVtbl, sizeof(IDataObjectVtbl)); + g_PseudoObj_DataObjectVtbl.QueryInterface = + PseudoObj_DataObj_QueryInterface; + g_PseudoObj_DataObjectVtbl.AddRef = PseudoObj_DataObj_AddRef; + g_PseudoObj_DataObjectVtbl.Release = PseudoObj_DataObj_Release; + g_PseudoObj_DataObjectVtbl.GetData = PseudoObj_DataObj_GetData; + g_PseudoObj_DataObjectVtbl.GetDataHere = PseudoObj_DataObj_GetDataHere; + g_PseudoObj_DataObjectVtbl.QueryGetData = PseudoObj_DataObj_QueryGetData; + g_PseudoObj_DataObjectVtbl.GetCanonicalFormatEtc = + PseudoObj_DataObj_GetCanonicalFormatEtc; + g_PseudoObj_DataObjectVtbl.SetData = PseudoObj_DataObj_SetData; + g_PseudoObj_DataObjectVtbl.EnumFormatEtc= PseudoObj_DataObj_EnumFormatEtc; + g_PseudoObj_DataObjectVtbl.DAdvise = PseudoObj_DataObj_DAdvise; + g_PseudoObj_DataObjectVtbl.DUnadvise = PseudoObj_DataObj_DUnadvise; + g_PseudoObj_DataObjectVtbl.EnumDAdvise = PseudoObj_DataObj_EnumAdvise; + + fStatus = OleStdCheckVtbl( + &g_PseudoObj_DataObjectVtbl, + sizeof(IDataObjectVtbl), + "IDataObject" + ); + if (! fStatus) return FALSE; + + return TRUE; +} + +#endif // OLE_SERVER + + + +#if defined( OLE_CNTR ) + +/************************************************************************* +** ContainerDoc Supprt Functions Used by Container versions +*************************************************************************/ + + +/* ContainerApp_InitInstance + * ------------------------- + * + * Initialize the app instance by creating the main frame window and + * performing app instance specific initializations + * (eg. initializing interface Vtbls). + * + * RETURNS: TRUE if the memory could be allocated, and the server app + * was properly initialized. + * FALSE otherwise + * + */ + +BOOL ContainerApp_InitInstance( + LPCONTAINERAPP lpContainerApp, + HINSTANCE hInst, + int nCmdShow +) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp; + + lpContainerApp->m_cfCntrOutl=RegisterClipboardFormat(CONTAINERDOCFORMAT); + if(! lpContainerApp->m_cfCntrOutl) { + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Can't register clipboard format!"); + return FALSE; + } + +#if defined( INPLACE_CNTR ) + + lpContainerApp->m_fPendingUIDeactivate = FALSE; + lpContainerApp->m_fMustResizeClientArea = FALSE; + lpContainerApp->m_lpIPActiveObj = NULL; + lpContainerApp->m_hWndUIActiveObj = NULL; + lpContainerApp->m_hAccelIPCntr = LoadAccelerators( + hInst, + "InPlaceCntrOutlAccel" + ); + lpContainerApp->m_hMenuFile = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_FILEMENU + ); + lpContainerApp->m_hMenuView = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_VIEWMENU + ); + lpContainerApp->m_hMenuDebug = GetSubMenu ( + lpOutlineApp->m_hMenuApp, + POS_DEBUGMENU + ); + + INIT_INTERFACEIMPL( + &lpContainerApp->m_OleInPlaceFrame, + &g_CntrApp_OleInPlaceFrameVtbl, + lpContainerApp + ); + +#endif + + /* Setup arrays used by IDataObject::EnumFormatEtc. This is used to + ** support copy/paste and drag/drop operations. + ** + ** OLE2NOTE: The order that the formats are listed for GetData is very + ** significant. It should be listed in order of highest fidelity + ** formats to least fidelity formats. A common ordering will be: + ** 1. private app formats + ** 2. CF_EMBEDSOURCE or CF_EMBEDOBJECT (as appropriate) + ** 3. lower fidelity interchange formats + ** 4. CF_METAFILEPICT + ** (graphic-related apps might offer picture 1st!) + ** 5. CF_OBJECTDESCRIPTOR + ** 6. CF_LINKSOURCE + ** 6. CF_LINKSRCDESCRIPTOR + */ + + /* m_arrDocGetFmts array enumerates the formats that a ContainerDoc + ** object can offer (give) through a IDataObject::GetData call + ** when the selection copied is NOT a single embedded object. + ** when a single embedded object this list of formats available + ** is built dynamically depending on the object copied. (see + ** ContainerDoc_SetupDocGetFmts). + ** The formats are listed in priority order. + ** ContainerDoc objects accept data formats in the following order: + ** 1. CF_CNTROUTL + ** 2. CF_OUTLINE + ** 3. CF_TEXT + ** 4. CF_OBJECTDESCRIPTOR + ** + ** OLE2NOTE: CF_OBJECTDESCRIPTOR format is used to describe the + ** data on the clipboard. this information is intended to be + ** used, for example, to drive the PasteSpecial dialog. it is + ** useful to render CF_OBJECTDESCRIPTOR format even when the + ** data on the clipboard does NOT include CF_EMBEDDEDOBJECT + ** format or CF_EMBEDSOURCE format as when a selection that is + ** not a single OLE object is copied from the container only + ** version CNTROUTL. by rendering CF_OBJECTDESCRIPTOR format the + ** app can indicate a useful string to identifiy the source of + ** the copy to the user. + */ + + lpOleApp->m_arrDocGetFmts[0].cfFormat = lpContainerApp->m_cfCntrOutl; + lpOleApp->m_arrDocGetFmts[0].ptd = NULL; + lpOleApp->m_arrDocGetFmts[0].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[0].tymed = TYMED_ISTORAGE; + lpOleApp->m_arrDocGetFmts[0].lindex = -1; + + lpOleApp->m_arrDocGetFmts[1].cfFormat = lpOutlineApp->m_cfOutline; + lpOleApp->m_arrDocGetFmts[1].ptd = NULL; + lpOleApp->m_arrDocGetFmts[1].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[1].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[1].lindex = -1; + + lpOleApp->m_arrDocGetFmts[2].cfFormat = CF_TEXT; + lpOleApp->m_arrDocGetFmts[2].ptd = NULL; + lpOleApp->m_arrDocGetFmts[2].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[2].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[2].lindex = -1; + + lpOleApp->m_arrDocGetFmts[3].cfFormat = lpOleApp->m_cfObjectDescriptor; + lpOleApp->m_arrDocGetFmts[3].ptd = NULL; + lpOleApp->m_arrDocGetFmts[3].dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrDocGetFmts[3].tymed = TYMED_HGLOBAL; + lpOleApp->m_arrDocGetFmts[3].lindex = -1; + + lpOleApp->m_nDocGetFmts = 4; + + /* m_arrSingleObjGetFmts array enumerates the formats that a + ** ContainerDoc object can offer (give) through a + ** IDataObject::GetData call when the selection copied IS a + ** single OLE object. + ** ContainerDoc objects accept data formats in the following order: + ** 1. CF_CNTROUTL + ** 2. CF_EMBEDDEDOBJECT + ** 3. CF_OBJECTDESCRIPTOR + ** 4. CF_METAFILEPICT (note DVASPECT will vary) + ** 5. CF_LINKSOURCE * + ** 6. CF_LINKSRCDESCRIPTOR * + ** + ** * OLE2NOTE: CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR is only + ** offered if the OLE object is allowed to be linked to from the + ** inside (ie. we are allowed to give out a moniker which binds + ** to the running OLE object), then we want to offer + ** CF_LINKSOURCE format. if the object is an OLE 2.0 embedded + ** object then it is allowed to be linked to from the inside. if + ** the object is either an OleLink or an OLE 1.0 embedding then + ** it can not be linked to from the inside. if we were a + ** container/server app then we could offer linking to the + ** outside of the object (ie. a pseudo object within our + ** document). we are a container only app that does not support + ** linking to ranges of its data. + ** the simplest way to determine if an object can be linked to + ** on the inside is to call IOleObject::GetMiscStatus and test + ** to see if the OLEMISC_CANTLINKINSIDE bit is NOT set. + ** + ** OLE2NOTE: optionally, a container that wants to have a + ** potentially richer data transfer, can enumerate the data + ** formats from the OLE object's cache and offer them too. if + ** the object has a special handler, then it might be able to + ** render additional data formats. + */ + lpContainerApp->m_arrSingleObjGetFmts[0].cfFormat = + lpContainerApp->m_cfCntrOutl; + lpContainerApp->m_arrSingleObjGetFmts[0].ptd = NULL; + lpContainerApp->m_arrSingleObjGetFmts[0].dwAspect = DVASPECT_CONTENT; + lpContainerApp->m_arrSingleObjGetFmts[0].tymed = TYMED_ISTORAGE; + lpContainerApp->m_arrSingleObjGetFmts[0].lindex = -1; + + lpContainerApp->m_arrSingleObjGetFmts[1].cfFormat = + lpOleApp->m_cfEmbeddedObject; + lpContainerApp->m_arrSingleObjGetFmts[1].ptd = NULL; + lpContainerApp->m_arrSingleObjGetFmts[1].dwAspect = DVASPECT_CONTENT; + lpContainerApp->m_arrSingleObjGetFmts[1].tymed = TYMED_ISTORAGE; + lpContainerApp->m_arrSingleObjGetFmts[1].lindex = -1; + + lpContainerApp->m_arrSingleObjGetFmts[2].cfFormat = + lpOleApp->m_cfObjectDescriptor; + lpContainerApp->m_arrSingleObjGetFmts[2].ptd = NULL; + lpContainerApp->m_arrSingleObjGetFmts[2].dwAspect = DVASPECT_CONTENT; + lpContainerApp->m_arrSingleObjGetFmts[2].tymed = TYMED_HGLOBAL; + lpContainerApp->m_arrSingleObjGetFmts[2].lindex = -1; + + lpContainerApp->m_arrSingleObjGetFmts[3].cfFormat = CF_METAFILEPICT; + lpContainerApp->m_arrSingleObjGetFmts[3].ptd = NULL; + lpContainerApp->m_arrSingleObjGetFmts[3].dwAspect = DVASPECT_CONTENT; + lpContainerApp->m_arrSingleObjGetFmts[3].tymed = TYMED_MFPICT; + lpContainerApp->m_arrSingleObjGetFmts[3].lindex = -1; + + lpContainerApp->m_arrSingleObjGetFmts[4].cfFormat = + lpOleApp->m_cfLinkSource; + lpContainerApp->m_arrSingleObjGetFmts[4].ptd = NULL; + lpContainerApp->m_arrSingleObjGetFmts[4].dwAspect = DVASPECT_CONTENT; + lpContainerApp->m_arrSingleObjGetFmts[4].tymed = TYMED_ISTREAM; + lpContainerApp->m_arrSingleObjGetFmts[4].lindex = -1; + + lpContainerApp->m_arrSingleObjGetFmts[5].cfFormat = + lpOleApp->m_cfLinkSrcDescriptor; + lpContainerApp->m_arrSingleObjGetFmts[5].ptd = NULL; + lpContainerApp->m_arrSingleObjGetFmts[5].dwAspect = DVASPECT_CONTENT; + lpContainerApp->m_arrSingleObjGetFmts[5].tymed = TYMED_HGLOBAL; + lpContainerApp->m_arrSingleObjGetFmts[5].lindex = -1; + + lpContainerApp->m_nSingleObjGetFmts = 6; + + /* NOTE: the Container-Only version of Outline does NOT offer + ** IDataObject interface from its User documents and the + ** IDataObject interface available from DataTransferDoc's do NOT + ** support SetData. IDataObject interface is required by objects + ** which can be embedded or linked. the Container-only app only + ** allows linking to its contained objects, NOT the data of the + ** container itself. + */ + + /* m_arrPasteEntries array enumerates the formats that a ContainerDoc + ** object can accept from the clipboard. this array is used to + ** support the PasteSpecial dialog. + ** The formats are listed in priority order. + ** ContainerDoc objects accept data formats in the following order: + ** 1. CF_CNTROUTL + ** 2. CF_OUTLINE + ** 3. CF_EMBEDDEDOBJECT + ** 4. CF_TEXT + ** 5. CF_METAFILEPICT + ** 6. CF_DIB + ** 7. CF_BITMAP + ** 8. CF_LINKSOURCE + ** + ** NOTE: specifying CF_EMBEDDEDOBJECT in the PasteEntry array + ** indicates that the caller is interested in pasting OLE + ** objects (ie. the caller calls OleCreateFromData). the + ** OleUIPasteSpecial dialog and OleStdGetPriorityClipboardFormat + ** call OleQueryCreateFromData to see if an OLE object format is + ** available. thus, in fact if CF_EMBEDSOURCE or CF_FILENAME are + ** available from the data source then and OLE object can be + ** created and this entry will be matched. the caller should + ** only specify one object type format. + ** CF_FILENAME format (as generated by copying a file to + ** the clipboard from the FileManager) is considered an object + ** format; OleCreatFromData creates an object if the file has an + ** associated class (see GetClassFile API) or if no class it + ** creates an OLE 1.0 Package object. this format can also be + ** paste linked by calling OleCreateLinkFromData. + */ + // REVIEW: strings should be loaded from string resource + + lpOleApp->m_arrPasteEntries[0].fmtetc.cfFormat = + lpContainerApp->m_cfCntrOutl; + lpOleApp->m_arrPasteEntries[0].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[0].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[0].fmtetc.tymed = TYMED_ISTORAGE; + lpOleApp->m_arrPasteEntries[0].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[0].lpstrFormatName = "Container Outline Data"; + lpOleApp->m_arrPasteEntries[0].lpstrResultText = + "Container Outline Data"; + lpOleApp->m_arrPasteEntries[0].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[1].fmtetc.cfFormat =lpOutlineApp->m_cfOutline; + lpOleApp->m_arrPasteEntries[1].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[1].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[1].fmtetc.tymed = TYMED_HGLOBAL; + lpOleApp->m_arrPasteEntries[1].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[1].lpstrFormatName = "Outline Data"; + lpOleApp->m_arrPasteEntries[1].lpstrResultText = "Outline Data"; + lpOleApp->m_arrPasteEntries[1].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[2].fmtetc.cfFormat = + lpOleApp->m_cfEmbeddedObject; + lpOleApp->m_arrPasteEntries[2].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[2].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[2].fmtetc.tymed = TYMED_ISTORAGE; + lpOleApp->m_arrPasteEntries[2].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[2].lpstrFormatName = "%s"; + lpOleApp->m_arrPasteEntries[2].lpstrResultText = "%s"; + lpOleApp->m_arrPasteEntries[2].dwFlags = + OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON; + + lpOleApp->m_arrPasteEntries[3].fmtetc.cfFormat = CF_TEXT; + lpOleApp->m_arrPasteEntries[3].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[3].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[3].fmtetc.tymed = TYMED_HGLOBAL; + lpOleApp->m_arrPasteEntries[3].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[3].lpstrFormatName = "Text"; + lpOleApp->m_arrPasteEntries[3].lpstrResultText = "text"; + lpOleApp->m_arrPasteEntries[3].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[4].fmtetc.cfFormat = CF_METAFILEPICT; + lpOleApp->m_arrPasteEntries[4].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[4].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[4].fmtetc.tymed = TYMED_MFPICT; + lpOleApp->m_arrPasteEntries[4].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[4].lpstrFormatName = "Picture (Metafile)"; + lpOleApp->m_arrPasteEntries[4].lpstrResultText = "a static picture"; + lpOleApp->m_arrPasteEntries[4].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[5].fmtetc.cfFormat = CF_DIB; + lpOleApp->m_arrPasteEntries[5].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[5].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[5].fmtetc.tymed = TYMED_HGLOBAL; + lpOleApp->m_arrPasteEntries[5].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[5].lpstrFormatName = "Picture (DIB)"; + lpOleApp->m_arrPasteEntries[5].lpstrResultText = "a static picture"; + lpOleApp->m_arrPasteEntries[5].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[6].fmtetc.cfFormat = CF_BITMAP; + lpOleApp->m_arrPasteEntries[6].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[6].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[6].fmtetc.tymed = TYMED_GDI; + lpOleApp->m_arrPasteEntries[6].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[6].lpstrFormatName = "Picture (Bitmap)"; + lpOleApp->m_arrPasteEntries[6].lpstrResultText = "a static picture"; + lpOleApp->m_arrPasteEntries[6].dwFlags = OLEUIPASTE_PASTEONLY; + + lpOleApp->m_arrPasteEntries[7].fmtetc.cfFormat = lpOleApp->m_cfLinkSource; + lpOleApp->m_arrPasteEntries[7].fmtetc.ptd = NULL; + lpOleApp->m_arrPasteEntries[7].fmtetc.dwAspect = DVASPECT_CONTENT; + lpOleApp->m_arrPasteEntries[7].fmtetc.tymed = TYMED_ISTREAM; + lpOleApp->m_arrPasteEntries[7].fmtetc.lindex = -1; + lpOleApp->m_arrPasteEntries[7].lpstrFormatName = "%s"; + lpOleApp->m_arrPasteEntries[7].lpstrResultText = "%s"; + lpOleApp->m_arrPasteEntries[7].dwFlags = + OLEUIPASTE_LINKTYPE1 | OLEUIPASTE_ENABLEICON; + + lpOleApp->m_nPasteEntries = 8; + + /* m_arrLinkTypes array enumerates the link types that a ContainerDoc + ** object can accept from the clipboard + */ + + lpOleApp->m_arrLinkTypes[0] = lpOleApp->m_cfLinkSource; + lpOleApp->m_nLinkTypes = 1; + + return TRUE; +} + + +/* ContainerApp_InitVtbls +** ---------------------- +** +** initialize the interface Vtbl's used to support the OLE 2.0 +** Container functionality. +*/ + +BOOL ContainerApp_InitVtbls(LPCONTAINERAPP lpApp) +{ + BOOL fStatus; + + // ContainerDoc::IOleUILinkContainer method table + OleStdInitVtbl( + &g_CntrDoc_OleUILinkContainerVtbl, + sizeof(IOleUILinkContainerVtbl) + ); + g_CntrDoc_OleUILinkContainerVtbl.QueryInterface = + CntrDoc_LinkCont_QueryInterface; + g_CntrDoc_OleUILinkContainerVtbl.AddRef = CntrDoc_LinkCont_AddRef; + g_CntrDoc_OleUILinkContainerVtbl.Release = CntrDoc_LinkCont_Release; + g_CntrDoc_OleUILinkContainerVtbl.GetNextLink = + CntrDoc_LinkCont_GetNextLink; + g_CntrDoc_OleUILinkContainerVtbl.SetLinkUpdateOptions = + CntrDoc_LinkCont_SetLinkUpdateOptions; + g_CntrDoc_OleUILinkContainerVtbl.GetLinkUpdateOptions = + CntrDoc_LinkCont_GetLinkUpdateOptions; + g_CntrDoc_OleUILinkContainerVtbl.SetLinkSource = + CntrDoc_LinkCont_SetLinkSource; + g_CntrDoc_OleUILinkContainerVtbl.GetLinkSource = + CntrDoc_LinkCont_GetLinkSource; + g_CntrDoc_OleUILinkContainerVtbl.OpenLinkSource = + CntrDoc_LinkCont_OpenLinkSource; + g_CntrDoc_OleUILinkContainerVtbl.UpdateLink = + CntrDoc_LinkCont_UpdateLink; + g_CntrDoc_OleUILinkContainerVtbl.CancelLink = + CntrDoc_LinkCont_CancelLink; + fStatus = OleStdCheckVtbl( + &g_CntrDoc_OleUILinkContainerVtbl, + sizeof(IOleUILinkContainerVtbl), + "IOleUILinkContainer" + ); + if (! fStatus) return FALSE; + +#if defined( INPLACE_CNTR ) + + // ContainerApp::IOleInPlaceFrame interface method table + OleStdInitVtbl( + &g_CntrApp_OleInPlaceFrameVtbl, + sizeof(g_CntrApp_OleInPlaceFrameVtbl) + ); + + g_CntrApp_OleInPlaceFrameVtbl.QueryInterface + = CntrApp_IPFrame_QueryInterface; + g_CntrApp_OleInPlaceFrameVtbl.AddRef + = CntrApp_IPFrame_AddRef; + g_CntrApp_OleInPlaceFrameVtbl.Release + = CntrApp_IPFrame_Release; + g_CntrApp_OleInPlaceFrameVtbl.GetWindow + = CntrApp_IPFrame_GetWindow; + g_CntrApp_OleInPlaceFrameVtbl.ContextSensitiveHelp + = CntrApp_IPFrame_ContextSensitiveHelp; + + g_CntrApp_OleInPlaceFrameVtbl.GetBorder + = CntrApp_IPFrame_GetBorder; + g_CntrApp_OleInPlaceFrameVtbl.RequestBorderSpace + = CntrApp_IPFrame_RequestBorderSpace; + g_CntrApp_OleInPlaceFrameVtbl.SetBorderSpace + = CntrApp_IPFrame_SetBorderSpace; + g_CntrApp_OleInPlaceFrameVtbl.SetActiveObject + = CntrApp_IPFrame_SetActiveObject; + g_CntrApp_OleInPlaceFrameVtbl.InsertMenus + = CntrApp_IPFrame_InsertMenus; + g_CntrApp_OleInPlaceFrameVtbl.SetMenu + = CntrApp_IPFrame_SetMenu; + g_CntrApp_OleInPlaceFrameVtbl.RemoveMenus + = CntrApp_IPFrame_RemoveMenus; + g_CntrApp_OleInPlaceFrameVtbl.SetStatusText + = CntrApp_IPFrame_SetStatusText; + g_CntrApp_OleInPlaceFrameVtbl.EnableModeless + = CntrApp_IPFrame_EnableModeless; + g_CntrApp_OleInPlaceFrameVtbl.TranslateAccelerator + = CntrApp_IPFrame_TranslateAccelerator; + + fStatus = OleStdCheckVtbl( + &g_CntrApp_OleInPlaceFrameVtbl, + sizeof(g_CntrApp_OleInPlaceFrameVtbl), + "IOleInPlaceFrame" + ); + if (! fStatus) return FALSE; + +#endif // INPLACE_CNTR + + + // ContainerLine::IUnknown interface method table + OleStdInitVtbl( + &g_CntrLine_UnknownVtbl, + sizeof(g_CntrLine_UnknownVtbl) + ); + g_CntrLine_UnknownVtbl.QueryInterface = CntrLine_Unk_QueryInterface; + g_CntrLine_UnknownVtbl.AddRef = CntrLine_Unk_AddRef; + g_CntrLine_UnknownVtbl.Release = CntrLine_Unk_Release; + fStatus = OleStdCheckVtbl( + &g_CntrLine_UnknownVtbl, + sizeof(g_CntrLine_UnknownVtbl), + "IUnknown" + ); + if (! fStatus) return FALSE; + + // ContainerLine::IOleClientSite interface method table + OleStdInitVtbl( + &g_CntrLine_OleClientSiteVtbl, + sizeof(g_CntrLine_OleClientSiteVtbl) + ); + g_CntrLine_OleClientSiteVtbl.QueryInterface = + CntrLine_CliSite_QueryInterface; + g_CntrLine_OleClientSiteVtbl.AddRef = CntrLine_CliSite_AddRef; + g_CntrLine_OleClientSiteVtbl.Release = CntrLine_CliSite_Release; + g_CntrLine_OleClientSiteVtbl.SaveObject = CntrLine_CliSite_SaveObject; + g_CntrLine_OleClientSiteVtbl.GetMoniker = CntrLine_CliSite_GetMoniker; + g_CntrLine_OleClientSiteVtbl.GetContainer = CntrLine_CliSite_GetContainer; + g_CntrLine_OleClientSiteVtbl.ShowObject = CntrLine_CliSite_ShowObject; + g_CntrLine_OleClientSiteVtbl.OnShowWindow = CntrLine_CliSite_OnShowWindow; + g_CntrLine_OleClientSiteVtbl.RequestNewObjectLayout = + CntrLine_CliSite_RequestNewObjectLayout; + fStatus = OleStdCheckVtbl( + &g_CntrLine_OleClientSiteVtbl, + sizeof(g_CntrLine_OleClientSiteVtbl), + "IOleClientSite" + ); + if (! fStatus) return FALSE; + + // ContainerLine::IAdviseSink interface method table + OleStdInitVtbl( + &g_CntrLine_AdviseSinkVtbl, + sizeof(g_CntrLine_AdviseSinkVtbl) + ); + g_CntrLine_AdviseSinkVtbl.QueryInterface= CntrLine_AdvSink_QueryInterface; + g_CntrLine_AdviseSinkVtbl.AddRef = CntrLine_AdvSink_AddRef; + g_CntrLine_AdviseSinkVtbl.Release = CntrLine_AdvSink_Release; + g_CntrLine_AdviseSinkVtbl.OnDataChange = CntrLine_AdvSink_OnDataChange; + g_CntrLine_AdviseSinkVtbl.OnViewChange = CntrLine_AdvSink_OnViewChange; + g_CntrLine_AdviseSinkVtbl.OnRename = CntrLine_AdvSink_OnRename; + g_CntrLine_AdviseSinkVtbl.OnSave = CntrLine_AdvSink_OnSave; + g_CntrLine_AdviseSinkVtbl.OnClose = CntrLine_AdvSink_OnClose; + fStatus = OleStdCheckVtbl( + &g_CntrLine_AdviseSinkVtbl, + sizeof(g_CntrLine_AdviseSinkVtbl), + "IAdviseSink" + ); + if (! fStatus) return FALSE; + + +#if defined( INPLACE_CNTR ) + + // ContainerLine::IOleInPlaceSite interface method table + OleStdInitVtbl( + &g_CntrLine_OleInPlaceSiteVtbl, + sizeof(g_CntrLine_OleInPlaceSiteVtbl) + ); + + g_CntrLine_OleInPlaceSiteVtbl.QueryInterface + = CntrLine_IPSite_QueryInterface; + g_CntrLine_OleInPlaceSiteVtbl.AddRef + = CntrLine_IPSite_AddRef; + g_CntrLine_OleInPlaceSiteVtbl.Release + = CntrLine_IPSite_Release; + g_CntrLine_OleInPlaceSiteVtbl.GetWindow + = CntrLine_IPSite_GetWindow; + g_CntrLine_OleInPlaceSiteVtbl.ContextSensitiveHelp + = CntrLine_IPSite_ContextSensitiveHelp; + g_CntrLine_OleInPlaceSiteVtbl.CanInPlaceActivate + = CntrLine_IPSite_CanInPlaceActivate; + g_CntrLine_OleInPlaceSiteVtbl.OnInPlaceActivate + = CntrLine_IPSite_OnInPlaceActivate; + g_CntrLine_OleInPlaceSiteVtbl.OnUIActivate + = CntrLine_IPSite_OnUIActivate; + g_CntrLine_OleInPlaceSiteVtbl.GetWindowContext + = CntrLine_IPSite_GetWindowContext; + g_CntrLine_OleInPlaceSiteVtbl.Scroll + = CntrLine_IPSite_Scroll; + g_CntrLine_OleInPlaceSiteVtbl.OnUIDeactivate + = CntrLine_IPSite_OnUIDeactivate; + + g_CntrLine_OleInPlaceSiteVtbl.OnInPlaceDeactivate + = CntrLine_IPSite_OnInPlaceDeactivate; + g_CntrLine_OleInPlaceSiteVtbl.DiscardUndoState + = CntrLine_IPSite_DiscardUndoState; + g_CntrLine_OleInPlaceSiteVtbl.DeactivateAndUndo + = CntrLine_IPSite_DeactivateAndUndo; + g_CntrLine_OleInPlaceSiteVtbl.OnPosRectChange + = CntrLine_IPSite_OnPosRectChange; + + fStatus = OleStdCheckVtbl( + &g_CntrLine_OleInPlaceSiteVtbl, + sizeof(g_CntrLine_OleInPlaceSiteVtbl), + "IOleInPlaceSite" + ); + if (! fStatus) return FALSE; + +#endif // INPLACE_CNTR + + return TRUE; +} + + +#endif // OLE_CNTR diff --git a/private/oleutest/letest/outline/oledoc.c b/private/oleutest/letest/outline/oledoc.c new file mode 100644 index 000000000..53bbe08e5 --- /dev/null +++ b/private/oleutest/letest/outline/oledoc.c @@ -0,0 +1,1179 @@ +/************************************************************************* +** +** OLE 2 Server Sample Code +** +** oledoc.c +** +** This file contains general OleDoc methods and related support +** functions. OleDoc implementation is used by both the Container +** versions and the Server (Object) versions of the Outline Sample. +** +** This file includes general support for the following: +** 1. show/hide doc window +** 2. QueryInterface, AddRef, Release +** 3. document locking (calls CoLockObjectExternal) +** 4. document shutdown (Close, Destroy) +** 5. clipboard support +** +** OleDoc Object +** exposed interfaces: +** IUnknown +** IPersistFile +** IOleItemContainer +** IDataObject +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +extern IUnknownVtbl g_OleDoc_UnknownVtbl; +extern IPersistFileVtbl g_OleDoc_PersistFileVtbl; +extern IOleItemContainerVtbl g_OleDoc_OleItemContainerVtbl; +extern IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl; +extern IDataObjectVtbl g_OleDoc_DataObjectVtbl; + +#if defined( USE_DRAGDROP ) +extern IDropTargetVtbl g_OleDoc_DropTargetVtbl; +extern IDropSourceVtbl g_OleDoc_DropSourceVtbl; +#endif // USE_DRAGDROP + +#if defined( INPLACE_CNTR ) +extern BOOL g_fInsideOutContainer; +#endif + + +/* OleDoc_Init + * ----------- + * + * Initialize the fields of a new OleDoc object. The object is initially + * not associated with a file or an (Untitled) document. This function sets + * the docInitType to DOCTYPE_UNKNOWN. After calling this function the + * caller should call: + * 1.) Doc_InitNewFile to set the OleDoc to (Untitled) + * 2.) Doc_LoadFromFile to associate the OleDoc with a file. + * This function creates a new window for the document. + * + * NOTE: the window is initially created with a NIL size. it must be + * sized and positioned by the caller. also the document is initially + * created invisible. the caller must call OutlineDoc_ShowWindow + * after sizing it to make the document window visible. + */ +BOOL OleDoc_Init(LPOLEDOC lpOleDoc, BOOL fDataTransferDoc) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + + lpOleDoc->m_cRef = 0; + lpOleDoc->m_dwStrongExtConn = 0; +#if defined( _DEBUG ) + lpOleDoc->m_cCntrLock = 0; +#endif + lpOleDoc->m_lpStg = NULL; + lpOleDoc->m_lpLLStm = NULL; + lpOleDoc->m_lpNTStm = NULL; + lpOleDoc->m_dwRegROT = 0; + lpOleDoc->m_lpFileMoniker = NULL; + lpOleDoc->m_fLinkSourceAvail = FALSE; + lpOleDoc->m_lpSrcDocOfCopy = NULL; + lpOleDoc->m_fObjIsClosing = FALSE; + lpOleDoc->m_fObjIsDestroying = FALSE; + lpOleDoc->m_fUpdateEditMenu = FALSE; + +#if defined( USE_DRAGDROP ) + lpOleDoc->m_dwTimeEnterScrollArea = 0L; + lpOleDoc->m_dwNextScrollTime = 0L; + lpOleDoc->m_dwLastScrollDir = SCROLLDIR_NULL; + lpOleDoc->m_fRegDragDrop = FALSE; + lpOleDoc->m_fLocalDrag = FALSE; + lpOleDoc->m_fCanDropCopy = FALSE; + lpOleDoc->m_fCanDropLink = FALSE; + lpOleDoc->m_fLocalDrop = FALSE; + lpOleDoc->m_fDragLeave = FALSE; + lpOleDoc->m_fPendingDrag = FALSE; +#endif +#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR ) + lpOleDoc->m_fCSHelpMode = FALSE; // Shift-F1 context + // sensitive help mode +#endif + + INIT_INTERFACEIMPL( + &lpOleDoc->m_Unknown, + &g_OleDoc_UnknownVtbl, + lpOleDoc + ); + + INIT_INTERFACEIMPL( + &lpOleDoc->m_PersistFile, + &g_OleDoc_PersistFileVtbl, + lpOleDoc + ); + + INIT_INTERFACEIMPL( + &lpOleDoc->m_OleItemContainer, + &g_OleDoc_OleItemContainerVtbl, + lpOleDoc + ); + + INIT_INTERFACEIMPL( + &lpOleDoc->m_ExternalConnection, + &g_OleDoc_ExternalConnectionVtbl, + lpOleDoc + ); + + INIT_INTERFACEIMPL( + &lpOleDoc->m_DataObject, + &g_OleDoc_DataObjectVtbl, + lpOleDoc + ); + +#if defined( USE_DRAGDROP ) + INIT_INTERFACEIMPL( + &lpOleDoc->m_DropSource, + &g_OleDoc_DropSourceVtbl, + lpOleDoc + ); + + INIT_INTERFACEIMPL( + &lpOleDoc->m_DropTarget, + &g_OleDoc_DropTargetVtbl, + lpOleDoc + ); +#endif // USE_DRAGDROP + + /* + ** OLE2NOTE: each user level document addref's the app object in + ** order to guarentee that the app does not shut down while the + ** doc is still open. + */ + + // OLE2NOTE: data transfer documents should not hold the app alive + if (! fDataTransferDoc) + OleApp_DocLockApp(lpOleApp); + +#if defined( OLE_SERVER ) + /* OLE2NOTE: perform initialization specific for an OLE server */ + if (! ServerDoc_Init((LPSERVERDOC)lpOleDoc, fDataTransferDoc)) + return FALSE; +#endif +#if defined( OLE_CNTR ) + + /* OLE2NOTE: perform initialization specific for an OLE container */ + if (! ContainerDoc_Init((LPCONTAINERDOC)lpOleDoc, fDataTransferDoc)) + return FALSE; +#endif + + return TRUE; +} + + + +/* OleDoc_InitNewFile + * ------------------ + * + * Initialize the document to be a new (Untitled) document. + * This function sets the docInitType to DOCTYPE_NEW. + * + * OLE2NOTE: if this is a visible user document then generate a unique + * untitled name that we can use to register in the RunningObjectTable. + * We need a unique name so that clients can link to data in this document + * even when the document is in the un-saved (untitled) state. it would be + * ambiguous to register two documents titled "Outline1" in the ROT. we + * thus generate the lowest numbered document that is not already + * registered in the ROT. + */ +BOOL OleDoc_InitNewFile(LPOLEDOC lpOleDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + static UINT uUnique = 1; + + OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN); + +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; +#if defined( _DEBUG ) + OleDbgAssertSz(lpOleDoc->m_lpStg == NULL, + "Setting to untitled with current file open" + ); +#endif + + /* Create a temp, (delete-on-release) file base storage + ** for the untitled document. + */ + lpOleDoc->m_lpStg = OleStdCreateRootStorage( + NULL, + STGM_SHARE_EXCLUSIVE + ); + if (! lpOleDoc->m_lpStg) return FALSE; + } +#endif + + lpOutlineDoc->m_docInitType = DOCTYPE_NEW; + + if (! lpOutlineDoc->m_fDataTransferDoc) { + /* OLE2NOTE: choose a unique name for a Moniker so that + ** potential clients can link to our new, untitled document. + ** if links are established (and currently are connected), + ** then they will be notified that we have been renamed when + ** this document is saved to a file. + */ + + lpOleDoc->m_fLinkSourceAvail = TRUE; + + // REVIEW: should load UNTITLED string from string resource + OleStdCreateTempFileMoniker( + UNTITLED, + (UINT FAR*)&uUnique, + lpOutlineDoc->m_szFileName, + &lpOleDoc->m_lpFileMoniker + ); + + OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n") + OleStdRegisterAsRunning( + (LPUNKNOWN)&lpOleDoc->m_PersistFile, + (LPMONIKER)lpOleDoc->m_lpFileMoniker, + &lpOleDoc->m_dwRegROT + ); + OLEDBG_END3 + + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/); + } else { + lstrcpy(lpOutlineDoc->m_szFileName, UNTITLED); + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + } + + return TRUE; +} + + +/* OleDoc_ShowWindow + * ----------------- + * + * Show the window of the document to the user. + * make sure app window is visible and bring the document to the top. + * if the document is a file-based document or a new untitled + * document, give the user the control over the life-time of the doc. + */ +void OleDoc_ShowWindow(LPOLEDOC lpOleDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; +#if defined( OLE_SERVER ) + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; +#endif // OLE_SERVER + + OLEDBG_BEGIN3("OleDoc_ShowWindow\r\n") + + /* OLE2NOTE: while the document is visible, we do NOT want it to be + ** prematurely destroyed when a linking client disconnects. thus + ** we must inform OLE to hold an external lock on our document. + ** this arranges that OLE holds at least 1 reference to our + ** document that will NOT be released until we release this + ** external lock. later, when the document window is hidden, we + ** will release this external lock. + */ + if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc)) + OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */); + +#if defined( USE_DRAGDROP ) + /* OLE2NOTE: since our window is now being made visible, we will + ** register our window as a potential drop target. when the + ** window is hidden there is no reason to be registered as a + ** drop target. + */ + if (! lpOleDoc->m_fRegDragDrop) { + OLEDBG_BEGIN2("RegisterDragDrop called\r\n") + RegisterDragDrop( + LineList_GetWindow(lpLL), + (LPDROPTARGET)&lpOleDoc->m_DropTarget + ); + OLEDBG_END2 + lpOleDoc->m_fRegDragDrop = TRUE; + } +#endif // USE_DRAGDROP + +#if defined( USE_FRAMETOOLS ) + { + /* OLE2NOTE: we need to enable our frame level tools + */ + FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE); + } +#endif // USE_FRAMETOOLS + +#if defined( OLE_SERVER ) + + if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED && + lpServerDoc->m_lpOleClientSite != NULL) { + + /* OLE2NOTE: we must also ask our container to show itself if + ** it is not already visible and to scroll us into view. we + ** must make sure to call this BEFORE showing our server's + ** window and taking focus. we do not want our container's + ** window to end up on top. + */ + OLEDBG_BEGIN2("IOleClientSite::ShowObject called\r\n"); + lpServerDoc->m_lpOleClientSite->lpVtbl->ShowObject( + lpServerDoc->m_lpOleClientSite + ); + OLEDBG_END2 + + /* OLE2NOTE: if we are an embedded object and we are not + ** in-place active in our containers window, we must inform our + ** embedding container that our window is opening. + ** the container must now hatch our object. + */ + +#if defined( INPLACE_SVR ) + if (! lpServerDoc->m_fInPlaceActive) +#endif + { + OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(TRUE) called\r\n"); + lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow( + lpServerDoc->m_lpOleClientSite, + TRUE + ); + OLEDBG_END2 + } + + /* OLE2NOTE: the life-time of our document is controlled by our + ** client and NOT by the user. we are not an independent + ** file-level object. we simply want to show our window here. + ** + ** if we are not in-place active (ie. we are opening + ** our own window), we must make sure our main app window is + ** visible. we do not, however, want to give the user + ** control of the App window; we do not want OleApp_ShowWindow + ** to call OleApp_Lock on behalf of the user. + */ + if (! IsWindowVisible(lpOutlineApp->m_hWndApp) || + IsIconic(lpOutlineApp->m_hWndApp)) { +#if defined( INPLACE_SVR ) + if (! ((LPSERVERDOC)lpOleDoc)->m_fInPlaceActive) +#endif + OleApp_ShowWindow(lpOleApp, FALSE /* fGiveUserCtrl */); + SetFocus(lpOutlineDoc->m_hWndDoc); + } + + } else +#endif // OLE_SERVER + + { // DOCTYPE_NEW || DOCTYPE_FROMFILE + + // we must make sure our app window is visible + OleApp_ShowWindow(lpOleApp, TRUE /* fGiveUserCtrl */); + } + + // make document window visible and make sure it is not minimized + ShowWindow(lpOutlineDoc->m_hWndDoc, SW_SHOWNORMAL); + SetFocus(lpOutlineDoc->m_hWndDoc); + + OLEDBG_END3 +} + + +/* OleDoc_HideWindow + * ----------------- + * + * Hide the window of the document from the user. + * take away the control of the document by the user. + */ +void OleDoc_HideWindow(LPOLEDOC lpOleDoc, BOOL fShutdown) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + + if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc)) + return; // already visible + + OLEDBG_BEGIN3("OleDoc_HideWindow\r\n") + +#if defined( USE_DRAGDROP ) + // The document's window is being hidden, revoke it as a DropTarget + if (lpOleDoc->m_fRegDragDrop) { + OLEDBG_BEGIN2("RevokeDragDrop called\r\n"); + RevokeDragDrop(LineList_GetWindow(lpLL)); + OLEDBG_END2 + + lpOleDoc->m_fRegDragDrop = FALSE ; + } +#endif // USE_DRAGDROP + + /* OLE2NOTE: the document is now being hidden, so we must release + ** the external lock made when the document was made visible. + ** if this is a shutdown situation (fShutdown==TRUE), then OLE + ** is instructed to release our document. if this is that last + ** external lock on our document, thus enabling our document to + ** complete its shutdown operation. If This is not a shutdown + ** situation (eg. in-place server hiding its window when + ** UIDeactivating or IOleObject::DoVerb(OLEVERB_HIDE) is called), + ** then OLE is told to NOT immediately release the document. + ** this leaves the document in an unstable state where the next + ** Lock/Unlock sequence will shut the document down (eg. a + ** linking client connecting and disconnecting). + */ + if (IsWindowVisible(lpOutlineDoc->m_hWndDoc)) + OleDoc_Lock(lpOleDoc, FALSE /* fLock */, fShutdown); + + ShowWindow(((LPOUTLINEDOC)lpOleDoc)->m_hWndDoc, SW_HIDE); + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + + /* OLE2NOTE: if we are an embedded object and we are not + ** in-place active, we must inform our + ** embedding container that our window is hiding (closing + ** from the user's perspective). the container must now + ** un-hatch our object. + */ + if (lpServerDoc->m_lpOleClientSite != NULL +#if defined( INPLACE_SVR ) + && !lpServerDoc->m_fInPlaceVisible +#endif + ) { + OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(FALSE) called\r\n"); + lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow( + lpServerDoc->m_lpOleClientSite, + FALSE + ); + OLEDBG_END2 + } + } +#endif + + /* OLE2NOTE: if there are no more documents visible to the user. + ** and the app itself is not under user control, then + ** it has no reason to stay visible. we thus should hide the + ** app. we can not directly destroy the app, because it may be + ** validly being used programatically by another client + ** application and should remain running. it should simply be + ** hidded from the user. + */ + OleApp_HideIfNoReasonToStayVisible(lpOleApp); + OLEDBG_END3 +} + + +/* OleDoc_Lock +** ----------- +** Lock/Unlock the Doc object. if the last lock is unlocked and +** fLastUnlockReleases == TRUE, then the Doc object will shut down +** (ie. it will recieve its final release and its refcnt will go to 0). +*/ +HRESULT OleDoc_Lock(LPOLEDOC lpOleDoc, BOOL fLock, BOOL fLastUnlockReleases) +{ + HRESULT hrErr; + +#if defined( _DEBUG ) + if (fLock) { + OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,TRUE) called\r\n") + } else { + if (fLastUnlockReleases) + OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,TRUE) called\r\n") + else + OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,FALSE) called\r\n") + } +#endif // _DEBUG + + hrErr = CoLockObjectExternal( + (LPUNKNOWN)&lpOleDoc->m_Unknown, fLock, fLastUnlockReleases); + + OLEDBG_END2 + return hrErr; +} + + +/* OleDoc_AddRef +** ------------- +** +** increment the ref count of the document object. +** +** Returns the new ref count on the object +*/ +ULONG OleDoc_AddRef(LPOLEDOC lpOleDoc) +{ + ++lpOleDoc->m_cRef; + +#if defined( _DEBUG ) + OleDbgOutRefCnt4( + "OleDoc_AddRef: cRef++\r\n", + lpOleDoc, + lpOleDoc->m_cRef + ); +#endif + return lpOleDoc->m_cRef; +} + + +/* OleDoc_Release +** -------------- +** +** decrement the ref count of the document object. +** if the ref count goes to 0, then the document is destroyed. +** +** Returns the remaining ref count on the object +*/ +ULONG OleDoc_Release (LPOLEDOC lpOleDoc) +{ + ULONG cRef; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + + /********************************************************************* + ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. ** + ** otherwise the object is still in use. ** + *********************************************************************/ + + cRef = --lpOleDoc->m_cRef; + +#if defined( _DEBUG ) + OleDbgAssertSz (lpOleDoc->m_cRef >= 0, "Release called with cRef == 0"); + + OleDbgOutRefCnt4( + "OleDoc_Release: cRef--\r\n", lpOleDoc, cRef); +#endif + if (cRef == 0) + OutlineDoc_Destroy((LPOUTLINEDOC)lpOleDoc); + + return cRef; +} + + +/* OleDoc_QueryInterface +** --------------------- +** +** Retrieve a pointer to an interface on the document object. +** +** OLE2NOTE: this function will AddRef the ref cnt of the object. +** +** Returns S_OK if interface is successfully retrieved. +** E_NOINTERFACE if the interface is not supported +*/ +HRESULT OleDoc_QueryInterface( + LPOLEDOC lpOleDoc, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + SCODE sc = E_NOINTERFACE; + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) { + OleDbgOut4("OleDoc_QueryInterface: IUnknown* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_Unknown; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + else if(lpOutlineDoc->m_fDataTransferDoc + && IsEqualIID(riid, &IID_IDataObject)) { + OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + + /* OLE2NOTE: if this document is a DataTransferDocument used to + ** support a clipboard or drag/drop operation, then it should + ** only expose IUnknown, IDataObject, and IDropSource + ** interfaces. if the document is a normal user document, then + ** we will also continue to consider our other interfaces. + */ + if (lpOutlineDoc->m_fDataTransferDoc) + goto done; + + if(IsEqualIID(riid,&IID_IPersist) || IsEqualIID(riid,&IID_IPersistFile)) { + OleDbgOut4("OleDoc_QueryInterface: IPersistFile* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_PersistFile; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + else if(IsEqualIID(riid, &IID_IOleItemContainer) || + IsEqualIID(riid, &IID_IOleContainer) || + IsEqualIID(riid, &IID_IParseDisplayName) ) { + OleDbgOut4("OleDoc_QueryInterface: IOleItemContainer* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_OleItemContainer; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + else if(IsEqualIID(riid, &IID_IExternalConnection)) { + OleDbgOut4("OleDoc_QueryInterface: IExternalConnection* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_ExternalConnection; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + +#if defined( USE_DRAGDROP ) + else if(IsEqualIID(riid, &IID_IDropTarget)) { + OleDbgOut4("OleDoc_QueryInterface: IDropTarget* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_DropTarget; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + else if(IsEqualIID(riid, &IID_IDropSource)) { + OleDbgOut4("OleDoc_QueryInterface: IDropSource* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_DropSource; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } +#endif + +#if defined( OLE_CNTR ) + else if (IsEqualIID(riid, &IID_IOleUILinkContainer)) { + OleDbgOut4("OleDoc_QueryInterface: IOleUILinkContainer* RETURNED\r\n"); + + *lplpvObj=(LPVOID)&((LPCONTAINERDOC)lpOleDoc)->m_OleUILinkContainer; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } +#endif + +#if defined( OLE_SERVER ) + + /* OLE2NOTE: if OLE server version, than also offer the server + ** specific interfaces: IOleObject and IPersistStorage. + */ + else if (IsEqualIID(riid, &IID_IOleObject)) { + OleDbgOut4("OleDoc_QueryInterface: IOleObject* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleObject; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + else if(IsEqualIID(riid, &IID_IPersistStorage)) { + OleDbgOut4("OleDoc_QueryInterface: IPersistStorage* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_PersistStorage; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + else if(IsEqualIID(riid, &IID_IDataObject)) { + OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } + +#if defined( SVR_TREATAS ) + else if(IsEqualIID(riid, &IID_IStdMarshalInfo)) { + OleDbgOut4("OleDoc_QueryInterface: IStdMarshalInfo* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_StdMarshalInfo; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } +#endif // SVR_TREATAS + +#if defined( INPLACE_SVR ) + else if (IsEqualIID(riid, &IID_IOleWindow) || + IsEqualIID(riid, &IID_IOleInPlaceObject)) { + OleDbgOut4("OleDoc_QueryInterface: IOleInPlaceObject* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleInPlaceObject; + OleDoc_AddRef(lpOleDoc); + sc = S_OK; + } +#endif // INPLACE_SVR +#endif // OLE_SERVER + +done: + OleDbgQueryInterfaceMethod(*lplpvObj); + + return ResultFromScode(sc); +} + + +/* OleDoc_Close + * ------------ + * + * Close the document. + * This functions performs the actions that are in common to all + * document types which derive from OleDoc (eg. ContainerDoc and + * ServerDoc) which are required to close a document. + * + * Returns: + * FALSE -- user canceled the closing of the doc. + * TRUE -- the doc was successfully closed + */ + +BOOL OleDoc_Close(LPOLEDOC lpOleDoc, DWORD dwSaveOption) +{ + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEDOC lpClipboardDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + BOOL fAbortIfSaveCanceled = (dwSaveOption == OLECLOSE_PROMPTSAVE); + + if (! lpOleDoc) + return TRUE; // active doc's are already destroyed + + if (lpOleDoc->m_fObjIsClosing) + return TRUE; // Closing is already in progress + + OLEDBG_BEGIN3("OleDoc_Close\r\n") + + if (! OutlineDoc_CheckSaveChanges((LPOUTLINEDOC)lpOleDoc,&dwSaveOption) + && fAbortIfSaveCanceled) { + OLEDBG_END3 + return FALSE; // cancel closing the doc + } + + lpOleDoc->m_fObjIsClosing = TRUE; // guard against recursive call + + /* OLE2NOTE: in order to have a stable app and doc during the + ** process of closing, we intially AddRef the App and Doc ref + ** cnts and later Release them. These initial AddRefs are + ** artificial; they simply guarantee that these objects do not + ** get destroyed until the end of this routine. + */ + OleApp_AddRef(lpOleApp); + OleDoc_AddRef(lpOleDoc); + +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; + + /* OLE2NOTE: force all OLE objects to close. this forces all + ** OLE object to transition from running to loaded. we can + ** NOT exit if any embeddings are still running. + ** if an object can't be closed and this close operation was + ** started by the user, then we will abort closing our document. + */ + if (! ContainerDoc_CloseAllOleObjects(lpContainerDoc, OLECLOSE_NOSAVE) + && fAbortIfSaveCanceled) { + OleDoc_Release(lpOleDoc); // release artificial AddRef above + OleApp_Release(lpOleApp); // release artificial AddRef above + lpOleDoc->m_fObjIsClosing = FALSE; // clear recursion guard + + OLEDBG_END3 + return FALSE; // Closing is aborted + } + } +#endif + +#if defined( INPLACE_SVR ) + /* OLE2NOTE: if the server is currently in-place active we must + ** deactivate it now before closing + */ + ServerDoc_DoInPlaceDeactivate((LPSERVERDOC)lpOleDoc); +#endif + + /* OLE2NOTE: if this document is the source of data for the + ** clipboard, then flush the clipboard. it is important to flush + ** the clipboard BEFORE calling sending any notifications to + ** clients (eg. IOleClientSite::OnShowWindow(FALSE)) which could + ** give them a chance to run and try to get our clipboard data + ** object that we want to destroy. (eg. our app tries to + ** update the paste button of the toolbar when + ** WM_ACTIVATEAPP is received.) + */ + lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc; + if (lpClipboardDoc && + lpClipboardDoc->m_lpSrcDocOfCopy == lpOleDoc) { + OleApp_FlushClipboard(lpOleApp); + } + + /* OLE2NOTE: Revoke the object from the Running Object Table. it is + ** best if the object is revoke prior to calling + ** COLockObjectExternal(FALSE,TRUE) which is called when the + ** document window is hidden from the user. + */ + OLEDBG_BEGIN3("OleStdRevokeAsRunning called\r\n") + OleStdRevokeAsRunning(&lpOleDoc->m_dwRegROT); + OLEDBG_END3 + + /* OLE2NOTE: if the user is in control of the document, the user + ** accounts for one refcnt on the document. Closing the + ** document is achieved by releasing the object on behalf of + ** the user. if the document is not referenced by any other + ** clients, then the document will also be destroyed. if it + ** is referenced by other clients, then it will remain until + ** they release it. it is important to hide the window and call + ** IOleClientSite::OnShowWindow(FALSE) BEFORE sending OnClose + ** notification. + */ + OleDoc_HideWindow(lpOleDoc, TRUE); + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + LPSERVERNAMETABLE lpServerNameTable = + (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpOleDoc)->m_lpNameTable; + + /* OLE2NOTE: force all pseudo objects to close. this informs all + ** linking clients of pseudo objects to release their PseudoObj. + */ + ServerNameTable_CloseAllPseudoObjs(lpServerNameTable); + + /* OLE2NOTE: send last OnDataChange notification to clients + ** that have registered for data notifications when object + ** stops running (ADVF_DATAONSTOP), if the data in our + ** object has ever changed. it is best to only send this + ** notification if necessary. + */ + if (lpServerDoc->m_lpDataAdviseHldr) { + if (lpServerDoc->m_fSendDataOnStop) { + ServerDoc_SendAdvise( + (LPSERVERDOC)lpOleDoc, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + ADVF_DATAONSTOP + ); + } + /* OLE2NOTE: we just sent the last data notification that we + ** need to send; release our DataAdviseHolder. we SHOULD be + ** the only one using it. + */ + + OleStdVerifyRelease( + (LPUNKNOWN)lpServerDoc->m_lpDataAdviseHldr, + "DataAdviseHldr not released properly" + ); + lpServerDoc->m_lpDataAdviseHldr = NULL; + } + + // OLE2NOTE: inform all of our linking clients that we are closing. + + + if (lpServerDoc->m_lpOleAdviseHldr) { + ServerDoc_SendAdvise( + (LPSERVERDOC)lpOleDoc, + OLE_ONCLOSE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- not relevant here */ + ); + + /* OLE2NOTE: OnClose is the last notification that we need to + ** send; release our OleAdviseHolder. we SHOULD be the only + ** one using it. this will make our destructor realize that + ** OnClose notification has already been sent. + */ + OleStdVerifyRelease( + (LPUNKNOWN)lpServerDoc->m_lpOleAdviseHldr, + "OleAdviseHldr not released properly" + ); + lpServerDoc->m_lpOleAdviseHldr = NULL; + } + + /* release our Container's ClientSite. */ + if(lpServerDoc->m_lpOleClientSite) { + OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite); + lpServerDoc->m_lpOleClientSite = NULL; + } + } +#endif + + if (lpOleDoc->m_lpLLStm) { + /* release our LineList stream. */ + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm); + lpOleDoc->m_lpLLStm = NULL; + } + + if (lpOleDoc->m_lpNTStm) { + /* release our NameTable stream. */ + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm); + lpOleDoc->m_lpNTStm = NULL; + } + + if (lpOleDoc->m_lpStg) { + /* release our doc storage. */ + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg); + lpOleDoc->m_lpStg = NULL; + } + + if (lpOleDoc->m_lpFileMoniker) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker); + lpOleDoc->m_lpFileMoniker = NULL; + } + + /* OLE2NOTE: this call forces all external connections to our + ** object to close down and therefore guarantees that we receive + ** all releases associated with those external connections. + */ + OLEDBG_BEGIN2("CoDisconnectObject(lpDoc) called\r\n") + CoDisconnectObject((LPUNKNOWN)&lpOleDoc->m_Unknown, 0); + OLEDBG_END2 + + OleDoc_Release(lpOleDoc); // release artificial AddRef above + OleApp_Release(lpOleApp); // release artificial AddRef above + + OLEDBG_END3 + return TRUE; +} + + +/* OleDoc_Destroy + * -------------- + * + * Free all OLE related resources that had been allocated for a document. + */ +void OleDoc_Destroy(LPOLEDOC lpOleDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + if (lpOleDoc->m_fObjIsDestroying) + return; // Doc destruction is already in progress + + lpOleDoc->m_fObjIsDestroying = TRUE; // guard against recursive call + +#if defined( OLE_SERVER ) + + /* OLE2NOTE: it is ALWAYS necessary to make sure that the work we + ** do in our OleDoc_Close function is performed before we + ** destroy our document object. this includes revoking from the + ** Running Object Table (ROT), sending OnClose notification, + ** revoking from Drag/Drop, closing all pseudo objects, etc. + ** There are some tricky scenarios involving linking and + ** when IOleObject::Close is called versus when we get our + ** final release causing us to call our OleDoc_Destroy + ** (destructor) function. + ** + ** SCENARIO 1 -- closing from server (File.Exit or File.Close) + ** OleDoc_Close function is called directly by the + ** server in response to the menu command + ** (WM_COMMAND processing). + ** + ** SCENARIO 2 -- closed by embedding container + ** our embedding container calls IOleObject::Close + ** directly. + ** + ** SCENARIO 3 -- silent-update final release + ** THIS IS THE TRICKY ONE!!! + ** in the case that our object is launched because + ** a linking client calls IOleObject::Update on + ** its link, then our object will be run + ** invisibly, typically GetData will be called, + ** and then the connection from the linking client + ** will be released. the release of this last + ** linking connection should cause our object to + ** shut down. + ** there are 2 strategies to deal with this scenario: + ** + ** STRATEGY 1 -- implement IExternalConnection. + ** IExternalConnection::AddConnection will be + ** called (by the StubManager) every time that an + ** external (linking) connection is created or + ** CoLockObjectExternal is called. the object + ** should maintain a count of strong connections + ** (m_dwStrongExtConn). IExternalConnection:: + ** ReleaseConnection will be called when these + ** connections are released. when the + ** m_dwStrongExtConn transistions to 0, the object + ** should call its IOleObject::Close function. + ** this assumes that CoLockObjectExternal is used + ** to manage locks by the object itself (eg. when + ** the object is visible to the user--fUserCtrl, + ** and when PseudoObjects are created, etc.) + ** this is the strategy implemented by SVROUTL. + ** + ** STRATEGY 2 -- guard both the destructor + ** function and the Close function. if the + ** destructor is called directly without Close + ** first being called, then call Close before + ** proceeding with the destruction code. + ** previously SVROUTL was organized in this + ** manner. that old code is conditionaly compiled + ** away with "#ifdef OBSOLETE" below. this + ** method has the disadvantage that external + ** remoting is no longer possible by the time the + ** Close is called making it impossible for + ** the object to ask its container to save the + ** object if the object is dirty. this can result + ** in data loss. thus STRATEGY 1 is safer. + ** consider the scenario where an in-place + ** container UIDeactivates an object but does NOT + ** keep the object locked running (this is + ** required--see CntrLine_IPSite_OnInPlaceActivate + ** in cntrline.c), then, if a linking client binds + ** and unbinds from the object, the object will be + ** destroyed and will NOT have an opportunity to + ** be saved. by implementing IExternalConnection, + ** a server can insulate itself from a poorly + ** written container. + */ +#if defined( _DEBUG ) + +#ifndef WIN32 + // this is not a valid assert in Ole32; if file moniker binding + // fails, for example, we will only get releases coming in + // (no external connections are involved because OLE32 does a + // private rpc to the server (us) where the IPersistFile::Load is + // done. + + OleDbgAssertSz( + (lpOutlineDoc->m_fDataTransferDoc || lpOleDoc->m_fObjIsClosing), + "Destroy called without Close being called\r\n" + ); +#endif //!WIN32 + +#endif // _DEBUG +#if defined( OBSOLETE ) + /* OLE2NOTE: if the document destructor is called directly because + ** the object's refcnt went to 0 (ie. without OleDoc_Close first + ** being called), then we need to make sure that the document is + ** properly closed before destroying the object. this scenario + ** could arise during a silent-update of a link. calling + ** OleDoc_Close here guarantees that the clipboard will be + ** properly flushed, the doc's moniker will be properly revoked, + ** the document will be saved if necessary, etc. + */ + if (!lpOutlineDoc->m_fDataTransferDoc && !lpOleDoc->m_fObjIsClosing) + OleDoc_Close(lpOleDoc, OLECLOSE_NOSAVE); +#endif + + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + /* OLE2NOTE: perform processing specific for an OLE server */ + +#if defined( SVR_TREATAS ) + if (lpServerDoc->m_lpszTreatAsType) { + OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL); + lpServerDoc->m_lpszTreatAsType = NULL; + } +#endif // SVR_TREATAS + +#if defined( INPLACE_SVR ) + if (IsWindow(lpServerDoc->m_hWndHatch)) + DestroyWindow(lpServerDoc->m_hWndHatch); +#endif // INPLACE_SVR + } +#endif // OLE_SERVER + + if (lpOleDoc->m_lpLLStm) { + /* release our LineList stream. */ + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm); + lpOleDoc->m_lpLLStm = NULL; + } + + if (lpOleDoc->m_lpNTStm) { + /* release our NameTable stream. */ + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm); + lpOleDoc->m_lpNTStm = NULL; + } + + if (lpOleDoc->m_lpStg) { + /* release our doc storage. */ + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg); + lpOleDoc->m_lpStg = NULL; + } + + if (lpOleDoc->m_lpFileMoniker) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker); + lpOleDoc->m_lpFileMoniker = NULL; + } + + /***************************************************************** + ** OLE2NOTE: each document addref's the app object in order to ** + ** guarentee that the app does not shut down while the doc ** + ** is still open. since this doc is now destroyed, we will ** + ** release this refcnt now. if there are now more open ** + ** documents AND the app is not under the control of the ** + ** user (ie. launched by OLE) then the app will revoke its ** + ** ClassFactory. if there are no more references to the ** + ** ClassFactory after it is revoked, then the app will shut ** + ** down. this whole procedure is triggered by calling ** + ** OutlineApp_DocUnlockApp. ** + *****************************************************************/ + + OutlineApp_DocUnlockApp(lpOutlineApp, lpOutlineDoc); +} + + +/* OleDoc_SetUpdateEditMenuFlag + * ---------------------------- + * + * Purpose: + * Set/clear the UpdateEditMenuFlag in OleDoc. + * + * Parameters: + * fUpdate new value of the flag + * + * Returns: + */ +void OleDoc_SetUpdateEditMenuFlag(LPOLEDOC lpOleDoc, BOOL fUpdate) +{ + if (!lpOleDoc) + return; + + lpOleDoc->m_fUpdateEditMenu = fUpdate; +} + + +/* OleDoc_GetUpdateEditMenuFlag + * ---------------------------- + * + * Purpose: + * Get the value of the UpdateEditMenuFlag in OleDoc + * + * Parameters: + * + * Returns: + * value of the flag + */ +BOOL OleDoc_GetUpdateEditMenuFlag(LPOLEDOC lpOleDoc) +{ + if (!lpOleDoc) + return FALSE; + + return lpOleDoc->m_fUpdateEditMenu; +} + + + +/************************************************************************* +** OleDoc::IUnknown interface implementation +*************************************************************************/ + +STDMETHODIMP OleDoc_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) OleDoc_Unk_AddRef(LPUNKNOWN lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IUnknown"); + + return OleDoc_AddRef(lpOleDoc); +} + + +STDMETHODIMP_(ULONG) OleDoc_Unk_Release (LPUNKNOWN lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IUnknown"); + + return OleDoc_Release(lpOleDoc); +} diff --git a/private/oleutest/letest/outline/oleoutl.h b/private/oleutest/letest/outline/oleoutl.h new file mode 100644 index 000000000..f936295cc --- /dev/null +++ b/private/oleutest/letest/outline/oleoutl.h @@ -0,0 +1,734 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** oleoutl.h +** +** This file contains file contains data structure defintions, +** function prototypes, constants, etc. which are common to the +** server version and the container version of the app. +** app version of the Outline series of sample applications: +** Outline -- base version of the app (without OLE functionality) +** SvrOutl -- OLE 2.0 Server sample app +** CntrOutl -- OLE 2.0 Containter sample app +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if !defined( _OLEOUTL_H_ ) +#define _OLEOUTL_H_ + +#ifndef RC_INVOKED +#pragma message ("INCLUDING OLEOUTL.H from " __FILE__) +// make 'different levels of inderection' considered an error +#pragma warning (error:4047) +#endif /* RC_INVOKED */ + +#if defined( USE_MSGFILTER ) +#include "msgfiltr.h" +#endif // USE_MSGFILTER + +#include "defguid.h" + +/* Defines */ + +/* OLE2NOTE: these strings should correspond to the strings registered +** in the registration database. +*/ +// REVIEW: should load strings from resource file +#if defined( INPLACE_SVR ) +#define CLSID_APP CLSID_ISvrOtl +#define FULLUSERTYPENAME "Ole 2.0 In-Place Server Outline" +#define SHORTUSERTYPENAME "Outline" // max 15 chars +#undef APPFILENAMEFILTER +#define APPFILENAMEFILTER "Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|" +#undef DEFEXTENSION +#define DEFEXTENSION "oln" // Default file extension +#endif // INPLACE_SVR + +#if defined( INPLACE_CNTR ) +#define CLSID_APP CLSID_ICntrOtl +#define FULLUSERTYPENAME "Ole 2.0 In-Place Container Outline" +// #define SHORTUSERTYPENAME "Outline" // max 15 chars +#undef APPFILENAMEFILTER +#define APPFILENAMEFILTER "CntrOutl Files (*.OLC)|*.olc|Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|" +#undef DEFEXTENSION +#define DEFEXTENSION "olc" // Default file extension +#endif // INPLACE_CNTR + +#if defined( OLE_SERVER ) && !defined( INPLACE_SVR ) +#define CLSID_APP CLSID_SvrOutl +#define FULLUSERTYPENAME "Ole 2.0 Server Sample Outline" +#define SHORTUSERTYPENAME "Outline" +#undef APPFILENAMEFILTER +#define APPFILENAMEFILTER "Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|" +#undef DEFEXTENSION +#define DEFEXTENSION "oln" // Default file extension +#endif // OLE_SERVER && ! INPLACE_SVR + +#if defined( OLE_CNTR ) && !defined( INPLACE_CNTR ) +#define CLSID_APP CLSID_CntrOutl +#define FULLUSERTYPENAME "Ole 2.0 Container Sample Outline" +// #define SHORTUSERTYPENAME "Outline" // max 15 chars +#undef APPFILENAMEFILTER +#define APPFILENAMEFILTER "CntrOutl Files (*.OLC)|*.olc|Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|" +#undef DEFEXTENSION +#define DEFEXTENSION "olc" // Default file extension +#endif // OLE_CNTR && ! INPLACE_CNTR + +// Maximum number of formats offered by IDataObject::GetData/SetData +#define MAXNOFMTS 10 +#define MAXNOLINKTYPES 3 + +#if defined( USE_DRAGDROP ) +#define DD_SEL_THRESH HITTESTDELTA // Border threshold to start drag +#define MAX_SEL_ITEMS 0x0080 +#endif // USE_DRAGDROP + +/* Positions of the various menus */ +#define POS_FILEMENU 0 +#define POS_EDITMENU 1 +#define POS_VIEWMENU 2 +#define POS_LINEMENU 3 +#define POS_NAMEMENU 4 +#define POS_OPTIONSMENU 5 +#define POS_DEBUGMENU 6 +#define POS_HELPMENU 7 + + +#define POS_OBJECT 11 + + +/* Types */ + +// Document initialization type +#define DOCTYPE_EMBEDDED 3 // init from an IStorage* of an embedded obj +#define DOCTYPE_FROMSTG 4 // init from an IStorage* with doc bit set + +/* Forward type definitions */ +typedef struct tagOLEAPP FAR* LPOLEAPP; +typedef struct tagOLEDOC FAR* LPOLEDOC; + +/* Flags to control Moniker assignment for OleDoc_GetFullMoniker */ +// REVIEW: should use official OLEGETMONIKER type for final version +typedef enum tagGETMONIKERTYPE { + GETMONIKER_ONLYIFTHERE = 1, + GETMONIKER_FORCEASSIGN = 2, + GETMONIKER_UNASSIGN = 3, + GETMONIKER_TEMPFORUSER = 4 +} GETMONIKERTYPE; + +/* Flags to control direction for drag scrolling */ +typedef enum tagSCROLLDIR { + SCROLLDIR_NULL = 0, + SCROLLDIR_UP = 1, + SCROLLDIR_DOWN = 2, + SCROLLDIR_RIGHT = 3, // currently not used + SCROLLDIR_LEFT = 4 // currently not used +} SCROLLDIR; + + +/************************************************************************* +** class OLEDOC : OUTLINEDOC +** OLEDOC is an extention to the base OUTLINEDOC object (structure) +** that adds common OLE 2.0 functionality used by both the server +** and container versions. This is an abstract class. You do not +** instantiate an instance of OLEDOC directly but instead +** instantiate one of its concrete subclasses: SERVERDOC or +** CONTAINERDOC. There is one instance of an document +** object created per document open in the app. The SDI +** version of the app supports one ServerDoc at a time. The MDI +** version of the app can manage multiple documents at one time. +** The OLEDOC class inherits all fields from the OUTLINEDOC class. +** This inheritance is achieved by including a member variable of +** type OUTLINEDOC as the first field in the OLEDOC +** structure. Thus a pointer to an OLEDOC object can be cast to be +** a pointer to a OUTLINEDOC object. +*************************************************************************/ + +typedef struct tagOLEDOC { + OUTLINEDOC m_OutlineDoc; // ServerDoc inherits from OutlineDoc + ULONG m_cRef; // total ref count for document + ULONG m_dwStrongExtConn; // total strong connection count + // (from IExternalConnection) + // when this count transitions to 0 + // and fLastUnlockCloses==TRUE, then + // IOleObject::Close is called to + // close the document. +#if defined( _DEBUG ) + ULONG m_cCntrLock; // total count of LockContainer locks + // (for debugging purposes only) +#endif + LPSTORAGE m_lpStg; // OleDoc must keep its stg open + // even in-memory server doc should + // keep Stg open for low memory save + LPSTREAM m_lpLLStm; // Hold LineList IStream* open for + // low memory save + LPSTREAM m_lpNTStm; // Hold NameTable IStream* open for + // low memory save + BOOL m_fObjIsClosing; // flag to guard recursive close call + BOOL m_fObjIsDestroying; // flag to guard recursiv destroy call + DWORD m_dwRegROT; // key if doc registered as running + LPMONIKER m_lpFileMoniker; // moniker if file-based/untitled doc + BOOL m_fLinkSourceAvail; // can doc offer CF_LINKSOURCE + LPOLEDOC m_lpSrcDocOfCopy; // src doc if doc created for copy + BOOL m_fUpdateEditMenu; // need to update edit menu?? + +#if defined( USE_DRAGDROP ) + DWORD m_dwTimeEnterScrollArea; // time entering scroll region + DWORD m_dwLastScrollDir; // current dir for drag scroll + DWORD m_dwNextScrollTime; // time for next scroll + BOOL m_fRegDragDrop; // is doc registered as drop target? + BOOL m_fLocalDrag; // is doc source of the drag + BOOL m_fLocalDrop; // was doc target of the drop + BOOL m_fCanDropCopy; // is Drag/Drop copy/move possible? + BOOL m_fCanDropLink; // is Drag/Drop link possible? + BOOL m_fDragLeave; // has drag left + BOOL m_fPendingDrag; // LButtonDown--possible drag pending + POINT m_ptButDown; // LButtonDown coordinates +#endif // USE_DRAGDROP + +#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR ) + BOOL m_fCSHelpMode; // Shift-F1 context help mode +#endif + + struct CDocUnknownImpl { + IUnknownVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_Unknown; + + struct CDocPersistFileImpl { + IPersistFileVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_PersistFile; + + struct CDocOleItemContainerImpl { + IOleItemContainerVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_OleItemContainer; + + struct CDocExternalConnectionImpl { + IExternalConnectionVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_ExternalConnection; + + struct CDocDataObjectImpl { + IDataObjectVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_DataObject; + +#ifdef USE_DRAGDROP + struct CDocDropSourceImpl { + IDropSourceVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_DropSource; + + struct CDocDropTargetImpl { + IDropTargetVtbl FAR* lpVtbl; + LPOLEDOC lpOleDoc; + int cRef; // interface specific ref count. + } m_DropTarget; +#endif // USE_DRAGDROP + +} OLEDOC; + +/* OleDoc methods (functions) */ +BOOL OleDoc_Init(LPOLEDOC lpOleDoc, BOOL fDataTransferDoc); +BOOL OleDoc_InitNewFile(LPOLEDOC lpOleDoc); +void OleDoc_ShowWindow(LPOLEDOC lpOleDoc); +void OleDoc_HideWindow(LPOLEDOC lpOleDoc, BOOL fShutDown); +HRESULT OleDoc_Lock(LPOLEDOC lpOleDoc, BOOL fLock, BOOL fLastUnlockReleases); +ULONG OleDoc_AddRef(LPOLEDOC lpOleDoc); +ULONG OleDoc_Release (LPOLEDOC lpOleDoc); +HRESULT OleDoc_QueryInterface( + LPOLEDOC lpOleDoc, + REFIID riid, + LPVOID FAR* lplpUnk +); +BOOL OleDoc_Close(LPOLEDOC lpOleDoc, DWORD dwSaveOption); +void OleDoc_Destroy(LPOLEDOC lpOleDoc); +void OleDoc_SetUpdateEditMenuFlag(LPOLEDOC lpOleDoc, BOOL fUpdate); +BOOL OleDoc_GetUpdateEditMenuFlag(LPOLEDOC lpOleDoc); +void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel); +HGLOBAL OleDoc_GetObjectDescriptorData( + LPOLEDOC lpOleDoc, + LPLINERANGE lplrSel +); +LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign); +void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel); +void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc); +void OleDoc_CopyCommand(LPOLEDOC lpSrcOleDoc); +void OleDoc_PasteCommand(LPOLEDOC lpOleDoc); +void OleDoc_PasteSpecialCommand(LPOLEDOC lpOleDoc); +LPOUTLINEDOC OleDoc_CreateDataTransferDoc(LPOLEDOC lpSrcOleDoc); +BOOL OleDoc_PasteFromData( + LPOLEDOC lpOleDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink +); +BOOL OleDoc_PasteFormatFromData( + LPOLEDOC lpOleDoc, + CLIPFORMAT cfFormat, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink, + BOOL fDisplayAsIcon, + HGLOBAL hMetaPict, + LPSIZEL lpSizelInSrc +); +BOOL OleDoc_QueryPasteFromData( + LPOLEDOC lpOleDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLink +); + +#if defined( USE_DRAGDROP ) + +BOOL OleDoc_QueryDrag( LPOLEDOC lpOleDoc, int y ); +BOOL OleDoc_QueryDrop ( + LPOLEDOC lpOleDoc, + DWORD grfKeyState, + POINTL pointl, + BOOL fDragScroll, + LPDWORD lpdwEffect +); +DWORD OleDoc_DoDragDrop (LPOLEDOC lpSrcOleDoc); +BOOL OleDoc_DoDragScroll(LPOLEDOC lpOleDoc, POINTL pointl); + +#endif // USE_DRAGDROP + +/* OleDoc::IUnknown methods (functions) */ +STDMETHODIMP OleDoc_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_Unk_AddRef(LPUNKNOWN lpThis); +STDMETHODIMP_(ULONG) OleDoc_Unk_Release (LPUNKNOWN lpThis); + +/* OleDoc::IPersistFile methods (functions) */ +STDMETHODIMP OleDoc_PFile_QueryInterface( + LPPERSISTFILE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis); +STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis); +STDMETHODIMP OleDoc_PFile_GetClassID ( + LPPERSISTFILE lpThis, + CLSID FAR* lpclsid +); +STDMETHODIMP OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis); +STDMETHODIMP OleDoc_PFile_Load ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName, + DWORD grfMode +); +STDMETHODIMP OleDoc_PFile_Save ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName, + BOOL fRemember +); +STDMETHODIMP OleDoc_PFile_SaveCompleted ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName +); +STDMETHODIMP OleDoc_PFile_GetCurFile ( + LPPERSISTFILE lpThis, + LPOLESTR FAR* lplpszFileName +); + +/* OleDoc::IOleItemContainer methods (functions) */ +STDMETHODIMP OleDoc_ItemCont_QueryInterface( + LPOLEITEMCONTAINER lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis); +STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis); +STDMETHODIMP OleDoc_ItemCont_ParseDisplayName( + LPOLEITEMCONTAINER lpThis, + LPBC lpbc, + LPOLESTR lpszDisplayName, + ULONG FAR* lpchEaten, + LPMONIKER FAR* lplpmkOut +); + +STDMETHODIMP OleDoc_ItemCont_EnumObjects( + LPOLEITEMCONTAINER lpThis, + DWORD grfFlags, + LPENUMUNKNOWN FAR* lplpenumUnknown +); +STDMETHODIMP OleDoc_ItemCont_LockContainer( + LPOLEITEMCONTAINER lpThis, + BOOL fLock +); +STDMETHODIMP OleDoc_ItemCont_GetObject( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvObject +); +STDMETHODIMP OleDoc_ItemCont_GetObjectStorage( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvStorage +); +STDMETHODIMP OleDoc_ItemCont_IsRunning( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem +); + +/* OleDoc::IPersistFile methods (functions) */ +STDMETHODIMP OleDoc_ExtConn_QueryInterface( + LPEXTERNALCONNECTION lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_ExtConn_AddRef(LPEXTERNALCONNECTION lpThis); +STDMETHODIMP_(ULONG) OleDoc_ExtConn_Release (LPEXTERNALCONNECTION lpThis); +STDMETHODIMP_(DWORD) OleDoc_ExtConn_AddConnection( + LPEXTERNALCONNECTION lpThis, + DWORD extconn, + DWORD reserved +); +STDMETHODIMP_(DWORD) OleDoc_ExtConn_ReleaseConnection( + LPEXTERNALCONNECTION lpThis, + DWORD extconn, + DWORD reserved, + BOOL fLastReleaseCloses +); + +/* OleDoc::IDataObject methods (functions) */ +STDMETHODIMP OleDoc_DataObj_QueryInterface ( + LPDATAOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_DataObj_AddRef(LPDATAOBJECT lpThis); +STDMETHODIMP_(ULONG) OleDoc_DataObj_Release (LPDATAOBJECT lpThis); +STDMETHODIMP OleDoc_DataObj_GetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc, + LPSTGMEDIUM lpMedium +); +STDMETHODIMP OleDoc_DataObj_GetDataHere ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc, + LPSTGMEDIUM lpMedium +); +STDMETHODIMP OleDoc_DataObj_QueryGetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc +); +STDMETHODIMP OleDoc_DataObj_GetCanonicalFormatEtc( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPFORMATETC lpformatetcOut +); +STDMETHODIMP OleDoc_DataObj_SetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpFormatetc, + LPSTGMEDIUM lpMedium, + BOOL fRelease +); +STDMETHODIMP OleDoc_DataObj_EnumFormatEtc( + LPDATAOBJECT lpThis, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +); +STDMETHODIMP OleDoc_DataObj_DAdvise( + LPDATAOBJECT lpThis, + FORMATETC FAR* lpFormatetc, + DWORD advf, + LPADVISESINK lpAdvSink, + DWORD FAR* lpdwConnection +); +STDMETHODIMP OleDoc_DataObj_DUnadvise(LPDATAOBJECT lpThis,DWORD dwConnection); +STDMETHODIMP OleDoc_DataObj_EnumDAdvise( + LPDATAOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +); + + +#ifdef USE_DRAGDROP + +/* OleDoc::IDropSource methods (functions) */ +STDMETHODIMP OleDoc_DropSource_QueryInterface( + LPDROPSOURCE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_DropSource_AddRef( LPDROPSOURCE lpThis ); +STDMETHODIMP_(ULONG) OleDoc_DropSource_Release ( LPDROPSOURCE lpThis); +STDMETHODIMP OleDoc_DropSource_QueryContinueDrag ( + LPDROPSOURCE lpThis, + BOOL fEscapePressed, + DWORD grfKeyState +); +STDMETHODIMP OleDoc_DropSource_GiveFeedback ( + LPDROPSOURCE lpThis, + DWORD dwEffect +); + +/* OleDoc::IDropTarget methods (functions) */ +STDMETHODIMP OleDoc_DropTarget_QueryInterface( + LPDROPTARGET lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleDoc_DropTarget_AddRef(LPDROPTARGET lpThis); +STDMETHODIMP_(ULONG) OleDoc_DropTarget_Release ( LPDROPTARGET lpThis); +STDMETHODIMP OleDoc_DropTarget_DragEnter ( + LPDROPTARGET lpThis, + LPDATAOBJECT lpDataObj, + DWORD grfKeyState, + POINTL pointl, + LPDWORD lpdwEffect +); +STDMETHODIMP OleDoc_DropTarget_DragOver ( + LPDROPTARGET lpThis, + DWORD grfKeyState, + POINTL pointl, + LPDWORD lpdwEffect +); +STDMETHODIMP OleDoc_DropTarget_DragLeave ( LPDROPTARGET lpThis); +STDMETHODIMP OleDoc_DropTarget_Drop ( + LPDROPTARGET lpThis, + LPDATAOBJECT lpDataObj, + DWORD grfKeyState, + POINTL pointl, + LPDWORD lpdwEffect +); + +#endif // USE_DRAGDROP + + +/************************************************************************* +** class APPCLASSFACTORY +** APPCLASSFACTORY implements the IClassFactory interface. it +** instantiates document instances of the correct type depending on +** how the application is compiled (either ServerDoc or ContainerDoc +** instances). by implementing this +** interface in a seperate interface from the App object itself, it +** is easier to manage when the IClassFactory should be +** registered/revoked. when the OleApp object is first initialized +** in OleApp_InitInstance an instance of APPCLASSFACTORY is created +** and registered (CoRegisterClassObject called). when the App +** object gets destroyed (in OleApp_Destroy) this APPCLASSFACTORY is +** revoked (CoRevokeClassObject called) and released. the simple +** fact that the IClassFactory is registered does not on its own keep +** the application alive. +*************************************************************************/ + +typedef struct tagAPPCLASSFACTORY { + IClassFactoryVtbl FAR* m_lpVtbl; + UINT m_cRef; +#if defined( _DEBUG ) + LONG m_cSvrLock; // total count of LockServer locks + // (for debugging purposes only) +#endif + } APPCLASSFACTORY, FAR* LPAPPCLASSFACTORY; + +/* PUBLIC FUNCTIONS */ +LPCLASSFACTORY WINAPI AppClassFactory_Create(void); + +/* interface IClassFactory implementation */ +STDMETHODIMP AppClassFactory_QueryInterface( + LPCLASSFACTORY lpThis, REFIID riid, LPVOID FAR* ppvObj); +STDMETHODIMP_(ULONG) AppClassFactory_AddRef(LPCLASSFACTORY lpThis); +STDMETHODIMP_(ULONG) AppClassFactory_Release(LPCLASSFACTORY lpThis); +STDMETHODIMP AppClassFactory_CreateInstance ( + LPCLASSFACTORY lpThis, + LPUNKNOWN lpUnkOuter, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP AppClassFactory_LockServer ( + LPCLASSFACTORY lpThis, + BOOL fLock +); + + +/************************************************************************* +** class OLEAPP : OUTLINEAPP +** OLEAPP is an extention to the base OUTLINEAPP object (structure) +** that adds common OLE 2.0 functionality used by both the server +** and container versions. This is an abstract class. You do not +** instantiate an instance of OLEAPP directly but instead +** instantiate one of its concrete subclasses: SERVERAPP or +** CONTAINERAPP. There is one instance of an document application +** object created per running application instance. This +** object holds many fields that could otherwise be organized as +** global variables. The OLEAPP class inherits all fields +** from the OUTLINEAPP class. This inheritance is achieved by including a +** member variable of type OUTLINEAPP as the first field in the OLEAPP +** structure. Thus a pointer to a OLEAPP object can be cast to be +** a pointer to a OUTLINEAPP object. +*************************************************************************/ + +typedef struct tagOLEAPP { + OUTLINEAPP m_OutlineApp; // inherits all fields of OutlineApp + ULONG m_cRef; // total ref count for app + ULONG m_cDoc; // total count of open documents + BOOL m_fUserCtrl; // does user control life-time of app? + DWORD m_dwRegClassFac; // value returned by CoRegisterClassObject + LPCLASSFACTORY m_lpClassFactory;// ptr to allocated ClassFactory instance +#if defined( USE_MSGFILTER ) + LPMESSAGEFILTER m_lpMsgFilter; // ptr to allocated MsgFilter instance + MSGPENDINGPROC m_lpfnMsgPending;// ptr to msg pending callback function +#endif // USE_MSGFILTER + BOOL m_fOleInitialized; // was OleInitialize called + UINT m_cModalDlgActive; // count of modal dialogs up; 0 = no dlg. + UINT m_cfEmbedSource; // OLE 2.0 clipboard format + UINT m_cfEmbeddedObject; // OLE 2.0 clipboard format + UINT m_cfLinkSource; // OLE 2.0 clipboard format + UINT m_cfObjectDescriptor; // OLE 2.0 clipboard format + UINT m_cfLinkSrcDescriptor; // OLE 2.0 clipboard format + UINT m_cfFileName; // std Windows clipboard format + FORMATETC m_arrDocGetFmts[MAXNOFMTS]; // fmts offered by copy & GetData + UINT m_nDocGetFmts; // no of fmtetc's for GetData + + OLEUIPASTEENTRY m_arrPasteEntries[MAXNOFMTS]; // input for PasteSpl. + int m_nPasteEntries; // input for PasteSpl. + UINT m_arrLinkTypes[MAXNOLINKTYPES]; // input for PasteSpl. + int m_nLinkTypes; // input for PasteSpl. + +#if defined( USE_DRAGDROP ) + int m_nDragDelay; // time delay (in msec) before drag should start + int m_nDragMinDist; // min. distance (radius) before drag should start + int m_nScrollDelay; // time delay (in msec) before scroll should start + int m_nScrollInset; // Border inset distance to start drag scroll + int m_nScrollInterval; // scroll interval time (in msec) + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) + // This would be used if the app wanted to have custom drag/drop cursors + HCURSOR m_hcursorDragNone; + HCURSOR m_hcursorDragCopy; + HCURSOR m_hcursorDragLink; +#endif // IF_SPECIAL_DD_CURSORS_NEEDED +#endif // USE_DRAGDROP + + +#if defined( OLE_CNTR ) + HPALETTE m_hStdPal; // standard color palette for OLE + // it is a good idea for containers + // to use this standard palette + // even if they do not use colors + // themselves. this will allow + // embedded object to get a good + // distribution of colors when they + // are being drawn by the container. + // +#endif + + struct CAppUnknownImpl { + IUnknownVtbl FAR* lpVtbl; + LPOLEAPP lpOleApp; + int cRef; // interface specific ref count. + } m_Unknown; + +} OLEAPP; + +/* ServerApp methods (functions) */ +BOOL OleApp_InitInstance(LPOLEAPP lpOleApp, HINSTANCE hInst, int nCmdShow); +void OleApp_TerminateApplication(LPOLEAPP lpOleApp); +BOOL OleApp_ParseCmdLine(LPOLEAPP lpOleApp, LPSTR lpszCmdLine, int nCmdShow); +void OleApp_Destroy(LPOLEAPP lpOleApp); +BOOL OleApp_CloseAllDocsAndExitCommand( + LPOLEAPP lpOleApp, + BOOL fForceEndSession +); +void OleApp_ShowWindow(LPOLEAPP lpOleApp, BOOL fGiveUserCtrl); +void OleApp_HideWindow(LPOLEAPP lpOleApp); +void OleApp_HideIfNoReasonToStayVisible(LPOLEAPP lpOleApp); +void OleApp_DocLockApp(LPOLEAPP lpOleApp); +void OleApp_DocUnlockApp(LPOLEAPP lpOleApp, LPOUTLINEDOC lpOutlineDoc); +HRESULT OleApp_Lock(LPOLEAPP lpOleApp, BOOL fLock, BOOL fLastUnlockReleases); +ULONG OleApp_AddRef(LPOLEAPP lpOleApp); +ULONG OleApp_Release (LPOLEAPP lpOleApp); +HRESULT OleApp_QueryInterface ( + LPOLEAPP lpOleApp, + REFIID riid, + LPVOID FAR* lplpUnk +); +void OleApp_RejectInComingCalls(LPOLEAPP lpOleApp, BOOL fReject); +void OleApp_DisableBusyDialogs( + LPOLEAPP lpOleApp, + BOOL FAR* lpfPrevBusyEnable, + BOOL FAR* lpfPrevNREnable +); +void OleApp_EnableBusyDialogs( + LPOLEAPP lpOleApp, + BOOL fPrevBusyEnable, + BOOL fPrevNREnable +); +void OleApp_PreModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpActiveOleDoc); +void OleApp_PostModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpActiveOleDoc); +BOOL OleApp_InitVtbls (LPOLEAPP lpOleApp); +void OleApp_InitMenu( + LPOLEAPP lpOleApp, + LPOLEDOC lpOleDoc, + HMENU hMenu +); +void OleApp_UpdateEditMenu( + LPOLEAPP lpOleApp, + LPOUTLINEDOC lpOutlineDoc, + HMENU hMenuEdit +); +BOOL OleApp_RegisterClassFactory(LPOLEAPP lpOleApp); +void OleApp_RevokeClassFactory(LPOLEAPP lpOleApp); + +#if defined( USE_MSGFILTER ) +BOOL OleApp_RegisterMessageFilter(LPOLEAPP lpOleApp); +void OleApp_RevokeMessageFilter(LPOLEAPP lpOleApp); +BOOL FAR PASCAL EXPORT MessagePendingProc(MSG FAR *lpMsg); +#endif // USE_MSGFILTER + +void OleApp_FlushClipboard(LPOLEAPP lpOleApp); +void OleApp_NewCommand(LPOLEAPP lpOleApp); +void OleApp_OpenCommand(LPOLEAPP lpOleApp); + +#if defined( OLE_CNTR ) +LRESULT OleApp_QueryNewPalette(LPOLEAPP lpOleApp); +#endif // OLE_CNTR + +LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground); + + +/* OleApp::IUnknown methods (functions) */ +STDMETHODIMP OleApp_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) OleApp_Unk_AddRef(LPUNKNOWN lpThis); +STDMETHODIMP_(ULONG) OleApp_Unk_Release (LPUNKNOWN lpThis); + + +/* Function prototypes in debug.c */ +void InstallMessageFilterCommand(void); +void RejectIncomingCommand(void); + + +#if defined( OLE_SERVER ) +#include "svroutl.h" +#endif +#if defined( OLE_CNTR ) +#include "cntroutl.h" +#endif + +#endif // _OLEOUTL_H_ + diff --git a/private/oleutest/letest/outline/outlapp.c b/private/oleutest/letest/outline/outlapp.c new file mode 100644 index 000000000..caa5da006 --- /dev/null +++ b/private/oleutest/letest/outline/outlapp.c @@ -0,0 +1,1514 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outlapp.c +** +** This file contains OutlineApp functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +#if defined( USE_STATUSBAR ) +#include "status.h" +#endif + +#if !defined( WIN32 ) +#include <print.h> +#endif + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; +extern RECT g_rectNull; + + +// REVIEW: should use string resource for messages +char ErrMsgClass[] = "Can't register window classes!"; +char ErrMsgFrame[] = "Can't create Frame Window!"; +char ErrMsgPrinting[] = "Can't access printer!"; + + +/* OutlineApp_InitApplication +** -------------------------- +** Sets up the class data structures and does a one-time +** initialization of the app by registering the window classes. +** Returns TRUE if initialization is successful +** FALSE otherwise +*/ + +BOOL OutlineApp_InitApplication(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst) +{ + WNDCLASS wndclass; + + // REVIEW: should load msg strings from string resource + + /* Register the app frame class */ + wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW; + wndclass.lpfnWndProc = AppWndProc; + /* Extra storage for Class and Window objects */ + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof(LPOUTLINEAPP); /* to store lpApp */ + wndclass.hInstance = hInst; + wndclass.hIcon = LoadIcon(hInst, APPICON); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + /* Create brush for erasing background */ + wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wndclass.lpszMenuName = APPMENU; /* Menu Name is App Name */ + wndclass.lpszClassName = APPWNDCLASS; /* Class Name is App Name */ + + if(! RegisterClass(&wndclass)) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFrame); + return FALSE; + } + + /* Register the document window class */ + wndclass.style = CS_BYTEALIGNWINDOW; + wndclass.lpfnWndProc = DocWndProc; + wndclass.hIcon = NULL; + wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = DOCWNDCLASS; + wndclass.cbWndExtra = sizeof(LPOUTLINEDOC); /* to store lpDoc */ + if(! RegisterClass(&wndclass)) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgClass); + return FALSE; + } + +#if defined( USE_STATUSBAR ) + if (! RegisterStatusClass(hInst)) + return FALSE; +#endif + +#if defined( USE_FRAMETOOLS ) + if (! FrameToolsRegisterClass(hInst)) { + return FALSE; + } +#endif + +#if defined( INPLACE_SVR ) + // We should only register the hatch window class + // in the UI Library once per application. + RegisterHatchWindowClass(hInst); + +#endif + + return TRUE; +} + + +/* OutlineApp_InitInstance + * ----------------------- + * + * Performs a per-instance initialization of app. + * This method creates the frame window. + * + * RETURNS : TRUE - If initialization was successful. + * FALSE - otherwise. + */ + +BOOL OutlineApp_InitInstance(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst, int nCmdShow) +{ + lpOutlineApp->m_hInst = hInst; + + /* create application's Frame window */ + lpOutlineApp->m_hWndApp = CreateWindow( + APPWNDCLASS, /* Window class name */ + APPNAME, /* initial Window title */ + WS_OVERLAPPEDWINDOW| + WS_CLIPCHILDREN, + CW_USEDEFAULT, 0, /* Use default X, Y */ + CW_USEDEFAULT, 0, /* Use default X, Y */ + HWND_DESKTOP, /* Parent window's handle */ + NULL, /* Default to Class Menu */ + hInst, /* Instance of window */ + NULL /* Create struct for WM_CREATE */ + ); + + if(! lpOutlineApp->m_hWndApp) { + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFrame); + return FALSE; + } + + SetWindowLong(lpOutlineApp->m_hWndApp, 0, (LONG) lpOutlineApp); + + /* defer creating the user's SDI document until we parse the cmd line. */ + lpOutlineApp->m_lpDoc = NULL; + + /* Initialize clipboard. + */ + lpOutlineApp->m_lpClipboardDoc = NULL; + if(!(lpOutlineApp->m_cfOutline = RegisterClipboardFormat(OUTLINEDOCFORMAT))) { + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Can't register clipboard format!"); + return FALSE; + } + + /* init the standard font to be used for drawing/printing text + * request a Roman style True Type font of the desired size + */ + lpOutlineApp->m_hStdFont = CreateFont( + -DEFFONTSIZE, + 0,0,0,0,0,0,0,0, + OUT_TT_PRECIS, // use TrueType + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + VARIABLE_PITCH | FF_ROMAN, + DEFFONTFACE + ); + + // Load special cursor for selection of Lines in ListBox. + lpOutlineApp->m_hcursorSelCur = LoadCursor ( hInst, "SelCur" ); + + /* init the Print Dialog structure */ + _fmemset((LPVOID)&lpOutlineApp->m_PrintDlg,0,sizeof(PRINTDLG)); + lpOutlineApp->m_PrintDlg.lStructSize = sizeof(PRINTDLG); + lpOutlineApp->m_PrintDlg.hDevMode = NULL; + lpOutlineApp->m_PrintDlg.hDevNames = NULL; + lpOutlineApp->m_PrintDlg.Flags = PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS | + PD_HIDEPRINTTOFILE; + lpOutlineApp->m_PrintDlg.nCopies = 1; + lpOutlineApp->m_PrintDlg.hwndOwner = lpOutlineApp->m_hWndApp; + +#if defined( USE_STATUSBAR ) + lpOutlineApp->m_hWndStatusBar = CreateStatusWindow(lpOutlineApp->m_hWndApp, hInst); + if (! lpOutlineApp->m_hWndStatusBar) + return FALSE; + + lpOutlineApp->m_hMenuApp = GetMenu(lpOutlineApp->m_hWndApp); + + /* setup status messages for the application menus */ + { + HMENU hMenuFile = GetSubMenu(lpOutlineApp->m_hMenuApp, 0); + HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1); + HMENU hMenuOutline = GetSubMenu(lpOutlineApp->m_hMenuApp, 2); + HMENU hMenuLine = GetSubMenu(lpOutlineApp->m_hMenuApp, 3); + HMENU hMenuName = GetSubMenu(lpOutlineApp->m_hMenuApp, 4); + HMENU hMenuOptions = GetSubMenu(lpOutlineApp->m_hMenuApp, 5); + HMENU hMenuDebug = GetSubMenu(lpOutlineApp->m_hMenuApp, 6); + HMENU hMenuHelp = GetSubMenu(lpOutlineApp->m_hMenuApp, 7); + HMENU hMenuSys = GetSystemMenu(lpOutlineApp->m_hWndApp, FALSE); + + AssignPopupMessage(hMenuFile, "Create, open, save, print outlines or quit application"); + AssignPopupMessage(hMenuEdit, "Cut, copy, paste or clear selection"); + AssignPopupMessage(hMenuOutline, "Set zoom and margins"); + AssignPopupMessage(hMenuLine, "Create, edit, and indent lines"); + AssignPopupMessage(hMenuName, "Create, edit, delete and goto names"); + AssignPopupMessage(hMenuOptions, "Modify tools, row/col headings, display options"); + AssignPopupMessage(hMenuDebug, "Set debug trace level and other debug options"); + AssignPopupMessage(hMenuHelp, "Get help on using the application"); + AssignPopupMessage(hMenuSys,"Move, size or close application window"); + } +#endif + +#if defined ( USE_FRAMETOOLS ) || defined ( INPLACE_CNTR ) + lpOutlineApp->m_FrameToolWidths = g_rectNull; +#endif // USE_FRAMETOOLS || INPLACE_CNTR + +#if defined( USE_FRAMETOOLS ) + if (! FrameTools_Init(&lpOutlineApp->m_frametools, + lpOutlineApp->m_hWndApp, lpOutlineApp->m_hInst)) + return FALSE; +#endif + +#if defined( OLE_VERSION ) + + /* OLE2NOTE: perform initialization required for OLE */ + if (! OleApp_InitInstance((LPOLEAPP)lpOutlineApp, hInst, nCmdShow)) + return FALSE; +#else + /* OLE2NOTE: Although no OLE call is made in the base outline, + ** OLE memory allocator is used and thus CoInitialize() needs to + ** be called. + */ + { + HRESULT hrErr; + + hrErr = CoInitialize(NULL); + if (hrErr != NOERROR) { + OutlineApp_ErrorMessage(lpOutlineApp, + "CoInitialize initialization failed!"); + return FALSE; + } + } +#endif + + return TRUE; +} + + +/* OutlineApp_ParseCmdLine + * ----------------------- + * + * Parse the command line for any execution flags/arguments. + */ +BOOL OutlineApp_ParseCmdLine(LPOUTLINEAPP lpOutlineApp, LPSTR lpszCmdLine, int nCmdShow) +{ + +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + return OleApp_ParseCmdLine((LPOLEAPP)lpOutlineApp,lpszCmdLine,nCmdShow); + +#else + + BOOL fStatus = TRUE; + char szFileName[256]; /* buffer for filename in command line */ + + szFileName[0] = '\0'; + ParseCmdLine(lpszCmdLine, NULL, (LPSTR)szFileName); + + if(*szFileName) { + // allocate a new document + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + // open the specified file + if (! OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, szFileName)) + goto error; + } else { + // create a new document + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + // set the doc to an (Untitled) doc. + if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc)) + goto error; + } + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); + + // show main app window + ShowWindow(lpOutlineApp->m_hWndApp, nCmdShow); + UpdateWindow(lpOutlineApp->m_hWndApp); + + return TRUE; + +error: + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Could not create new document"); + + if (lpOutlineApp->m_lpDoc) { + OutlineDoc_Destroy(lpOutlineApp->m_lpDoc); + lpOutlineApp->m_lpDoc = NULL; + } + + return FALSE; + +#endif +} + + +/* OutlineApp_InitMenu + * ------------------- + * + * Enable or Disable menu items depending on the state of + * the appliation + */ +void OutlineApp_InitMenu(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpOutlineDoc, HMENU hMenu) +{ + WORD status; + static UINT uCurrentZoom = (UINT)-1; + static UINT uCurrentMargin = (UINT)-1; + static UINT uBBState = (UINT)-1; + static UINT uFBState = (UINT)-1; + + if (!lpOutlineApp || !lpOutlineDoc || !hMenu) + return; + + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_UNDO, MF_GRAYED); + + status = (WORD)(OutlineDoc_GetLineCount(lpOutlineDoc) ? MF_ENABLED : MF_GRAYED); + + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_CUT ,status); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_COPY ,status); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_CLEAR ,status); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_SELECTALL ,status); + + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_EDITLINE ,status); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_INDENTLINE ,status); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_UNINDENTLINE ,status); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_SETLINEHEIGHT ,status); + + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_N_DEFINENAME ,status); + + status = (WORD)(OutlineDoc_GetNameCount(lpOutlineDoc) ? MF_ENABLED : MF_GRAYED); + + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_N_GOTONAME, status); + + if (uCurrentZoom != (UINT)-1) + CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentZoom, MF_UNCHECKED); + uCurrentZoom = OutlineDoc_GetCurrentZoomMenuCheck(lpOutlineDoc); + CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentZoom, MF_CHECKED); + + if (uCurrentMargin != (UINT)-1) + CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentMargin, MF_UNCHECKED); + uCurrentMargin = OutlineDoc_GetCurrentMarginMenuCheck(lpOutlineDoc); + CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentMargin, MF_CHECKED); + +#if defined( USE_FRAMETOOLS ) + if (uBBState != (UINT)-1) + CheckMenuItem(lpOutlineApp->m_hMenuApp, uBBState, MF_UNCHECKED); + if (lpOutlineDoc->m_lpFrameTools) { + switch (FrameTools_BB_GetState(lpOutlineDoc->m_lpFrameTools)) { + case BARSTATE_TOP: + uBBState = IDM_O_BB_TOP; + break; + case BARSTATE_BOTTOM: + uBBState = IDM_O_BB_BOTTOM; + break; + case BARSTATE_POPUP: + uBBState = IDM_O_BB_POPUP; + break; + case BARSTATE_HIDE: + uBBState = IDM_O_BB_HIDE; + break; + } + CheckMenuItem(lpOutlineApp->m_hMenuApp, uBBState, MF_CHECKED); + } + + if (uFBState != (UINT)-1) + CheckMenuItem(lpOutlineApp->m_hMenuApp, uFBState, MF_UNCHECKED); + if (lpOutlineDoc->m_lpFrameTools) { + switch (FrameTools_FB_GetState(lpOutlineDoc->m_lpFrameTools)) { + case BARSTATE_TOP: + uFBState = IDM_O_FB_TOP; + break; + case BARSTATE_BOTTOM: + uFBState = IDM_O_FB_BOTTOM; + break; + case BARSTATE_POPUP: + uFBState = IDM_O_FB_POPUP; + break; + } + CheckMenuItem(lpOutlineApp->m_hMenuApp, uFBState, MF_CHECKED); + } +#endif // USE_FRAMETOOLS + +#if defined( OLE_VERSION ) + /* OLE2NOTE: perform OLE specific menu initialization. + ** the OLE versions use the OleGetClipboard mechanism for + ** clipboard handling. thus, they determine if the Paste and + ** PasteSpecial commands should be enabled in an OLE specific + ** manner. + ** (Container only) build the OLE object verb menu if necessary. + */ + OleApp_InitMenu( + (LPOLEAPP)lpOutlineApp, + (LPOLEDOC)lpOutlineDoc, + lpOutlineApp->m_hMenuApp + ); + + /* OLE2NOTE: To avoid the overhead of initializing the Edit menu, + ** we do it only when it is popped up. Thus we just set a flag + ** in the OleDoc saying that the Edit menu needs to be updated + ** but we don't do it immediately + */ + OleDoc_SetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc, TRUE); + +#else + // Base Outline version uses standard Windows clipboard handling + if(IsClipboardFormatAvailable(lpOutlineApp->m_cfOutline) || + IsClipboardFormatAvailable(CF_TEXT)) + status = MF_ENABLED; + else + status = MF_GRAYED; + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_PASTE, status); + +#endif + +#if defined( USE_FRAMETOOLS ) + if (! OutlineDoc_IsEditFocusInFormulaBar(lpOutlineDoc)) { + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_ADDLINE, MF_GRAYED); + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_EDITLINE, MF_GRAYED); + } + else + EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_ADDLINE, MF_ENABLED); + +#endif // USE_FRAMETOOLS + +} + + +/* OutlineApp_GetWindow + * -------------------- + * + * Get the window handle of the application frame. + */ +HWND OutlineApp_GetWindow(LPOUTLINEAPP lpOutlineApp) +{ + if (!lpOutlineApp) + return NULL; + + return lpOutlineApp->m_hWndApp; +} + + +/* OutlineApp_GetFrameWindow +** ------------------------- +** Gets the current frame window to use as a parent to any dialogs +** this app uses. +** +** OLE2NOTE: normally this is simply the main hWnd of the app. but, +** if the app is currently supporting an in-place server document, +** then the frame window of the top in-place container must be used. +*/ +HWND OutlineApp_GetFrameWindow(LPOUTLINEAPP lpOutlineApp) +{ + HWND hWndApp = OutlineApp_GetWindow(lpOutlineApp); + +#if defined( INPLACE_SVR ) + LPSERVERDOC lpServerDoc = + (LPSERVERDOC)OutlineApp_GetActiveDoc(lpOutlineApp); + if (lpServerDoc && lpServerDoc->m_fUIActive) + return lpServerDoc->m_lpIPData->frameInfo.hwndFrame; +#endif + + return hWndApp; +} + + +/* OutlineApp_GetInstance + * ---------------------- + * + * Get the process instance of the application. + */ +HINSTANCE OutlineApp_GetInstance(LPOUTLINEAPP lpOutlineApp) +{ + if (!lpOutlineApp) + return NULL; + + return lpOutlineApp->m_hInst; +} + + +/* OutlineApp_CreateDoc + * -------------------- + * + * Allocate a new document of the appropriate type. + * OutlineApp --> creates OutlineDoc type documents + * + * Returns lpOutlineDoc for successful, NULL if error. + */ +LPOUTLINEDOC OutlineApp_CreateDoc( + LPOUTLINEAPP lpOutlineApp, + BOOL fDataTransferDoc +) +{ + LPOUTLINEDOC lpOutlineDoc; + + OLEDBG_BEGIN3("OutlineApp_CreateDoc\r\n") + +#if defined( OLE_SERVER ) + lpOutlineDoc = (LPOUTLINEDOC)New((DWORD)sizeof(SERVERDOC)); + _fmemset(lpOutlineDoc, 0, sizeof(SERVERDOC)); +#endif +#if defined( OLE_CNTR ) + lpOutlineDoc = (LPOUTLINEDOC)New((DWORD)sizeof(CONTAINERDOC)); + _fmemset(lpOutlineDoc, 0, sizeof(CONTAINERDOC)); +#endif +#if !defined( OLE_VERSION ) + lpOutlineDoc = (LPOUTLINEDOC)New((DWORD)sizeof(OUTLINEDOC)); + _fmemset(lpOutlineDoc, 0, sizeof(OUTLINEDOC)); +#endif + + OleDbgAssertSz(lpOutlineDoc != NULL, "Error allocating OutlineDoc"); + if (lpOutlineDoc == NULL) + return NULL; + + // initialize new document + if (! OutlineDoc_Init(lpOutlineDoc, fDataTransferDoc)) + goto error; + + OLEDBG_END3 + return lpOutlineDoc; + +error: + if (lpOutlineDoc) + Delete(lpOutlineDoc); + + OLEDBG_END3 + return NULL; +} + + +/* OutlineApp_CreateName + * --------------------- + * + * Allocate a new Name of the appropriate type. + * OutlineApp --> creates standard OutlineName type names. + * ServerApp --> creates enhanced SeverName type names. + * + * Returns lpOutlineName for successful, NULL if error. + */ +LPOUTLINENAME OutlineApp_CreateName(LPOUTLINEAPP lpOutlineApp) +{ + LPOUTLINENAME lpOutlineName; + +#if defined( OLE_SERVER ) + lpOutlineName = (LPOUTLINENAME)New((DWORD)sizeof(SERVERNAME)); +#else + lpOutlineName = (LPOUTLINENAME)New((DWORD)sizeof(OUTLINENAME)); +#endif + + OleDbgAssertSz(lpOutlineName != NULL, "Error allocating Name"); + if (lpOutlineName == NULL) + return NULL; + +#if defined( OLE_SERVER ) + _fmemset((LPVOID)lpOutlineName,0,sizeof(SERVERNAME)); +#else + _fmemset((LPVOID)lpOutlineName,0,sizeof(OUTLINENAME)); +#endif + + return lpOutlineName; +} + + +/* OutlineApp_DocUnlockApp +** ----------------------- +** Forget all references to a closed document. +*/ +void OutlineApp_DocUnlockApp(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpOutlineDoc) +{ + /* forget pointers to destroyed document */ + if (lpOutlineApp->m_lpDoc == lpOutlineDoc) + lpOutlineApp->m_lpDoc = NULL; + else if (lpOutlineApp->m_lpClipboardDoc == lpOutlineDoc) + lpOutlineApp->m_lpClipboardDoc = NULL; + +#if defined( OLE_VERSION ) + /* OLE2NOTE: when there are no open documents and the app is not + ** under the control of the user then revoke our ClassFactory to + ** enable the app to shut down. + ** + ** NOTE: data transfer documents (non-user documents) do NOT + ** hold the app alive. therefore they do not Lock the app. + */ + if (! lpOutlineDoc->m_fDataTransferDoc) + OleApp_DocUnlockApp((LPOLEAPP)lpOutlineApp, lpOutlineDoc); +#endif +} + + +/* OutlineApp_NewCommand + * --------------------- + * + * Start a new untitled document (File.New command). + */ +void OutlineApp_NewCommand(LPOUTLINEAPP lpOutlineApp) +{ +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + OleApp_NewCommand((LPOLEAPP)lpOutlineApp); + +#else + + LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc; + + if (! OutlineDoc_Close(lpOutlineDoc, OLECLOSE_PROMPTSAVE)) + return; + + OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed"); + + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + // set the doc to an (Untitled) doc. + if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc)) + goto error; + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); // calls OleDoc_Lock + + return; + +error: + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Could not create new document"); + + if (lpOutlineApp->m_lpDoc) { + OutlineDoc_Destroy(lpOutlineApp->m_lpDoc); + lpOutlineApp->m_lpDoc = NULL; + } + + return; + +#endif +} + + +/* OutlineApp_OpenCommand + * ---------------------- + * + * Load a document from file (File.Open command). + */ +void OutlineApp_OpenCommand(LPOUTLINEAPP lpOutlineApp) +{ +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + OleApp_OpenCommand((LPOLEAPP)lpOutlineApp); + +#else + + OPENFILENAME ofn; + char szFilter[]=APPFILENAMEFILTER; + char szFileName[256]; + UINT i; + DWORD dwSaveOption = OLECLOSE_PROMPTSAVE; + BOOL fStatus = TRUE; + + if (! OutlineDoc_CheckSaveChanges(lpOutlineApp->m_lpDoc, &dwSaveOption)) + return; // abort opening new doc + + for(i=0; szFilter[i]; i++) + if(szFilter[i]=='|') szFilter[i]='\0'; + + _fmemset((LPOPENFILENAME)&ofn,0,sizeof(OPENFILENAME)); + + szFileName[0]='\0'; + + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.hwndOwner=lpOutlineApp->m_hWndApp; + ofn.lpstrFilter=(LPSTR)szFilter; + ofn.lpstrFile=(LPSTR)szFileName; + ofn.nMaxFile=sizeof(szFileName); + ofn.Flags=OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt=DEFEXTENSION; + + if(! GetOpenFileName((LPOPENFILENAME)&ofn)) + return; // user canceled file open dialog + + OutlineDoc_Close(lpOutlineApp->m_lpDoc, OLECLOSE_NOSAVE); + OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed"); + + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + + fStatus=OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, (LPSTR)szFileName); + + if (! fStatus) { + // loading the doc failed; create an untitled instead + OutlineDoc_Destroy(lpOutlineApp->m_lpDoc); // destroy unused doc + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) goto error; + if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc)) + goto error; + } + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); + + return; + +error: + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, "Could not create new document"); + + if (lpOutlineApp->m_lpDoc) { + OutlineDoc_Destroy(lpOutlineApp->m_lpDoc); + lpOutlineApp->m_lpDoc = NULL; + } + + return; + +#endif +} + + +/* OutlineApp_PrintCommand + * ----------------------- + * + * Print the document + */ +void OutlineApp_PrintCommand(LPOUTLINEAPP lpOutlineApp) +{ + LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc; + HDC hDC=NULL; + BOOL fMustDeleteDC = FALSE; + BOOL fStatus; + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + fStatus = PrintDlg((LPPRINTDLG)&lpOutlineApp->m_PrintDlg); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + if (!fStatus) { + if (!CommDlgExtendedError()) { // Cancel button pressed + return; + } + } + else { + hDC = OutlineApp_GetPrinterDC(lpOutlineApp); + if (hDC) { + +#if defined( OLE_VERSION ) + /* OLE2NOTE: while we are printing we do NOT want to + ** receive any OnDataChange notifications or other OLE + ** interface calls which could disturb the printing of + ** the document. we will temporarily reply + ** SERVERCALL_RETRYLATER + */ + OleApp_RejectInComingCalls((LPOLEAPP)lpOutlineApp, TRUE); +#endif + + OutlineDoc_Print(lpOutlineDoc, hDC); + DeleteDC(hDC); + +#if defined( OLE_VERSION ) + // re-enable LRPC calls + OleApp_RejectInComingCalls((LPOLEAPP)lpOutlineApp, FALSE); +#endif + + return; // Printing completed + } + } + + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPrinting); +} + + +/* OutlineApp_PrinterSetupCommand + * ------------------------------ + * + * Setup a different printer for printing + */ +void OutlineApp_PrinterSetupCommand(LPOUTLINEAPP lpOutlineApp) +{ + DWORD FlagSave; + + FlagSave = lpOutlineApp->m_PrintDlg.Flags; + lpOutlineApp->m_PrintDlg.Flags |= PD_PRINTSETUP; + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + PrintDlg((LPPRINTDLG)&lpOutlineApp->m_PrintDlg); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + lpOutlineApp->m_PrintDlg.Flags = FlagSave; +} + +/* + * FUNCTION : OutlineApp_GetPrinterDC () + * + * PURPOSE : Creates a printer display context for the printer + * + * RETURNS : HDC - A handle to printer DC. + */ +HDC OutlineApp_GetPrinterDC(LPOUTLINEAPP lpApp) +{ + + HDC hDC; + LPDEVMODE lpDevMode = NULL; + LPDEVNAMES lpDevNames; + LPSTR lpszDriverName; + LPSTR lpszDeviceName; + LPSTR lpszPortName; + + if(lpApp->m_PrintDlg.hDC) { + hDC = lpApp->m_PrintDlg.hDC; + } else { + if(! lpApp->m_PrintDlg.hDevNames) + return(NULL); + lpDevNames = (LPDEVNAMES)GlobalLock(lpApp->m_PrintDlg.hDevNames); + lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset; + lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset; + lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset; + GlobalUnlock(lpApp->m_PrintDlg.hDevNames); + + if(lpApp->m_PrintDlg.hDevMode) + lpDevMode = (LPDEVMODE)GlobalLock(lpApp->m_PrintDlg.hDevMode); +#if defined( WIN32 ) + hDC = CreateDC( + lpszDriverName, + lpszDeviceName, + lpszPortName, + (CONST DEVMODE FAR*)lpDevMode); +#else + hDC = CreateDC( + lpszDriverName, + lpszDeviceName, + lpszPortName, + (LPSTR)lpDevMode); +#endif + + if(lpApp->m_PrintDlg.hDevMode && lpDevMode) + GlobalUnlock(lpApp->m_PrintDlg.hDevMode); + } + + return(hDC); +} + + +/* OutlineApp_SaveCommand + * ---------------------- + * + * Save the document with same name. If no name exists, prompt the user + * for a name (via SaveAsCommand) + * + * Parameters: + * + * Returns: + * TRUE if succesfully + * FALSE if failed or aborted + */ +BOOL OutlineApp_SaveCommand(LPOUTLINEAPP lpOutlineApp) +{ + LPOUTLINEDOC lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp); + + if(lpOutlineDoc->m_docInitType == DOCTYPE_NEW) /* file with no name */ + return OutlineApp_SaveAsCommand(lpOutlineApp); + + + if(OutlineDoc_IsModified(lpOutlineDoc)) { + +#if defined( OLE_SERVER ) + + if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED) { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + HRESULT hrErr; + + /* OLE2NOTE: if the document is an embedded object, then + ** the "File.Save" command is changed to "File.Update". + ** in order to update our container, we must ask our + ** container to save us. + */ + OleDbgAssert(lpServerDoc->m_lpOleClientSite != NULL); + OLEDBG_BEGIN2("IOleClientSite::SaveObject called\r\n") + hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->SaveObject( + lpServerDoc->m_lpOleClientSite + ); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleClientSite::SaveObject returned",hrErr); + return FALSE; + } + } else + // document is file-base user document, save it to its file. + +#endif // OLE_SERVER + + (void)OutlineDoc_SaveToFile( + lpOutlineDoc, + NULL, + lpOutlineDoc->m_cfSaveFormat, + TRUE + ); + } + + return TRUE; +} + + +/* OutlineApp_SaveAsCommand + * ------------------------ + * + * Save the document as another name + * + * Parameters: + * + * Returns: + * TRUE if saved successful + * FALSE if failed or aborted + */ +BOOL OutlineApp_SaveAsCommand(LPOUTLINEAPP lpOutlineApp) +{ + LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc; + OPENFILENAME ofn; + char szFilter[]=APPFILENAMEFILTER; + char szFileName[256]=""; + int i; + UINT uFormat; + BOOL fNoError = TRUE; + BOOL fRemember = TRUE; + BOOL fStatus; + + for(i=0; szFilter[i]; i++) + if(szFilter[i]=='|') szFilter[i]='\0'; + + _fmemset((LPOPENFILENAME)&ofn,0,sizeof(OPENFILENAME)); + + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.hwndOwner=lpOutlineDoc->m_hWndDoc; + ofn.lpstrFilter=(LPSTR)szFilter; + ofn.lpstrFile=(LPSTR)szFileName; + ofn.nMaxFile=sizeof(szFileName); + + ofn.Flags=OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; + ofn.lpstrDefExt=DEFEXTENSION; + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + fStatus = GetSaveFileName((LPOPENFILENAME)&ofn); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + if (fStatus) { + +#if defined( OLE_CNTR ) + // determine which file type the user selected. + switch (ofn.nFilterIndex) { + case 1: + uFormat = ((LPCONTAINERAPP)lpOutlineApp)->m_cfCntrOutl; + break; + case 2: + uFormat = lpOutlineApp->m_cfOutline; + break; + default: + uFormat = ((LPCONTAINERAPP)lpOutlineApp)->m_cfCntrOutl; + break; + } +#else + uFormat = lpOutlineApp->m_cfOutline; +#endif + +#if defined( OLE_SERVER ) + /* OLE2NOTE: if the document is an embedded object, then the + ** File.SaveAs command is changed to File.SaveCopyAs. with the + ** Save Copy As operation, the document does NOT remember the + ** saved file as the associated file for the document. + */ + if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED) + fRemember = FALSE; +#endif + + (void)OutlineDoc_SaveToFile( + lpOutlineDoc, + szFileName, + uFormat, + fRemember + ); + + } + else + fNoError = FALSE; + + return fNoError; + +} + + +/* OutlineApp_AboutCommand + * ----------------------- + * + * Show the About dialog box + */ +void OutlineApp_AboutCommand(LPOUTLINEAPP lpOutlineApp) +{ +#if defined( OLE_VERSION ) + OleApp_PreModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + DialogBox( + lpOutlineApp->m_hInst, + (LPSTR)"About", + OutlineApp_GetFrameWindow(lpOutlineApp), + (DLGPROC)AboutDlgProc + ); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif +} + + +/* OutlineApp_CloseAllDocsAndExitCommand + * ------------------------------------- + * + * Close all active documents and exit the app. + * Because this is an SDI, there is only one document + * If the doc was modified, prompt the user if he wants to save it. + * + * Returns: + * TRUE if the app is successfully closed + * FALSE if failed or aborted + */ +BOOL OutlineApp_CloseAllDocsAndExitCommand( + LPOUTLINEAPP lpOutlineApp, + BOOL fForceEndSession +) +{ + BOOL fResult; + + OLEDBG_BEGIN2("OutlineApp_CloseAllDocsAndExitCommand\r\n") + +#if defined( OLE_VERSION ) + // Call OLE specific version of this function + fResult = OleApp_CloseAllDocsAndExitCommand( + (LPOLEAPP)lpOutlineApp, fForceEndSession); + +#else + + /* Because this is an SDI app, there is only one document. + ** Close the doc. if it is successfully closed and the app will + ** not automatically exit, then also exit the app. + ** if this were an MDI app, we would loop through and close all + ** open MDI child documents. + */ + if (OutlineDoc_Close(lpOutlineApp->m_lpDoc, OLECLOSE_PROMPTSAVE)) { + +#if defined( _DEBUG ) + OleDbgAssertSz( + lpOutlineApp->m_lpDoc==NULL, + "Closed doc NOT properly destroyed" + ); +#endif + + OutlineApp_Destroy(lpOutlineApp); + fResult = TRUE; + + } // else User Canceled shutdown + else + fResult = FALSE; + +#endif + + OLEDBG_END2 + + return fResult; +} + + +/* OutlineApp_Destroy + * ------------------ + * + * Destroy all data structures used by the app and force the + * app to shut down. This should be called after all documents have + * been closed. + */ +void OutlineApp_Destroy(LPOUTLINEAPP lpOutlineApp) +{ + OLEDBG_BEGIN3("OutlineApp_Destroy\r\n"); + +#if defined( OLE_VERSION ) + /* OLE2NOTE: perform processing required for OLE */ + OleApp_Destroy((LPOLEAPP)lpOutlineApp); +#endif + + SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); + DestroyCursor(lpOutlineApp->m_hcursorSelCur); + +#if defined( USE_FRAMETOOLS ) + FrameTools_Destroy(&lpOutlineApp->m_frametools); +#endif + + if (lpOutlineApp->m_hStdFont) + DeleteObject(lpOutlineApp->m_hStdFont); + + if(lpOutlineApp->m_PrintDlg.hDevMode) + GlobalFree(lpOutlineApp->m_PrintDlg.hDevMode); + if(lpOutlineApp->m_PrintDlg.hDevNames) + GlobalFree(lpOutlineApp->m_PrintDlg.hDevNames); + +#if defined( USE_STATUSBAR ) + if(lpOutlineApp->m_hWndStatusBar) { + DestroyStatusWindow(lpOutlineApp->m_hWndStatusBar); + lpOutlineApp->m_hWndStatusBar = NULL; + } +#endif + + OutlineApp_DestroyWindow(lpOutlineApp); + OleDbgOut1("@@@@ APP DESTROYED\r\n"); + + OLEDBG_END3 +} + + +/* OutlineApp_DestroyWindow + * ------------------------ + * + * Destroy all windows created by the App. + */ +void OutlineApp_DestroyWindow(LPOUTLINEAPP lpOutlineApp) +{ + HWND hWndApp = lpOutlineApp->m_hWndApp; + + if(hWndApp) { + lpOutlineApp->m_hWndApp = NULL; + lpOutlineApp->m_hWndAccelTarget = NULL; + DestroyWindow(hWndApp); /* Quit the app */ + } +} + + +/* OutlineApp_GetFrameRect +** ----------------------- +** Get the rectangle of the app frame window EXCLUDING space for the +** status line. +** +** OLE2NOTE: this is the rectangle that an in-place container can +** offer to an in-place active object from which to get frame tool +** space. +*/ +void OutlineApp_GetFrameRect(LPOUTLINEAPP lpOutlineApp, LPRECT lprcFrameRect) +{ + GetClientRect(lpOutlineApp->m_hWndApp, lprcFrameRect); + +#if defined( USE_STATUSBAR ) + lprcFrameRect->bottom -= STATUS_HEIGHT; +#endif + +} + + +/* OutlineApp_GetClientAreaRect +** ---------------------------- +** Get the rectangle of the app frame window EXCLUDING space for the +** status line AND EXCLUDING space for any frame-level tools. +** +** OLE2NOTE: this is the rectangle that an in-place container gives +** to its in-place active object as the lpClipRect in +** IOleInPlaceSite::GetWindowContext. +*/ +void OutlineApp_GetClientAreaRect( + LPOUTLINEAPP lpOutlineApp, + LPRECT lprcClientAreaRect +) +{ + OutlineApp_GetFrameRect(lpOutlineApp, lprcClientAreaRect); + + /* if the app either uses frame-level tools itself or, as in-place + ** container, is prepared to allow an in-place active object to + ** have space for tools, then it must subtract away the space + ** required for the tools. + */ +#if defined ( USE_FRAMETOOLS ) || defined ( INPLACE_CNTR ) + + lprcClientAreaRect->top += lpOutlineApp->m_FrameToolWidths.top; + lprcClientAreaRect->left += lpOutlineApp->m_FrameToolWidths.left; + lprcClientAreaRect->right -= lpOutlineApp->m_FrameToolWidths.right; + lprcClientAreaRect->bottom -= lpOutlineApp->m_FrameToolWidths.bottom; +#endif // USE_FRAMETOOLS || INPLACE_CNTR + +} + + +/* OutlineApp_GetStatusLineRect +** ---------------------------- +** Get the rectangle required for the status line. +** +** OLE2NOTE: the top frame-level in-place container displays its +** status line even when an object is active in-place. +*/ +void OutlineApp_GetStatusLineRect( + LPOUTLINEAPP lpOutlineApp, + LPRECT lprcStatusLineRect +) +{ + RECT rcFrameRect; + GetClientRect(lpOutlineApp->m_hWndApp, (LPRECT)&rcFrameRect); + lprcStatusLineRect->left = rcFrameRect.left; + lprcStatusLineRect->top = rcFrameRect.bottom - STATUS_HEIGHT; + lprcStatusLineRect->right = rcFrameRect.right; + lprcStatusLineRect->bottom = rcFrameRect.bottom; +} + + +/* OutlineApp_ResizeWindows + * ------------------------ + * + * Changes the size and position of the SDI document and tool windows. + * Normally called on a WM_SIZE message. + * + * Currently the app supports a status bar and a single SDI document window. + * In the future it will have a formula bar and possibly multiple MDI + * document windows. + * + * CUSTOMIZATION: Change positions of windows. + */ +void OutlineApp_ResizeWindows(LPOUTLINEAPP lpOutlineApp) +{ + LPOUTLINEDOC lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp); + RECT rcStatusLineRect; + + if (! lpOutlineApp) + return; + +#if defined( INPLACE_CNTR ) + if (lpOutlineDoc) + ContainerDoc_FrameWindowResized((LPCONTAINERDOC)lpOutlineDoc); +#else +#if defined( USE_FRAMETOOLS ) + if (lpOutlineDoc) + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); +#else + OutlineApp_ResizeClientArea(lpOutlineApp); +#endif // ! USE_FRAMETOOLS +#endif // ! INPLACE_CNTR + +#if defined( USE_STATUSBAR ) + if (lpOutlineApp->m_hWndStatusBar) { + OutlineApp_GetStatusLineRect(lpOutlineApp, (LPRECT)&rcStatusLineRect); + MoveWindow( + lpOutlineApp->m_hWndStatusBar, + rcStatusLineRect.left, + rcStatusLineRect.top, + rcStatusLineRect.right - rcStatusLineRect.left, + rcStatusLineRect.bottom - rcStatusLineRect.top, + TRUE /* fRepaint */ + ); + } +#endif // USE_STATUSBAR +} + + +#if defined( USE_FRAMETOOLS ) || defined( INPLACE_CNTR ) + +void OutlineApp_SetBorderSpace( + LPOUTLINEAPP lpOutlineApp, + LPBORDERWIDTHS lpBorderWidths +) +{ + lpOutlineApp->m_FrameToolWidths = *lpBorderWidths; + OutlineApp_ResizeClientArea(lpOutlineApp); +} +#endif // USE_FRAMETOOLS || INPLACE_CNTR + + +void OutlineApp_ResizeClientArea(LPOUTLINEAPP lpOutlineApp) +{ + RECT rcClientAreaRect; + +#if defined( MDI_VERSION ) + + // Resize MDI Client Area Window here + +#else + + if (lpOutlineApp->m_lpDoc) { + OutlineApp_GetClientAreaRect( + lpOutlineApp, (LPRECT)&rcClientAreaRect); + OutlineDoc_Resize(lpOutlineApp->m_lpDoc, + (LPRECT)&rcClientAreaRect); + } + +#endif + +} + + +/* OutlineApp_GetActiveDoc + * ----------------------- + * + * Return the document in focus. For SDI, the same (only one) document is + * always returned. + */ +LPOUTLINEDOC OutlineApp_GetActiveDoc(LPOUTLINEAPP lpOutlineApp) +{ + return lpOutlineApp->m_lpDoc; +} + +/* OutlineApp_GetMenu + * ------------------ + * + * Return the menu handle of the app + */ +HMENU OutlineApp_GetMenu(LPOUTLINEAPP lpOutlineApp) +{ + if (!lpOutlineApp) { + return NULL; + } + + return lpOutlineApp->m_hMenuApp; +} + + +#if defined( USE_FRAMETOOLS ) + +/* OutlineApp_GetFrameTools + * --------------------- + * + * Return the pointer to the toolbar object + */ +LPFRAMETOOLS OutlineApp_GetFrameTools(LPOUTLINEAPP lpOutlineApp) +{ + return (LPFRAMETOOLS)&lpOutlineApp->m_frametools; +} +#endif + + +/* OutlineApp_SetStatusText + * ------------------------ + * + * Show the given string in the status line + */ +void OutlineApp_SetStatusText(LPOUTLINEAPP lpOutlineApp, LPSTR lpszMessage) +{ + SetStatusText(lpOutlineApp->m_hWndStatusBar, lpszMessage); +} + + +/* OutlineApp_GetActiveFont + * ------------------------ + * + * Return the font used by the application + */ +HFONT OutlineApp_GetActiveFont(LPOUTLINEAPP lpOutlineApp) +{ + return lpOutlineApp->m_hStdFont; +} + + +/* OutlineApp_GetAppName + * --------------------- + * + * Retrieve the application name + */ +void OutlineApp_GetAppName(LPOUTLINEAPP lpOutlineApp, LPSTR lpszAppName) +{ + lstrcpy(lpszAppName, APPNAME); +} + + +/* OutlineApp_GetAppVersionNo + * -------------------------- + * + * Get the version number (major and minor) of the application + */ +void OutlineApp_GetAppVersionNo(LPOUTLINEAPP lpOutlineApp, int narrAppVersionNo[]) +{ + narrAppVersionNo[0] = APPMAJORVERSIONNO; + narrAppVersionNo[1] = APPMINORVERSIONNO; +} + + +/* OutlineApp_VersionNoCheck + * ------------------------- + * + * Check if the version stamp read from a file is compatible + * with the current instance of the application. + * returns TRUE if the file can be read, else FALSE. + */ +BOOL OutlineApp_VersionNoCheck(LPOUTLINEAPP lpOutlineApp, LPSTR lpszFormatName, int narrAppVersionNo[]) +{ +#if defined( OLE_CNTR ) + + /* ContainerApp accepts both CF_OUTLINE and CF_CONTAINEROUTLINE formats */ + if (lstrcmp(lpszFormatName, CONTAINERDOCFORMAT) != 0 && + lstrcmp(lpszFormatName, OUTLINEDOCFORMAT) != 0) { + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage( + lpOutlineApp, + "File is either corrupted or not of proper type." + ); + return FALSE; + } + +#else + + /* OutlineApp accepts CF_OUTLINE format only */ + if (lstrcmp(lpszFormatName, OUTLINEDOCFORMAT) != 0) { + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage( + lpOutlineApp, + "File is either corrupted or not of proper type." + ); + return FALSE; + } +#endif + + if (narrAppVersionNo[0] < APPMAJORVERSIONNO) { + // REVIEW: should load string from string resource + OutlineApp_ErrorMessage( + lpOutlineApp, + "File was created by an older version; it can not be read." + ); + return FALSE; + } + + return TRUE; +} + + +/* OutlineApp_ErrorMessage + * ----------------------- + * + * Display an error message box + */ +void OutlineApp_ErrorMessage(LPOUTLINEAPP lpOutlineApp, LPSTR lpszErrMsg) +{ + HWND hWndFrame = OutlineApp_GetFrameWindow(lpOutlineApp); + + // OLE2NOTE: only put up user message boxes if app is visible + if (IsWindowVisible(hWndFrame)) { +#if defined( OLE_VERSION ) + OleApp_PreModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + + MessageBox(hWndFrame, lpszErrMsg, NULL, MB_ICONEXCLAMATION | MB_OK); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + } +} + + +#if defined( USE_FRAMETOOLS ) + +/* OutlineApp_SetFormulaBarAccel + * ----------------------------- + * + * Set accelerator table based on state of formula bar. + */ +void OutlineApp_SetFormulaBarAccel( + LPOUTLINEAPP lpOutlineApp, + BOOL fEditFocus +) +{ + if (fEditFocus) + lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelFocusEdit; + else + lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelApp; +} + +#endif // USE_FRAMETOOLS + + + + +/* OutlineApp_ForceRedraw + * ---------------------- + * + * Force the Application window to repaint. + */ +void OutlineApp_ForceRedraw(LPOUTLINEAPP lpOutlineApp, BOOL fErase) +{ + if (!lpOutlineApp) + return; + + InvalidateRect(lpOutlineApp->m_hWndApp, NULL, fErase); +} diff --git a/private/oleutest/letest/outline/outldoc.c b/private/oleutest/letest/outline/outldoc.c new file mode 100644 index 000000000..8e36101f0 --- /dev/null +++ b/private/oleutest/letest/outline/outldoc.c @@ -0,0 +1,3247 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outldoc.c +** +** This file contains OutlineDoc functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +#if !defined( OLE_VERSION ) +#include <commdlg.h> +#endif + + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +// REVIEW: should use string resource for messages +char ErrMsgDocWnd[] = "Can't create Document Window!"; +char ErrMsgFormatNotSupported[] = "Clipboard format not supported!"; +char MsgSaveFile[] = "Save existing file ?"; +char ErrMsgSaving[] = "Error in saving file!"; +char ErrMsgOpening[] = "Error in opening file!"; +char ErrMsgFormat[] = "Improper file format!"; +char ErrOutOfMemory[] = "Error: out of memory!"; +static char ErrMsgPrint[] = "Printing Error!"; + +static BOOL fCancelPrint; // TRUE if the user has canceled the print job +static HWND hWndPDlg; // Handle to the cancel print dialog + + +/* OutlineDoc_Init + * --------------- + * + * Initialize the fields of a new OutlineDoc object. The object is initially + * not associated with a file or an (Untitled) document. This function sets + * the docInitType to DOCTYPE_UNKNOWN. After calling this function the + * caller should call: + * 1. OutlineDoc_InitNewFile to set the OutlineDoc to (Untitled) + * 2. OutlineDoc_LoadFromFile to associate the OutlineDoc with a file. + * This function creates a new window for the document. + * + * NOTE: the window is initially created with a NIL size. it must be + * sized and positioned by the caller. also the document is initially + * created invisible. the caller must call OutlineDoc_ShowWindow + * after sizing it to make the document window visible. + */ +BOOL OutlineDoc_Init(LPOUTLINEDOC lpOutlineDoc, BOOL fDataTransferDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + +#if defined( INPLACE_CNTR ) + lpOutlineDoc->m_hWndDoc = CreateWindow( + DOCWNDCLASS, // Window class name + NULL, // Window's title + + /* OLE2NOTE: an in-place contanier MUST use + ** WS_CLIPCHILDREN window style for the window + ** that it uses as the parent for the server's + ** in-place active window so that its + ** painting does NOT interfere with the painting + ** of the server's in-place active child window. + */ + + WS_CLIPCHILDREN | WS_CLIPSIBLINGS | + WS_CHILDWINDOW, + 0, 0, + 0, 0, + lpOutlineApp->m_hWndApp,// Parent window's handle + (HMENU)1, // child window id + lpOutlineApp->m_hInst, // Instance of window + NULL); // Create struct for WM_CREATE + +#else + + lpOutlineDoc->m_hWndDoc = CreateWindow( + DOCWNDCLASS, // Window class name + NULL, // Window's title + WS_CHILDWINDOW, + 0, 0, + 0, 0, + lpOutlineApp->m_hWndApp,// Parent window's handle + (HMENU)1, // child window id + lpOutlineApp->m_hInst, // Instance of window + NULL); // Create struct for WM_CREATE +#endif + + if(! lpOutlineDoc->m_hWndDoc) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgDocWnd); + return FALSE; + } + + SetWindowLong(lpOutlineDoc->m_hWndDoc, 0, (LONG) lpOutlineDoc); + + if (! LineList_Init(&lpOutlineDoc->m_LineList, lpOutlineDoc)) + return FALSE; + + lpOutlineDoc->m_lpNameTable = OutlineDoc_CreateNameTable(lpOutlineDoc); + if (! lpOutlineDoc->m_lpNameTable ) + return FALSE; + + lpOutlineDoc->m_docInitType = DOCTYPE_UNKNOWN; + lpOutlineDoc->m_cfSaveFormat = lpOutlineApp->m_cfOutline; + lpOutlineDoc->m_szFileName[0] = '\0'; + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + lpOutlineDoc->m_fDataTransferDoc = fDataTransferDoc; + lpOutlineDoc->m_uCurrentZoom = IDM_V_ZOOM_100; + lpOutlineDoc->m_scale.dwSxN = (DWORD) 1; + lpOutlineDoc->m_scale.dwSxD = (DWORD) 1; + lpOutlineDoc->m_scale.dwSyN = (DWORD) 1; + lpOutlineDoc->m_scale.dwSyD = (DWORD) 1; + lpOutlineDoc->m_uCurrentMargin = IDM_V_SETMARGIN_0; + lpOutlineDoc->m_nLeftMargin = 0; + lpOutlineDoc->m_nRightMargin = 0; + lpOutlineDoc->m_nDisableDraw = 0; + OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE); + +#if defined( USE_HEADING ) + if (! fDataTransferDoc) { + if (!Heading_Create((LPHEADING)&lpOutlineDoc->m_heading, + lpOutlineDoc->m_hWndDoc, lpOutlineApp->m_hInst)) { + return FALSE; + + } + } +#endif // USE_HEADING + +#if defined( USE_FRAMETOOLS ) + if (! fDataTransferDoc) { + lpOutlineDoc->m_lpFrameTools = OutlineApp_GetFrameTools(lpOutlineApp); + FrameTools_AssociateDoc( + lpOutlineDoc->m_lpFrameTools, + lpOutlineDoc + ); + } +#endif // USE_FRAMETOOLS + +#if defined( OLE_VERSION ) + /* OLE2NOTE: perform initialization required for OLE */ + if (! OleDoc_Init((LPOLEDOC)lpOutlineDoc, fDataTransferDoc)) + return FALSE; +#endif // OLE_VERSION + + return TRUE; +} + + +/* OutlineDoc_InitNewFile + * ---------------------- + * + * Initialize the OutlineDoc object to be a new (Untitled) document. + * This function sets the docInitType to DOCTYPE_NEW. + */ +BOOL OutlineDoc_InitNewFile(LPOUTLINEDOC lpOutlineDoc) +{ +#if defined( OLE_VERSION ) + // OLE2NOTE: call OLE version of this function instead + return OleDoc_InitNewFile((LPOLEDOC)lpOutlineDoc); + +#else + + OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN); + + // set file name to untitled + // REVIEW: should load from string resource + lstrcpy(lpOutlineDoc->m_szFileName, UNTITLED); + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + lpOutlineDoc->m_docInitType = DOCTYPE_NEW; + + if (! lpOutlineDoc->m_fDataTransferDoc) + OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/); + + return TRUE; + +#endif // BASE OUTLINE VERSION +} + + +/* OutlineDoc_CreateNameTable + * -------------------------- + * + * Allocate a new NameTable of the appropriate type. Each document has + * a NameTable and a LineList. + * OutlineDoc --> creates standard OutlineNameTable type name tables. + * ServerDoc --> creates enhanced SeverNameTable type name tables. + * + * Returns lpNameTable for successful, NULL if error. + */ +LPOUTLINENAMETABLE OutlineDoc_CreateNameTable(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINENAMETABLE lpOutlineNameTable; + + lpOutlineNameTable = (LPOUTLINENAMETABLE)New( + (DWORD)sizeof(OUTLINENAMETABLE) + ); + + OleDbgAssertSz(lpOutlineNameTable != NULL,"Error allocating NameTable"); + if (lpOutlineNameTable == NULL) + return NULL; + + // initialize new NameTable + if (! OutlineNameTable_Init(lpOutlineNameTable, lpOutlineDoc) ) + goto error; + + return lpOutlineNameTable; + +error: + if (lpOutlineNameTable) + Delete(lpOutlineNameTable); + return NULL; +} + + +/* OutlineDoc_ClearCommand + * ----------------------- + * + * Delete selection in list box by calling OutlineDoc_Delete + */ +void OutlineDoc_ClearCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + int i; + int nNumSel; + LINERANGE lrSel; + + nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel); + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + for(i = 0; i < nNumSel; i++) + OutlineDoc_DeleteLine(lpOutlineDoc, lrSel.m_nStartLine); + + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + + LineList_RecalcMaxLineWidthInHimetric(lpLL, 0); +} + + +/* OutlineDoc_CutCommand + * --------------------- + * + * Cut selection to clipboard + */ +void OutlineDoc_CutCommand(LPOUTLINEDOC lpOutlineDoc) +{ + OutlineDoc_CopyCommand(lpOutlineDoc); + OutlineDoc_ClearCommand(lpOutlineDoc); +} + + +/* OutlineDoc_CopyCommand + * ---------------------- + * Copy selection to clipboard. + * Post to the clipboard the formats that the app can render. + * the actual data is not rendered at this time. using the + * delayed rendering technique, Windows will send the clipboard + * owner window either a WM_RENDERALLFORMATS or a WM_RENDERFORMAT + * message when the actual data is requested. + * + * OLE2NOTE: the normal delayed rendering technique where Windows + * sends the clipboard owner window either a WM_RENDERALLFORMATS or + * a WM_RENDERFORMAT message when the actual data is requested is + * NOT exposed to the app calling OleSetClipboard. OLE internally + * creates its own window as the clipboard owner and thus our app + * will NOT get these WM_RENDER messages. + */ +void OutlineDoc_CopyCommand(LPOUTLINEDOC lpSrcOutlineDoc) +{ +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + OleDoc_CopyCommand((LPOLEDOC)lpSrcOutlineDoc); + +#else + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpClipboardDoc; + + OpenClipboard(lpSrcOutlineDoc->m_hWndDoc); + EmptyClipboard(); + + /* squirrel away a copy of the current selection to the ClipboardDoc */ + lpClipboardDoc = OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc); + + if (! lpClipboardDoc) + return; // Error: could not create DataTransferDoc + + lpOutlineApp->m_lpClipboardDoc = (LPOUTLINEDOC)lpClipboardDoc; + + SetClipboardData(lpOutlineApp->m_cfOutline, NULL); + SetClipboardData(CF_TEXT, NULL); + + CloseClipboard(); + +#endif // ! OLE_VERSION +} + + +/* OutlineDoc_ClearAllLines + * ------------------------ + * + * Delete all lines in the document. + */ +void OutlineDoc_ClearAllLines(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + int i; + + for(i = 0; i < lpLL->m_nNumLines; i++) + OutlineDoc_DeleteLine(lpOutlineDoc, 0); + + LineList_RecalcMaxLineWidthInHimetric(lpLL, 0); +} + + +/* OutlineDoc_CreateDataTransferDoc + * -------------------------------- + * + * Create a document to be use to transfer data (either via a + * drag/drop operation of the clipboard). Copy the selection of the + * source doc to the data transfer document. A data transfer document is + * the same as a document that is created by the user except that it is + * NOT made visible to the user. it is specially used to hold a copy of + * data that the user should not be able to change. + * + * OLE2NOTE: in the OLE version the data transfer document is used + * specifically to provide an IDataObject* that renders the data copied. + */ +LPOUTLINEDOC OutlineDoc_CreateDataTransferDoc(LPOUTLINEDOC lpSrcOutlineDoc) +{ +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + return OleDoc_CreateDataTransferDoc((LPOLEDOC)lpSrcOutlineDoc); + +#else + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpDestOutlineDoc; + LPLINELIST lpSrcLL = &lpSrcOutlineDoc->m_LineList; + LINERANGE lrSel; + int nCopied; + + lpDestOutlineDoc = OutlineApp_CreateDoc(lpOutlineApp, TRUE); + if (! lpDestOutlineDoc) return NULL; + + // set the ClipboardDoc to an (Untitled) doc. + if (! OutlineDoc_InitNewFile(lpDestOutlineDoc)) + goto error; + + LineList_GetSel(lpSrcLL, (LPLINERANGE)&lrSel); + nCopied = LineList_CopySelToDoc( + lpSrcLL, + (LPLINERANGE)&lrSel, + lpDestOutlineDoc + ); + + return lpDestOutlineDoc; + +error: + if (lpDestOutlineDoc) + OutlineDoc_Destroy(lpDestOutlineDoc); + + return NULL; + +#endif // ! OLE_VERSION +} + + +/* OutlineDoc_PasteCommand + * ----------------------- + * + * Paste lines from clipboard + */ +void OutlineDoc_PasteCommand(LPOUTLINEDOC lpOutlineDoc) +{ +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + OleDoc_PasteCommand((LPOLEDOC)lpOutlineDoc); + +#else + + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPLINELIST lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList; + int nIndex; + int nCount; + HGLOBAL hData; + LINERANGE lrSel; + UINT uFormat; + + if (LineList_GetCount(lpLL) == 0) + nIndex = -1; // pasting to empty list + else + nIndex=LineList_GetFocusLineIndex(lpLL); + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + + OpenClipboard(lpOutlineDoc->m_hWndDoc); + + uFormat = 0; + while(uFormat = EnumClipboardFormats(uFormat)) { + if(uFormat == lpOutlineApp->m_cfOutline) { + hData = GetClipboardData(lpOutlineApp->m_cfOutline); + nCount = OutlineDoc_PasteOutlineData(lpOutlineDoc, hData, nIndex); + break; + } + if(uFormat == CF_TEXT) { + hData = GetClipboardData(CF_TEXT); + nCount = OutlineDoc_PasteTextData(lpOutlineDoc, hData, nIndex); + break; + } + } + + lrSel.m_nStartLine = nIndex + nCount; + lrSel.m_nEndLine = nIndex + 1; + LineList_SetSel(lpLL, &lrSel); + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + + CloseClipboard(); + +#endif // ! OLE_VERSION +} + + +/* OutlineDoc_PasteOutlineData + * --------------------------- + * + * Put an array of Line Objects (stored in hOutline) into the document + * + * Return the number of items added + */ +int OutlineDoc_PasteOutlineData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hOutline, int nStartIndex) +{ + int nCount; + int i; + LPTEXTLINE arrLine; + + nCount = (int) GlobalSize(hOutline) / sizeof(TEXTLINE); + arrLine = (LPTEXTLINE)GlobalLock(hOutline); + if (!arrLine) + return 0; + + for(i = 0; i < nCount; i++) + Line_CopyToDoc((LPLINE)&arrLine[i], lpOutlineDoc, nStartIndex+i); + + GlobalUnlock(hOutline); + + return nCount; +} + + +/* OutlineDoc_PasteTextData + * ------------------------ + * + * Build Line Objects from the strings (separated by '\n') in hText + * and put them into the document + */ +int OutlineDoc_PasteTextData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hText, int nStartIndex) +{ + LPLINELIST lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList; + HDC hDC; + LPSTR lpszText; + LPSTR lpszEnd; + LPTEXTLINE lpLine; + int nLineCount; + int i; + UINT nTab; + char szBuf[MAXSTRLEN+1]; + + lpszText=(LPSTR)GlobalLock(hText); + if(!lpszText) + return 0; + + lpszEnd = lpszText + lstrlen(lpszText); + nLineCount=0; + + while(*lpszText && (lpszText<lpszEnd)) { + + // count the tab level + nTab = 0; + while((*lpszText == '\t') && (lpszText<lpszEnd)) { + nTab++; + lpszText++; + } + + // collect the text string character by character + for(i=0; (i<MAXSTRLEN) && (lpszText<lpszEnd); i++) { + if ((! *lpszText) || (*lpszText == '\n')) + break; + szBuf[i] = *lpszText++; + } + szBuf[i] = 0; + lpszText++; + if ((i > 0) && (szBuf[i-1] == '\r')) + szBuf[i-1] = 0; // remove carriage return at the end + + hDC = LineList_GetDC(lpLL); + lpLine = TextLine_Create(hDC, nTab, szBuf); + LineList_ReleaseDC(lpLL, hDC); + + OutlineDoc_AddLine( + lpOutlineDoc, + (LPLINE)lpLine, + nStartIndex + nLineCount + ); + nLineCount++; + + } + + GlobalUnlock(hText); + + return nLineCount; +} + + +/* OutlineDoc_AddTextLineCommand + * ----------------------------- + * + * Add a new text line following the current focus line. + */ +void OutlineDoc_AddTextLineCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + HDC hDC; + int nIndex = LineList_GetFocusLineIndex(lpLL); + char szBuf[MAXSTRLEN+1]; + UINT nTab = 0; + LPLINE lpLine; + LPTEXTLINE lpTextLine; + + szBuf[0] = '\0'; + +#if defined( USE_FRAMETOOLS ) + FrameTools_FB_GetEditText( + lpOutlineDoc->m_lpFrameTools, szBuf, sizeof(szBuf)); +#else + if (! InputTextDlg(lpOutlineDoc->m_hWndDoc, szBuf, "Add Line")) + return; +#endif + + hDC = LineList_GetDC(lpLL); + lpLine = LineList_GetLine(lpLL, nIndex); + if (lpLine) + nTab = Line_GetTabLevel(lpLine); + + lpTextLine=TextLine_Create(hDC, nTab, szBuf); + LineList_ReleaseDC(lpLL, hDC); + + if (! lpTextLine) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrOutOfMemory); + return; + } + OutlineDoc_AddLine(lpOutlineDoc, (LPLINE)lpTextLine, nIndex); +} + + +/* OutlineDoc_AddTopLineCommand + * ---------------------------- + * + * Add a top (margin) line as the first line in the LineList. + * (do not change the current selection) + */ +void OutlineDoc_AddTopLineCommand( + LPOUTLINEDOC lpOutlineDoc, + UINT nHeightInHimetric +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + HDC hDC = LineList_GetDC(lpLL); + LPTEXTLINE lpTextLine = TextLine_Create(hDC, 0, NULL); + LPLINE lpLine = (LPLINE)lpTextLine; + LINERANGE lrSel; + int nNumSel; + + LineList_ReleaseDC(lpLL, hDC); + + if (! lpTextLine) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrOutOfMemory); + return; + } + + Line_SetHeightInHimetric(lpLine, nHeightInHimetric); + + nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel); + if (nNumSel > 0) { + // adjust current selection to keep equivalent selection + lrSel.m_nStartLine += 1; + lrSel.m_nEndLine += 1; + } + OutlineDoc_AddLine(lpOutlineDoc, lpLine, -1); + if (nNumSel > 0) + LineList_SetSel(lpLL, (LPLINERANGE)&lrSel); +} + + +#if defined( USE_FRAMETOOLS ) + + +/* OutlineDoc_SetFormulaBarEditText + * -------------------------------- + * + * Fill the edit control in the formula with the text string from a + * TextLine in focus. + */ +void OutlineDoc_SetFormulaBarEditText( + LPOUTLINEDOC lpOutlineDoc, + LPLINE lpLine +) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + char cBuf[MAXSTRLEN+1]; + + if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools) + return; + + if (Line_GetLineType(lpLine) != TEXTLINETYPE) { + FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, NULL); + } else { + TextLine_GetTextData((LPTEXTLINE)lpLine, (LPSTR)cBuf); + FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, (LPSTR)cBuf); + } +} + + +/* OutlineDoc_SetFormulaBarEditFocus + * --------------------------------- + * + * Setup for formula bar to gain or loose edit focus. + * if gaining focus, setup up special accelerator table and scroll line + * into view. + * else restore normal accelerator table. + */ +void OutlineDoc_SetFormulaBarEditFocus( + LPOUTLINEDOC lpOutlineDoc, + BOOL fEditFocus +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPLINELIST lpLL; + int nFocusIndex; + + if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools) + return; + + lpOutlineDoc->m_lpFrameTools->m_fInFormulaBar = fEditFocus; + + if (fEditFocus && lpOutlineDoc->m_lpFrameTools) { + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + + nFocusIndex = LineList_GetFocusLineIndex(lpLL); + LineList_ScrollLineIntoView(lpLL, nFocusIndex); + FrameTools_FB_FocusEdit(lpOutlineDoc->m_lpFrameTools); + } + + OutlineApp_SetFormulaBarAccel(lpOutlineApp, fEditFocus); +} + + +/* OutlineDoc_IsEditFocusInFormulaBar +** ---------------------------------- +** Returns TRUE if edit focus is currently in the formula bar +** else FALSE if not. +*/ +BOOL OutlineDoc_IsEditFocusInFormulaBar(LPOUTLINEDOC lpOutlineDoc) +{ + if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools) + return FALSE; + + return lpOutlineDoc->m_lpFrameTools->m_fInFormulaBar; +} + + +/* OutlineDoc_UpdateFrameToolButtons +** --------------------------------- +** Update the Enable/Disable states of the buttons in the formula +** bar and button bar. +*/ +void OutlineDoc_UpdateFrameToolButtons(LPOUTLINEDOC lpOutlineDoc) +{ + if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools) + return; + FrameTools_UpdateButtons(lpOutlineDoc->m_lpFrameTools, lpOutlineDoc); +} +#endif // USE_FRAMETOOLS + + +/* OutlineDoc_EditLineCommand + * -------------------------- + * + * Edit the current focus line. + */ +void OutlineDoc_EditLineCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + HDC hDC = LineList_GetDC(lpLL); + int nIndex = LineList_GetFocusLineIndex(lpLL); + LPLINE lpLine = LineList_GetLine(lpLL, nIndex); + int nOrgLineWidthInHimetric; + int nNewLineWidthInHimetric; + BOOL fSizeChanged; + + if (!lpLine) + return; + + nOrgLineWidthInHimetric = Line_GetTotalWidthInHimetric(lpLine); + if (Line_Edit(lpLine, lpOutlineDoc->m_hWndDoc, hDC)) { + nNewLineWidthInHimetric = Line_GetTotalWidthInHimetric(lpLine); + + if (nNewLineWidthInHimetric > nOrgLineWidthInHimetric) { + fSizeChanged = LineList_SetMaxLineWidthInHimetric( + lpLL, + nNewLineWidthInHimetric + ); + } else { + fSizeChanged = LineList_RecalcMaxLineWidthInHimetric( + lpLL, + nOrgLineWidthInHimetric + ); + } + +#if defined( OLE_SERVER ) + /* Update Name Table */ + ServerNameTable_EditLineUpdate( + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, + nIndex + ); +#endif + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fSizeChanged); + + LineList_ForceLineRedraw(lpLL, nIndex, TRUE); + } + LineList_ReleaseDC(lpLL, hDC); +} + + +/* OutlineDoc_IndentCommand + * ------------------------ + * + * Indent selection of lines + */ +void OutlineDoc_IndentCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + LPLINE lpLine; + HDC hDC = LineList_GetDC(lpLL); + int i; + int nIndex; + int nNumSel; + LINERANGE lrSel; + BOOL fSizeChanged = FALSE; + + nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel); + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + + for(i = 0; i < nNumSel; i++) { + nIndex = lrSel.m_nStartLine + i; + lpLine=LineList_GetLine(lpLL, nIndex); + if (! lpLine) + continue; + + Line_Indent(lpLine, hDC); + if (LineList_SetMaxLineWidthInHimetric(lpLL, + Line_GetTotalWidthInHimetric(lpLine))) { + fSizeChanged = TRUE; + } + LineList_ForceLineRedraw(lpLL, nIndex, TRUE); + +#if defined( OLE_SERVER ) + /* Update Name Table */ + ServerNameTable_EditLineUpdate( + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, + nIndex + ); +#endif + + } + + LineList_ReleaseDC(lpLL, hDC); + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fSizeChanged); + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); +} + + +/* OutlineDoc_UnindentCommand + * -------------------------- + * + * Unindent selection of lines + */ +void OutlineDoc_UnindentCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + LPLINE lpLine; + HDC hDC = LineList_GetDC(lpLL); + int nOrgLineWidthInHimetric; + int nOrgMaxLineWidthInHimetric = 0; + int i; + int nIndex; + int nNumSel; + LINERANGE lrSel; + BOOL fSizeChanged; + + nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel); + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + + for(i = 0; i < nNumSel; i++) { + nIndex = lrSel.m_nStartLine + i; + lpLine=LineList_GetLine(lpLL, nIndex); + if (!lpLine) + continue; + + nOrgLineWidthInHimetric = Line_GetTotalWidthInHimetric(lpLine); + nOrgMaxLineWidthInHimetric = + (nOrgLineWidthInHimetric > nOrgMaxLineWidthInHimetric ? + nOrgLineWidthInHimetric : nOrgMaxLineWidthInHimetric); + Line_Unindent(lpLine, hDC); + LineList_ForceLineRedraw(lpLL, nIndex, TRUE); + +#if defined( OLE_SERVER ) + /* Update Name Table */ + ServerNameTable_EditLineUpdate( + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, + nIndex + ); +#endif + + } + + LineList_ReleaseDC(lpLL, hDC); + + fSizeChanged = LineList_RecalcMaxLineWidthInHimetric( + lpLL, + nOrgMaxLineWidthInHimetric + ); + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fSizeChanged); + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); +} + + +/* OutlineDoc_SetLineHeightCommand + * ------------------------------- + * + * Set height of the selection of lines + */ +void OutlineDoc_SetLineHeightCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPLINELIST lpLL; + HDC hDC; + LPLINE lpLine; + int nNewHeight; + int i; + int nIndex; + int nNumSel; + LINERANGE lrSel; + + if (!lpOutlineDoc) + return; + + lpLL = &lpOutlineDoc->m_LineList; + nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel); + lpLine = LineList_GetLine(lpLL, lrSel.m_nStartLine); + if (!lpLine) + return; + + nNewHeight = Line_GetHeightInHimetric(lpLine); + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc); +#endif + + DialogBoxParam( + lpOutlineApp->m_hInst, + (LPSTR)"SetLineHeight", + lpOutlineDoc->m_hWndDoc, + (DLGPROC)SetLineHeightDlgProc, + (LPARAM)(LPINT)&nNewHeight + ); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc); +#endif + + if (nNewHeight == 0) + return; /* user hit cancel */ + + hDC = LineList_GetDC(lpLL); + + for (i = 0; i < nNumSel; i++) { + nIndex = lrSel.m_nStartLine + i; + lpLine=LineList_GetLine(lpLL, nIndex); + if (nNewHeight == -1) { + switch (Line_GetLineType(lpLine)) { + + case TEXTLINETYPE: + + TextLine_CalcExtents((LPTEXTLINE)lpLine, hDC); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + + ContainerLine_SetHeightInHimetric( + (LPCONTAINERLINE)lpLine, -1); + break; +#endif + + } + } + else + Line_SetHeightInHimetric(lpLine, nNewHeight); + + + LineList_SetLineHeight(lpLL, nIndex, + Line_GetHeightInHimetric(lpLine)); + } + + LineList_ReleaseDC(lpLL, hDC); + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE); + LineList_ForceRedraw(lpLL, TRUE); +} + + + +/* OutlineDoc_SelectAllCommand + * --------------------------- + * + * Select all the lines in the document. + */ +void OutlineDoc_SelectAllCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + LINERANGE lrSel; + + lrSel.m_nStartLine = 0; + lrSel.m_nEndLine = LineList_GetCount(lpLL) - 1; + LineList_SetSel(lpLL, &lrSel); +} + + +/* OutlineDoc_DefineNameCommand + * ---------------------------- + * + * Define a name in the document + */ +void OutlineDoc_DefineNameCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc); +#endif + + DialogBoxParam( + lpOutlineApp->m_hInst, + (LPSTR)"DefineName", + lpOutlineDoc->m_hWndDoc, + (DLGPROC)DefineNameDlgProc, + (LPARAM) lpOutlineDoc + ); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc); +#endif +} + + +/* OutlineDoc_GotoNameCommand + * -------------------------- + * + * Goto a predefined name in the document + */ +void OutlineDoc_GotoNameCommand(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + +#if defined( OLE_VERSION ) + OleApp_PreModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc); +#endif + + DialogBoxParam( + lpOutlineApp->m_hInst, + (LPSTR)"GotoName", + lpOutlineDoc->m_hWndDoc, + (DLGPROC)GotoNameDlgProc, + (LPARAM)lpOutlineDoc + ); + +#if defined( OLE_VERSION ) + OleApp_PostModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc); +#endif +} + + +/* OutlineDoc_ShowWindow + * --------------------- + * + * Show the window of the document to the user. + */ +void OutlineDoc_ShowWindow(LPOUTLINEDOC lpOutlineDoc) +{ +#if defined( _DEBUG ) + OleDbgAssertSz(lpOutlineDoc->m_docInitType != DOCTYPE_UNKNOWN, + "OutlineDoc_ShowWindow: can't show unitialized document\r\n"); +#endif + if (lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN) + return; + +#if defined( OLE_VERSION ) + // Call OLE version of this function instead + OleDoc_ShowWindow((LPOLEDOC)lpOutlineDoc); +#else + ShowWindow(lpOutlineDoc->m_hWndDoc, SW_SHOWNORMAL); + SetFocus(lpOutlineDoc->m_hWndDoc); +#endif +} + + +#if defined( USE_FRAMETOOLS ) + +void OutlineDoc_AddFrameLevelTools(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; +#if defined( INPLACE_CNTR ) + // Call OLE In-Place Container version of this function instead + ContainerDoc_AddFrameLevelTools((LPCONTAINERDOC)lpOutlineDoc); + +#else // ! INPLACE_CNTR + RECT rcFrameRect; + BORDERWIDTHS frameToolWidths; + +#if defined( INPLACE_SVR ) + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + LPOLEINPLACEFRAME lpTopIPFrame=ServerDoc_GetTopInPlaceFrame(lpServerDoc); + + // if in-place active, add our tools to our in-place container's frame. + if (lpTopIPFrame) { + ServerDoc_AddFrameLevelTools(lpServerDoc); + return; + } +#endif // INPLACE_SVR + + OutlineApp_GetFrameRect(g_lpApp, (LPRECT)&rcFrameRect); + FrameTools_GetRequiredBorderSpace( + lpOutlineDoc->m_lpFrameTools, + (LPBORDERWIDTHS)&frameToolWidths + ); + OutlineApp_SetBorderSpace(g_lpApp, (LPBORDERWIDTHS)&frameToolWidths); + FrameTools_AttachToFrame( + lpOutlineDoc->m_lpFrameTools, OutlineApp_GetWindow(lpOutlineApp)); + FrameTools_Move(lpOutlineDoc->m_lpFrameTools, (LPRECT)&rcFrameRect); +#endif // ! INPLACE_CNTR + +} + +#endif // USE_FRAMETOOLS + + +/* OutlineDoc_GetWindow + * -------------------- + * + * Get the window handle of the document. + */ +HWND OutlineDoc_GetWindow(LPOUTLINEDOC lpOutlineDoc) +{ + if(! lpOutlineDoc) return NULL; + return lpOutlineDoc->m_hWndDoc; +} + + +/* OutlineDoc_AddLine + * ------------------ + * + * Add one line to the Document's LineList + */ +void OutlineDoc_AddLine(LPOUTLINEDOC lpOutlineDoc, LPLINE lpLine, int nIndex) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + + LineList_AddLine(lpLL, lpLine, nIndex); + + /* Update Name Table */ + OutlineNameTable_AddLineUpdate(lpOutlineDoc->m_lpNameTable, nIndex); + +#if defined( INPLACE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + /* OLE2NOTE: after adding a line we need to + ** update the PosRect of the In-Place active + ** objects (if any) that follow the added line. + ** NOTE: nIndex is index of line before new line. + ** nIndex+1 is index of new line + ** nIndex+2 is index of line after new line. + */ + ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, nIndex+2); + } +#endif + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE); +} + + +/* OutlineDoc_DeleteLine + * --------------------- + * + * + * Delete one line from the document's LineList + */ +void OutlineDoc_DeleteLine(LPOUTLINEDOC lpOutlineDoc, int nIndex) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + +#if defined( OLE_CNTR ) + LPLINE lpLine = LineList_GetLine(lpLL, nIndex); + LPSTORAGE lpStgDoc = NULL; + char szSaveStgName[CWCSTORAGENAME]; + BOOL fDeleteChildStg = FALSE; + + if (lpLine && (Line_GetLineType(lpLine) == CONTAINERLINETYPE) ) { + + /* OLE2NOTE: when a ContainerLine is being deleted by the user, + ** it is important to delete the object's sub-storage + ** otherwise it wastes space in the ContainerDoc's file. + ** this function is called when lines are deleted by the + ** Clear command and when lines are deleted by a DRAGMOVE + ** operation. + */ + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + // save name of child storage + LSTRCPYN(szSaveStgName, lpContainerLine->m_szStgName, + sizeof(szSaveStgName)); + lpStgDoc = ((LPOLEDOC)lpContainerLine->m_lpDoc)->m_lpStg; + fDeleteChildStg = TRUE; + } +#endif // OLE_CNTR + + LineList_DeleteLine(lpLL, nIndex); + +#if defined( OLE_CNTR ) + if (fDeleteChildStg && lpStgDoc) { + HRESULT hrErr; + + // delete the obsolete child storage. it is NOT fatal if this fails + + hrErr = CallIStorageDestroyElementA(lpStgDoc, szSaveStgName); + +#if defined( _DEBUG ) + if (hrErr != NOERROR) { + OleDbgOutHResult("IStorage::DestroyElement return", hrErr); + } +#endif + } +#endif // OLE_CNTR + + /* Update Name Table */ + OutlineNameTable_DeleteLineUpdate(lpOutlineDoc->m_lpNameTable, nIndex); + +#if defined( INPLACE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + /* OLE2NOTE: after deleting a line we need to + ** update the PosRect of the In-Place active + ** objects (if any). + */ + ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, nIndex); + } +#endif + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE); + +#if defined( OLE_VERSION ) + { + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOLEDOC lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc; + + /* OLE2NOTE: if the document that is the source of data on the + ** clipborad has just had lines deleted, then the copied data + ** is no longer considered a valid potential link source. + ** disable the offering of CF_LINKSOURCE from the clipboard + ** document. this avoids problems that arise when the + ** editing operation changes or deletes the original data + ** copied. we will not go to the trouble of determining if + ** the deleted line actually is part of the link source. + */ + if (lpClipboardDoc + && lpClipboardDoc->m_fLinkSourceAvail + && lpClipboardDoc->m_lpSrcDocOfCopy == (LPOLEDOC)lpOutlineDoc) { + lpClipboardDoc->m_fLinkSourceAvail = FALSE; + + /* OLE2NOTE: since we are changing the list of formats on + ** the clipboard (ie. removing CF_LINKSOURCE), we must + ** call OleSetClipboard again. to be sure that the + ** clipboard datatransfer document object does not get + ** destroyed we will guard the call to OleSetClipboard + ** within a pair of AddRef/Release. + */ + OleDoc_AddRef((LPOLEDOC)lpClipboardDoc); // guard obj life-time + + OLEDBG_BEGIN2("OleSetClipboard called\r\n") + OleSetClipboard( + (LPDATAOBJECT)&((LPOLEDOC)lpClipboardDoc)->m_DataObject); + OLEDBG_END2 + + OleDoc_Release((LPOLEDOC)lpClipboardDoc); // rel. AddRef above + } + } +#endif // OLE_VERSION +} + + +/* OutlineDoc_AddName + * ------------------ + * + * Add a Name to the Document's NameTable + */ +void OutlineDoc_AddName(LPOUTLINEDOC lpOutlineDoc, LPOUTLINENAME lpOutlineName) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = lpOutlineDoc->m_lpNameTable; + + OutlineNameTable_AddName(lpOutlineNameTable, lpOutlineName); + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE); +} + + +/* OutlineDoc_DeleteName + * --------------------- + * + * + * Delete Name from the document's NameTable + */ +void OutlineDoc_DeleteName(LPOUTLINEDOC lpOutlineDoc, int nIndex) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = lpOutlineDoc->m_lpNameTable; + + OutlineNameTable_DeleteName(lpOutlineNameTable, nIndex); + + OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE); +} + + +/* OutlineDoc_Destroy + * ------------------ + * + * Free all memory that had been allocated for a document. + * this destroys the LineList & NameTable of the document. + */ +void OutlineDoc_Destroy(LPOUTLINEDOC lpOutlineDoc) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; +#if defined( OLE_VERSION ) + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + + if (lpOleDoc->m_fObjIsDestroying) + return; // doc destruction is in progress +#endif // OLE_VERSION + + OLEDBG_BEGIN3("OutlineDoc_Destroy\r\n"); + +#if defined( OLE_VERSION ) + + /* OLE2NOTE: in order to guarantee that the application does not + ** prematurely exit before the destruction of the document is + ** complete, we intially AddRef the App refcnt later Release it. + ** This initial AddRef is artificial; it simply guarantees that + ** the app object does not get destroyed until the end of this + ** routine. + */ + OleApp_AddRef(lpOleApp); + + /* OLE2NOTE: perform processing required for OLE */ + OleDoc_Destroy(lpOleDoc); +#endif + + LineList_Destroy(lpLL); + OutlineNameTable_Destroy(lpOutlineDoc->m_lpNameTable); + +#if defined( USE_HEADING ) + if (! lpOutlineDoc->m_fDataTransferDoc) + Heading_Destroy((LPHEADING)&lpOutlineDoc->m_heading); +#endif + +#if defined( USE_FRAMETOOLS ) + if (! lpOutlineDoc->m_fDataTransferDoc) + FrameTools_AssociateDoc(lpOutlineDoc->m_lpFrameTools, NULL); +#endif // USE_FRAMETOOLS + + DestroyWindow(lpOutlineDoc->m_hWndDoc); + Delete(lpOutlineDoc); // free memory for doc itself + OleDbgOut1("@@@@ DOC DESTROYED\r\n"); + +#if defined( OLE_VERSION ) + OleApp_Release(lpOleApp); // release artificial AddRef above +#endif + + OLEDBG_END3 +} + + +/* OutlineDoc_ReSize + * ----------------- + * + * Resize the document and its components + * + * Parameter: + * lpRect the new size of the document. Use current size if NULL + */ +void OutlineDoc_Resize(LPOUTLINEDOC lpOutlineDoc, LPRECT lpRect) +{ + RECT rect; + LPLINELIST lpLL; + +#if defined( USE_HEADING ) + LPHEADING lphead; +#endif // USE_HEADING + + LPSCALEFACTOR lpscale; + HWND hWndLL; + + if (!lpOutlineDoc) + return; + + lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList; + lpscale = (LPSCALEFACTOR)&lpOutlineDoc->m_scale; + hWndLL = LineList_GetWindow(lpLL); + + if (lpRect) { + CopyRect((LPRECT)&rect, lpRect); + MoveWindow(lpOutlineDoc->m_hWndDoc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, TRUE); + } + + GetClientRect(lpOutlineDoc->m_hWndDoc, (LPRECT)&rect); + +#if defined( USE_HEADING ) + lphead = OutlineDoc_GetHeading(lpOutlineDoc); + rect.left += Heading_RH_GetWidth(lphead, lpscale); + rect.top += Heading_CH_GetHeight(lphead, lpscale); +#endif // USE_HEADING + + if (lpLL) { + MoveWindow(hWndLL, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, TRUE); + } + +#if defined( USE_HEADING ) + if (lphead) + Heading_Move(lphead, lpOutlineDoc->m_hWndDoc, lpscale); +#endif // USE_HEADING + +#if defined( INPLACE_CNTR ) + ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0); +#endif +} + + +/* OutlineDoc_GetNameTable + * ----------------------- + * + * Get nametable associated with the line list + */ +LPOUTLINENAMETABLE OutlineDoc_GetNameTable(LPOUTLINEDOC lpOutlineDoc) +{ + if (!lpOutlineDoc) + return NULL; + else + return lpOutlineDoc->m_lpNameTable; +} + + +/* OutlineDoc_GetLineList + * ---------------------- + * + * Get listlist associated with the OutlineDoc + */ +LPLINELIST OutlineDoc_GetLineList(LPOUTLINEDOC lpOutlineDoc) +{ + if (!lpOutlineDoc) + return NULL; + else + return (LPLINELIST)&lpOutlineDoc->m_LineList; +} + + +/* OutlineDoc_GetNameCount + * ----------------------- + * + * Return number of names in table + */ +int OutlineDoc_GetNameCount(LPOUTLINEDOC lpOutlineDoc) +{ + return OutlineNameTable_GetCount(lpOutlineDoc->m_lpNameTable); +} + + +/* OutlineDoc_GetLineCount + * ----------------------- + * + * Return number of lines in the LineList + */ +int OutlineDoc_GetLineCount(LPOUTLINEDOC lpOutlineDoc) +{ + return LineList_GetCount(&lpOutlineDoc->m_LineList); +} + + +/* OutlineDoc_SetFileName + * ---------------------- + * + * Set the filename of a document. + * + * OLE2NOTE: If the ServerDoc has a valid filename then, the object is + * registered in the running object table (ROT). if the name of the doc + * changes (eg. via SaveAs) then the previous registration must be revoked + * and the document re-registered under the new name. + */ +BOOL OutlineDoc_SetFileName(LPOUTLINEDOC lpOutlineDoc, LPSTR lpszNewFileName, LPSTORAGE lpNewStg) +{ + OleDbgAssertSz(lpszNewFileName != NULL, "Can't reset doc to Untitled!"); + if (lpszNewFileName == NULL) + return FALSE; + + AnsiLowerBuff(lpszNewFileName, (UINT)lstrlen(lpszNewFileName)); + +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + + /* OLE2NOTE: the container version of the application keeps its + ** storage open at all times. if the document's storage is not + ** open, then open it. + */ + + if (lpNewStg) { + + /* CASE 1 -- document is being loaded from a file. lpNewStg is + ** still open from the OutlineDoc_LoadFromFile function. + */ + + lpOutlineDoc->m_docInitType = DOCTYPE_FROMFILE; + + } else { + + /* CASE 2 -- document is being associated with a valid file + ** that is not yet open. thus we must now open the file. + */ + + if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE && + lstrcmp(lpOutlineDoc->m_szFileName,lpszNewFileName)==0) { + + /* CASE 2a -- new filename is same as current file. if the + ** stg is already open, then the lpStg is still valid. + ** if it is not open, then open it. + */ + if (! lpOleDoc->m_lpStg) { + lpOleDoc->m_lpStg = OleStdOpenRootStorage( + lpszNewFileName, + STGM_READWRITE | STGM_SHARE_DENY_WRITE + ); + if (! lpOleDoc->m_lpStg) return FALSE; + } + + } else { + + /* CASE 2b -- new filename is NOT same as current file. + ** a SaveAs operation is pending. open the new file and + ** hold the storage pointer in m_lpNewStg. the + ** subsequent call to Doc_SaveToFile will save the + ** document into the new storage pointer and release the + ** old storage pointer. + */ + + lpOutlineDoc->m_docInitType = DOCTYPE_FROMFILE; + + lpContainerDoc->m_lpNewStg = OleStdCreateRootStorage( + lpszNewFileName, + STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_CREATE + ); + if (! lpContainerDoc->m_lpNewStg) return FALSE; + } + } + } +#endif // OLE_CNTR + + if (lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE || + lstrcmp(lpOutlineDoc->m_szFileName, lpszNewFileName) != 0) { + + /* A new valid file name is being associated with the document */ + + lstrcpy(lpOutlineDoc->m_szFileName, lpszNewFileName); + lpOutlineDoc->m_docInitType = DOCTYPE_FROMFILE; + + // set lpszDocTitle to point to filename without path + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName + + lstrlen(lpOutlineDoc->m_szFileName) - 1; + while (lpOutlineDoc->m_lpszDocTitle > lpOutlineDoc->m_szFileName + && ! IS_FILENAME_DELIM(lpOutlineDoc->m_lpszDocTitle[-1])) { + lpOutlineDoc->m_lpszDocTitle--; + } + + OutlineDoc_SetTitle(lpOutlineDoc, TRUE /*fMakeUpperCase*/); + +#if defined( OLE_VERSION ) + { + /* OLE2NOTE: both containers and servers must properly + ** register in the RunningObjectTable. if the document + ** is performing a SaveAs operation, then it must + ** re-register in the ROT with the new moniker. in + ** addition any embedded object, pseudo objects, and/or + ** linking clients must be informed that the document's + ** moniker has changed. + */ + + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + + if (lpOleDoc->m_lpFileMoniker) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker); + lpOleDoc->m_lpFileMoniker = NULL; + } + + CreateFileMonikerA(lpszNewFileName, + &lpOleDoc->m_lpFileMoniker); + + OleDoc_DocRenamedUpdate(lpOleDoc, lpOleDoc->m_lpFileMoniker); + } +#endif // OLE_VERSION + + } + + return TRUE; +} + + +/* OutlineDoc_SetTitle + * ------------------- + * + * Set window text to be current filename. + * The following window hierarchy exits: + * hWndApp + * hWndDoc + * hWndListBox + * The frame window is the window which gets the title. + */ +void OutlineDoc_SetTitle(LPOUTLINEDOC lpOutlineDoc, BOOL fMakeUpperCase) +{ + HWND hWnd; + LPSTR lpszText; + + if (!lpOutlineDoc->m_hWndDoc) return; + if ((hWnd = GetParent(lpOutlineDoc->m_hWndDoc)) == NULL) return; + + lpszText = OleStdMalloc((UINT)(lstrlen(APPNAME) + 4 + + lstrlen(lpOutlineDoc->m_lpszDocTitle))); + if (!lpszText) return; + + lstrcpy(lpszText, APPNAME); + lstrcat(lpszText," - "); + lstrcat(lpszText, (LPSTR)lpOutlineDoc->m_lpszDocTitle); + + if (fMakeUpperCase) + AnsiUpperBuff(lpszText, (UINT)lstrlen(lpszText)); + + SetWindowText(hWnd,lpszText); + OleStdFree(lpszText); +} + + +/* OutlineDoc_Close + * ---------------- + * + * Close active document. If modified, prompt the user if + * he wants to save. + * + * Returns: + * FALSE -- user canceled the closing of the doc. + * TRUE -- the doc was successfully closed + */ +BOOL OutlineDoc_Close(LPOUTLINEDOC lpOutlineDoc, DWORD dwSaveOption) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + +#if defined( OLE_VERSION ) + /* OLE2NOTE: call OLE specific function instead */ + return OleDoc_Close((LPOLEDOC)lpOutlineDoc, dwSaveOption); + +#else + + if (! lpOutlineDoc) + return TRUE; // active doc's are already destroyed + + if (! OutlineDoc_CheckSaveChanges(lpOutlineDoc, &dwSaveOption)) + return FALSE; // abort closing the doc + + OutlineDoc_Destroy(lpOutlineDoc); + + OutlineApp_DocUnlockApp(lpOutlineApp, lpOutlineDoc); + + return TRUE; + +#endif // ! OLE_VERSION +} + + +/* OutlineDoc_CheckSaveChanges + * --------------------------- + * + * Check if the document has been modified. if so, prompt the user if + * the changes should be saved. if yes save them. + * Returns TRUE if the doc is safe to close (user answered Yes or No) + * FALSE if the user canceled the save changes option. + */ +BOOL OutlineDoc_CheckSaveChanges( + LPOUTLINEDOC lpOutlineDoc, + LPDWORD lpdwSaveOption +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + int nResponse; + + if (*lpdwSaveOption == OLECLOSE_NOSAVE) + return TRUE; + + if(! OutlineDoc_IsModified(lpOutlineDoc)) + return TRUE; // saving is not necessary + + /* OLE2NOTE: our document is dirty so it needs to be saved. if + ** OLECLOSE_PROMPTSAVE the user should be prompted to see if the + ** document should be saved. is specified but the document is NOT + ** visible to the user, then the user can NOT be prompted. in + ** the situation the document should be saved without prompting. + ** if OLECLOSE_SAVEIFDIRTY is specified then, the document + ** should also be saved without prompting. + */ + if (*lpdwSaveOption == OLECLOSE_PROMPTSAVE && + IsWindowVisible(lpOutlineDoc->m_hWndDoc)) { + + // prompt the user to see if changes should be saved. +#if defined( OLE_VERSION ) + OleApp_PreModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + nResponse = MessageBox( + lpOutlineApp->m_hWndApp, + MsgSaveFile, + APPNAME, + MB_ICONQUESTION | MB_YESNOCANCEL + ); +#if defined( OLE_VERSION ) + OleApp_PostModalDialog( + (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc); +#endif + if(nResponse==IDCANCEL) + return FALSE; // close is canceled + if(nResponse==IDNO) { + // Reset the save option to NOSAVE per user choice + *lpdwSaveOption = OLECLOSE_NOSAVE; + return TRUE; // don't save, but is ok to close + } + } else if (*lpdwSaveOption != OLECLOSE_SAVEIFDIRTY) { + OleDbgAssertSz(FALSE, "Invalid dwSaveOption\r\n"); + *lpdwSaveOption = OLECLOSE_NOSAVE; + return TRUE; // unknown *lpdwSaveOption; close w/o saving + } + +#if defined( OLE_SERVER ) + if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED) { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + HRESULT hrErr; + + /* OLE2NOTE: Update the container before closing without prompting + ** the user. To update the container, we must ask our container + ** to save us. + */ + OleDbgAssert(lpServerDoc->m_lpOleClientSite != NULL); + OLEDBG_BEGIN2("IOleClientSite::SaveObject called\r\n") + hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->SaveObject( + lpServerDoc->m_lpOleClientSite + ); + OLEDBG_END2 + + if (hrErr != NOERROR) { + OleDbgOutHResult("IOleClientSite::SaveObject returned", hrErr); + return FALSE; + } + + return TRUE; // doc is safe to be closed + + } else +#endif // OLE_SERVER + { + return OutlineApp_SaveCommand(lpOutlineApp); + } +} + + +/* OutlineDoc_IsModified + * --------------------- + * + * Return modify flag of OUTLINEDOC + */ +BOOL OutlineDoc_IsModified(LPOUTLINEDOC lpOutlineDoc) +{ + if (lpOutlineDoc->m_fModified) + return lpOutlineDoc->m_fModified; + +#if defined( OLE_CNTR ) + { + /* OLE2NOTE: if there are OLE objects, then we must ask if any of + ** them are dirty. if so we must consider our document + ** as modified. + */ + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + LPLINELIST lpLL; + int nLines; + int nIndex; + LPLINE lpLine; + HRESULT hrErr; + + lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + nLines = LineList_GetCount(lpLL); + + for (nIndex = 0; nIndex < nLines; nIndex++) { + lpLine = LineList_GetLine(lpLL, nIndex); + if (!lpLine) + break; + if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + if (lpContainerLine->m_lpPersistStg) { + hrErr = lpContainerLine->m_lpPersistStg->lpVtbl->IsDirty( + lpContainerLine->m_lpPersistStg); + /* OLE2NOTE: we will only accept an explicit "no i + ** am NOT dirty statement" (ie. S_FALSE) as an + ** indication that the object is clean. eg. if + ** the object returns E_NOTIMPL we must + ** interpret it as the object IS dirty. + */ + if (GetScode(hrErr) != S_FALSE) + return TRUE; + } + } + } + } +#endif + return FALSE; +} + + +/* OutlineDoc_SetModified + * ---------------------- + * + * Set the modified flag of the document + * + */ +void OutlineDoc_SetModified(LPOUTLINEDOC lpOutlineDoc, BOOL fModified, BOOL fDataChanged, BOOL fSizeChanged) +{ + lpOutlineDoc->m_fModified = fModified; + +#if defined( OLE_SERVER ) + if (! lpOutlineDoc->m_fDataTransferDoc) { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + + /* OLE2NOTE: if the document has changed, then broadcast the change + ** to all clients who have set up Advise connections. notify + ** them that our data (and possibly also our extents) have + ** changed. + */ + if (fDataChanged) { + lpServerDoc->m_fDataChanged = TRUE; + lpServerDoc->m_fSizeChanged = fSizeChanged; + lpServerDoc->m_fSendDataOnStop = TRUE; + + ServerDoc_SendAdvise( + lpServerDoc, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); + } + } +#endif // OLE_SERVER +} + + +/* OutlineDoc_SetRedraw + * -------------------- + * + * Enable/Disable the redraw of the document on screen. + * The calls to SetRedraw counted so that nested calls can be handled + * properly. calls to SetRedraw must be balanced. + * + * fEnbaleDraw = TRUE - enable redraw + * FALSE - disable redraw + */ +void OutlineDoc_SetRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fEnableDraw) +{ + static HCURSOR hPrevCursor = NULL; + + if (fEnableDraw) { + if (lpOutlineDoc->m_nDisableDraw == 0) + return; // already enabled; no state transition + + if (--lpOutlineDoc->m_nDisableDraw > 0) + return; // drawing should still be disabled + } else { + if (lpOutlineDoc->m_nDisableDraw++ > 0) + return; // already disabled; no state transition + } + + if (lpOutlineDoc->m_nDisableDraw > 0) { + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + } else { + if (hPrevCursor) { + SetCursor(hPrevCursor); // restore original cursor + hPrevCursor = NULL; + } + } + +#if defined( OLE_SERVER ) + /* OLE2NOTE: for the Server version, while Redraw is disabled + ** postpone sending advise notifications until Redraw is re-enabled. + */ + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + LPSERVERNAMETABLE lpServerNameTable = + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable; + + if (lpOutlineDoc->m_nDisableDraw == 0) { + /* drawing is being Enabled. if changes occurred while drawing + ** was disabled, then notify clients now. + */ + if (lpServerDoc->m_fDataChanged) + ServerDoc_SendAdvise( + lpServerDoc, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); + + /* OLE2NOTE: send pending change notifications for pseudo objs. */ + ServerNameTable_SendPendingAdvises(lpServerNameTable); + + } + } +#endif // OLE_SERVER + +#if defined( OLE_CNTR ) + /* OLE2NOTE: for the Container version, while Redraw is disabled + ** postpone updating the extents of OLE objects until Redraw is + ** re-enabled. + */ + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + + /* Update the extents of any OLE object that is marked that + ** its size may have changed. when an + ** IAdviseSink::OnViewChange notification is received, + ** the corresponding ContainerLine is marked + ** (m_fDoGetExtent==TRUE) and a message + ** (WM_U_UPDATEOBJECTEXTENT) is posted to the document + ** indicating that there are dirty objects. + */ + if (lpOutlineDoc->m_nDisableDraw == 0) + ContainerDoc_UpdateExtentOfAllOleObjects(lpContainerDoc); + } +#endif // OLE_CNTR + + // enable/disable redraw of the LineList listbox + LineList_SetRedraw(&lpOutlineDoc->m_LineList, fEnableDraw); +} + + +/* OutlineDoc_SetSel + * ----------------- + * + * Set the selection in the documents's LineList + */ +void OutlineDoc_SetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel) +{ + LineList_SetSel(&lpOutlineDoc->m_LineList, lplrSel); +} + + +/* OutlineDoc_GetSel + * ----------------- + * + * Get the selection in the documents's LineList. + * + * Returns the count of items selected + */ +int OutlineDoc_GetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel) +{ + return LineList_GetSel(&lpOutlineDoc->m_LineList, lplrSel); +} + + +/* OutlineDoc_ForceRedraw + * ---------------------- + * + * Force the document window to repaint. + */ +void OutlineDoc_ForceRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fErase) +{ + if (!lpOutlineDoc) + return; + + LineList_ForceRedraw(&lpOutlineDoc->m_LineList, fErase); + Heading_CH_ForceRedraw(&lpOutlineDoc->m_heading, fErase); + Heading_RH_ForceRedraw(&lpOutlineDoc->m_heading, fErase); +} + + +/* OutlineDoc_RenderFormat + * ----------------------- + * + * Render a clipboard format supported by ClipboardDoc + */ +void OutlineDoc_RenderFormat(LPOUTLINEDOC lpOutlineDoc, UINT uFormat) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HGLOBAL hData = NULL; + + if (uFormat == lpOutlineApp->m_cfOutline) + hData = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL); + + else if (uFormat == CF_TEXT) + hData = OutlineDoc_GetTextData(lpOutlineDoc, NULL); + + else { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFormatNotSupported); + return; + } + + SetClipboardData(uFormat, hData); +} + + +/* OutlineDoc_RenderAllFormats + * --------------------------- + * + * Render all formats supported by ClipboardDoc + */ +void OutlineDoc_RenderAllFormats(LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HGLOBAL hData = NULL; + + OpenClipboard(lpOutlineDoc->m_hWndDoc); + + hData = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL); + SetClipboardData(lpOutlineApp->m_cfOutline, hData); + + hData = OutlineDoc_GetTextData(lpOutlineDoc, NULL); + SetClipboardData(CF_TEXT, hData); + + CloseClipboard(); +} + + + +/* OutlineDoc_GetOutlineData + * ------------------------- + * + * Return a handle to an array of TextLine objects for the desired line + * range. + * NOTE: if lplrSel == NULL, then all lines are returned + * + */ +HGLOBAL OutlineDoc_GetOutlineData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel) +{ + HGLOBAL hOutline = NULL; + LPLINELIST lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList; + LPLINE lpLine; + LPTEXTLINE arrLine; + int i; + int nStart = (lplrSel ? lplrSel->m_nStartLine : 0); + int nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1); + int nLines = nEnd - nStart + 1; + int nCopied = 0; + + hOutline=GlobalAlloc(GMEM_SHARE | GMEM_ZEROINIT,sizeof(TEXTLINE)*nLines); + + if (! hOutline) return NULL; + + arrLine=(LPTEXTLINE)GlobalLock(hOutline); + + for (i = nStart; i <= nEnd; i++) { + lpLine=LineList_GetLine(lpLL, i); + if (lpLine && Line_GetOutlineData(lpLine, &arrLine[nCopied])) + nCopied++; + } + + GlobalUnlock(hOutline); + + return hOutline; +} + + + +/* OutlineDoc_GetTextData + * ---------------------- + * + * Return a handle to an object's data in text form for the desired line + * range. + * NOTE: if lplrSel == NULL, then all lines are returned + * + */ +HGLOBAL OutlineDoc_GetTextData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel) +{ + LPLINELIST lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList; + LPLINE lpLine; + HGLOBAL hText = NULL; + LPSTR lpszText = NULL; + DWORD dwMemSize=0; + int i,j; + int nStart = (lplrSel ? lplrSel->m_nStartLine : 0); + int nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1); + int nTabLevel; + + // calculate memory size required + for(i = nStart; i <= nEnd; i++) { + lpLine=LineList_GetLine(lpLL, i); + if (! lpLine) + continue; + + dwMemSize += Line_GetTabLevel(lpLine); + dwMemSize += Line_GetTextLen(lpLine); + + dwMemSize += 2; // add 1 for '\r\n' at the end of each line + } + dwMemSize++; // add 1 for '\0' at the end of string + + if(!(hText = GlobalAlloc(GMEM_SHARE | GMEM_ZEROINIT, dwMemSize))) + return NULL; + + if(!(lpszText = (LPSTR)GlobalLock(hText))) + return NULL; + + // put line text to memory + for(i = nStart; i <= nEnd; i++) { + lpLine=LineList_GetLine(lpLL, i); + if (! lpLine) + continue; + + nTabLevel=Line_GetTabLevel(lpLine); + for(j = 0; j < nTabLevel; j++) + *lpszText++='\t'; + + Line_GetTextData(lpLine, lpszText); + while(*lpszText) + lpszText++; // advance to end of string + + *lpszText++ = '\r'; + *lpszText++ = '\n'; + } + + GlobalUnlock (hText); + + return hText; +} + + +/* OutlineDoc_SaveToFile + * --------------------- + * + * Save the document to a file with the same name as stored in the + * document + */ +BOOL OutlineDoc_SaveToFile(LPOUTLINEDOC lpOutlineDoc, LPCSTR lpszFileName, UINT uFormat, BOOL fRemember) +{ +#if defined( OLE_CNTR ) + // Call OLE container specific function instead + return ContainerDoc_SaveToFile( + (LPCONTAINERDOC)lpOutlineDoc, + lpszFileName, + uFormat, + fRemember + ); + +#else + + LPSTORAGE lpDestStg = NULL; + HRESULT hrErr; + BOOL fStatus; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + + if (fRemember) { + if (lpszFileName) { + fStatus = OutlineDoc_SetFileName( + lpOutlineDoc, + (LPSTR)lpszFileName, + NULL + ); + if (! fStatus) goto error; + } else + lpszFileName = lpOutlineDoc->m_szFileName; // use cur. file name + } else if (! lpszFileName) { + goto error; + } + + hrErr = StgCreateDocfileA( + lpszFileName, + STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_CREATE, + 0, + &lpDestStg + ); + + OleDbgAssertSz(hrErr == NOERROR, "Could not create Docfile"); + if (hrErr != NOERROR) + goto error; + +#if defined( OLE_SERVER ) + + /* OLE2NOTE: we must be sure to write our class ID into our + ** storage. this information is used by OLE to determine the + ** class of the data stored in our storage. Even for top + ** "file-level" objects this information should be written to + ** the file. + */ + if(WriteClassStg(lpDestStg, &CLSID_APP) != NOERROR) + goto error; +#endif + + fStatus = OutlineDoc_SaveSelToStg( + lpOutlineDoc, + NULL, + uFormat, + lpDestStg, + FALSE, /* fSameAsLoad */ + fRemember + ); + if (! fStatus) goto error; + + OleStdRelease((LPUNKNOWN)lpDestStg); + + if (fRemember) + OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE); + +#if defined( OLE_SERVER ) + + /* OLE2NOTE: (SERVER-ONLY) inform any linking clients that the + ** document has been saved. in addition, any currently active + ** pseudo objects should also inform their clients. + */ + ServerDoc_SendAdvise ( + (LPSERVERDOC)lpOutlineDoc, + OLE_ONSAVE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- not relevant here */ + ); + +#endif + + return TRUE; + +error: + if (lpDestStg) + OleStdRelease((LPUNKNOWN)lpDestStg); + + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgSaving); + return FALSE; + +#endif // ! OLE_CNTR +} + + +/* OutlineDoc_LoadFromFile + * ----------------------- + * + * Load a document from a file + */ +BOOL OutlineDoc_LoadFromFile(LPOUTLINEDOC lpOutlineDoc, LPSTR lpszFileName) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + HRESULT hrErr; + SCODE sc; + LPSTORAGE lpSrcStg; + BOOL fStatus; + + hrErr = StgOpenStorageA(lpszFileName, + NULL, +#if defined( OLE_CNTR ) + STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE, +#else + STGM_READ | STGM_SHARE_DENY_WRITE, +#endif + NULL, + 0, + &lpSrcStg + ); + + if ((sc = GetScode(hrErr)) == STG_E_FILENOTFOUND) { + OutlineApp_ErrorMessage(lpOutlineApp, "File not found"); + return FALSE; + } else if (sc == STG_E_FILEALREADYEXISTS) { + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFormat); + return FALSE; + } else if (sc != S_OK) { + OleDbgOutScode("StgOpenStorage returned", sc); + OutlineApp_ErrorMessage( + lpOutlineApp, + "File already in use--could not be opened" + ); + return FALSE; + } + + if(! OutlineDoc_LoadFromStg(lpOutlineDoc, lpSrcStg)) goto error; + + fStatus = OutlineDoc_SetFileName(lpOutlineDoc, lpszFileName, lpSrcStg); + if (! fStatus) goto error; + + OleStdRelease((LPUNKNOWN)lpSrcStg); + + return TRUE; + +error: + OleStdRelease((LPUNKNOWN)lpSrcStg); + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgOpening); + return FALSE; +} + + + +/* OutlineDoc_LoadFromStg + * ---------------------- + * + * Load entire document from an open IStorage pointer (lpSrcStg) + * Return TRUE if ok, FALSE if error. + */ +BOOL OutlineDoc_LoadFromStg(LPOUTLINEDOC lpOutlineDoc, LPSTORAGE lpSrcStg) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HRESULT hrErr; + BOOL fStatus; + ULONG nRead; + LINERANGE lrSel = { 0, 0 }; + LPSTREAM lpLLStm; + OUTLINEDOCHEADER_ONDISK docRecordOnDisk; + OUTLINEDOCHEADER docRecord; + + hrErr = CallIStorageOpenStreamA( + lpSrcStg, + "LineList", + NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, + 0, + &lpLLStm + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("Open LineList Stream returned", hrErr); + goto error; + } + + /* read OutlineDoc header record */ + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&docRecordOnDisk, + sizeof(docRecordOnDisk), + &nRead + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("Read OutlineDoc header returned", hrErr); + goto error; + } + + // Transform docRecordOnDisk into docRecord + // Compilers should handle aligment correctly + strcpy(docRecord.m_szFormatName, docRecordOnDisk.m_szFormatName); + docRecord.m_narrAppVersionNo[0] = (int) docRecordOnDisk.m_narrAppVersionNo[0]; + docRecord.m_narrAppVersionNo[1] = (int) docRecordOnDisk.m_narrAppVersionNo[1]; + docRecord.m_fShowHeading = (BOOL) docRecordOnDisk.m_fShowHeading; + docRecord.m_reserved1 = docRecordOnDisk.m_reserved1; + docRecord.m_reserved2 = docRecordOnDisk.m_reserved2; + docRecord.m_reserved3 = docRecordOnDisk.m_reserved3; + docRecord.m_reserved4 = docRecordOnDisk.m_reserved4; + + fStatus = OutlineApp_VersionNoCheck( + lpOutlineApp, + docRecord.m_szFormatName, + docRecord.m_narrAppVersionNo + ); + + /* storage is an incompatible version; file can not be read */ + if (! fStatus) + goto error; + + lpOutlineDoc->m_heading.m_fShow = docRecord.m_fShowHeading; + +#if defined( OLE_SERVER ) + { + // Load ServerDoc specific data + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; +#if defined( SVR_TREATAS ) + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + CLSID clsid; + CLIPFORMAT cfFmt; + LPSTR lpszType; +#endif // SVR_TREATAS + + lpServerDoc->m_nNextRangeNo = (ULONG)docRecord.m_reserved1; + +#if defined( SVR_TREATAS ) + /* OLE2NOTE: if the Server is capable of supporting "TreatAs" + ** (aka. ActivateAs), it must read the class that is written + ** into the storage. if this class is NOT the app's own + ** class ID, then this is a TreatAs operation. the server + ** then must faithfully pretend to be the class that is + ** written into the storage. it must also faithfully write + ** the data back to the storage in the SAME format as is + ** written in the storage. + ** + ** SVROUTL and ISVROTL can emulate each other. they have the + ** simplification that they both read/write the identical + ** format. thus for these apps no actual conversion of the + ** native bits is actually required. + */ + lpServerDoc->m_clsidTreatAs = CLSID_NULL; + if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpSrcStg, &clsid, + (CLIPFORMAT FAR*)&cfFmt, (LPSTR FAR*)&lpszType)) { + + if (cfFmt == lpOutlineApp->m_cfOutline) { + // We should perform TreatAs operation + if (lpServerDoc->m_lpszTreatAsType) + OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL); + + lpServerDoc->m_clsidTreatAs = clsid; + ((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt; + lpServerDoc->m_lpszTreatAsType = lpszType; + + OleDbgOut3("OutlineDoc_LoadFromStg: TreateAs ==> '"); + OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType); + OleDbgOutNoPrefix3("'\r\n"); + } else { + // ERROR: we ONLY support TreatAs for CF_OUTLINE format + OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Format\r\n"); + OleStdFreeString(lpszType, NULL); + } + } +#endif // SVR_TREATAS + } +#endif // OLE_SVR +#if defined( OLE_CNTR ) + { + // Load ContainerDoc specific data + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + + lpContainerDoc->m_nNextObjNo = (ULONG)docRecord.m_reserved2; + } +#endif // OLE_CNTR + + OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE ); + + if(! LineList_LoadFromStg(&lpOutlineDoc->m_LineList, lpSrcStg, lpLLStm)) + goto error; + if(! OutlineNameTable_LoadFromStg(lpOutlineDoc->m_lpNameTable, lpSrcStg)) + goto error; + + OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE); + OutlineDoc_SetSel(lpOutlineDoc, &lrSel); + + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + + OleStdRelease((LPUNKNOWN)lpLLStm); + +#if defined( OLE_CNTR ) + { + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + + /* A ContainerDoc keeps its storage open at all times. it is necessary + * to AddRef the lpSrcStg in order to hang on to it. + */ + if (lpOleDoc->m_lpStg) { + OleStdVerifyRelease((LPUNKNOWN)lpOleDoc->m_lpStg, + "Doc Storage not released properly"); + } + lpSrcStg->lpVtbl->AddRef(lpSrcStg); + lpOleDoc->m_lpStg = lpSrcStg; + } +#endif // OLE_CNTR + + return TRUE; + +error: + OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE ); + if (lpLLStm) + OleStdRelease((LPUNKNOWN)lpLLStm); + return FALSE; +} + +BOOL Booga(void) +{ + return FALSE; +} + + +/* OutlineDoc_SaveSelToStg + * ----------------------- + * + * Save the specified selection of document into an IStorage*. All lines + * within the selection along with any names completely contained within the + * selection will be written + * + * Return TRUE if ok, FALSE if error + */ +BOOL OutlineDoc_SaveSelToStg( + LPOUTLINEDOC lpOutlineDoc, + LPLINERANGE lplrSel, + UINT uFormat, + LPSTORAGE lpDestStg, + BOOL fSameAsLoad, + BOOL fRemember +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HRESULT hrErr = NOERROR; + LPSTREAM lpLLStm = NULL; + LPSTREAM lpNTStm = NULL; + ULONG nWritten; + BOOL fStatus; + OUTLINEDOCHEADER docRecord; + OUTLINEDOCHEADER_ONDISK docRecordOnDisk; + HCURSOR hPrevCursor; + +#if defined( OLE_VERSION ) + LPSTR lpszUserType; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc; + + /* OLE2NOTE: we must be sure to write the information required for + ** OLE into our docfile. this includes user type + ** name, data format, etc. Even for top "file-level" objects + ** this information should be written to the file. Both + ** containters and servers should write this information. + */ + +#if defined( OLE_SERVER ) && defined( SVR_TREATAS ) + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + + /* OLE2NOTE: if the Server is emulating another class (ie. + ** "TreatAs" aka. ActivateAs), it must write the same user type + ** name and format that was was originally written into the + ** storage rather than its own user type name. + ** + ** SVROUTL and ISVROTL can emulate each other. they have the + ** simplification that they both read/write the identical + ** format. thus for these apps no actual conversion of the + ** native bits is actually required. + */ + if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL)) + lpszUserType = lpServerDoc->m_lpszTreatAsType; + else +#endif // OLE_SERVER && SVR_TREATAS + + lpszUserType = (LPSTR)FULLUSERTYPENAME; + + hrErr = WriteFmtUserTypeStgA(lpDestStg, (CLIPFORMAT) uFormat, + lpszUserType); + + if(hrErr != NOERROR) goto error; + + if (fSameAsLoad) { + /* OLE2NOTE: we are saving into to same storage that we were + ** passed an load time. we deliberatly opened the streams we + ** need (lpLLStm and lpNTStm) at load time, so that we can + ** robustly save at save time in a low-memory situation. + ** this is particulary important the embedded objects do NOT + ** consume additional memory when + ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. + */ + LARGE_INTEGER libZero; + ULARGE_INTEGER ulibZero; + LISet32( libZero, 0 ); + LISet32( ulibZero, 0 ); + lpLLStm = lpOleDoc->m_lpLLStm; + + /* because this is the fSameAsLoad==TRUE case, we will save + ** into the streams that we hold open. we will AddRef the + ** stream here so that the release below will NOT close the + ** stream. + */ + lpLLStm->lpVtbl->AddRef(lpLLStm); + + // truncate the current stream and seek to beginning + lpLLStm->lpVtbl->SetSize(lpLLStm, ulibZero); + lpLLStm->lpVtbl->Seek( + lpLLStm, libZero, STREAM_SEEK_SET, NULL); + + lpNTStm = lpOleDoc->m_lpNTStm; + lpNTStm->lpVtbl->AddRef(lpNTStm); // (see comment above) + + // truncate the current stream and seek to beginning + lpNTStm->lpVtbl->SetSize(lpNTStm, ulibZero); + lpNTStm->lpVtbl->Seek( + lpNTStm, libZero, STREAM_SEEK_SET, NULL); + } else +#endif // OLE_VERSION + { + hrErr = CallIStorageCreateStreamA( + lpDestStg, + "LineList", + STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, + 0, + &lpLLStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream"); + OleDbgOutHResult("LineList CreateStream returned", hrErr); + goto error; + } + + hrErr = CallIStorageCreateStreamA( + lpDestStg, + "NameTable", + STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, + 0, + &lpNTStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream"); + OleDbgOutHResult("NameTable CreateStream returned", hrErr); + goto error; + } + } + + // this may take a while, put up hourglass cursor + hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + _fmemset((LPOUTLINEDOCHEADER)&docRecord,0,sizeof(OUTLINEDOCHEADER)); + GetClipboardFormatName( + uFormat, + docRecord.m_szFormatName, + sizeof(docRecord.m_szFormatName) + ); + OutlineApp_GetAppVersionNo(lpOutlineApp, docRecord.m_narrAppVersionNo); + + docRecord.m_fShowHeading = lpOutlineDoc->m_heading.m_fShow; + +#if defined( OLE_SERVER ) + { + // Store ServerDoc specific data + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; + + docRecord.m_reserved1 = (DWORD)lpServerDoc->m_nNextRangeNo; + } +#endif +#if defined( OLE_CNTR ) + { + // Store ContainerDoc specific data + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc; + + docRecord.m_reserved2 = (DWORD)lpContainerDoc->m_nNextObjNo; + } +#endif + + /* write OutlineDoc header record */ + + // Transform docRecord into docRecordOnDisk + // Compilers should handle aligment correctly + strcpy(docRecordOnDisk.m_szFormatName, docRecord.m_szFormatName); + docRecordOnDisk.m_narrAppVersionNo[0] = (short) docRecord.m_narrAppVersionNo[0]; + docRecordOnDisk.m_narrAppVersionNo[1] = (short) docRecord.m_narrAppVersionNo[1]; + docRecordOnDisk.m_fShowHeading = (USHORT) docRecord.m_fShowHeading; + docRecordOnDisk.m_reserved1 = docRecord.m_reserved1; + docRecordOnDisk.m_reserved2 = docRecord.m_reserved2; + docRecordOnDisk.m_reserved3 = docRecord.m_reserved3; + docRecordOnDisk.m_reserved4 = docRecord.m_reserved4; + + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&docRecordOnDisk, + sizeof(docRecordOnDisk), + &nWritten + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("Write OutlineDoc header returned", hrErr); + goto error; + } + + // Save LineList + /* OLE2NOTE: A ContainerDoc keeps its storage open at all times. It is + ** necessary to pass the current open storage (lpOleDoc->m_lpStg) + ** to the LineList_SaveSelToStg method so that currently written data + ** for any embeddings is also saved to the new destination + ** storage. The data required by a contained object is both the + ** ContainerLine information and the associated sub-storage that is + ** written directly by the embedded object. + */ + fStatus = LineList_SaveSelToStg( + &lpOutlineDoc->m_LineList, + lplrSel, + uFormat, +#if defined( OLE_CNTR ) + lpOleDoc->m_lpStg, +#else + NULL, +#endif + lpDestStg, + lpLLStm, + fRemember + ); + if (! fStatus) goto error; + + // Save associated NameTable + fStatus = OutlineNameTable_SaveSelToStg( + lpOutlineDoc->m_lpNameTable, + lplrSel, + uFormat, + lpNTStm + ); + + if (! fStatus) goto error; + + OleStdRelease((LPUNKNOWN)lpLLStm); + lpOutlineDoc->m_cfSaveFormat = uFormat; // remember format used to save + + SetCursor(hPrevCursor); // restore original cursor + return TRUE; + +error: + if (lpLLStm) + OleStdRelease((LPUNKNOWN)lpLLStm); + + SetCursor(hPrevCursor); // restore original cursor + return FALSE; +} + + +/* OutlineDoc_Print + * ---------------- + * Prints the contents of the list box in HIMETRIC mapping mode. Origin + * remains to be the upper left corner and the print proceeds down the + * page using a negative y-cordinate. + * + */ +void OutlineDoc_Print(LPOUTLINEDOC lpOutlineDoc, HDC hDC) +{ + LPLINELIST lpLL = &lpOutlineDoc->m_LineList; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + WORD nIndex; + WORD nTotal; + int dy; + BOOL fError = FALSE; + LPLINE lpLine; + RECT rcLine; + RECT rcPix; + RECT rcHim; + RECT rcWindowOld; + RECT rcViewportOld; + HFONT hOldFont; + DOCINFO di; /* Document information for StartDoc function */ + + /* Get dimension of page */ + rcPix.left = 0; + rcPix.top = 0; + rcPix.right = GetDeviceCaps(hDC, HORZRES); + rcPix.bottom = GetDeviceCaps(hDC, VERTRES); + + SetDCToDrawInHimetricRect(hDC, (LPRECT)&rcPix, (LPRECT)&rcHim, + (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld); + + // Set the default font size, and font face name + hOldFont = SelectObject(hDC, lpOutlineApp->m_hStdFont); + + /* Get the lines in document */ + nIndex = 0; + nTotal = LineList_GetCount(lpLL); + + /* Create the Cancel dialog */ + // REVIEW: should load dialog title from string resource file + hWndPDlg = CreateDialog ( + lpOutlineApp->m_hInst, + "Print", + lpOutlineApp->m_hWndApp, + (DLGPROC)PrintDlgProc + ); + + if(!hWndPDlg) + goto getout; + + /* Allow the app. to inform GDI of the abort function to call */ + if(SetAbortProc(hDC, (ABORTPROC)AbortProc) < 0) { + fError = TRUE; + goto getout3; + } + + /* Disable the main application window */ + EnableWindow (lpOutlineApp->m_hWndApp, FALSE); + + // initialize the rectangle for the first line + rcLine.left = rcHim.left; + rcLine.bottom = rcHim.top; + + /* Initialize the document */ + fCancelPrint = FALSE; + + di.cbSize = sizeof(di); + di.lpszDocName = lpOutlineDoc->m_lpszDocTitle; + di.lpszOutput = NULL; + + if(StartDoc(hDC, (DOCINFO FAR*)&di) <= 0) { + fError = TRUE; + OleDbgOut2("StartDoc error\n"); + goto getout5; + } + + if(StartPage(hDC) <= 0) { // start first page + fError = TRUE; + OleDbgOut2("StartPage error\n"); + goto getout2; + } + + /* While more lines print out the text */ + while(nIndex < nTotal) { + lpLine = LineList_GetLine(lpLL, nIndex); + if (! lpLine) + continue; + + dy = Line_GetHeightInHimetric(lpLine); + + /* Reached end of page. Tell the device driver to eject a page */ + if(rcLine.bottom - dy < rcHim.bottom) { + if (EndPage(hDC) < 0) { + fError=TRUE; + OleDbgOut2("EndPage error\n"); + goto getout2; + } + + // NOTE: Reset the Mapping mode of DC + SetDCToDrawInHimetricRect(hDC, (LPRECT)&rcPix, (LPRECT)&rcHim, + (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld); + + // Set the default font size, and font face name + SelectObject(hDC, lpOutlineApp->m_hStdFont); + + if (StartPage(hDC) <= 0) { + fError=TRUE; + OleDbgOut2("StartPage error\n"); + goto getout2; + } + + rcLine.bottom = rcHim.top; + } + + rcLine.top = rcLine.bottom; + rcLine.bottom -= dy; + rcLine.right = rcLine.left + Line_GetWidthInHimetric(lpLine); + + /* Print the line */ + Line_Draw(lpLine, hDC, &rcLine, NULL, FALSE /*fHighlight*/); + + OleDbgOut2("a line is drawn\n"); + + /* Test and see if the Abort flag has been set. If yes, exit. */ + if (fCancelPrint) + goto getout2; + + /* Move down the page */ + nIndex++; + } + + { + int nCode; + + /* Eject the last page. */ + if((nCode = EndPage(hDC)) < 0) { +#if defined( _DEBUG ) + char szBuf[255]; + wsprintf(szBuf, "EndPage error code is %d\n", nCode); + OleDbgOut2(szBuf); +#endif + fError=TRUE; + goto getout2; + } + } + + + /* Complete the document. */ + if(EndDoc(hDC) < 0) { + fError=TRUE; + OleDbgOut2("EndDoc error\n"); + +getout2: + /* Ran into a problem before NEWFRAME? Abort the document */ + AbortDoc(hDC); + } + +getout5: + /* Re-enable main app. window */ + EnableWindow (lpOutlineApp->m_hWndApp, TRUE); + +getout3: + /* Close the cancel dialog */ + DestroyWindow (hWndPDlg); + +getout: + + /* Error? make sure the user knows... */ + if(fError || CommDlgExtendedError()) + OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPrint); + + SelectObject(hDC, hOldFont); +} + + + + + +/* OutlineDoc_DialogHelp + * --------------------- + * + * Show help message for ole2ui dialogs. + * + * Parameters: + * + * hDlg HWND to the dialog the help message came from - use + * this in the call to WinHelp/MessageBox so that + * activation/focus goes back to the dialog, and not the + * main window. + * + * wParam ID of the dialog (so we know what type of dialog it is). + */ +void OutlineDoc_DialogHelp(HWND hDlg, WPARAM wDlgID) +{ + + char szMessageBoxText[64]; + + if (!IsWindow(hDlg)) // don't do anything if we've got a bogus hDlg. + return; + + lstrcpy(szMessageBoxText, "Help Message for "); + + switch (wDlgID) + { + + case IDD_CONVERT: + lstrcat(szMessageBoxText, "Convert"); + break; + + case IDD_CHANGEICON: + lstrcat(szMessageBoxText, "Change Icon"); + break; + + case IDD_INSERTOBJECT: + lstrcat(szMessageBoxText, "Insert Object"); + break; + + case IDD_PASTESPECIAL: + lstrcat(szMessageBoxText, "Paste Special"); + break; + + case IDD_EDITLINKS: + lstrcat(szMessageBoxText, "Edit Links"); + break; + + case IDD_CHANGESOURCE: + lstrcat(szMessageBoxText, "Change Source"); + break; + + case IDD_INSERTFILEBROWSE: + lstrcat(szMessageBoxText, "Insert From File Browse"); + break; + + case IDD_CHANGEICONBROWSE: + lstrcat(szMessageBoxText, "Change Icon Browse"); + break; + + default: + lstrcat(szMessageBoxText, "Unknown"); + break; + } + + lstrcat(szMessageBoxText, " Dialog."); + + // You'd probably really a call to WinHelp here. + MessageBox(hDlg, szMessageBoxText, "Help", MB_OK); + + return; +} + + +/* OutlineDoc_SetCurrentZoomCommand + * -------------------------------- + * + * Set current zoom level to be checked in the menu. + * Set the corresponding scalefactor for the document. + */ +void OutlineDoc_SetCurrentZoomCommand( + LPOUTLINEDOC lpOutlineDoc, + UINT uCurrentZoom +) +{ + SCALEFACTOR scale; + + if (!lpOutlineDoc) + return; + + lpOutlineDoc->m_uCurrentZoom = uCurrentZoom; + + switch (uCurrentZoom) { + +#if !defined( OLE_CNTR ) + case IDM_V_ZOOM_400: + scale.dwSxN = (DWORD) 4; + scale.dwSxD = (DWORD) 1; + scale.dwSyN = (DWORD) 4; + scale.dwSyD = (DWORD) 1; + break; + + case IDM_V_ZOOM_300: + scale.dwSxN = (DWORD) 3; + scale.dwSxD = (DWORD) 1; + scale.dwSyN = (DWORD) 3; + scale.dwSyD = (DWORD) 1; + break; + + case IDM_V_ZOOM_200: + scale.dwSxN = (DWORD) 2; + scale.dwSxD = (DWORD) 1; + scale.dwSyN = (DWORD) 2; + scale.dwSyD = (DWORD) 1; + break; +#endif // !OLE_CNTR + + case IDM_V_ZOOM_100: + scale.dwSxN = (DWORD) 1; + scale.dwSxD = (DWORD) 1; + scale.dwSyN = (DWORD) 1; + scale.dwSyD = (DWORD) 1; + break; + + case IDM_V_ZOOM_75: + scale.dwSxN = (DWORD) 3; + scale.dwSxD = (DWORD) 4; + scale.dwSyN = (DWORD) 3; + scale.dwSyD = (DWORD) 4; + break; + + case IDM_V_ZOOM_50: + scale.dwSxN = (DWORD) 1; + scale.dwSxD = (DWORD) 2; + scale.dwSyN = (DWORD) 1; + scale.dwSyD = (DWORD) 2; + break; + + case IDM_V_ZOOM_25: + scale.dwSxN = (DWORD) 1; + scale.dwSxD = (DWORD) 4; + scale.dwSyN = (DWORD) 1; + scale.dwSyD = (DWORD) 4; + break; + } + + OutlineDoc_SetScaleFactor(lpOutlineDoc, (LPSCALEFACTOR)&scale, NULL); +} + + +/* OutlineDoc_GetCurrentZoomMenuCheck + * ---------------------------------- + * + * Get current zoom level to be checked in the menu. + */ +UINT OutlineDoc_GetCurrentZoomMenuCheck(LPOUTLINEDOC lpOutlineDoc) +{ + return lpOutlineDoc->m_uCurrentZoom; +} + + +/* OutlineDoc_SetScaleFactor + * ------------------------- + * + * Set the scale factor of the document which will affect the + * size of the document on the screen + * + * Parameters: + * + * scale structure containing x and y scales + */ +void OutlineDoc_SetScaleFactor( + LPOUTLINEDOC lpOutlineDoc, + LPSCALEFACTOR lpscale, + LPRECT lprcDoc +) +{ + LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + HWND hWndLL = LineList_GetWindow(lpLL); + + if (!lpOutlineDoc || !lpscale) + return; + + InvalidateRect(hWndLL, NULL, TRUE); + + lpOutlineDoc->m_scale = *lpscale; + LineList_ReScale((LPLINELIST)&lpOutlineDoc->m_LineList, lpscale); + +#if defined( USE_HEADING ) + Heading_ReScale((LPHEADING)&lpOutlineDoc->m_heading, lpscale); +#endif + + OutlineDoc_Resize(lpOutlineDoc, lprcDoc); +} + + +/* OutlineDoc_GetScaleFactor + * ------------------------- + * + * Retrieve the scale factor of the document + * + * Parameters: + * + */ +LPSCALEFACTOR OutlineDoc_GetScaleFactor(LPOUTLINEDOC lpOutlineDoc) +{ + if (!lpOutlineDoc) + return NULL; + + return (LPSCALEFACTOR)&lpOutlineDoc->m_scale; +} + + +/* OutlineDoc_SetCurrentMarginCommand + * ---------------------------------- + * + * Set current Margin level to be checked in the menu. + */ +void OutlineDoc_SetCurrentMarginCommand( + LPOUTLINEDOC lpOutlineDoc, + UINT uCurrentMargin +) +{ + if (!lpOutlineDoc) + return; + + lpOutlineDoc->m_uCurrentMargin = uCurrentMargin; + + switch (uCurrentMargin) { + case IDM_V_SETMARGIN_0: + OutlineDoc_SetMargin(lpOutlineDoc, 0, 0); + break; + + case IDM_V_SETMARGIN_1: + OutlineDoc_SetMargin(lpOutlineDoc, 1000, 1000); + break; + + case IDM_V_SETMARGIN_2: + OutlineDoc_SetMargin(lpOutlineDoc, 2000, 2000); + break; + + case IDM_V_SETMARGIN_3: + OutlineDoc_SetMargin(lpOutlineDoc, 3000, 3000); + break; + + case IDM_V_SETMARGIN_4: + OutlineDoc_SetMargin(lpOutlineDoc, 4000, 4000); + break; + } +} + + +/* OutlineDoc_GetCurrentMarginMenuCheck + * ------------------------------------ + * + * Get current Margin level to be checked in the menu. + */ +UINT OutlineDoc_GetCurrentMarginMenuCheck(LPOUTLINEDOC lpOutlineDoc) +{ + return lpOutlineDoc->m_uCurrentMargin; +} + + +/* OutlineDoc_SetMargin + * -------------------- + * + * Set the left and right margin of the document + * + * Parameters: + * nLeftMargin - left margin in Himetric values + * nRightMargin - right margin in Himetric values + */ +void OutlineDoc_SetMargin(LPOUTLINEDOC lpOutlineDoc, int nLeftMargin, int nRightMargin) +{ + LPLINELIST lpLL; + int nMaxWidthInHim; + + if (!lpOutlineDoc) + return; + + lpOutlineDoc->m_nLeftMargin = nLeftMargin; + lpOutlineDoc->m_nRightMargin = nRightMargin; + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + + // Force recalculation of Horizontal extent + nMaxWidthInHim = LineList_GetMaxLineWidthInHimetric(lpLL); + LineList_SetMaxLineWidthInHimetric(lpLL, -nMaxWidthInHim); + +#if defined( INPLACE_CNTR ) + ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0); +#endif + + OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE); +} + + +/* OutlineDoc_GetMargin + * -------------------- + * + * Get the left and right margin of the document + * + * Parameters: + * nLeftMargin - left margin in Himetric values + * nRightMargin - right margin in Himetric values + * + * Returns: + * low order word - left margin + * high order word - right margin + */ +LONG OutlineDoc_GetMargin(LPOUTLINEDOC lpOutlineDoc) +{ + if (!lpOutlineDoc) + return 0; + + return MAKELONG(lpOutlineDoc->m_nLeftMargin, lpOutlineDoc->m_nRightMargin); +} + +#if defined( USE_HEADING ) + +/* OutlineDoc_GetHeading + * --------------------- + * + * Get Heading Object in OutlineDoc + */ +LPHEADING OutlineDoc_GetHeading(LPOUTLINEDOC lpOutlineDoc) +{ + if (!lpOutlineDoc || lpOutlineDoc->m_fDataTransferDoc) + return NULL; + else + return (LPHEADING)&lpOutlineDoc->m_heading; +} + + +/* OutlineDoc_ShowHeading + * ---------------------- + * + * Show/Hide document row/column headings. + */ +void OutlineDoc_ShowHeading(LPOUTLINEDOC lpOutlineDoc, BOOL fShow) +{ + LPHEADING lphead = OutlineDoc_GetHeading(lpOutlineDoc); +#if defined( INPLACE_SVR ) + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc; +#endif + + if (! lphead) + return; + + Heading_Show(lphead, fShow); + +#if defined( INPLACE_SVR ) + if (lpServerDoc->m_fUIActive) { + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + + /* OLE2NOTE: our extents have NOT changed; only our the size of + ** our object-frame adornments is changing. we can use the + ** current PosRect and ClipRect and simply resize our + ** windows WITHOUT informing our in-place container. + */ + ServerDoc_ResizeInPlaceWindow( + lpServerDoc, + (LPRECT)&(lpIPData->rcPosRect), + (LPRECT)&(lpIPData->rcClipRect) + ); + } else +#else // !INPLACE_SVR + + OutlineDoc_Resize(lpOutlineDoc, NULL); + +#if defined( INPLACE_CNTR ) + ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0); +#endif // INPLACE_CNTR + +#endif // INPLACE_SVR + + OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE); +} + +#endif // USE_HEADING + + +/* AbortProc + * --------- + * AborProc is called by GDI print code to check for user abort. + */ +BOOL FAR PASCAL EXPORT AbortProc (HDC hdc, WORD reserved) +{ + MSG msg; + + /* Allow other apps to run, or get abort messages */ + while(! fCancelPrint && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { + if(!hWndPDlg || !IsDialogMessage (hWndPDlg, &msg)) { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + return !fCancelPrint; +} + + +/* PrintDlgProc + * ------------ + * Dialog function for the print cancel dialog box. + * + * RETURNS : TRUE - OK to abort/ not OK to abort + * FALSE - otherwise. + */ +BOOL FAR PASCAL EXPORT PrintDlgProc( + HWND hwnd, + WORD msg, + WORD wParam, + LONG lParam +) +{ + switch (msg) { + case WM_COMMAND: + /* abort printing if the only button gets hit */ + fCancelPrint = TRUE; + return TRUE; + } + + return FALSE; +} diff --git a/private/oleutest/letest/outline/outline.h b/private/oleutest/letest/outline/outline.h new file mode 100644 index 000000000..4c3f4b88c --- /dev/null +++ b/private/oleutest/letest/outline/outline.h @@ -0,0 +1,790 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outline.h +** +** This file contains file contains data structure defintions, +** function prototypes, constants, etc. used by the Outline series +** of sample applications: +** Outline -- base version of the app (without OLE functionality) +** SvrOutl -- OLE 2.0 Server sample app +** CntrOutl -- OLE 2.0 Containter (Container) sample app +** ISvrOtl -- OLE 2.0 Server sample app +** CntrOutl -- OLE 2.0 Containter (Container) sample app +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +** For structures which we read from and write to disk we define shadow +** structures (with the _ONDISK suffix) that allow us to maintain +** 16-bit Windows and Macintosh compatibility. +** +*************************************************************************/ + +#if !defined( _OUTLINE_H_ ) +#define _OUTLINE_H_ + +#include <testmess.h> + + +#if !defined( RC_INVOKED ) +#pragma message ("INCLUDING OUTLINE.H from " __FILE__) +#endif /* RC_INVOKED */ + +// use strict ANSI standard (for DVOBJ.H) +//#define NONAMELESSUNION + +// use system defined bitmap, this line must go before windows.h +#define OEMRESOURCE + +#ifdef WIN32 +#define _INC_OLE +// #define __RPC_H__ +#define EXPORT + +#define _fstrchr strchr + +#else +#define EXPORT _export +#endif + +#define SDI_VERSION 1 // ONLY SDI version is currently supported + +#if defined( OLE_SERVER ) || defined( OLE_CNTR ) +#define OLE_VERSION 1 +#define USE_DRAGDROP 1 // enable drag/drop code in OLE versions +#define USE_MSGFILTER 1 // enable IMessageFilter implementation +#endif + +#define USE_HEADING 1 // enable the row/col headings +#define USE_STATUSBAR 1 // enable status bar window +#define USE_FRAMETOOLS 1 // enable the toolbar +#ifndef WIN32 //BUGBUG32 +#define USE_CTL3D 1 // enable 3D looking dialogs +#endif + +#define STRICT 1 +#undef UNICODE +#include <windows.h> +#include <string.h> +#include <commdlg.h> +#include <ole2.h> +#include <ole2ui.h> +#include <olestr.h> +#include "outlrc.h" + + +#define APPMAJORVERSIONNO 3 // major no. incremented for major releases + // (eg. when an incompatible change is made + // to the storage format) +#define APPMINORVERSIONNO 5 // minor no. incremented for minor releases + + +/* Definition of SCALEFACTOR */ +typedef struct tagSCALEFACTOR { + ULONG dwSxN; // numerator in x direction + ULONG dwSxD; // denominator in x direction + ULONG dwSyN; // numerator in y direction + ULONG dwSyD; // denominator in y direction +} SCALEFACTOR, FAR* LPSCALEFACTOR; + + +#if defined( USE_FRAMETOOLS ) +#include "frametls.h" +#endif + +#if defined( USE_HEADING ) +#include "heading.h" +#endif + +/* max line height (in pixels) allowed in a listbox */ +#define LISTBOX_HEIGHT_LIMIT 255 + + +#define MAXSTRLEN 80 // max string len in bytes +#define MAXNAMESIZE 30 // max length of names +#define MAXFORMATSIZE 10 // max length of DEFDOCFORMAT (actually size is 5) +#define TABWIDTH 2000 // 2000 in Himetric units, i.e. 2cm +#define DEFFONTPTSIZE 12 +#define DEFFONTSIZE ((DEFFONTPTSIZE*HIMETRIC_PER_INCH)/PTS_PER_INCH) +#define DEFFONTFACE "Times New Roman" + +#define OUTLINEDOCFORMAT "Outline" // CF_Outline format name +#define IS_FILENAME_DELIM(c) ( (c) == '\\' || (c) == '/' || (c) == ':' ) +// REVIEW: some of these strings should be loaded from a resource file +#define UNTITLED "Outline" // title used for untitled document +#define HITTESTDELTA 5 + +/* Macro to get a random integer within a specified range */ +#define getrandom( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min)) + + +// REVIEW: should load strings from string resource file + +#define APPFILENAMEFILTER "Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|" +#define DEFEXTENSION "oln" // Default file extension + + +/* forward type references */ +typedef struct tagOUTLINEDOC FAR* LPOUTLINEDOC; +typedef struct tagTEXTLINE FAR* LPTEXTLINE; + + +typedef enum tagLINETYPE { + UNKNOWNLINETYPE, + TEXTLINETYPE, + CONTAINERLINETYPE +} LINETYPE; + + +/************************************************************************* +** class LINE +** The class LINE is an abstract base class. Instances of class LINE +** are NOT created; only instances of the concrete subclasses of +** LINE can be created. In the base app version and the OLE 2.0 +** server-only version only TEXTLINE objects can be created. In the +** OLE 2.0 client app version either TEXTLINE objects or CONTAINERLINE +** objects can be created. The LINE class has all fields and methods +** that are common independent of which subclass of LINE is used. +** Each LINE object that is created in added to the LINELIST of the +** OUTLINEDOC document. +*************************************************************************/ + +typedef struct tagLINE { + LINETYPE m_lineType; + UINT m_nTabLevel; + UINT m_nTabWidthInHimetric; + UINT m_nWidthInHimetric; + UINT m_nHeightInHimetric; + BOOL m_fSelected; // does line have selection feedback + +#if defined( USE_DRAGDROP ) + BOOL m_fDragOverLine; // does line have drop target feedback +#endif +} LINE, FAR* LPLINE; + +/* Line methods (functions) */ +void Line_Init(LPLINE lpLine, int nTab, HDC hDC); +void Line_Delete(LPLINE lpLine); +BOOL Line_CopyToDoc(LPLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex); +BOOL Line_Edit(LPLINE lpLine, HWND hWndDoc, HDC hDC); +void Line_Draw( + LPLINE lpLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight +); +void Line_DrawToScreen( + LPLINE lpLine, + HDC hDC, + LPRECT lprcPix, + UINT itemAction, + UINT itemState, + LPRECT lprcDevice +); +void Line_DrawSelHilight(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState); +void Line_DrawFocusRect(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState); +void Line_Unindent(LPLINE lpLine, HDC hDC); +void Line_Indent(LPLINE lpLine, HDC hDC); +LINETYPE Line_GetLineType(LPLINE lpLine); +UINT Line_GetTotalWidthInHimetric(LPLINE lpLine); +void Line_SetWidthInHimetric(LPLINE lpLine, int nWidth); +UINT Line_GetWidthInHimetric(LPLINE lpLine); +UINT Line_GetHeightInHimetric(LPLINE lpLine); +void Line_SetHeightInHimetric(LPLINE lpLine, int nHeight); +UINT Line_GetTabLevel(LPLINE lpLine); +int Line_GetTextLen(LPLINE lpLine); +void Line_GetTextData(LPLINE lpLine, LPSTR lpszBuf); +BOOL Line_GetOutlineData(LPLINE lpLine, LPTEXTLINE lpBuf); +int Line_CalcTabWidthInHimetric(LPLINE lpLine, HDC hDC); +BOOL Line_SaveToStg(LPLINE lpLine, UINT uFormat, LPSTORAGE lpSrcStg, LPSTORAGE lpDestStg, LPSTREAM lpLLStm, BOOL fRemember); +LPLINE Line_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc); +void Line_DrawDragFeedback(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemState ); +BOOL Line_IsSelected(LPLINE lpLine); + + +/************************************************************************* +** class TEXTLINE : LINE +** The class TEXTLINE is a concrete subclass of the abstract base +** class LINE. The TEXTLINE class holds a string that can be edited +** by the user. In the base app version and the OLE 2.0 +** server-only version only TEXTLINE objects can be created. In the +** OLE 2.0 client app version either TEXTLINE objects or CONTAINERLINE +** objects can be created. The TEXTLINE class inherits all fields +** from the LINE class. This inheritance is achieved by including a +** member variable of type LINE as the first field in the TEXTLINE +** structure. Thus a pointer to a TEXTLINE object can be cast to be +** a pointer to a LINE object. +** Each TEXTLINE object that is created in added to the LINELIST of +** the associated OUTLINEDOC document. +*************************************************************************/ + +typedef struct tagTEXTLINE { + LINE m_Line; // TextLine inherits all fields of Line + + UINT m_nLength; + char m_szText[MAXSTRLEN+1]; +} TEXTLINE; + +LPTEXTLINE TextLine_Create(HDC hDC, UINT nTab, LPSTR szText); +void TextLine_Init(LPTEXTLINE lpTextLine, int nTab, HDC hDC); +void TextLine_CalcExtents(LPTEXTLINE lpLine, HDC hDC); +void TextLine_SetHeightInHimetric(LPTEXTLINE lpTextLine, int nHeight); +void TextLine_Delete(LPTEXTLINE lpLine); +BOOL TextLine_Edit(LPTEXTLINE lpLine, HWND hWndDoc, HDC hDC); +void TextLine_Draw( + LPTEXTLINE lpTextLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight +); +void TextLine_DrawSelHilight(LPTEXTLINE lpTextLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState); +BOOL TextLine_Copy(LPTEXTLINE lpSrcLine, LPTEXTLINE lpDestLine); +BOOL TextLine_CopyToDoc(LPTEXTLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex); +int TextLine_GetTextLen(LPTEXTLINE lpTextLine); +void TextLine_GetTextData(LPTEXTLINE lpTextLine, LPSTR lpszBuf); +BOOL TextLine_GetOutlineData(LPTEXTLINE lpTextLine, LPTEXTLINE lpBuf); +BOOL TextLine_SaveToStm(LPTEXTLINE lpLine, LPSTREAM lpLLStm); +LPLINE TextLine_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc); + + + +/************************************************************************* +** class LINERANGE +** The class LINERANGE is a supporting object used to describe a +** particular range in an OUTLINEDOC. A range is defined by a starting +** line index and an ending line index. +*************************************************************************/ + +typedef struct tagLINERANGE { + signed short m_nStartLine; + signed short m_nEndLine; +} LINERANGE, FAR* LPLINERANGE; + + +/************************************************************************* +** class OUTLINENAME +** The class OUTLINENAME stores a particular named selection in the +** OUTLINEDOC document. The NAMETABLE class holds all of the names +** defined in a particular OUTLINEDOC document. Each OUTLINENAME +** object has a string as its key and a starting line index and an +** ending line index for the named range. +*************************************************************************/ + +#pragma pack(push, 2) +typedef struct tagOUTLINENAME { + char m_szName[MAXNAMESIZE+1]; + signed short m_nStartLine; // must be signed for table update + signed short m_nEndLine; // functions to work +} OUTLINENAME, FAR* LPOUTLINENAME; +#pragma pack(pop) + +void OutlineName_SetName(LPOUTLINENAME lpOutlineName, LPSTR lpszName); +void OutlineName_SetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, BOOL fRangeModified); +void OutlineName_GetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel); +BOOL OutlineName_SaveToStg(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, UINT uFormat, LPSTREAM lpNTStm, BOOL FAR* lpfNameSaved); + +BOOL OutlineName_SaveToStg(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, UINT uFormat, LPSTREAM lpNTStm, BOOL FAR* lpfNameSaved); +BOOL OutlineName_LoadFromStg(LPOUTLINENAME lpOutlineName, LPSTREAM lpNTStm); + + +/************************************************************************* +** class OUTLINENAMETABLE +** OUTLINENAMETABLE manages the table of named selections in the +** OUTLINEDOC document. Each OUTLINENAMETABLE entry has a string as its key +** and a starting line index and an ending line index for the +** named range. There is always one instance of OUTLINENAMETABLE for each +** OUTLINEDOC created. +*************************************************************************/ + +typedef struct tagOUTLINENAMETABLE { + HWND m_hWndListBox; + int m_nCount; +} OUTLINENAMETABLE, FAR* LPOUTLINENAMETABLE; + +/* OutlineNameTable methods (functions) */ +BOOL OutlineNameTable_Init(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINEDOC lpOutlineDoc); +void OutlineNameTable_Destroy(LPOUTLINENAMETABLE lpOutlineNameTable); +void OutlineNameTable_ClearAll(LPOUTLINENAMETABLE lpOutlineNameTable); +LPOUTLINENAME OutlineNameTable_CreateName(LPOUTLINENAMETABLE lpOutlineNameTable); +void OutlineNameTable_AddName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName); +void OutlineNameTable_DeleteName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex); +int OutlineNameTable_GetNameIndex(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName); +LPOUTLINENAME OutlineNameTable_GetName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex); +LPOUTLINENAME OutlineNameTable_FindName(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTR lpszName); +LPOUTLINENAME OutlineNameTable_FindNamedRange(LPOUTLINENAMETABLE lpOutlineNameTable, LPLINERANGE lplrSel); +int OutlineNameTable_GetCount(LPOUTLINENAMETABLE lpOutlineNameTable); +void OutlineNameTable_AddLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nAddIndex); +void OutlineNameTable_DeleteLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nDeleteIndex); +BOOL OutlineNameTable_LoadFromStg(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTORAGE lpSrcStg); +BOOL OutlineNameTable_SaveSelToStg( + LPOUTLINENAMETABLE lpOutlineNameTable, + LPLINERANGE lplrSel, + UINT uFormat, + LPSTREAM lpNTStm +); + + +/************************************************************************* +** class LINELIST +** The class LINELIST manages the list of Line objects in the +** OUTLINEDOC document. This class uses a Window's Owner-draw ListBox +** to hold the list of LINE objects. There is always one instance of +** LINELIST for each OUTLINEDOC created. +*************************************************************************/ + +typedef struct tagLINELIST { + HWND m_hWndListBox; // hWnd of OwnerDraw listbox + int m_nNumLines; // number of lines in LineList + int m_nMaxLineWidthInHimetric; // max width of listbox + LPOUTLINEDOC m_lpDoc; // ptr to associated OutlineDoc + LINERANGE m_lrSaveSel; // selection saved on WM_KILLFOCUS + +#if defined( USE_DRAGDROP ) + int m_iDragOverLine; // line index w/ drop target feedback +#endif +} LINELIST, FAR* LPLINELIST; + +/* LineList methods (functions) */ +BOOL LineList_Init(LPLINELIST lpLL, LPOUTLINEDOC lpOutlineDoc); +void LineList_Destroy(LPLINELIST lpLL); +void LineList_AddLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex); +void LineList_DeleteLine(LPLINELIST lpLL, int nIndex); +void LineList_ReplaceLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex); +int LineList_GetLineIndex(LPLINELIST lpLL, LPLINE lpLine); +LPLINE LineList_GetLine(LPLINELIST lpLL, int nIndex); +void LineList_SetFocusLine ( LPLINELIST lpLL, WORD wIndex ); +BOOL LineList_GetLineRect(LPLINELIST lpLL, int nIndex, LPRECT lpRect); +int LineList_GetFocusLineIndex(LPLINELIST lpLL); +int LineList_GetCount(LPLINELIST lpLL); +BOOL LineList_SetMaxLineWidthInHimetric( + LPLINELIST lpLL, + int nWidthInHimetric +); +void LineList_ScrollLineIntoView(LPLINELIST lpLL, int nIndex); +int LineList_GetMaxLineWidthInHimetric(LPLINELIST lpLL); +BOOL LineList_RecalcMaxLineWidthInHimetric( + LPLINELIST lpLL, + int nWidthInHimetric +); +void LineList_CalcSelExtentInHimetric( + LPLINELIST lpLL, + LPLINERANGE lplrSel, + LPSIZEL lpsizel +); +HWND LineList_GetWindow(LPLINELIST lpLL); +HDC LineList_GetDC(LPLINELIST lpLL); +void LineList_ReleaseDC(LPLINELIST lpLL, HDC hDC); +void LineList_SetLineHeight(LPLINELIST lpLL,int nIndex,int nHeightInHimetric); +void LineList_ReScale(LPLINELIST lpLL, LPSCALEFACTOR lpscale); +void LineList_SetSel(LPLINELIST lpLL, LPLINERANGE lplrSel); +int LineList_GetSel(LPLINELIST lpLL, LPLINERANGE lplrSel); +void LineList_RemoveSel(LPLINELIST lpLL); +void LineList_RestoreSel(LPLINELIST lpLL); +void LineList_SetRedraw(LPLINELIST lpLL, BOOL fEnableDraw); +void LineList_ForceRedraw(LPLINELIST lpLL, BOOL fErase); +void LineList_ForceLineRedraw(LPLINELIST lpLL, int nIndex, BOOL fErase); +int LineList_CopySelToDoc( + LPLINELIST lpSrcLL, + LPLINERANGE lplrSel, + LPOUTLINEDOC lpDestDoc +); +BOOL LineList_SaveSelToStg( + LPLINELIST lpLL, + LPLINERANGE lplrSel, + UINT uFormat, + LPSTORAGE lpSrcStg, + LPSTORAGE lpDestStg, + LPSTREAM lpLLStm, + BOOL fRemember +); +BOOL LineList_LoadFromStg( + LPLINELIST lpLL, + LPSTORAGE lpSrcStg, + LPSTREAM lpLLStm +); + +#if defined( USE_DRAGDROP ) +void LineList_SetFocusLineFromPointl( LPLINELIST lpLL, POINTL pointl ); +void LineList_SetDragOverLineFromPointl ( LPLINELIST lpLL, POINTL pointl ); +void LineList_Scroll(LPLINELIST lpLL, DWORD dwScrollDir); +int LineList_GetLineIndexFromPointl(LPLINELIST lpLL, POINTL pointl); +void LineList_RestoreDragFeedback(LPLINELIST lpLL); +#endif + +LRESULT FAR PASCAL LineListWndProc( + HWND hWnd, + UINT Message, + WPARAM wParam, + LPARAM lParam +); + + +// Document initialization type +#define DOCTYPE_UNKNOWN 0 // new doc created but not yet initialized +#define DOCTYPE_NEW 1 // init from scratch (new doc) +#define DOCTYPE_FROMFILE 2 // init from a file (open doc) + + + +/************************************************************************* +** class OUTLINEDOC +** There is one instance of the OutlineDoc class created per +** document open in the app. The SDI version of the app supports one +** OUTLINEDOC at a time. The MDI version of the app can manage +** multiple documents at one time. +*************************************************************************/ + +/* Definition of OUTLINEDOC */ +typedef struct tagOUTLINEDOC { + LINELIST m_LineList; // list of lines in the doc + LPOUTLINENAMETABLE m_lpNameTable; // table of names in the doc + HWND m_hWndDoc; // client area window for the Doc + int m_docInitType; // is doc new or loaded from a file? + BOOL m_fDataTransferDoc; // is doc created for copy | drag/drop + CLIPFORMAT m_cfSaveFormat; // format used to save the doc + char m_szFileName[256]; // associated file; "(Untitled)" if none + LPSTR m_lpszDocTitle; // name of doc to appear in window title + BOOL m_fModified; // is the doc dirty (needs to be saved)? + UINT m_nDisableDraw; // enable/disable updating the display + SCALEFACTOR m_scale; // current scale factor of the doc + int m_nLeftMargin; // left margin in Himetric + int m_nRightMargin; // right margin in Himetric + UINT m_uCurrentZoom; // cur. zoom (used for menu checking) + UINT m_uCurrentMargin; // cur. margin (used for menu checking) +#if defined( USE_HEADING ) + HEADING m_heading; +#endif + +#if defined( USE_FRAMETOOLS ) + LPFRAMETOOLS m_lpFrameTools; // ptr to frame tools used by this doc +#endif + +} OUTLINEDOC; + +/* OutlineDoc methods (functions) */ + +BOOL OutlineDoc_Init(LPOUTLINEDOC lpOutlineDoc, BOOL fDataTransferDoc); +BOOL OutlineDoc_InitNewFile(LPOUTLINEDOC lpOutlineDoc); +LPOUTLINENAMETABLE OutlineDoc_CreateNameTable(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_Destroy(LPOUTLINEDOC lpOutlineDoc); +BOOL OutlineDoc_Close(LPOUTLINEDOC lpOutlineDoc, DWORD dwSaveOption); +void OutlineDoc_ShowWindow(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_FrameWindowResized( + LPOUTLINEDOC lpOutlineDoc, + LPRECT lprcFrameRect, + LPBORDERWIDTHS lpFrameToolWidths +); + +void OutlineDoc_ClearCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_CutCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_CopyCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_ClearAllLines(LPOUTLINEDOC lpOutlineDoc); +LPOUTLINEDOC OutlineDoc_CreateDataTransferDoc(LPOUTLINEDOC lpSrcOutlineDoc); +void OutlineDoc_PasteCommand(LPOUTLINEDOC lpOutlineDoc); +int OutlineDoc_PasteOutlineData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hOutline, int nStartIndex); +int OutlineDoc_PasteTextData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hText, int nStartIndex); +void OutlineDoc_AddTextLineCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_AddTopLineCommand( + LPOUTLINEDOC lpOutlineDoc, + UINT nHeightInHimetric +); +void OutlineDoc_EditLineCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_IndentCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_UnindentCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetLineHeightCommand(LPOUTLINEDOC lpDoc); +void OutlineDoc_SelectAllCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_DefineNameCommand(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_GotoNameCommand(LPOUTLINEDOC lpOutlineDoc); + +void OutlineDoc_Print(LPOUTLINEDOC lpOutlineDoc, HDC hDC); +BOOL OutlineDoc_SaveToFile(LPOUTLINEDOC lpOutlineDoc, LPCSTR lpszFileName, UINT uFormat, BOOL fRemember); +void OutlineDoc_AddLine(LPOUTLINEDOC lpOutlineDoc, LPLINE lpLine, int nIndex); +void OutlineDoc_DeleteLine(LPOUTLINEDOC lpOutlineDoc, int nIndex); +void OutlineDoc_AddName(LPOUTLINEDOC lpOutlineDoc, LPOUTLINENAME lpOutlineName); +void OutlineDoc_DeleteName(LPOUTLINEDOC lpOutlineDoc, int nIndex); +void OutlineDoc_Resize(LPOUTLINEDOC lpDoc, LPRECT lpRect); +LPOUTLINENAMETABLE OutlineDoc_GetNameTable(LPOUTLINEDOC lpOutlineDoc); +LPLINELIST OutlineDoc_GetLineList(LPOUTLINEDOC lpOutlineDoc); +int OutlineDoc_GetNameCount(LPOUTLINEDOC lpOutlineDoc); +int OutlineDoc_GetLineCount(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetTitle(LPOUTLINEDOC lpOutlineDoc, BOOL fMakeUpperCase); +BOOL OutlineDoc_CheckSaveChanges( + LPOUTLINEDOC lpOutlineDoc, + LPDWORD lpdwSaveOption +); +BOOL OutlineDoc_IsModified(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetModified(LPOUTLINEDOC lpOutlineDoc, BOOL fModified, BOOL fDataChanged, BOOL fSizeChanged); +void OutlineDoc_SetRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fEnableDraw); +BOOL OutlineDoc_LoadFromFile(LPOUTLINEDOC lpOutlineDoc, LPSTR szFileName); +BOOL OutlineDoc_SaveSelToStg( + LPOUTLINEDOC lpOutlineDoc, + LPLINERANGE lplrSel, + UINT uFormat, + LPSTORAGE lpDestStg, + BOOL fSameAsLoad, + BOOL fRemember +); +BOOL OutlineDoc_LoadFromStg(LPOUTLINEDOC lpOutlineDoc, LPSTORAGE lpSrcStg); +BOOL OutlineDoc_SetFileName(LPOUTLINEDOC lpOutlineDoc, LPSTR lpszFileName, LPSTORAGE lpNewStg); +HWND OutlineDoc_GetWindow(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel); +int OutlineDoc_GetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel); +void OutlineDoc_ForceRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fErase); +void OutlineDoc_RenderFormat(LPOUTLINEDOC lpOutlineDoc, UINT uFormat); +void OutlineDoc_RenderAllFormats(LPOUTLINEDOC lpOutlineDoc); +HGLOBAL OutlineDoc_GetOutlineData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel); +HGLOBAL OutlineDoc_GetTextData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel); +void OutlineDoc_DialogHelp(HWND hDlg, WPARAM wDlgID); +void OutlineDoc_SetCurrentZoomCommand( + LPOUTLINEDOC lpOutlineDoc, + UINT uCurrentZoom +); +UINT OutlineDoc_GetCurrentZoomMenuCheck(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetScaleFactor( + LPOUTLINEDOC lpOutlineDoc, + LPSCALEFACTOR lpscale, + LPRECT lprcDoc +); +LPSCALEFACTOR OutlineDoc_GetScaleFactor(LPOUTLINEDOC lpDoc); +void OutlineDoc_SetCurrentMarginCommand( + LPOUTLINEDOC lpOutlineDoc, + UINT uCurrentMargin +); +UINT OutlineDoc_GetCurrentMarginMenuCheck(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetMargin(LPOUTLINEDOC lpDoc, int nLeftMargin, int nRightMargin); +LONG OutlineDoc_GetMargin(LPOUTLINEDOC lpDoc); + + +#if defined( USE_FRAMETOOLS ) +void OutlineDoc_AddFrameLevelTools(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_SetFormulaBarEditText( + LPOUTLINEDOC lpOutlineDoc, + LPLINE lpLine +); +void OutlineDoc_SetFormulaBarEditFocus( + LPOUTLINEDOC lpOutlineDoc, + BOOL fEditFocus +); +BOOL OutlineDoc_IsEditFocusInFormulaBar(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_UpdateFrameToolButtons(LPOUTLINEDOC lpOutlineDoc); +#endif // USE_FRAMETOOLS + +#if defined( USE_HEADING ) +LPHEADING OutlineDoc_GetHeading(LPOUTLINEDOC lpOutlineDoc); +void OutlineDoc_ShowHeading(LPOUTLINEDOC lpOutlineDoc, BOOL fShow); +#endif // USE_HEADING + +/************************************************************************* +** class OUTLINEAPP +** There is one instance of the OUTLINEAPP class created per running +** application instance. This object holds many fields that could +** otherwise be organized as global variables. +*************************************************************************/ + +/* Definition of OUTLINEAPP */ +typedef struct tagOUTLINEAPP { + HWND m_hWndApp; // top-level frame window for the App + HMENU m_hMenuApp; // handle to frame level menu for App + HACCEL m_hAccelApp; + HACCEL m_hAccelFocusEdit;// Accelerator when Edit in Focus + LPOUTLINEDOC m_lpDoc; // main SDI document visible to user + LPOUTLINEDOC m_lpClipboardDoc; // hidden doc for snapshot of copied sel + HWND m_hWndStatusBar; // window for the status bar + HCURSOR m_hcursorSelCur; // cursor used to select lines + HINSTANCE m_hInst; + PRINTDLG m_PrintDlg; + HFONT m_hStdFont; // font used for TextLines + UINT m_cfOutline; // clipboard format for Outline data + HACCEL m_hAccel; + HWND m_hWndAccelTarget; + FARPROC m_ListBoxWndProc; // orig listbox WndProc for subclassing + +#if defined ( USE_FRAMETOOLS ) || defined ( INPLACE_CNTR ) + BORDERWIDTHS m_FrameToolWidths; // space required by frame-level tools +#endif // USE_FRAMETOOLS || INPLACE_CNTR + +#if defined( USE_FRAMETOOLS ) + FRAMETOOLS m_frametools; // frame tools (button & formula bars) +#endif // USE_FRAMETOOLS + +} OUTLINEAPP, FAR* LPOUTLINEAPP; + +/* OutlineApp methods (functions) */ +BOOL OutlineApp_InitApplication(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst); +BOOL OutlineApp_InitInstance(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst, int nCmdShow); +BOOL OutlineApp_ParseCmdLine(LPOUTLINEAPP lpOutlineApp, LPSTR lpszCmdLine, int nCmdShow); +void OutlineApp_Destroy(LPOUTLINEAPP lpOutlineApp); +LPOUTLINEDOC OutlineApp_CreateDoc( + LPOUTLINEAPP lpOutlineApp, + BOOL fDataTransferDoc +); +HWND OutlineApp_GetWindow(LPOUTLINEAPP lpOutlineApp); +HWND OutlineApp_GetFrameWindow(LPOUTLINEAPP lpOutlineApp); +HINSTANCE OutlineApp_GetInstance(LPOUTLINEAPP lpOutlineApp); +LPOUTLINENAME OutlineApp_CreateName(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_DocUnlockApp(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpOutlineDoc); +void OutlineApp_InitMenu(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpDoc, HMENU hMenu); +void OutlineApp_GetFrameRect(LPOUTLINEAPP lpOutlineApp, LPRECT lprcFrameRect); +void OutlineApp_GetClientAreaRect( + LPOUTLINEAPP lpOutlineApp, + LPRECT lprcClientAreaRect +); +void OutlineApp_GetStatusLineRect( + LPOUTLINEAPP lpOutlineApp, + LPRECT lprcStatusLineRect +); +void OutlineApp_ResizeWindows(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_ResizeClientArea(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_AboutCommand(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_NewCommand(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_OpenCommand(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_PrintCommand(LPOUTLINEAPP lpOutlineApp); +BOOL OutlineApp_SaveCommand(LPOUTLINEAPP lpOutlineApp); +BOOL OutlineApp_SaveAsCommand(LPOUTLINEAPP lpOutlineApp); +BOOL OutlineApp_CloseAllDocsAndExitCommand( + LPOUTLINEAPP lpOutlineApp, + BOOL fForceEndSession +); +void OutlineApp_DestroyWindow(LPOUTLINEAPP lpOutlineApp); + +#if defined( USE_FRAMETOOLS ) +void OutlineApp_SetBorderSpace( + LPOUTLINEAPP lpOutlineApp, + LPBORDERWIDTHS lpBorderWidths +); +LPFRAMETOOLS OutlineApp_GetFrameTools(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_SetFormulaBarAccel( + LPOUTLINEAPP lpOutlineApp, + BOOL fEditFocus +); +#endif // USE_FRAMETOOLS + +void OutlineApp_SetStatusText(LPOUTLINEAPP lpOutlineApp, LPSTR lpszMessage); +LPOUTLINEDOC OutlineApp_GetActiveDoc(LPOUTLINEAPP lpOutlineApp); +HMENU OutlineApp_GetMenu(LPOUTLINEAPP lpOutlineApp); +HFONT OutlineApp_GetActiveFont(LPOUTLINEAPP lpOutlineApp); +HDC OutlineApp_GetPrinterDC(LPOUTLINEAPP lpApp); +void OutlineApp_PrinterSetupCommand(LPOUTLINEAPP lpOutlineApp); +void OutlineApp_ErrorMessage(LPOUTLINEAPP lpOutlineApp, LPSTR lpszMsg); +void OutlineApp_GetAppVersionNo(LPOUTLINEAPP lpOutlineApp, int narrAppVersionNo[]); +void OutlineApp_GetAppName(LPOUTLINEAPP lpOutlineApp, LPSTR lpszAppName); +BOOL OutlineApp_VersionNoCheck(LPOUTLINEAPP lpOutlineApp, LPSTR lpszAppName, int narrAppVersionNo[]); +void OutlineApp_SetEditText(LPOUTLINEAPP lpApp); +void OutlineApp_SetFocusEdit(LPOUTLINEAPP lpApp, BOOL bFocusEdit); +BOOL OutlineApp_GetFocusEdit(LPOUTLINEAPP lpApp); +void OutlineApp_ForceRedraw(LPOUTLINEAPP lpOutlineApp, BOOL fErase); + +/* struct definition for persistant data storage of OutlineDoc data */ + +#pragma pack(push, 2) +typedef struct tagOUTLINEDOCHEADER_ONDISK { + char m_szFormatName[32]; + short m_narrAppVersionNo[2]; + USHORT m_fShowHeading; + DWORD m_reserved1; // space reserved for future use + DWORD m_reserved2; // space reserved for future use + DWORD m_reserved3; // space reserved for future use + DWORD m_reserved4; // space reserved for future use +} OUTLINEDOCHEADER_ONDISK, FAR* LPOUTLINEDOCHEADER_ONDISK; +#pragma pack(pop) + +typedef struct tagOUTLINEDOCHEADER { + char m_szFormatName[32]; + int m_narrAppVersionNo[2]; + BOOL m_fShowHeading; + DWORD m_reserved1; // space reserved for future use + DWORD m_reserved2; // space reserved for future use + DWORD m_reserved3; // space reserved for future use + DWORD m_reserved4; // space reserved for future use +} OUTLINEDOCHEADER, FAR* LPOUTLINEDOCHEADER; + +#pragma pack(push,2) +typedef struct tagLINELISTHEADER_ONDISK { + USHORT m_nNumLines; + DWORD m_reserved1; // space reserved for future use + DWORD m_reserved2; // space reserved for future use +} LINELISTHEADER_ONDISK, FAR* LPLINELISTHEADER_ONDISK; +#pragma pack(pop) + +typedef struct tagLINELISTHEADER { + int m_nNumLines; + DWORD m_reserved1; // space reserved for future use + DWORD m_reserved2; // space reserved for future use +} LINELISTHEADER, FAR* LPLINELISTHEADER; + +#pragma pack(push,2) +typedef struct tagLINERECORD_ONDISK { + USHORT m_lineType; + USHORT m_nTabLevel; + USHORT m_nTabWidthInHimetric; + USHORT m_nWidthInHimetric; + USHORT m_nHeightInHimetric; + DWORD m_reserved; // space reserved for future use +} LINERECORD_ONDISK, FAR* LPLINERECORD_ONDISK; +#pragma pack(pop) + +typedef struct tagLINERECORD { + LINETYPE m_lineType; + UINT m_nTabLevel; + UINT m_nTabWidthInHimetric; + UINT m_nWidthInHimetric; + UINT m_nHeightInHimetric; + DWORD m_reserved; // space reserved for future use +} LINERECORD, FAR* LPLINERECORD; + + +/* Function prototypes in main.c */ +int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow); +BOOL MyTranslateAccelerator(LPMSG lpmsg); +int GetAccelItemCount(HACCEL hAccel); + +LRESULT CALLBACK EXPORT AppWndProc(HWND hWnd, UINT Message, WPARAM wParam, + LPARAM lParam); +LRESULT CALLBACK EXPORT DocWndProc(HWND hWnd, UINT Message, WPARAM wParam, + LPARAM lParam); + +/* Function prototypes in outldlgs.c */ +BOOL InputTextDlg(HWND hWnd, LPSTR lpszText, LPSTR lpszDlgTitle); +BOOL CALLBACK EXPORT AddEditDlgProc(HWND, UINT, WPARAM, LPARAM); +BOOL CALLBACK EXPORT SetLineHeightDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK EXPORT DefineNameDlgProc(HWND, UINT, WPARAM, LPARAM); +BOOL CALLBACK EXPORT GotoNameDlgProc(HWND, UINT, WPARAM, LPARAM); +void NameDlg_LoadComboBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hCombo); +void NameDlg_LoadListBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hListBox); +void NameDlg_AddName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, LPSTR lpszName, LPLINERANGE lplrSel); +void NameDlg_UpdateName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, int nIndex, LPSTR lpszName, LPLINERANGE lplrSel); +void NameDlg_DeleteName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, UINT nIndex); +BOOL CALLBACK EXPORT AboutDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam); + +/* Function prototypes in outldata.c */ +LPVOID New(DWORD lSize); +void Delete(LPVOID p); + +/* Function prototypes in outlprnt.c */ +BOOL CALLBACK EXPORT AbortProc (HDC hdc, WORD reserved); +BOOL CALLBACK EXPORT PrintDlgProc(HWND hwnd, WORD msg, WORD wParam, LONG lParam); + +/* Function prototypes in debug.c */ +void SetDebugLevelCommand(void); +void TraceDebug(HWND, int); + + +// now declare test functions + +extern HWND g_hwndDriver; + +void StartClipboardTest1( LPOUTLINEAPP lpOutlineApp ); +void ContinueClipboardTest1( LPOUTLINEAPP lpOutlineApp ); + +#if defined( OLE_VERSION ) +#include "oleoutl.h" + +#endif // OLE_VERSION + + +#endif // _OUTLINE_H_ + diff --git a/private/oleutest/letest/outline/outline.ico b/private/oleutest/letest/outline/outline.ico Binary files differnew file mode 100644 index 000000000..bb5d483ee --- /dev/null +++ b/private/oleutest/letest/outline/outline.ico diff --git a/private/oleutest/letest/outline/outline.mst b/private/oleutest/letest/outline/outline.mst new file mode 100644 index 000000000..319b3e006 --- /dev/null +++ b/private/oleutest/letest/outline/outline.mst @@ -0,0 +1,469 @@ +'******************************** TUTOR.MST ********************************** +'Demonstrates: This will test the OLE 2.0 sample app: OLine.EXE +' +'Required Files: MSTEST.INC, OUTLINE.EXE +' +'Uses: TESTSCRN, TESTCTRL, TESTEVENT. +' +'Notes: Assumes all exe's are in the PATH. +' +'****************************************************************************** + +Declare Sub Init +Declare Sub Windows +Declare Sub AddLines +Declare Sub NewDoc +Declare Sub ClearAll +Declare Sub TestNames +Declare Sub TestClip +Declare Sub EndTest + +Declare SUB LogPrint(szString$) +Declare SUB CheckAppExists(szAppName$, szErrMessage$) +Declare SUB CheckAppNotExists(szAppName$, szErrMessage$) +Declare FUNCTION CheckWndIsActive(szAppName$, szErrMessage$) AS INTEGER +Declare SUB IsDllLoaded(szDllName$) +Declare FUNCTION GetDllUsage(szDllName$) AS INTEGER +Declare SUB CheckDllUsage(szDllName$, nExpectedUsage%) + +'****************************************************************************** +' CONST +'****************************************************************************** + +Const DefAppName$ = "outline" +Const RootAppDir$ = "c:\ole2samp\outline\" +Const SDemo1AppName$ = "sdemo1" +Const SDemo1ClassName$ = "SDemo1" +Const EllipseWTClassName$ = "EllipseWT" +Const BELL = 7 + +Global WinHandle%, DbWinHandle%, logfile%, ErrCount, fSlaveMode%, fAutoMode%, AppName$, AppWndName$, AppDir$ + +Const nDll = 4 +GLOBAL DllList$(nDll) +GLOBAL DllExpectedUsage%(nDll) + +DllList(0) = "OLE2.DLL" +DllList(1) = "OLECLASS.DLL" +DllList(2) = "OLEREM.DLL" +DllList(3) = "OLEPROXY.DLL" +DllList(4) = "DOCFILE.DLL" + +'****************************************************************************** +' DEFINES +'****************************************************************************** + +'$DEFINE TESTSCRN +'$DEFINE TESTCTRL +'$DEFINE TESTEVNT + +'****************************************************************************** +' INCLUDES +'****************************************************************************** + +'$INCLUDE 'mstest.inc' +'$INCLUDE 'fasttest.inc' +'$INCLUDE 'winkern.inc' + +'****************************************************************************** +' Main program code +'****************************************************************************** + +ON ERROR GOTO ErrorTrap + + Init '*** Initialize logging, global constants. + Windows '*** Test various windowing features of app. + NewDoc '*** start a new document + AddLines '*** Add some lines to document + TestNames '*** Test naming functionality + TestClip '*** Test clipboard functionality + EndTest '*** Shut down. + +END + +'****************************************************************************** +' TRAPS +'****************************************************************************** + +ErrorTrap: + + ErrCount = ErrCount + 1 + SELECT CASE Err + CASE ERR_INVALID_PATH + LogPrint "Path not found. Error number " + STR$(Err) + LogPrint " on line " + STR$(ERL) + LogPrint " in script " + ERF + LogPrint ERROR$ ' The error message. + END + CASE ERR_CANT_OPEN_FILE + LogPrint "Can't Open File. Error number " + STR$(Err) + LogPrint " on line " + STR$(ERL) + LogPrint " in script " + ERF + LogPrint ERROR$ ' The error message. + END + CASE ERR_ILLEGAL_FUNCTION_CALL + LogPrint "Illegal function call. Error number " + STR$(Err) + LogPrint " on line " + STR$(ERL) + LogPrint " in script " + ERF + LogPrint ERROR$ ' The error message. + LogPrint " (NOTE: Check if OLETEST.EXE & SDEMO1.EXE are on your PATH)" + END + CASE ELSE + LogPrint "Unexpected error: Number " + STR$(Err) + LogPrint " on line " + STR$(ERL) + LogPrint " in script " +ERF + LogPrint ERROR$ ' The error message. + END + END SELECT + +'*** trap UAE from an application + +'TRAP UAETrap FROM "TESTDRVR.EXE" +' LogPrint "!!!!!! UNRECOVERERABLE APPLICATION ERROR ENCOUNTERED!" +' LogPrint " ABORT TESTING!" +' ErrCount = ErrCount + 1 +' EndTest +'END TRAP + +'****************************************************************************** +' SUBs and FUNCTIONs +'****************************************************************************** + + + +'****************************************************************************** +' SUB Init sets up several variables that are used thoughout the test. +'****************************************************************************** +SUB Init STATIC + + Viewport On + Viewport Clear + ErrCount = 0 + fSlaveMode = 0 + fAutoMode = 0 + IF TESTMODE$ = "auto" OR TESTMODE$ = "AUTO" THEN + fAutoMode = 1 + ENDIF + + '*** Determine name of app to run. this can be given with "/C appname" cmd line opt. + IF COMMAND$ = "" THEN + AppName$ = DefAppName$ + ELSE + AppName$ = COMMAND$ + ENDIF + AppWndName$ = AppName$ + " -" + + logfile = FREEFILE + OPEN "mstest.log" FOR OUTPUT AS # logfile + 'Set log file and write header to file. + + LogPrint "**********************************************" + LogPrint "STARTING TEST OF " + AppName$ + " APPLICATION" + LogPrint " " + DATETIME$ + LogPrint "**********************************************" + + 'Record the initial usage counts for all OLE2 related DLLs + FOR I = 0 TO nDll + DllExpectedUsage(I) = GetDllUsage(DllLIst(I)) + NEXT I + + 'Run the program and get its window handle. + + WinHandle = WFndWnd(AppWndName$, FW_PART or FW_FOCUS or FW_ALL) + IF WinHandle = 0 THEN + LogPrint "Launching new instance of " + AppName$ + " app--running test in slave mode" + LogPrint "NOTE: Running test in slave mode -- app will automatically shut down" + RUN "dbwin", NOWAIT '*** start up debug messages window + DbWinHandle = WGetActWnd(0) + DoKeys "%(e)e" '*** Edit.Clear buffer + RUN RootAppDir$ + AppName$ + "\" + AppName$, NOWAIT + WinHandle = WGetActWnd(0) + fSlaveMode = 1 '*** Test is run in slave mode, shut down afterwards + ELSE + LogPrint "Using existing instance of " + AppName$ + ENDIF + + IF CheckWndIsActive("Debug Messages", "") <> 0 THEN + DoKeys "%(o)t" '*** Toggle off 'always on top' mode of debug window + WSetActWnd WinHandle '*** activate app + ENDIF + + x = CheckWndIsActive(AppWndName$, AppName$ + " Test not launched successfully") + +END SUB + +'****************************************************************************** +' SUB Window will size app window and set it's position. +'****************************************************************************** + +SUB Windows STATIC + + DIM i% + + 'Position and size the form. + + WSetWndPos WinHandle, 200, 200 + WSetWndSiz WinHandle, 50, 60 + + 'Adjust the window to several locations. + + For i = 1 to 10 + WAdjWndSiz WinHandle, 4*i, 4*i + Next i + +END SUB + +'****************************************************************************** +' SUB NewDoc -- start a new doc. +'****************************************************************************** + +SUB NewDoc STATIC + + LogPrint "--- BEGIN NewDoc" + WSetActWnd WinHandle '*** activate app + DoKeys "%(l)axxxx" '*** add a line so doc is dirty + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(f)n" '*** New command + WButtonClick "No" '*** Do not save + x = CheckWndIsActive(AppWndName$, "Unknown Error") + + LogPrint "--- END" + +END SUB + +'****************************************************************************** +' SUB ClearAll -- clear all lines. +'****************************************************************************** + +SUB ClearAll STATIC + + LogPrint "--- BEGIN ClearALL" + WSetActWnd WinHandle '*** activate app + DoKeys "%(e)l" '*** select all + DoKeys "%(e)e" '*** clear selection + x = CheckWndIsActive(AppWndName$, "Unknown Error") + + LogPrint "--- END" + +END SUB + +'****************************************************************************** +' SUB AddLines -- add text lines. +'****************************************************************************** + +SUB AddLines STATIC + + LogPrint "--- BEGIN AddLines" + WSetActWnd WinHandle '*** activate app + DoKeys "%(l)aLine 1: This is a test" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)aLine 2: This is a test" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)aLine 3: This is a test" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)aLine 3.1: This is a sub point" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)aLine 3.2: This is a sub point" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)aLine 3.3: This is a sub point" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)i" '*** indent line + DoKeys "%(l)n" '*** un-indent line + DoKeys "%(l)n" '*** un-indent line + DoKeys "%(l)n" '*** un-indent line + DoKeys "%(l)n" '*** un-indent line + DoKeys "%(l)n" '*** un-indent line + DoKeys "%(l)n" '*** un-indent line + x = CheckWndIsActive(AppWndName$, "Unknown Error") + + LogPrint "--- END" + +END SUB + +'****************************************************************************** +' SUB TestNames -- test the naming functionality. +'****************************************************************************** + +SUB TestNames STATIC + + LogPrint "--- BEGIN TestNames" + WSetActWnd WinHandle '*** activate app + DoKeys "{UP}" + DoKeys "{Down}" + DoKeys "+({UP})+({UP})+({UP})" '*** select some lines + DoKeys "%(n)dx" '*** define a name + WButtonClick "Ok" '*** Close define name dialog box + DoKeys "%(l)aLine 4: This should be part of name x" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(l)aLine 5: This should be part of name x" '*** add a line + WButtonClick "OK" '*** Close input dialog box + DoKeys "%(n)gx" '*** goto name + WButtonClick "OK" '*** Close define name dialog box + DoKeys "{Down}" + DoKeys "+{Down}" '*** select the 2 lines that were added + DoKeys "%(e)e" '*** delete the selection + DoKeys "%(n)gx" '*** goto name + WButtonClick "OK" '*** Close define name dialog box + x = CheckWndIsActive(AppWndName$, "Unknown Error") + + LogPrint "--- END" + +END SUB + +'****************************************************************************** +' SUB TestClip -- test the clipboard functionality. +'****************************************************************************** + +SUB TestClip STATIC + + LogPrint "--- BEGIN TestClip" + WSetActWnd WinHandle '*** activate app + DoKeys "%(e)t" '*** cut the selection + DoKeys "%(e)p" '*** paste + DoKeys "%(e)p" '*** paste + x = CheckWndIsActive(AppWndName$, "Unknown Error") + + LogPrint "--- END" + +END SUB + +SUB EndTest STATIC + + IF fSlaveMode <> 0 THEN + LogPrint "*** EndTest" + IF CheckWndIsActive(AppWndName$, AppName$ + " can NOT be closed properly") THEN + DoKeys "%FX" '*** shut down OLETEST + WButtonClick "No" '*** Do not save + ENDIF + WMinWnd(DbWinHandle) '*** minimize debug messages window + CheckAppNotExists AppWndName$, AppName$ + " NOT shut down properly" + ENDIF + + 'Check that all OLE2 related DLLs have the expected usage counts + FOR I = 0 TO nDll + CheckDllUsage DllList(I), DllExpectedUsage(I) + NEXT I + + LogPrint "**********************************************" + LogPrint "SUCCESSFULLY COMPLETED " + AppName$ + "TEST" + LogPrint " " + DATETIME$ + LogPrint "Total of " + STR$(ErrCount) + " errors detected" + LogPrint "**********************************************" + + CLOSE # logfile + + IF fAutoMode = 0 THEN + PRINT, CHR$(BELL) '*** sound a BEEP, we are done! + IF ErrCount = 0 THEN + PAUSE "Test seems successful" + ELSE + PAUSE "*** TEST FAILED -- (" + STR$(ErrCount) + " Errors). See mstest.log" + ENDIF + ENDIF +END SUB + +'****************************************************************************** +' SUB LogPrint prints a string to the logfile and to the Viewport. +'****************************************************************************** + +SUB LogPrint(szString$) STATIC + + PRINT #logfile, szString$ + PRINT, szString$ + +END SUB + +SUB CheckAppExists(szAppName$, szErrMessage$) STATIC + + hWnd = WFndWnd(szAppName, FW_PART or FW_ALL or FW_NOCASE) + IF hWnd = 0 THEN + LogPrint "!!!!!! Operation FAILED..." + LogPrint " " + szErrMessage$ + ErrCount = ErrCount + 1 + ENDIF + +END SUB + +SUB CheckAppNotExists(szAppName$, szErrMessage$) STATIC + + hWnd = WFndWnd(szAppName, FW_PART or FW_ALL or FW_NOCASE) + IF hWnd <> 0 THEN + LogPrint "!!!!!! Operation FAILED..." + LogPrint " " + szErrMessage$ + ErrCount = ErrCount + 1 + ENDIF + +END SUB + +STATIC FUNCTION CheckWndIsActive(szAppName$, szErrMessage$) AS INTEGER + hWnd = WFndWnd(szAppName, FW_PART or FW_ALL or FW_NOCASE) + CheckWndIsActive = hWnd + IF hWnd <> WGetActWnd(0) THEN + CheckWndIsActive = 0 + + '*** if no message is given, then it is not considered an error + IF szErrMessage <> "" THEN + LogPrint "!!!!!! Operation FAILED..." + LogPrint " " + szErrMessage$ + LogPrint " <" + GetText(0) + "> Window is Active" + + IF fAutoMode = 0 THEN + PAUSE "<" + szAppName + "> Window expected.... " + "<" + GetText(0) + "> Window is Active" + ENDIF + + '*** if a dialog is active, then close it. it is probably an error message + IF WButtonExists("Ignore") THEN + WButtonClick "OK" '*** Close err message box + ELSEIF WButtonExists("OK") THEN + WButtonClick "OK" '*** Close err message box + ELSEIF WButtonExists("Ok") THEN + WButtonClick "Ok" '*** Close err message box + ELSEIF WButtonExists("Cancel") THEN + WButtonClick "Cancel" '*** Close err message box + ELSEIF WButtonExists("CANCEL") THEN + WButtonClick "CANCEL" '*** Close err message box + ELSEIF WButtonExists("Close") THEN + WButtonClick "Close" '*** Close err message box + ENDIF + ErrCount = ErrCount + 1 + ENDIF + ENDIF + +END FUNCTION + + +'****************************************************************************** +' FUNCTION GetDllUsage gets the usage count of a DLL. +'****************************************************************************** + +STATIC FUNCTION GetDllUsage(szDllName$) AS INTEGER + + hDll% = GetModuleHandle(szDllName) + GetDllUsage = GetModuleUsage(hDll) + +END FUNCTION + + +'****************************************************************************** +' SUB CheckDllUsage checks if a DLL is loaded the expected number of times. +'****************************************************************************** + +SUB CheckDllUsage(szDllName$, nExpectedUsage%) STATIC + + usage% = GetDllUsage(szDllName) + LogPrint "DLL: " + szDllName + " loadded" + STR$(usage) + " times (expected" + STR$(nExpectedUsage) + " times)" + + '*** can only reliably report an error when expected usage is 0 + IF usage <> nExpectedUsage AND nExpectedUsage = 0 THEN + LogPrint "!!!!!! " + szDllName + " NOT UNLOADED PROPERLY!" + ErrCount = ErrCount + 1 + ENDIF + +END SUB + diff --git a/private/oleutest/letest/outline/outline.rc b/private/oleutest/letest/outline/outline.rc new file mode 100644 index 000000000..795aa8124 --- /dev/null +++ b/private/oleutest/letest/outline/outline.rc @@ -0,0 +1,173 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** outline.rc +** +** Resource file for outline.exe +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "windows.h" +#include "outlrc.h" + +SelCur CURSOR selcross.cur + +OutlineMenu MENU + BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", IDM_F_NEW + MENUITEM "&Open...\t Ctrl+F12", IDM_F_OPEN + MENUITEM "&Save\t Shift+F12", IDM_F_SAVE + MENUITEM "Save &As...\t F12", IDM_F_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print...\t Ctrl+Shift+F12", IDM_F_PRINT + MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP + MENUITEM SEPARATOR + MENUITEM "E&xit\t Alt+F4", IDM_F_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", IDM_E_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\t Ctrl+X", IDM_E_CUT + MENUITEM "&Copy\t Ctrl+C", IDM_E_COPY + MENUITEM "&Paste\t Ctrl+V", IDM_E_PASTE + MENUITEM "Cl&ear\t Del", IDM_E_CLEAR + MENUITEM SEPARATOR + MENUITEM "Select A&ll\t Ctrl+A", IDM_E_SELECTALL + END + POPUP "O&utline" + BEGIN + POPUP "&Zoom" + BEGIN + MENUITEM "&400%", IDM_V_ZOOM_400 + MENUITEM "&300%", IDM_V_ZOOM_300 + MENUITEM "&200%", IDM_V_ZOOM_200 + MENUITEM "&100%", IDM_V_ZOOM_100 + MENUITEM "&75%", IDM_V_ZOOM_75 + MENUITEM "&50%", IDM_V_ZOOM_50 + MENUITEM "&25%", IDM_V_ZOOM_25 + END + POPUP "&Left and Right margins" + BEGIN + MENUITEM "&nil", IDM_V_SETMARGIN_0 + MENUITEM "&1 cm", IDM_V_SETMARGIN_1 + MENUITEM "&2 cm", IDM_V_SETMARGIN_2 + MENUITEM "&3 cm", IDM_V_SETMARGIN_3 + MENUITEM "&4 cm", IDM_V_SETMARGIN_4 + END + POPUP "Add &Top Line" + BEGIN + MENUITEM "&1 cm", IDM_V_ADDTOP_1 + MENUITEM "&2 cm", IDM_V_ADDTOP_2 + MENUITEM "&3 cm", IDM_V_ADDTOP_3 + MENUITEM "&4 cm", IDM_V_ADDTOP_4 + END + END + POPUP "&Line" + BEGIN + MENUITEM "&Add Line\t Enter", IDM_L_ADDLINE + MENUITEM "E&dit Line\t Alt+Enter", IDM_L_EDITLINE + MENUITEM SEPARATOR + MENUITEM "&Indent Line\t Tab", IDM_L_INDENTLINE + MENUITEM "U&nindent Line\t Shift+Tab", IDM_L_UNINDENTLINE + MENUITEM SEPARATOR + MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT + END + POPUP "&Name" + BEGIN + MENUITEM "&Define Name...", IDM_N_DEFINENAME + MENUITEM "&Goto Name...", IDM_N_GOTONAME + END + POPUP "&Options" + BEGIN + POPUP "&Button Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_BB_TOP + MENUITEM "At &Bottom", IDM_O_BB_BOTTOM + MENUITEM "&Popup", IDM_O_BB_POPUP + MENUITEM "&Hide", IDM_O_BB_HIDE + END + POPUP "&Formula Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_FB_TOP + MENUITEM "At &Bottom", IDM_O_FB_BOTTOM + MENUITEM "&Popup", IDM_O_FB_POPUP + END + POPUP "&Row and Column Heading" + BEGIN + MENUITEM "&Show", IDM_O_HEAD_SHOW + MENUITEM "&Hide", IDM_O_HEAD_HIDE + END + END + POPUP "&Help" + BEGIN + MENUITEM "&About...", IDM_H_ABOUT + END + END + +OutlineAccel ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CLEAR, VIRTKEY + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + + VK_F2, IDM_F2, VIRTKEY + END + + +; Same as OutlineAccel but without Delete +; used when edit control of Formula Bar in focus +; +OutlineAccelFocusEdit ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + END + +OutlineIcon ICON outline.ico + +Image72 BITMAP image72.bmp +Image96 BITMAP image96.bmp +Image120 BITMAP image120.bmp +LogoBitmap BITMAP ole2.bmp + +#include "DIALOGS.DLG" diff --git a/private/oleutest/letest/outline/outlline.c b/private/oleutest/letest/outline/outlline.c new file mode 100644 index 000000000..f0416a415 --- /dev/null +++ b/private/oleutest/letest/outline/outlline.c @@ -0,0 +1,731 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outlline.c +** +** This file contains Line functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + +/* Line_Init + * --------- + * + * Init the calculated data of a line object + */ +void Line_Init(LPLINE lpLine, int nTab, HDC hDC) +{ + lpLine->m_lineType = UNKNOWNLINETYPE; + lpLine->m_nTabLevel = nTab; + lpLine->m_nTabWidthInHimetric = Line_CalcTabWidthInHimetric(lpLine,hDC); + lpLine->m_nWidthInHimetric = 0; + lpLine->m_nHeightInHimetric = 0; + lpLine->m_fSelected = FALSE; + +#if defined( USE_DRAGDROP ) + lpLine->m_fDragOverLine = FALSE; +#endif +} + + +/* Line_Edit + * --------- + * + * Edit the line object. + * + * Returns TRUE if line was changed + * FALSE if the line was NOT changed + */ +BOOL Line_Edit(LPLINE lpLine, HWND hWndDoc, HDC hDC) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + return TextLine_Edit((LPTEXTLINE)lpLine, hWndDoc, hDC); + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + ContainerLine_Edit((LPCONTAINERLINE)lpLine, hWndDoc, hDC); + break; +#endif + + default: + return FALSE; // unknown line type + } +} + + +/* Line_GetLineType + * ---------------- + * + * Return type of the line + */ +LINETYPE Line_GetLineType(LPLINE lpLine) +{ + if (! lpLine) return 0; + + return lpLine->m_lineType; +} + + +/* Line_GetTextLen + * --------------- + * + * Return length of string representation of the Line + * (not considering the tab level). + */ +int Line_GetTextLen(LPLINE lpLine) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + return TextLine_GetTextLen((LPTEXTLINE)lpLine); + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + return ContainerLine_GetTextLen((LPCONTAINERLINE)lpLine); +#endif + + default: + return 0; // unknown line type + } +} + + +/* Line_GetTextData + * ---------------- + * + * Return the string representation of the Line. + * (not considering the tab level). + */ +void Line_GetTextData(LPLINE lpLine, LPSTR lpszBuf) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + TextLine_GetTextData((LPTEXTLINE)lpLine, lpszBuf); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + ContainerLine_GetTextData((LPCONTAINERLINE)lpLine, lpszBuf); + break; +#endif + + default: + *lpszBuf = '\0'; + return; // unknown line type + } +} + + +/* Line_GetOutlineData + * ------------------- + * + * Return the CF_OUTLINE format representation of the Line. + */ +BOOL Line_GetOutlineData(LPLINE lpLine, LPTEXTLINE lpBuf) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + return TextLine_GetOutlineData((LPTEXTLINE)lpLine, lpBuf); + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + return ContainerLine_GetOutlineData( + (LPCONTAINERLINE)lpLine, + lpBuf + ); +#endif + + default: + return FALSE; // unknown line type + } +} + + +/* Line_CalcTabWidthInHimetric + * --------------------------- + * + * Recalculate the width for the line's current tab level + */ +static int Line_CalcTabWidthInHimetric(LPLINE lpLine, HDC hDC) +{ + int nTabWidthInHimetric; + + nTabWidthInHimetric=lpLine->m_nTabLevel * TABWIDTH; + return nTabWidthInHimetric; +} + + +/* Line_Indent + * ----------- + * + * Increment the tab level for the line + */ +void Line_Indent(LPLINE lpLine, HDC hDC) +{ + lpLine->m_nTabLevel++; + lpLine->m_nTabWidthInHimetric = Line_CalcTabWidthInHimetric(lpLine, hDC); + +#if defined( INPLACE_CNTR ) + if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) + ContainerLine_UpdateInPlaceObjectRects((LPCONTAINERLINE)lpLine, NULL); +#endif +} + + +/* Line_Unindent + * ------------- + * + * Decrement the tab level for the line + */ +void Line_Unindent(LPLINE lpLine, HDC hDC) +{ + if(lpLine->m_nTabLevel > 0) { + lpLine->m_nTabLevel--; + lpLine->m_nTabWidthInHimetric = Line_CalcTabWidthInHimetric(lpLine, hDC); + } + +#if defined( INPLACE_CNTR ) + if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) + ContainerLine_UpdateInPlaceObjectRects((LPCONTAINERLINE)lpLine, NULL); +#endif +} + + +/* Line_GetTotalWidthInHimetric + * ---------------------------- + * + * Calculate the total width of the line + */ +UINT Line_GetTotalWidthInHimetric(LPLINE lpLine) +{ + return lpLine->m_nWidthInHimetric + lpLine->m_nTabWidthInHimetric; +} + + +/* Line_SetWidthInHimetric + * ----------------------- + * + * Set the width of the line + */ +void Line_SetWidthInHimetric(LPLINE lpLine, int nWidth) +{ + if (!lpLine) + return; + + lpLine->m_nWidthInHimetric = nWidth; +} + + +/* Line_GetWidthInHimetric + * ----------------------- + * + * Return the width of the line + */ +UINT Line_GetWidthInHimetric(LPLINE lpLine) +{ + if (!lpLine) + return 0; + + return lpLine->m_nWidthInHimetric; +} + + + + + +/* Line_GetTabLevel + * ---------------- + * + * Return the tab level of a line object. + */ +UINT Line_GetTabLevel(LPLINE lpLine) +{ + return lpLine->m_nTabLevel; +} + + +/* Line_DrawToScreen + * ----------------- + * + * Draw the item in the owner-draw listbox + */ +void Line_DrawToScreen( + LPLINE lpLine, + HDC hDC, + LPRECT lprcPix, + UINT itemAction, + UINT itemState, + LPRECT lprcDevice +) +{ + if (!lpLine || !hDC || !lprcPix || !lprcDevice) + return; + + /* Draw a list box item in its normal drawing action. + * Then check if it is selected or has the focus state, and call + * functions to handle drawing for these states if necessary. + */ + if(itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) { + HFONT hfontOld; + int nMapModeOld; + RECT rcWindowOld; + RECT rcViewportOld; + RECT rcLogical; + + // NOTE: we have to set the device context to HIMETRIC in order + // draw the line; however, we have to restore the HDC before + // we draw focus or dragfeedback... + + rcLogical.left = 0; + rcLogical.bottom = 0; + rcLogical.right = lpLine->m_nWidthInHimetric; + rcLogical.top = lpLine->m_nHeightInHimetric; + + { + HBRUSH hbr; + RECT rcDraw; + + lpLine->m_fSelected = (BOOL)(itemState & ODS_SELECTED); + + if (ODS_SELECTED & itemState) { + /*Get proper txt colors */ + hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); + } + else { + hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); + } + + rcDraw = *lprcPix; + rcDraw.right = lprcDevice->left; + FillRect(hDC, lprcPix, hbr); + + rcDraw = *lprcPix; + rcDraw.left = lprcDevice->right; + FillRect(hDC, lprcPix, hbr); + + DeleteObject(hbr); + } + + nMapModeOld=SetDCToAnisotropic(hDC, lprcDevice, &rcLogical, + (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld); + + // Set the default font size, and font face name + hfontOld = SelectObject(hDC, OutlineApp_GetActiveFont(g_lpApp)); + + Line_Draw(lpLine, hDC, &rcLogical, NULL, (ODS_SELECTED & itemState)); + + SelectObject(hDC, hfontOld); + + ResetOrigDC(hDC, nMapModeOld, (LPRECT)&rcWindowOld, + (LPRECT)&rcViewportOld); + +#if defined( OLE_CNTR ) + if ((itemState & ODS_SELECTED) && + (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) + ContainerLine_DrawSelHilight( + (LPCONTAINERLINE)lpLine, + hDC, + lprcPix, + ODA_SELECT, + ODS_SELECTED + ); +#endif + + } + + /* If a list box item just gained or lost the focus, + * call function (which could check if ODS_FOCUS bit is set) + * and draws item in focus or non-focus state. + */ + if(itemAction & ODA_FOCUS ) + Line_DrawFocusRect(lpLine, hDC, lprcPix, itemAction, itemState); + + +#if defined( OLE_CNTR ) + if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + LPCONTAINERDOC lpDoc = lpContainerLine->m_lpDoc; + BOOL fIsLink; + RECT rcObj; + + if (ContainerDoc_GetShowObjectFlag(lpDoc)) { + ContainerLine_GetOleObjectRectInPixels(lpContainerLine, &rcObj); + fIsLink = ContainerLine_IsOleLink(lpContainerLine); + OleUIShowObject(&rcObj, hDC, fIsLink); + } + } +#endif + +#if defined( USE_DRAGDROP ) + if (lpLine->m_fDragOverLine) + Line_DrawDragFeedback(lpLine, hDC, lprcPix, itemState ); +#endif + +} + + +/* Line_Draw + * --------- + * + * Draw a line on a DC. + * + * Parameters: + * hDC - DC to which the line will be drawn + * lpRect - the object rect in logical coordinates + */ +void Line_Draw( + LPLINE lpLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight +) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + TextLine_Draw( + (LPTEXTLINE)lpLine, hDC, lpRect,lpRectWBounds,fHighlight); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + ContainerLine_Draw( + (LPCONTAINERLINE)lpLine,hDC,lpRect,lpRectWBounds,fHighlight); + break; +#endif + + default: + return; // unknown line type + } + return; +} + + +/* Line_DrawSelHilight + * ------------------- + * + * Handles selection of list box item + */ +void Line_DrawSelHilight(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + TextLine_DrawSelHilight((LPTEXTLINE)lpLine, hDC, lpRect, + itemAction, itemState); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + ContainerLine_DrawSelHilight((LPCONTAINERLINE)lpLine, hDC, lpRect, + itemAction, itemState); + break; +#endif + + default: + return; // unknown line type + } + return; + +} + +/* Line_DrawFocusRect + * ------------------ + * + * Handles focus state of list box item + */ +void Line_DrawFocusRect(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState) +{ + if(lpLine) + DrawFocusRect(hDC, lpRect); +} + +#if defined( USE_DRAGDROP ) + +/* Line_DrawDragFeedback + * --------------------- + * + * Handles focus state of list box item + */ +void Line_DrawDragFeedback(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemState ) +{ + if(lpLine) + DrawFocusRect(hDC, lpRect); +} + +#endif // USE_DRAGDROP + + +/* Line_GetHeightInHimetric + * ------------------------ + * + * Return the height of the item in HIMETRIC units + */ +UINT Line_GetHeightInHimetric(LPLINE lpLine) +{ + if (!lpLine) + return 0; + + return (UINT)lpLine->m_nHeightInHimetric; +} + + +/* Line_SetHeightInHimetric + * ------------------------ + * + * Set the height of the item in HIMETRIC units. + */ +void Line_SetHeightInHimetric(LPLINE lpLine, int nHeight) +{ + if (!lpLine) + return; + + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + TextLine_SetHeightInHimetric((LPTEXTLINE)lpLine, nHeight); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + ContainerLine_SetHeightInHimetric((LPCONTAINERLINE)lpLine, + nHeight); + break; +#endif + + } +} + + +/* Line_Delete + * ----------- + * + * Delete the Line structure + */ +void Line_Delete(LPLINE lpLine) +{ + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + TextLine_Delete((LPTEXTLINE)lpLine); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + ContainerLine_Delete((LPCONTAINERLINE)lpLine); + break; +#endif + + default: + break; // unknown line type + } +} + + +/* Line_CopyToDoc + * -------------- + * + * Copy a line to another Document (usually ClipboardDoc) + */ +BOOL Line_CopyToDoc(LPLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex) +{ + switch (lpSrcLine->m_lineType) { + case TEXTLINETYPE: + return TextLine_CopyToDoc((LPTEXTLINE)lpSrcLine,lpDestDoc,nIndex); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + return ContainerLine_CopyToDoc( + (LPCONTAINERLINE)lpSrcLine, + lpDestDoc, + nIndex + ); + break; +#endif + + default: + return FALSE; // unknown line type + } +} + + +/* Line_SaveToStg + * -------------- + * + * Save a single line object to a storage + * + * Return TRUE if successful, FALSE otherwise + */ +BOOL Line_SaveToStg(LPLINE lpLine, UINT uFormat, LPSTORAGE lpSrcStg, LPSTORAGE lpDestStg, LPSTREAM lpLLStm, BOOL fRemember) +{ + LINERECORD_ONDISK lineRecord; + ULONG nWritten; + HRESULT hrErr; + BOOL fStatus; + LARGE_INTEGER dlibSavePos; + LARGE_INTEGER dlibZeroOffset; + LISet32( dlibZeroOffset, 0 ); + + /* save seek position before line record is written in case of error */ + hrErr = lpLLStm->lpVtbl->Seek( + lpLLStm, + dlibZeroOffset, + STREAM_SEEK_CUR, + (ULARGE_INTEGER FAR*)&dlibSavePos + ); + if (hrErr != NOERROR) return FALSE; + +#if defined( OLE_CNTR ) + if (lpLine->m_lineType == CONTAINERLINETYPE) { + /* OLE2NOTE: asking an OLE object to save may cause the + ** object to send an OnViewChange notification if there are any + ** outstanding changes to the object. this is particularly true + ** for objects with coarse update granularity like OLE 1.0 + ** objects. if an OnViewChange notification is received then the + ** object's presentation cache will be updated BEFORE it is + ** saved. It is important that the extents stored as part of + ** the ContainerLine/Line record associated with the OLE object + ** are updated before the Line data is saved to the storage. it + ** is important that this extent information matches the data + ** saved with the OLE object. the Line extent information is + ** updated in the IAdviseSink::OnViewChange method implementation. + */ + // only save the OLE object if format is compatible. + if (uFormat != ((LPCONTAINERAPP)g_lpApp)->m_cfCntrOutl) + goto error; + + fStatus = ContainerLine_SaveOleObjectToStg( + (LPCONTAINERLINE)lpLine, + lpSrcStg, + lpDestStg, + fRemember + ); + if (! fStatus) goto error; + } +#endif + + // Compilers should handle aligment correctly + lineRecord.m_lineType = (USHORT) lpLine->m_lineType; + lineRecord.m_nTabLevel = (USHORT) lpLine->m_nTabLevel; + lineRecord.m_nTabWidthInHimetric = (USHORT) lpLine->m_nTabWidthInHimetric; + lineRecord.m_nWidthInHimetric = (USHORT) lpLine->m_nWidthInHimetric; + lineRecord.m_nHeightInHimetric = (USHORT) lpLine->m_nHeightInHimetric; + lineRecord.m_reserved = 0; + + /* write line record header */ + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&lineRecord, + sizeof(lineRecord), + &nWritten + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("Write Line header returned", hrErr); + goto error; + } + + switch (lpLine->m_lineType) { + case TEXTLINETYPE: + fStatus = TextLine_SaveToStm((LPTEXTLINE)lpLine, lpLLStm); + if (! fStatus) goto error; + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + fStatus=ContainerLine_SaveToStm((LPCONTAINERLINE)lpLine,lpLLStm); + if (! fStatus) goto error; + break; +#endif + + default: + goto error; // unknown line type + } + + return TRUE; + +error: + + /* retore seek position prior to writing Line record */ + lpLLStm->lpVtbl->Seek( + lpLLStm, + dlibSavePos, + STREAM_SEEK_SET, + NULL + ); + + return FALSE; +} + + +/* Line_LoadFromStg + * ---------------- + * + * Load a single line object from storage + */ +LPLINE Line_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc) +{ + LINERECORD_ONDISK lineRecord; + LPLINE lpLine = NULL; + ULONG nRead; + HRESULT hrErr; + + /* read line record header */ + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&lineRecord, + sizeof(lineRecord), + &nRead + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("Read Line header returned", hrErr); + return NULL; + } + + switch ((LINETYPE) lineRecord.m_lineType) { + case TEXTLINETYPE: + lpLine = TextLine_LoadFromStg(lpSrcStg, lpLLStm, lpDestDoc); + break; + +#if defined( OLE_CNTR ) + case CONTAINERLINETYPE: + lpLine = ContainerLine_LoadFromStg(lpSrcStg, lpLLStm, lpDestDoc); + break; +#endif + + default: + return NULL; // unknown line type + } + + lpLine->m_lineType = (LINETYPE) lineRecord.m_lineType; + lpLine->m_nTabLevel = (UINT) lineRecord.m_nTabLevel; + lpLine->m_nTabWidthInHimetric = (UINT) lineRecord.m_nTabWidthInHimetric; + lpLine->m_nWidthInHimetric = (UINT) lineRecord.m_nWidthInHimetric; + lpLine->m_nHeightInHimetric = (UINT) lineRecord.m_nHeightInHimetric; + + return lpLine; +} + + +/* Line_IsSelected + * --------------- + * + * Return the selection state of the line + */ +BOOL Line_IsSelected(LPLINE lpLine) +{ + if (!lpLine) + return FALSE; + + return lpLine->m_fSelected; +} diff --git a/private/oleutest/letest/outline/outllist.c b/private/oleutest/letest/outline/outllist.c new file mode 100644 index 000000000..b263eebba --- /dev/null +++ b/private/oleutest/letest/outline/outllist.c @@ -0,0 +1,1183 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outldata.c +** +** This file contains LineList and NameTable functions +** and related support functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +char ErrMsgListBox[] = "Can't create ListBox!"; + +static int g_iMapMode; + +/* LineList_Init + * ------------- + * + * Create and Initialize the LineList (owner-drawn listbox) + */ +BOOL LineList_Init(LPLINELIST lpLL, LPOUTLINEDOC lpOutlineDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + +#if defined( INPLACE_CNTR ) + lpLL->m_hWndListBox = CreateWindow( + "listbox", /* Window class name */ + NULL, /* Window's title */ + + /* OLE2NOTE: an in-place contanier MUST use + ** WS_CLIPCHILDREN window style for the window + ** that it uses as the parent for the server's + ** in-place active window so that its + ** painting does NOT interfere with the painting + ** of the server's in-place active child window. + */ + + WS_CLIPCHILDREN | + WS_CHILDWINDOW | + WS_VISIBLE | + WS_VSCROLL | + WS_HSCROLL | + LBS_EXTENDEDSEL | + LBS_NOTIFY | + LBS_OWNERDRAWVARIABLE | + LBS_NOINTEGRALHEIGHT | + LBS_USETABSTOPS, + 0, 0, /* Use default X, Y */ + 0, 0, /* Use default X, Y */ + lpOutlineDoc->m_hWndDoc,/* Parent window's handle */ + (HMENU)IDC_LINELIST, /* Child Window ID */ + lpOutlineApp->m_hInst, /* Instance of window */ + NULL); /* Create struct for WM_CREATE */ +#else + lpLL->m_hWndListBox = CreateWindow( + "listbox", /* Window class name */ + NULL, /* Window's title */ + WS_CHILDWINDOW | + WS_VISIBLE | + WS_VSCROLL | + WS_HSCROLL | + LBS_EXTENDEDSEL | + LBS_NOTIFY | + LBS_OWNERDRAWVARIABLE | + LBS_NOINTEGRALHEIGHT | + LBS_USETABSTOPS, + 0, 0, /* Use default X, Y */ + 0, 0, /* Use default X, Y */ + lpOutlineDoc->m_hWndDoc,/* Parent window's handle */ + (HMENU)IDC_LINELIST, /* Child Window ID */ + lpOutlineApp->m_hInst, /* Instance of window */ + NULL); /* Create struct for WM_CREATE */ + +#endif + + + if(! lpLL->m_hWndListBox) { + OutlineApp_ErrorMessage(g_lpApp, ErrMsgListBox); + return FALSE; + } + + lpOutlineApp->m_ListBoxWndProc = + (FARPROC) GetWindowLong ( lpLL->m_hWndListBox, GWL_WNDPROC ); + SetWindowLong (lpLL->m_hWndListBox, GWL_WNDPROC, (LONG) LineListWndProc); + +#if defined ( USE_DRAGDROP ) + /* m_iDragOverLine saves index of line that has drag/drop target + ** feedback. we currently use our focus rectangle feedback for + ** this. it would be better to have a different visual feedback + ** for potential target of the pending drop. + */ + lpLL->m_iDragOverLine = -1; +#endif + + lpLL->m_nNumLines = 0; + lpLL->m_nMaxLineWidthInHimetric = 0; + lpLL->m_lpDoc = lpOutlineDoc; + _fmemset(&lpLL->m_lrSaveSel, 0, sizeof(LINERANGE)); + + return TRUE; +} + + +/* LineList_Destroy + * ---------------- + * + * Clear (delete) all Line objects from the list and free supporting + * memory (ListBox Window) used by the LineList object itself. + */ +void LineList_Destroy(LPLINELIST lpLL) +{ + int i; + int linesTotal = lpLL->m_nNumLines; + + // Delete all Line objects + for (i = 0; i < linesTotal; i++) + LineList_DeleteLine(lpLL, 0); // NOTE: always delete line 0 + + // Remove all Lines from the ListBox + SendMessage(lpLL->m_hWndListBox,LB_RESETCONTENT,0,0L); + + lpLL->m_nNumLines=0; + DestroyWindow(lpLL->m_hWndListBox); + lpLL->m_hWndListBox = NULL; +} + + +/* LineList_AddLine + * ---------------- + * + * Add one line to the list box. The line is added following the + * line with index "nIndex". If nIndex is larger than the number of lines + * in the ListBox, then the line is appended to the end. The selection + * is set to the newly added line. + */ +void LineList_AddLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex) +{ + int nAddIndex = (lpLL->m_nNumLines == 0 ? + 0 : + (nIndex >= lpLL->m_nNumLines ? lpLL->m_nNumLines : nIndex+1)); + LINERANGE lrSel; + +#if defined( USE_HEADING ) + int nHeight = Line_GetHeightInHimetric(lpLine); + + nHeight = XformHeightInHimetricToPixels(NULL, nHeight); + + // Add a dummy string to the row heading + Heading_RH_SendMessage(OutlineDoc_GetHeading(lpLL->m_lpDoc), + LB_INSERTSTRING, (WPARAM)nAddIndex, MAKELPARAM(nHeight, 0)); +#endif + + + lrSel.m_nStartLine = nAddIndex; + lrSel.m_nEndLine = nAddIndex; + + if (!lpLine) { + OutlineApp_ErrorMessage(g_lpApp, "Could not create line."); + return; + } + + SendMessage(lpLL->m_hWndListBox, LB_INSERTSTRING, (WPARAM)nAddIndex, + (DWORD)lpLine); + + LineList_SetMaxLineWidthInHimetric( + lpLL, + Line_GetTotalWidthInHimetric(lpLine) + ); + + lpLL->m_nNumLines++; + + LineList_SetSel(lpLL, &lrSel); +} + + +/* LineList_DeleteLine + * ------------------- + * + * Delete one line from listbox and memory + */ +void LineList_DeleteLine(LPLINELIST lpLL, int nIndex) +{ + LPLINE lpLine = LineList_GetLine(lpLL, nIndex); + BOOL fResetSel; + + fResetSel = (BOOL)SendMessage(lpLL->m_hWndListBox, LB_GETSEL, (WPARAM)nIndex, 0L); + + if (lpLine) + Line_Delete(lpLine); // free memory of Line + + // Remove the Line from the ListBox + SendMessage(lpLL->m_hWndListBox, LB_DELETESTRING, (WPARAM)nIndex, 0L); + lpLL->m_nNumLines--; + + if (fResetSel) { + if (nIndex > 0) { +#if defined( WIN32 ) + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)TRUE, + (LPARAM)nIndex-1 + ); +#else + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)TRUE, + MAKELPARAM(nIndex-1,0) + ); +#endif + } else { + if (lpLL->m_nNumLines > 0) { +#if defined( WIN32 ) + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)TRUE, + (LPARAM)0 + ); +#else + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)TRUE, + MAKELPARAM(0,0) + ); +#endif + } + } + } + +#if defined( USE_HEADING ) + // Remove the dummy string from the row heading + Heading_RH_SendMessage(OutlineDoc_GetHeading(lpLL->m_lpDoc), + LB_DELETESTRING, (WPARAM)nIndex, 0L); +#endif + +} + + +/* LineList_ReplaceLine + * -------------------- + * + * Replace the line at a given index in the list box with a new + * line. + */ +void LineList_ReplaceLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex) +{ + LPLINE lpOldLine = LineList_GetLine(lpLL, nIndex); + + if (lpOldLine) + Line_Delete(lpOldLine); // free memory of Line + else + return; // if no previous line then invalid index + + SendMessage( + lpLL->m_hWndListBox, + LB_SETITEMDATA, + (WPARAM)nIndex, + (LPARAM)lpLine + ); +} + + +/* LineList_GetLineIndex + * --------------------- + * + * Return the index of the Line given a pointer to the line. + * Return -1 if the line is not found. + */ +int LineList_GetLineIndex(LPLINELIST lpLL, LPLINE lpLine) +{ + LRESULT lRet; + + if (! lpLine) return -1; + + lRet = SendMessage( + lpLL->m_hWndListBox, + LB_FINDSTRING, + (WPARAM)-1, + (LPARAM)(LPCSTR)lpLine + ); + + return ((lRet == LB_ERR) ? -1 : (int)lRet); +} + + +/* LineList_GetLine + * ---------------- + * + * Retrieve the pointer to the Line given its index in the LineList + */ +LPLINE LineList_GetLine(LPLINELIST lpLL, int nIndex) +{ + DWORD dWord; + LRESULT lRet; + + if (lpLL->m_nNumLines == 0 || nIndex > lpLL->m_nNumLines || nIndex < 0) + return NULL; + + lRet = SendMessage( + lpLL->m_hWndListBox,LB_GETTEXT,nIndex,(LPARAM)(LPCSTR)&dWord); + + return ((lRet == LB_ERR || lRet == 0) ? NULL : (LPLINE)dWord); +} + + +/* LineList_SetFocusLine + * --------------------- + * + */ + +void LineList_SetFocusLine ( LPLINELIST lpLL, WORD wIndex ) +{ + + SendMessage(lpLL->m_hWndListBox, LB_SETCARETINDEX, (WPARAM)wIndex, 0L ); + +} + + +/* LineList_GetLineRect + * -------------------- + * + * Retrieve the rectangle of a Line given its index in the LineList + */ +BOOL LineList_GetLineRect(LPLINELIST lpLL, int nIndex, LPRECT lpRect) +{ + DWORD iReturn = (DWORD)LB_ERR; + + if ( !(lpLL->m_nNumLines == 0 || nIndex > lpLL->m_nNumLines || nIndex < 0) ) + iReturn = SendMessage(lpLL->m_hWndListBox,LB_GETITEMRECT,nIndex,(LPARAM)lpRect); + + return (iReturn == LB_ERR ? FALSE : TRUE ); +} + + +/* LineList_GetFocusLineIndex + * -------------------------- + * + * Get the index of the line that currently has focus (the active line). + */ +int LineList_GetFocusLineIndex(LPLINELIST lpLL) +{ + return (int)SendMessage(lpLL->m_hWndListBox,LB_GETCARETINDEX,0,0L); +} + + +/* LineList_GetCount + * ----------------- + * + * Return number of line objects + */ +int LineList_GetCount(LPLINELIST lpLL) +{ + if (lpLL) + return lpLL->m_nNumLines; + else { + OleDbgAssert(lpLL!=NULL); + return 0; + } +} + + +/* LineList_SetMaxLineWidthInHimetric + * ---------------------------------- + * + * Adjust the maximum line width for the listbox. The max line width is + * used to determine if a horizontal scroll bar is needed. + * + * Parameters: + * nWidthInHimetric - if +ve, width of an additional line + * - if -ve, reset Max to be the value + * + * Returns: + * TRUE is max line width of LineList changed + * FALSE if no change + */ +BOOL LineList_SetMaxLineWidthInHimetric(LPLINELIST lpLL, int nWidthInHimetric) +{ + int nWidthInPix; + BOOL fSizeChanged = FALSE; + LPSCALEFACTOR lpscale; + + if (!lpLL) + return FALSE; + + lpscale = OutlineDoc_GetScaleFactor(lpLL->m_lpDoc); + + if (nWidthInHimetric < 0) { + lpLL->m_nMaxLineWidthInHimetric = -1; + nWidthInHimetric *= -1; + } + + if (nWidthInHimetric > lpLL->m_nMaxLineWidthInHimetric) { + lpLL->m_nMaxLineWidthInHimetric = nWidthInHimetric; + nWidthInPix = XformWidthInHimetricToPixels(NULL, nWidthInHimetric + + LOWORD(OutlineDoc_GetMargin(lpLL->m_lpDoc)) + + HIWORD(OutlineDoc_GetMargin(lpLL->m_lpDoc))); + + nWidthInPix = (int)(nWidthInPix * lpscale->dwSxN / lpscale->dwSxD); + SendMessage( + lpLL->m_hWndListBox, + LB_SETHORIZONTALEXTENT, + nWidthInPix, + 0L + ); + fSizeChanged = TRUE; + +#if defined( USE_HEADING ) + Heading_CH_SetHorizontalExtent( + OutlineDoc_GetHeading(lpLL->m_lpDoc), lpLL->m_hWndListBox); +#endif + + } + return fSizeChanged; +} + + +/* LineList_GetMaxLineWidthInHimetric + * ---------------------------------- + * + * Return the width of the widest line + */ +int LineList_GetMaxLineWidthInHimetric(LPLINELIST lpLL) +{ + return lpLL->m_nMaxLineWidthInHimetric; +} + + +/* LineList_RecalcMaxLineWidthInHimetric + * ------------------------------------- + * + * Recalculate the maximum line width in the entire list. + * + * Parameters: + * nWidthInHimetric should be set to the width of line being removed. + * nWidthInHimetric == 0 forces list to recalculate in all cases. + * nWidthInHimetric == current max width => forces recalc. + * + * Returns: + * TRUE is max line width of LineList changed + * FALSE if no change + */ +BOOL LineList_RecalcMaxLineWidthInHimetric( + LPLINELIST lpLL, + int nWidthInHimetric +) +{ + int i; + LPLINE lpLine; + BOOL fSizeChanged = FALSE; + int nOrgMaxLineWidthInHimetric = lpLL->m_nMaxLineWidthInHimetric; + + if (nWidthInHimetric == 0 || + nWidthInHimetric == lpLL->m_nMaxLineWidthInHimetric) { + + lpLL->m_nMaxLineWidthInHimetric = -1; + + LineList_SetMaxLineWidthInHimetric(lpLL, 0); + + for(i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + LineList_SetMaxLineWidthInHimetric( + lpLL, + Line_GetTotalWidthInHimetric(lpLine) + ); + } + } + + if (nOrgMaxLineWidthInHimetric != lpLL->m_nMaxLineWidthInHimetric) + fSizeChanged = TRUE; + + return fSizeChanged; +} + + +/* LineList_CalcSelExtentInHimetric + * -------------------------------- + * + * Calculate the extents (widht and height) of a selection of lines. + * + * if lplrSel == NULL, calculate extent of all lines. + */ +void LineList_CalcSelExtentInHimetric( + LPLINELIST lpLL, + LPLINERANGE lplrSel, + LPSIZEL lpsizel +) +{ + int i; + int nEndLine; + int nStartLine; + LPLINE lpLine; + long lWidth; + + if (lplrSel) { + nEndLine = lplrSel->m_nEndLine; + nStartLine = lplrSel->m_nStartLine; + } else { + nEndLine = LineList_GetCount(lpLL) - 1; + nStartLine = 0; + } + + lpsizel->cx = 0; + lpsizel->cy = 0; + + for(i = nStartLine; i <= nEndLine; i++) { + lpLine=LineList_GetLine(lpLL,i); + if (lpLine) { + lWidth = (long)Line_GetTotalWidthInHimetric(lpLine); + lpsizel->cx = max(lpsizel->cx, lWidth); + lpsizel->cy += lpLine->m_nHeightInHimetric; + } + } +} + + +/* LineList_GetWindow + * ------------------ + * + * Return handle of list box + */ +HWND LineList_GetWindow(LPLINELIST lpLL) +{ + return lpLL->m_hWndListBox; +} + + +/* LineList_GetDC + * -------------- + * + * Return DC handle of list box + */ +HDC LineList_GetDC(LPLINELIST lpLL) +{ + HFONT hfontOld; + HDC hDC = GetDC(lpLL->m_hWndListBox); + int iXppli; //* pixels per logical inch along width + int iYppli; //* pixels per logical inch along height + SIZE size; + + // Setup a mapping mode for the DC which maps physical pixel + // coordinates to HIMETRIC units. The standard MM_HIMETRIC mapping + // mode does not work correctly because it does not take into + // account that a logical inch on the display screen is drawn + // physically larger than 1 inch. We will setup an anisotropic + // mapping mode which will perform the transformation properly. + + g_iMapMode = SetMapMode(hDC, MM_ANISOTROPIC); + iXppli = GetDeviceCaps (hDC, LOGPIXELSX); + iYppli = GetDeviceCaps (hDC, LOGPIXELSY); + SetViewportExtEx(hDC, iXppli, iYppli, &size); + SetWindowExtEx(hDC, HIMETRIC_PER_INCH, HIMETRIC_PER_INCH, &size); + + // Set the default font size, and font face name + hfontOld = SelectObject(hDC, OutlineApp_GetActiveFont(g_lpApp)); + + return hDC; +} + + +/* LineList_ReleaseDC + * ------------------ + * + * Release DC of list box returned from previous LineList_GetDC call. + */ +void LineList_ReleaseDC(LPLINELIST lpLL, HDC hDC) +{ + SetMapMode(hDC, g_iMapMode); + ReleaseDC(lpLL->m_hWndListBox, hDC); +} + + +/* LineList_SetLineHeight + * ---------------------- + * + * Set the height of a line in the LineList list box + */ +void LineList_SetLineHeight(LPLINELIST lpLL,int nIndex,int nHeightInHimetric) +{ + LPARAM lParam; + LPOUTLINEDOC lpDoc; + LPSCALEFACTOR lpscale; + UINT uHeightInPix; + LPHEADING lphead; + + if (!lpLL) + return; + + lpDoc = lpLL->m_lpDoc; + lphead = OutlineDoc_GetHeading(lpDoc); + lpscale = OutlineDoc_GetScaleFactor(lpDoc); + + uHeightInPix = XformHeightInHimetricToPixels(NULL, nHeightInHimetric); + + Heading_RH_SendMessage(lphead, LB_SETITEMDATA, (WPARAM)nIndex, + MAKELPARAM(uHeightInPix, 0)); + + uHeightInPix = (UINT)(uHeightInPix * lpscale->dwSyN / lpscale->dwSyD); + + if (uHeightInPix > LISTBOX_HEIGHT_LIMIT) + uHeightInPix = LISTBOX_HEIGHT_LIMIT; + + + lParam = MAKELPARAM(uHeightInPix, 0); + SendMessage(lpLL->m_hWndListBox,LB_SETITEMHEIGHT,(WPARAM)nIndex, lParam); + Heading_RH_SendMessage(lphead, LB_SETITEMHEIGHT, (WPARAM)nIndex, lParam); + Heading_RH_ForceRedraw(lphead, TRUE); +} + + +/* LineList_ReScale + * ---------------- + * + * Re-scale the LineList list box + */ +void LineList_ReScale(LPLINELIST lpLL, LPSCALEFACTOR lpscale) +{ + int nIndex; + LPLINE lpLine; + UINT uWidthInHim; + + if (!lpLL) + return; + + for (nIndex = 0; nIndex < lpLL->m_nNumLines; nIndex++) { + lpLine = LineList_GetLine(lpLL, nIndex); + if (lpLine) { + LineList_SetLineHeight( + lpLL, + nIndex, + Line_GetHeightInHimetric(lpLine) + ); + } + } + + uWidthInHim = LineList_GetMaxLineWidthInHimetric(lpLL); + LineList_SetMaxLineWidthInHimetric(lpLL, -(int)uWidthInHim); +} + +/* LineList_SetSel + * --------------- + * + * Set the selection in list box + */ +void LineList_SetSel(LPLINELIST lpLL, LPLINERANGE lplrSel) +{ + DWORD dwSel; + + if (lpLL->m_nNumLines <= 0 || lplrSel->m_nStartLine < 0) + return; // no lines in list; can't set a selection + + dwSel = MAKELPARAM(lplrSel->m_nStartLine, lplrSel->m_nEndLine); + + lpLL->m_lrSaveSel = *lplrSel; + + /* remove previous selection */ +#if defined( WIN32 ) + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)FALSE, + (LPARAM)-1 + ); +#else + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)FALSE, + MAKELPARAM(-1,0) + ); +#endif + + /* mark selection */ + SendMessage(lpLL->m_hWndListBox,LB_SELITEMRANGE, (WPARAM)TRUE, (LPARAM)dwSel); + /* set focus line (caret) */ + LineList_SetFocusLine ( lpLL, (WORD)lplrSel->m_nStartLine ); + +} + + +/* LineList_GetSel + * --------------- + * + * Get the selection in list box. + * + * Returns the count of items selected + */ +int LineList_GetSel(LPLINELIST lpLL, LPLINERANGE lplrSel) +{ + int nNumSel=(int)SendMessage(lpLL->m_hWndListBox,LB_GETSELCOUNT,0,0L); + + if (nNumSel) { + SendMessage(lpLL->m_hWndListBox,LB_GETSELITEMS, + (WPARAM)1,(LPARAM)(int FAR*)&(lplrSel->m_nStartLine)); + lplrSel->m_nEndLine = lplrSel->m_nStartLine + nNumSel - 1; + } else { + _fmemset(lplrSel, 0, sizeof(LINERANGE)); + } + return nNumSel; +} + + +/* LineList_RemoveSel + * ------------------ + * + * Remove the selection in list box but save the selection state so that + * it can be restored by calling LineList_RestoreSel + * LineList_RemoveSel is called when the LineList window looses focus. + */ +void LineList_RemoveSel(LPLINELIST lpLL) +{ + LINERANGE lrSel; + if (LineList_GetSel(lpLL, &lrSel) > 0) { + lpLL->m_lrSaveSel = lrSel; +#if defined( WIN32 ) + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)FALSE, + (LPARAM)-1 + ); +#else + SendMessage( + lpLL->m_hWndListBox, + LB_SETSEL, + (WPARAM)FALSE, + MAKELPARAM(-1,0) + ); +#endif + } +} + + +/* LineList_RestoreSel + * ------------------ + * + * Restore the selection in list box that was previously saved by a call to + * LineList_RemoveSel. + * LineList_RestoreSel is called when the LineList window gains focus. + */ +void LineList_RestoreSel(LPLINELIST lpLL) +{ + LineList_SetSel(lpLL, &lpLL->m_lrSaveSel); +} + + +/* LineList_SetRedraw + * ------------------ + * + * Enable/Disable the redraw of the linelist (listbox) on screen + * + * fEnbaleDraw = TRUE - enable redraw + * FALSE - disable redraw + */ +void LineList_SetRedraw(LPLINELIST lpLL, BOOL fEnableDraw) +{ + SendMessage(lpLL->m_hWndListBox,WM_SETREDRAW,(WPARAM)fEnableDraw,0L); +} + + +/* LineList_ForceRedraw + * -------------------- + * + * Force redraw of the linelist (listbox) on screen + */ +void LineList_ForceRedraw(LPLINELIST lpLL, BOOL fErase) +{ + InvalidateRect(lpLL->m_hWndListBox, NULL, fErase); +} + + +/* LineList_ForceLineRedraw + * ------------------------ + * + * Force a particular line of the linelist (listbox) to redraw. + */ +void LineList_ForceLineRedraw(LPLINELIST lpLL, int nIndex, BOOL fErase) +{ + RECT rect; + + LineList_GetLineRect( lpLL, nIndex, (LPRECT)&rect ); + InvalidateRect( lpLL->m_hWndListBox, (LPRECT)&rect, fErase ); +} + + +/* LineList_ScrollLineIntoView + * --------------------------- + * Make sure that the specified line is in view; if necessary scroll + * the listbox. if any portion of the line is visible, then no + * scrolling will occur. + */ +void LineList_ScrollLineIntoView(LPLINELIST lpLL, int nIndex) +{ + RECT rcWindow; + RECT rcLine; + RECT rcInt; + + if ( lpLL->m_nNumLines == 0 ) + return; + + if (! LineList_GetLineRect( lpLL, nIndex, (LPRECT)&rcLine ) ) + return; + + GetClientRect( lpLL->m_hWndListBox, (LPRECT) &rcWindow ); + + if (! IntersectRect((LPRECT)&rcInt, (LPRECT)&rcWindow, (LPRECT)&rcLine)) + SendMessage( + lpLL->m_hWndListBox, + LB_SETTOPINDEX, + (WPARAM)nIndex, + (LPARAM)NULL + ); +} + + +/* LineList_CopySelToDoc + * --------------------- + * + * Copy the selection of the linelist to another document + * + * RETURNS: number of lines copied. + */ +int LineList_CopySelToDoc( + LPLINELIST lpSrcLL, + LPLINERANGE lplrSel, + LPOUTLINEDOC lpDestDoc +) +{ + int nEndLine; + int nStartLine; + LPLINELIST lpDestLL = &lpDestDoc->m_LineList; + signed short nDestIndex = LineList_GetFocusLineIndex(lpDestLL); + LPLINE lpSrcLine; + int nCopied = 0; + int i; + + if (lplrSel) { + nEndLine = lplrSel->m_nEndLine; + nStartLine = lplrSel->m_nStartLine; + } else { + nEndLine = LineList_GetCount(lpSrcLL) - 1; + nStartLine = 0; + } + + for(i = nStartLine; i <= nEndLine; i++) { + lpSrcLine = LineList_GetLine(lpSrcLL, i); + if (lpSrcLine && Line_CopyToDoc(lpSrcLine, lpDestDoc, nDestIndex)) { + nDestIndex++; + nCopied++; + } + } + + return nCopied; +} + + +/* LineList_SaveSelToStg + * --------------------- + * + * Save lines in selection into lpDestStg. + * + * Return TRUE if ok, FALSE if error + */ +BOOL LineList_SaveSelToStg( + LPLINELIST lpLL, + LPLINERANGE lplrSel, + UINT uFormat, + LPSTORAGE lpSrcStg, + LPSTORAGE lpDestStg, + LPSTREAM lpLLStm, + BOOL fRemember +) +{ + int nEndLine; + int nStartLine; + int nNumLinesWritten = 0; + HRESULT hrErr = NOERROR; + ULONG nWritten; + LPLINE lpLine; + LINELISTHEADER_ONDISK llhRecord; + int i; + LARGE_INTEGER dlibSaveHeaderPos; + LARGE_INTEGER dlibZeroOffset; + LISet32( dlibZeroOffset, 0 ); + + if (lplrSel) { + nEndLine = lplrSel->m_nEndLine; + nStartLine = lplrSel->m_nStartLine; + } else { + nEndLine = LineList_GetCount(lpLL) - 1; + nStartLine = 0; + } + + _fmemset(&llhRecord,0,sizeof(llhRecord)); + + /* save seek position for LineList header record */ + hrErr = lpLLStm->lpVtbl->Seek( + lpLLStm, + dlibZeroOffset, + STREAM_SEEK_CUR, + (ULARGE_INTEGER FAR*)&dlibSaveHeaderPos + ); + if (hrErr != NOERROR) goto error; + + /* write LineList header record */ + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&llhRecord, + sizeof(llhRecord), + &nWritten + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Write LineList header returned", hrErr); + goto error; + } + + for(i = nStartLine; i <= nEndLine; i++) { + lpLine = LineList_GetLine(lpLL, i); + if(lpLine && + Line_SaveToStg(lpLine, uFormat, lpSrcStg, lpDestStg, lpLLStm, + fRemember)) + llhRecord.m_nNumLines++; + } + + /* retore seek position for LineList header record */ + hrErr = lpLLStm->lpVtbl->Seek( + lpLLStm, + dlibSaveHeaderPos, + STREAM_SEEK_SET, + NULL + ); + if (hrErr != NOERROR) goto error; + + /* write LineList header record */ + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&llhRecord, + sizeof(llhRecord), + &nWritten + ); + if (hrErr != NOERROR) goto error; + + /* reset seek position to end of stream */ + hrErr = lpLLStm->lpVtbl->Seek( + lpLLStm, + dlibZeroOffset, + STREAM_SEEK_END, + NULL + ); + if (hrErr != NOERROR) goto error; + + return TRUE; + +error: +#if defined( _DEBUG ) + OleDbgAssertSz( + hrErr == NOERROR, + "Could not write LineList header to LineList stream" + ); +#endif + return FALSE; +} + + +/* LineList_LoadFromStg + * -------------------- + * + * Load lines into linelist from storage. + * + * Return TRUE if ok, FALSE if error + */ +BOOL LineList_LoadFromStg( + LPLINELIST lpLL, + LPSTORAGE lpSrcStg, + LPSTREAM lpLLStm +) +{ + HRESULT hrErr; + ULONG nRead; + LPLINE lpLine; + int i; + int nNumLines; + LINELISTHEADER_ONDISK llineRecord; + + /* write LineList header record */ + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&llineRecord, + sizeof(llineRecord), + &nRead + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("Read LineList header returned", hrErr); + goto error; + } + + nNumLines = (int) llineRecord.m_nNumLines; + + for(i = 0; i < nNumLines; i++) { + lpLine = Line_LoadFromStg(lpSrcStg, lpLLStm, lpLL->m_lpDoc); + if (! lpLine) + goto error; + + // Directly add lines to LineList without trying to update a NameTbl + LineList_AddLine(lpLL, lpLine, i-1); + } + + return TRUE; + +error: + // Delete any Line objects that were created + if (lpLL->m_nNumLines > 0) { + int nNumLines = lpLL->m_nNumLines; + for (i = 0; i < nNumLines; i++) + LineList_DeleteLine(lpLL, i); + } + + return FALSE; +} + + +#if defined( USE_DRAGDROP ) + + +/* LineList_SetFocusLineFromPointl + * ------------------------------- + * + */ + +void LineList_SetFocusLineFromPointl( LPLINELIST lpLL, POINTL pointl ) +{ + int i = LineList_GetLineIndexFromPointl( lpLL, pointl ); + + if ( i == (int)-1) + return ; + else + LineList_SetFocusLine( lpLL, (WORD)i ); +} + + +/* LineList_SetDragOverLineFromPointl + * ---------------------------------- + * + */ + +void LineList_SetDragOverLineFromPointl ( LPLINELIST lpLL, POINTL pointl ) +{ + int nIndex = LineList_GetLineIndexFromPointl( lpLL, pointl ); + LPLINE lpline = LineList_GetLine( lpLL, nIndex ); + + if (!lpline) + return; + + if (! lpline->m_fDragOverLine) { + /* user has dragged over a new line. force new drop target line + ** to repaint so that drop feedback will be drawn. + */ + lpline->m_fDragOverLine = TRUE; + LineList_ForceLineRedraw( lpLL, nIndex, TRUE /*fErase*/); + + if (lpLL->m_iDragOverLine!= -1 && lpLL->m_iDragOverLine!=nIndex) { + + /* force previous drop target line to repaint so that drop + ** feedback will be undrawn + */ + lpline = LineList_GetLine( lpLL, lpLL->m_iDragOverLine ); + if (lpline) + lpline->m_fDragOverLine = FALSE; + + LineList_ForceLineRedraw( + lpLL,lpLL->m_iDragOverLine,TRUE /*fErase*/); + } + + lpLL->m_iDragOverLine = nIndex; + + // Force repaint immediately + UpdateWindow(lpLL->m_hWndListBox); + } +} + + +/* LineList_Scroll + * --------------- + * + * Scroll the LineList list box in the desired direction by one line. + * + * this function is called during a drag operation. + */ + +void LineList_Scroll(LPLINELIST lpLL, DWORD dwScrollDir) +{ + switch (dwScrollDir) { + case SCROLLDIR_UP: + SendMessage( lpLL->m_hWndListBox, WM_VSCROLL, SB_LINEUP, 0L ); + break; + + case SCROLLDIR_DOWN: + SendMessage( lpLL->m_hWndListBox, WM_VSCROLL, SB_LINEDOWN, 0L ); + break; + } +} + + +/* LineList_GetLineIndexFromPointl + * ------------------------------- + * do hit test to get index of line corresponding to pointl + */ +int LineList_GetLineIndexFromPointl(LPLINELIST lpLL, POINTL pointl) +{ + RECT rect; + POINT point; + DWORD i; + + point.x = (int)pointl.x; + point.y = (int)pointl.y; + + ScreenToClient( lpLL->m_hWndListBox, &point); + + if ( lpLL->m_nNumLines == 0 ) + return -1; + + GetClientRect( lpLL->m_hWndListBox, (LPRECT) &rect ); + + i = SendMessage( lpLL->m_hWndListBox, LB_GETTOPINDEX, (WPARAM)NULL, (LPARAM)NULL ); + + for ( ;; i++){ + + RECT rectItem; + + if (!LineList_GetLineRect( lpLL, (int)i, (LPRECT)&rectItem ) ) + return -1; + + if ( rectItem.top > rect.bottom ) + return -1; + + if ( rectItem.top <= point.y && point.y <= rectItem.bottom) + return (int)i; + + } + +} + + +/* LineList_RestoreDragFeedback + * ---------------------------- + * + * Retore the index of the line that currently has focus (the active line). + */ +void LineList_RestoreDragFeedback(LPLINELIST lpLL) +{ + LPLINE lpLine; + + if (lpLL->m_iDragOverLine < 0 ) + return; + + lpLine = LineList_GetLine( lpLL, lpLL->m_iDragOverLine); + + if (lpLine) { + + lpLine->m_fDragOverLine = FALSE; + LineList_ForceLineRedraw( lpLL,lpLL->m_iDragOverLine,TRUE /*fErase*/); + + // Force repaint immediately + UpdateWindow(lpLL->m_hWndListBox); + } + + lpLL->m_iDragOverLine = -1; + +} + +#endif diff --git a/private/oleutest/letest/outline/outlname.c b/private/oleutest/letest/outline/outlname.c new file mode 100644 index 000000000..640f7f27d --- /dev/null +++ b/private/oleutest/letest/outline/outlname.c @@ -0,0 +1,112 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outlname.c +** +** This file contains OutlineName functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + + +/* OutlineName_SetName + * ------------------- + * + * Change the string of a name. + */ +void OutlineName_SetName(LPOUTLINENAME lpOutlineName, LPSTR lpszName) +{ + lstrcpy(lpOutlineName->m_szName, lpszName); +} + + +/* OutlineName_SetSel + * ------------------ + * + * Change the line range of a name. + */ +void OutlineName_SetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, BOOL fRangeModified) +{ +#if defined( OLE_SERVER ) + // Call OLE server specific function instead + ServerName_SetSel((LPSERVERNAME)lpOutlineName, lplrSel, fRangeModified); +#else + + lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; + lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; +#endif +} + + +/* OutlineName_GetSel + * ------------------ + * + * Retrieve the line range of a name. + */ +void OutlineName_GetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel) +{ + lplrSel->m_nStartLine = lpOutlineName->m_nStartLine; + lplrSel->m_nEndLine = lpOutlineName->m_nEndLine; +} + + +/* OutlineName_SaveToStg + * --------------------- + * + * Save a name into a storage + */ +BOOL OutlineName_SaveToStg(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, UINT uFormat, LPSTREAM lpNTStm, BOOL FAR* lpfNameSaved) +{ + HRESULT hrErr = NOERROR; + ULONG nWritten; + + *lpfNameSaved = FALSE; + + /* if no range given or if the name is completely within the range, + ** write it out. + */ + if (!lplrSel || + ((lplrSel->m_nStartLine <= lpOutlineName->m_nStartLine) && + (lplrSel->m_nEndLine >= lpOutlineName->m_nEndLine))) { + + hrErr = lpNTStm->lpVtbl->Write( + lpNTStm, + lpOutlineName, + sizeof(OUTLINENAME), + &nWritten + ); + *lpfNameSaved = TRUE; + } + return ((hrErr == NOERROR) ? TRUE : FALSE); +} + + +/* OutlineName_LoadFromStg + * ----------------------- + * + * Load names from an open stream of a storage. if the name already + * exits in the OutlineNameTable, it is NOT modified. + * + * Returns TRUE is all ok, else FALSE. + */ +BOOL OutlineName_LoadFromStg(LPOUTLINENAME lpOutlineName, LPSTREAM lpNTStm) +{ + HRESULT hrErr = NOERROR; + ULONG nRead; + + hrErr = lpNTStm->lpVtbl->Read( + lpNTStm, + lpOutlineName, + sizeof(OUTLINENAME), + &nRead + ); + + return ((hrErr == NOERROR) ? TRUE : FALSE); +} diff --git a/private/oleutest/letest/outline/outlntbl.c b/private/oleutest/letest/outline/outlntbl.c new file mode 100644 index 000000000..e4263c9fe --- /dev/null +++ b/private/oleutest/letest/outline/outlntbl.c @@ -0,0 +1,460 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outlntbl.c +** +** This file contains OutlineNameTable functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + +char ErrMsgNameTable[] = "Can't create NameTable!"; + + +/* OutlineNameTable_Init + * --------------------- + * + * initialize a name table. + */ +BOOL OutlineNameTable_Init(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINEDOC lpOutlineDoc) +{ + HWND lpParent = OutlineDoc_GetWindow(lpOutlineDoc); + + lpOutlineNameTable->m_nCount = 0; + + /* We will use an OwnerDraw listbox as our data structure to + ** maintain the table of Names. this listbox will never be made + ** visible. the listbox is just a convenient data structure to + ** manage a collection. + */ + lpOutlineNameTable->m_hWndListBox = CreateWindow( + "listbox", /* Window class name */ + NULL, /* Window's title */ + WS_CHILDWINDOW | + LBS_OWNERDRAWFIXED, + 0, 0, /* Use default X, Y */ + 0, 0, /* Use default X, Y */ + lpParent, /* Parent window's handle */ + (HMENU)IDC_NAMETABLE, /* Child Window ID */ + g_lpApp->m_hInst, /* Instance of window */ + NULL); /* Create struct for WM_CREATE */ + + if (! lpOutlineNameTable->m_hWndListBox) { + OutlineApp_ErrorMessage(g_lpApp, ErrMsgNameTable); + return FALSE; + } + + return TRUE; +} + + +/* OutlineNameTable_Destroy + * ------------------------ + * + * Free memory used by the name table. + */ +void OutlineNameTable_Destroy(LPOUTLINENAMETABLE lpOutlineNameTable) +{ + // Delete all names + OutlineNameTable_ClearAll(lpOutlineNameTable); + + DestroyWindow(lpOutlineNameTable->m_hWndListBox); + Delete(lpOutlineNameTable); +} + + +/* OutlineNameTable_AddName + * ------------------------ + * + * Add a name to the table + */ +void OutlineNameTable_AddName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName) +{ + SendMessage( + lpOutlineNameTable->m_hWndListBox, + LB_ADDSTRING, + 0, + (DWORD)lpOutlineName + ); + lpOutlineNameTable->m_nCount++; +} + + +/* OutlineNameTable_DeleteName + * --------------------------- + * + * Delete a name from table + */ +void OutlineNameTable_DeleteName(LPOUTLINENAMETABLE lpOutlineNameTable,int nIndex) +{ + LPOUTLINENAME lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, nIndex); + +#if defined( OLE_SERVER ) + /* OLE2NOTE: if there is a pseudo object attached to this name, it + ** must first be closed before deleting the Name. this will + ** cause OnClose notification to be sent to all linking clients. + */ + ServerName_ClosePseudoObj((LPSERVERNAME)lpOutlineName); +#endif + + if (lpOutlineName) + Delete(lpOutlineName); // free memory for name + + SendMessage( + lpOutlineNameTable->m_hWndListBox, + LB_DELETESTRING, + (WPARAM)nIndex, + 0L + ); + lpOutlineNameTable->m_nCount--; +} + + +/* OutlineNameTable_GetNameIndex + * ----------------------------- + * + * Return the index of the Name given a pointer to the Name. + * Return -1 if the Name is not found. + */ +int OutlineNameTable_GetNameIndex(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName) +{ + LRESULT lReturn; + + if (! lpOutlineName) return -1; + + lReturn = SendMessage( + lpOutlineNameTable->m_hWndListBox, + LB_FINDSTRING, + (WPARAM)-1, + (LPARAM)(LPCSTR)lpOutlineName + ); + + return ((lReturn == LB_ERR) ? -1 : (int)lReturn); +} + + +/* OutlineNameTable_GetName + * ------------------------ + * + * Retrieve the pointer to the Name given its index in the NameTable + */ +LPOUTLINENAME OutlineNameTable_GetName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex) +{ + LPOUTLINENAME lpOutlineName = NULL; + LRESULT lResult; + + if (lpOutlineNameTable->m_nCount == 0 || + nIndex > lpOutlineNameTable->m_nCount || + nIndex < 0) { + return NULL; + } + + lResult = SendMessage( + lpOutlineNameTable->m_hWndListBox, + LB_GETTEXT, + nIndex, + (LPARAM)(LPCSTR)&lpOutlineName + ); + OleDbgAssert(lResult != LB_ERR); + return lpOutlineName; +} + + +/* OutlineNameTable_FindName + * ------------------------- + * + * Find a name in the name table given a string. + */ +LPOUTLINENAME OutlineNameTable_FindName(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTR lpszName) +{ + LPOUTLINENAME lpOutlineName; + BOOL fFound = FALSE; + int i; + + for (i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i); + if (lstrcmp(lpOutlineName->m_szName, lpszName) == 0) { + fFound = TRUE; + break; // FOUND MATCH! + } + } + + return (fFound ? lpOutlineName : NULL); +} + + +/* OutlineNameTable_FindNamedRange + * ------------------------------- + * + * Find a name in the name table which matches a given line range. + */ +LPOUTLINENAME OutlineNameTable_FindNamedRange(LPOUTLINENAMETABLE lpOutlineNameTable, LPLINERANGE lplrSel) +{ + LPOUTLINENAME lpOutlineName; + BOOL fFound = FALSE; + int i; + + for (i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i); + if ((lpOutlineName->m_nStartLine == lplrSel->m_nStartLine) && + (lpOutlineName->m_nEndLine == lplrSel->m_nEndLine) ) { + fFound = TRUE; + break; // FOUND MATCH! + } + } + + return (fFound ? lpOutlineName : NULL); +} + + +/* OutlineNameTable_GetCount + * ------------------------- + * + * Return number of names in nametable + */ +int OutlineNameTable_GetCount(LPOUTLINENAMETABLE lpOutlineNameTable) +{ + if (!lpOutlineNameTable) + return 0; + + return lpOutlineNameTable->m_nCount; +} + + +/* OutlineNameTable_ClearAll + * ------------------------- + * + * Remove all names from table + */ +void OutlineNameTable_ClearAll(LPOUTLINENAMETABLE lpOutlineNameTable) +{ + LPOUTLINENAME lpOutlineName; + int i; + int nCount = lpOutlineNameTable->m_nCount; + + for (i = 0; i < nCount; i++) { + lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i); + Delete(lpOutlineName); // free memory for name + } + + lpOutlineNameTable->m_nCount = 0; + SendMessage(lpOutlineNameTable->m_hWndListBox,LB_RESETCONTENT,0,0L); +} + + +/* OutlineNameTable_AddLineUpdate + * ------------------------------ + * + * Update table when a new line is added at nAddIndex + * The line used to be at nAddIndex is pushed down + */ +void OutlineNameTable_AddLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nAddIndex) +{ + LPOUTLINENAME lpOutlineName; + LINERANGE lrSel; + int i; + BOOL fRangeModified = FALSE; + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + OutlineName_GetSel(lpOutlineName, &lrSel); + + if((int)lrSel.m_nStartLine > nAddIndex) { + lrSel.m_nStartLine++; + fRangeModified = !fRangeModified; + } + if((int)lrSel.m_nEndLine > nAddIndex) { + lrSel.m_nEndLine++; + fRangeModified = !fRangeModified; + } + + OutlineName_SetSel(lpOutlineName, &lrSel, fRangeModified); + } +} + + +/* OutlineNameTable_DeleteLineUpdate + * --------------------------------- + * + * Update the table when a line at nDeleteIndex is removed + */ +void OutlineNameTable_DeleteLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nDeleteIndex) +{ + LPOUTLINENAME lpOutlineName; + LINERANGE lrSel; + int i; + BOOL fRangeModified = FALSE; + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + OutlineName_GetSel(lpOutlineName, &lrSel); + + if((int)lrSel.m_nStartLine > nDeleteIndex) { + lrSel.m_nStartLine--; + fRangeModified = !fRangeModified; + } + if((int)lrSel.m_nEndLine >= nDeleteIndex) { + lrSel.m_nEndLine--; + fRangeModified = !fRangeModified; + } + + // delete the name if its entire range is deleted + if(lrSel.m_nStartLine > lrSel.m_nEndLine) { + OutlineNameTable_DeleteName(lpOutlineNameTable, i); + i--; // re-examine this name + } else { + OutlineName_SetSel(lpOutlineName, &lrSel, fRangeModified); + } + } +} + + +/* OutlineNameTable_SaveSelToStg + * ----------------------------- + * + * Save only the names that refer to lines completely contained in the + * specified selection range. + */ +BOOL OutlineNameTable_SaveSelToStg( + LPOUTLINENAMETABLE lpOutlineNameTable, + LPLINERANGE lplrSel, + UINT uFormat, + LPSTREAM lpNTStm +) +{ + HRESULT hrErr; + ULONG nWritten; + LPOUTLINENAME lpOutlineName; + short nNameCount = 0; + BOOL fNameSaved; + BOOL fStatus; + int i; + LARGE_INTEGER dlibZeroOffset; + LISet32( dlibZeroOffset, 0 ); + + /* initially write 0 for count of names. the correct count will be + ** written at the end when we know how many names qualified to + ** be written (within the selection). + */ + hrErr = lpNTStm->lpVtbl->Write( + lpNTStm, + (short FAR*)&nNameCount, + sizeof(nNameCount), + &nWritten + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Write NameTable header returned", hrErr); + goto error; + } + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + fStatus = OutlineName_SaveToStg( + lpOutlineName, + lplrSel, + uFormat, + lpNTStm, + (BOOL FAR*)&fNameSaved + ); + if (! fStatus) goto error; + if (fNameSaved) nNameCount++; + } + + /* write the final count of names written. */ + hrErr = lpNTStm->lpVtbl->Seek( + lpNTStm, + dlibZeroOffset, + STREAM_SEEK_SET, + NULL + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Seek to NameTable header returned", hrErr); + goto error; + } + + hrErr = lpNTStm->lpVtbl->Write( + lpNTStm, + (short FAR*)&nNameCount, + sizeof(nNameCount), + &nWritten + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Write NameTable count in header returned", hrErr); + goto error; + } + + OleStdRelease((LPUNKNOWN)lpNTStm); + return TRUE; + +error: + if (lpNTStm) + OleStdRelease((LPUNKNOWN)lpNTStm); + + return FALSE; +} + + +/* OutlineNameTable_LoadFromStg + * ---------------------------- + * + * Load Name Table from file + * + * Return TRUE if ok, FALSE if error + */ +BOOL OutlineNameTable_LoadFromStg(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTORAGE lpSrcStg) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HRESULT hrErr; + IStream FAR* lpNTStm; + ULONG nRead; + short nCount; + LPOUTLINENAME lpOutlineName; + BOOL fStatus; + short i; + + hrErr = CallIStorageOpenStreamA( + lpSrcStg, + "NameTable", + NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, + 0, + &lpNTStm + ); + + if (hrErr != NOERROR) { + OleDbgOutHResult("OpenStream NameTable returned", hrErr); + goto error; + } + + hrErr = lpNTStm->lpVtbl->Read(lpNTStm,&nCount,sizeof(nCount),&nRead); + if (hrErr != NOERROR) { + OleDbgOutHResult("Read NameTable header returned", hrErr); + goto error; + } + + for (i = 0; i < nCount; i++) { + lpOutlineName = OutlineApp_CreateName(lpOutlineApp); + if (! lpOutlineName) goto error; + fStatus = OutlineName_LoadFromStg(lpOutlineName, lpNTStm); + if (! fStatus) goto error; + OutlineNameTable_AddName(lpOutlineNameTable, lpOutlineName); + } + + OleStdRelease((LPUNKNOWN)lpNTStm); + return TRUE; + +error: + if (lpNTStm) + OleStdRelease((LPUNKNOWN)lpNTStm); + + return FALSE; +} diff --git a/private/oleutest/letest/outline/outlrc.h b/private/oleutest/letest/outline/outlrc.h new file mode 100644 index 000000000..c8b88e99a --- /dev/null +++ b/private/oleutest/letest/outline/outlrc.h @@ -0,0 +1,164 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** outlrc.h +** +** This file containes constants used in rc file for Outline.exe +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if !defined( _OUTLRC_H_ ) +#define _OUTLRC_H_ + +#ifndef RC_INVOKED +#pragma message ("INCLUDING OUTLRC.H from " __FILE__) +#endif /* RC_INVOKED */ + +#if defined( OLE_SERVER ) && ! defined( INPLACE_SVR ) +#define APPNAME "SvrOutl" +#define APPMENU "SvrOutlMenu" +#define APPACCEL "SvrOutlAccel" +#define FB_EDIT_ACCEL "SvrOutlAccelFocusEdit" +#define APPICON "SvrOutlIcon" +#define APPWNDCLASS "SvrOutlApp" +#define DOCWNDCLASS "SvrOutlDoc" +#define APPDESC "OLE 2.0 Server Sample Code" +#endif // OLE_SERVER && ! INPLACE_SVR + +#if defined( INPLACE_SVR ) +#define APPNAME "ISvrOtl" +#define APPMENU "SvrOutlMenu" +#define APPACCEL "SvrOutlAccel" +#define FB_EDIT_ACCEL "SvrOutlAccelFocusEdit" +#define APPICON "SvrOutlIcon" +#define APPWNDCLASS "SvrOutlApp" +#define DOCWNDCLASS "SvrOutlDoc" +#define APPDESC "OLE 2.0 In-Place Server Sample Code" +#endif // INPLACE_SVR + +#if defined( OLE_CNTR ) && ! defined( INPLACE_CNTR ) +#define APPNAME "CntrOutl" +#define APPMENU "CntrOutlMenu" +#define APPACCEL "CntrOutlAccel" +#define FB_EDIT_ACCEL "CntrOutlAccelFocusEdit" +#define APPICON "CntrOutlIcon" +#define APPWNDCLASS "CntrOutlApp" +#define DOCWNDCLASS "CntrOutlDoc" +#define APPDESC "OLE 2.0 Container Sample Code" +#endif // OLE_CNTR && ! INPLACE_CNTR + +#if defined( INPLACE_CNTR ) +#define APPNAME "ICntrOtl" +#define APPMENU "CntrOutlMenu" +#define APPACCEL "CntrOutlAccel" +#define FB_EDIT_ACCEL "CntrOutlAccelFocusEdit" +#define APPICON "CntrOutlIcon" +#define APPWNDCLASS "CntrOutlApp" +#define DOCWNDCLASS "CntrOutlDoc" +#define APPDESC "OLE 2.0 In-Place Container Sample Code" +#endif // INPLACE_CNTR + +#if !defined( OLE_VERSION ) +#define APPNAME "Outline" +#define APPMENU "OutlineMenu" +#define APPACCEL "OutlineAccel" +#define FB_EDIT_ACCEL "OutlineAccelFocusEdit" +#define APPICON "OutlineIcon" +#define APPWNDCLASS "OutlineApp" +#define DOCWNDCLASS "OutlineDoc" +#define APPDESC "OLE 2.0 Sample Code" +#endif // OLE_VERSION + +#define IDM_FILE 1000 +#define IDM_F_NEW 1050 +#define IDM_F_OPEN 1100 +#define IDM_F_SAVE 1150 +#define IDM_F_SAVEAS 1200 +#define IDM_F_PRINT 1300 +#define IDM_F_PRINTERSETUP 1350 +#define IDM_F_EXIT 1450 +#define IDM_EDIT 2000 +#define IDM_E_UNDO 2050 +#define IDM_E_CUT 2150 +#define IDM_E_COPY 2200 +#define IDM_E_PASTE 2250 +#define IDM_E_PASTESPECIAL 2255 +#define IDM_E_CLEAR 2300 +#define IDM_E_SELECTALL 2560 +#define IDM_LINE 3000 +#define IDM_L_ADDLINE 3400 +#define IDM_L_EDITLINE 3450 +#define IDM_L_INDENTLINE 3500 +#define IDM_L_UNINDENTLINE 3550 +#define IDM_L_SETLINEHEIGHT 3560 +#define IDM_NAME 4000 +#define IDM_N_DEFINENAME 4050 +#define IDM_N_GOTONAME 4100 +#define IDM_HELP 5000 +#define IDM_H_ABOUT 5050 +#define IDM_DEBUG 6000 +#define IDM_D_DEBUGLEVEL 6050 +#define IDM_D_INSTALLMSGFILTER 6060 +#define IDM_D_REJECTINCOMING 6070 +#define IDM_O_BB_TOP 6100 +#define IDM_O_BB_BOTTOM 6150 +#define IDM_O_BB_POPUP 6200 +#define IDM_O_BB_HIDE 6210 +#define IDM_O_FB_TOP 6250 +#define IDM_O_FB_BOTTOM 6300 +#define IDM_O_FB_POPUP 6350 +#define IDM_O_HEAD_SHOW 6400 +#define IDM_O_HEAD_HIDE 6450 +#define IDM_O_SHOWOBJECT 6460 +#define IDM_V_ZOOM_400 6500 +#define IDM_V_ZOOM_300 6510 +#define IDM_V_ZOOM_200 6520 +#define IDM_V_ZOOM_100 6550 +#define IDM_V_ZOOM_75 6600 +#define IDM_V_ZOOM_50 6650 +#define IDM_V_ZOOM_25 6700 +#define IDM_V_SETMARGIN_0 6750 +#define IDM_V_SETMARGIN_1 6800 +#define IDM_V_SETMARGIN_2 6850 +#define IDM_V_SETMARGIN_3 6860 +#define IDM_V_SETMARGIN_4 6870 +#define IDM_V_ADDTOP_1 6900 +#define IDM_V_ADDTOP_2 6910 +#define IDM_V_ADDTOP_3 6920 +#define IDM_V_ADDTOP_4 6930 + + +#define IDM_FB_EDIT 7000 +#define IDM_FB_CANCEL 7005 +#define IDM_F2 7010 +#define IDM_ESCAPE 7015 + + +#define IDD_LINELISTBOX 101 +#define IDD_EDIT 102 +#define IDD_COMBO 103 +#define IDD_DELETE 104 +#define IDD_CLOSE 105 +#define IDD_APPTEXT 106 +#define IDD_FROM 107 +#define IDD_TO 108 +#define IDD_BITMAPLOCATION 109 +#define IDD_CHECK 110 +#define IDD_TEXT 111 +#define IDD_LIMIT 112 + + +#define IDC_LINELIST 201 +#define IDC_NAMETABLE 202 + + +#define WM_U_INITFRAMETOOLS WM_USER + +#ifdef RC_INVOKED +#include "debug.rc" +#endif /* RC_INVOKED */ + +#endif // _OUTLRC_H_ diff --git a/private/oleutest/letest/outline/outltxtl.c b/private/oleutest/letest/outline/outltxtl.c new file mode 100644 index 000000000..2779e701e --- /dev/null +++ b/private/oleutest/letest/outline/outltxtl.c @@ -0,0 +1,408 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** outltxtl.c +** +** This file contains TextLine methods and related support functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + +/* TextLine_Create + * --------------- + * + * Create a text line object and return the pointer + */ +LPTEXTLINE TextLine_Create(HDC hDC, UINT nTab, LPSTR lpszText) +{ + LPTEXTLINE lpTextLine; + + lpTextLine=(LPTEXTLINE) New((DWORD)sizeof(TEXTLINE)); + if (lpTextLine == NULL) { + OleDbgAssertSz(lpTextLine!=NULL,"Error allocating TextLine"); + return NULL; + } + + TextLine_Init(lpTextLine, nTab, hDC); + + if (lpszText) { + lpTextLine->m_nLength = lstrlen(lpszText); + lstrcpy((LPSTR)lpTextLine->m_szText, lpszText); + } else { + lpTextLine->m_nLength = 0; + lpTextLine->m_szText[0] = '\0'; + } + + TextLine_CalcExtents(lpTextLine, hDC); + + return(lpTextLine); +} + + +/* TextLine_Init + * ------------- + * + * Calculate the width/height of a text line object. + */ +void TextLine_Init(LPTEXTLINE lpTextLine, int nTab, HDC hDC) +{ + Line_Init((LPLINE)lpTextLine, nTab, hDC); // init the base class fields + + ((LPLINE)lpTextLine)->m_lineType = TEXTLINETYPE; + lpTextLine->m_nLength = 0; + lpTextLine->m_szText[0] = '\0'; +} + + +/* TextLine_Delete + * --------------- + * + * Delete the TextLine structure + */ +void TextLine_Delete(LPTEXTLINE lpTextLine) +{ + Delete((LPVOID)lpTextLine); +} + + +/* TextLine_Edit + * ------------- + * + * Edit the text line object. + * + * Returns TRUE if line was changed + * FALSE if the line was NOT changed + */ +BOOL TextLine_Edit(LPTEXTLINE lpLine, HWND hWndDoc, HDC hDC) +{ +#if defined( USE_FRAMETOOLS ) + LPFRAMETOOLS lptb = OutlineApp_GetFrameTools(g_lpApp); +#endif + BOOL fStatus = FALSE; + +#if defined( USE_FRAMETOOLS ) + FrameTools_FB_GetEditText(lptb, lpLine->m_szText, sizeof(lpLine->m_szText)); +#else + if (! InputTextDlg(hWndDoc, lpLine->m_szText, "Edit Line")) + return FALSE; +#endif + + lpLine->m_nLength = lstrlen(lpLine->m_szText); + TextLine_CalcExtents(lpLine, hDC); + fStatus = TRUE; + + return fStatus; +} + + +/* TextLine_CalcExtents + * -------------------- + * + * Calculate the width/height of a text line object. + */ +void TextLine_CalcExtents(LPTEXTLINE lpTextLine, HDC hDC) +{ + SIZE size; + LPLINE lpLine = (LPLINE)lpTextLine; + + if (lpTextLine->m_nLength) { + GetTextExtentPoint(hDC, lpTextLine->m_szText, + lpTextLine->m_nLength, &size); + lpLine->m_nWidthInHimetric=size.cx; + lpLine->m_nHeightInHimetric=size.cy; + } else { + // we still need to calculate proper height even for NULL string + TEXTMETRIC tm; + GetTextMetrics(hDC, &tm); + + // required to set height + lpLine->m_nHeightInHimetric = tm.tmHeight; + lpLine->m_nWidthInHimetric = 0; + } + +#if defined( _DEBUG ) + { + RECT rc; + rc.left = 0; + rc.top = 0; + rc.right = XformWidthInHimetricToPixels(hDC, + lpLine->m_nWidthInHimetric); + rc.bottom = XformHeightInHimetricToPixels(hDC, + lpLine->m_nHeightInHimetric); + + OleDbgOutRect3("TextLine_CalcExtents", (LPRECT)&rc); + } +#endif +} + + + +/* TextLine_SetHeightInHimetric + * ---------------------------- + * + * Set the height of a textline object. + */ +void TextLine_SetHeightInHimetric(LPTEXTLINE lpTextLine, int nHeight) +{ + if (!lpTextLine) + return; + + ((LPLINE)lpTextLine)->m_nHeightInHimetric = nHeight; +} + + + +/* TextLine_GetTextLen + * ------------------- + * + * Return length of string of the TextLine (not considering the tab level). + */ +int TextLine_GetTextLen(LPTEXTLINE lpTextLine) +{ + return lstrlen((LPSTR)lpTextLine->m_szText); +} + + +/* TextLine_GetTextData + * -------------------- + * + * Return the string of the TextLine (not considering the tab level). + */ +void TextLine_GetTextData(LPTEXTLINE lpTextLine, LPSTR lpszBuf) +{ + lstrcpy(lpszBuf, (LPSTR)lpTextLine->m_szText); +} + + +/* TextLine_GetOutlineData + * ----------------------- + * + * Return the CF_OUTLINE format data for the TextLine. + */ +BOOL TextLine_GetOutlineData(LPTEXTLINE lpTextLine, LPTEXTLINE lpBuf) +{ + TextLine_Copy((LPTEXTLINE)lpTextLine, lpBuf); + return TRUE; +} + + +/* TextLine_Draw + * ------------- + * + * Draw a text line object on a DC. + * Parameters: + * hDC - DC to which the line will be drawn + * lpRect - the object rectangle in logical coordinates + * lpRectWBounds - bounding rect of the metafile underneath hDC + * (NULL if hDC is not a metafile DC) + * this is used by ContainerLine_Draw to draw the OLE obj + * fHighlight - TRUE use selection highlight text color + */ +void TextLine_Draw( + LPTEXTLINE lpTextLine, + HDC hDC, + LPRECT lpRect, + LPRECT lpRectWBounds, + BOOL fHighlight +) +{ + RECT rc; + int nBkMode; + COLORREF clrefOld; + + if (!lpTextLine) + return; + + rc = *lpRect; + rc.left += ((LPLINE)lpTextLine)->m_nTabWidthInHimetric; + rc.right += ((LPLINE)lpTextLine)->m_nTabWidthInHimetric; + + nBkMode = SetBkMode(hDC, TRANSPARENT); + + if (fHighlight) { + /*Get proper txt colors */ + clrefOld = SetTextColor(hDC,GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + else { + clrefOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); + } + + ExtTextOut( + hDC, + rc.left, + rc.top, + ETO_CLIPPED, + (LPRECT)&rc, + lpTextLine->m_szText, + lpTextLine->m_nLength, + (LPINT) NULL /* default char spacing */ + ); + + SetTextColor(hDC, clrefOld); + SetBkMode(hDC, nBkMode); +} + +/* TextLine_DrawSelHilight + * ----------------------- + * + * Handles selection of textline + */ +void TextLine_DrawSelHilight(LPTEXTLINE lpTextLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState) +{ + if (itemAction & ODA_SELECT) { + // check if there is a selection state change, ==> invert rect + if (itemState & ODS_SELECTED) { + if (!((LPLINE)lpTextLine)->m_fSelected) { + ((LPLINE)lpTextLine)->m_fSelected = TRUE; + InvertRect(hDC, (LPRECT)lpRect); + } + } else { + if (((LPLINE)lpTextLine)->m_fSelected) { + ((LPLINE)lpTextLine)->m_fSelected = FALSE; + InvertRect(hDC, lpRect); + } + } + } else if (itemAction & ODA_DRAWENTIRE) { + ((LPLINE)lpTextLine)->m_fSelected=((itemState & ODS_SELECTED) ? TRUE : FALSE); + InvertRect(hDC, lpRect); + } +} + +/* TextLine_Copy + * ------------- + * + * Duplicate a textline + */ +BOOL TextLine_Copy(LPTEXTLINE lpSrcLine, LPTEXTLINE lpDestLine) +{ + _fmemcpy(lpDestLine, lpSrcLine, sizeof(TEXTLINE)); + return TRUE; +} + + +/* TextLine_CopyToDoc + * ------------------ + * + * Copy a textline to another Document (usually ClipboardDoc) + */ +BOOL TextLine_CopyToDoc(LPTEXTLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex) +{ + LPTEXTLINE lpDestLine; + BOOL fStatus = FALSE; + + lpDestLine = (LPTEXTLINE) New((DWORD)sizeof(TEXTLINE)); + if (lpDestLine == NULL) { + OleDbgAssertSz(lpDestLine!=NULL,"Error allocating TextLine"); + return FALSE; + } + + if (TextLine_Copy(lpSrcLine, lpDestLine)) { + OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex); + fStatus = TRUE; + } + + return fStatus; +} + + +/* TextLine_SaveToStg + * ------------------ + * + * Save a textline into a storage + * + * Return TRUE if successful, FALSE otherwise + */ +BOOL TextLine_SaveToStm(LPTEXTLINE lpTextLine, LPSTREAM lpLLStm) +{ + HRESULT hrErr; + ULONG nWritten; + USHORT nLengthOnDisk; + + nLengthOnDisk = (USHORT) lpTextLine->m_nLength; + + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)&nLengthOnDisk, + sizeof(nLengthOnDisk), + &nWritten + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Write TextLine data (1) returned", hrErr); + return FALSE; + } + + hrErr = lpLLStm->lpVtbl->Write( + lpLLStm, + (LPVOID)lpTextLine->m_szText, + lpTextLine->m_nLength, + &nWritten + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Write TextLine data (2) returned", hrErr); + return FALSE; + } + + return TRUE; +} + + +/* TextLine_LoadFromStg + * -------------------- + * + * Load a textline from storage + */ +LPLINE TextLine_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc) +{ + HRESULT hrErr; + ULONG nRead; + LPTEXTLINE lpTextLine; + USHORT nLengthOnDisk; + + lpTextLine=(LPTEXTLINE) New((DWORD)sizeof(TEXTLINE)); + if (lpTextLine == NULL) { + OleDbgAssertSz(lpTextLine!=NULL,"Error allocating TextLine"); + return NULL; + } + + TextLine_Init(lpTextLine, 0, NULL); + + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&nLengthOnDisk, + sizeof(nLengthOnDisk), + &nRead + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Read TextLine data (1) returned", hrErr); + return NULL; + } + + lpTextLine->m_nLength = (UINT) nLengthOnDisk; + + OleDbgAssert(lpTextLine->m_nLength < sizeof(lpTextLine->m_szText)); + + hrErr = lpLLStm->lpVtbl->Read( + lpLLStm, + (LPVOID)&lpTextLine->m_szText, + lpTextLine->m_nLength, + &nRead + ); + if (hrErr != NOERROR) { + OleDbgOutHResult("Read TextLine data (1) returned", hrErr); + return NULL; + } + + lpTextLine->m_szText[lpTextLine->m_nLength] = '\0'; // add str terminator + + return (LPLINE)lpTextLine; +} diff --git a/private/oleutest/letest/outline/precomp.c b/private/oleutest/letest/outline/precomp.c new file mode 100644 index 000000000..c9053eeeb --- /dev/null +++ b/private/oleutest/letest/outline/precomp.c @@ -0,0 +1,13 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** precomp.c +** +** This file is used to precompile the OUTLINE.H header file +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" diff --git a/private/oleutest/letest/outline/selcross.cur b/private/oleutest/letest/outline/selcross.cur Binary files differnew file mode 100644 index 000000000..de3d14703 --- /dev/null +++ b/private/oleutest/letest/outline/selcross.cur diff --git a/private/oleutest/letest/outline/state.rst b/private/oleutest/letest/outline/state.rst new file mode 100644 index 000000000..8615f7aac --- /dev/null +++ b/private/oleutest/letest/outline/state.rst @@ -0,0 +1,12 @@ +[edit-] +screen=80 50 +toggles=1 1 0 1 0 0 +srch=SaveToFile +src= +rpl= +file=e:\src\ole2samp\outline\svrbase.c 1 1508 1 1508 +[brief] +file=e:\src\ole2samp\outline\svrbase.c 1 1508 1 1508 1 47 78 1 c=0 +[shared-] +pmark=e:\src\ole2samp\outline\svrbase.c 1 1508 +
\ No newline at end of file diff --git a/private/oleutest/letest/outline/status.c b/private/oleutest/letest/outline/status.c new file mode 100644 index 000000000..d499bad70 --- /dev/null +++ b/private/oleutest/letest/outline/status.c @@ -0,0 +1,369 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** status.c +** +** This file contains the window handlers, and various initialization +** and utility functions for an application status bar. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +// Application specific include files +#include "outline.h" +#include "message.h" +#include "status.h" + +// Current status message. +static LPSTR lpszStatusMessage = NULL; + +// Window proc for status window. +LRESULT FAR PASCAL StatusWndProc + (HWND hwnd, unsigned message, WPARAM wParam, LPARAM lParam); + +// List of all constant messages. +static STATMESG ControlList[2] = +{ + { STATUS_READY, "Ready." }, + { STATUS_BLANK, " " } +}; + +// List of all system menu messages. +static STATMESG SysMenuList[16] = +{ + { SC_SIZE, "Change the size of the window." }, + { SC_MOVE, "Move the window." }, + { SC_MINIMIZE, "Make the window iconic." }, + { SC_MAXIMIZE, "Make the window the size of the screen." }, + { SC_NEXTWINDOW, "Activate the next window." }, + { SC_PREVWINDOW, "Activate the previous window." }, + { SC_CLOSE, "Close this window." }, + { SC_VSCROLL, "Vertical scroll?" }, + { SC_HSCROLL, "Horizontal scroll?" }, + { SC_MOUSEMENU, "A menu for mice." }, + { SC_KEYMENU, "A menu for keys (I guess)." }, + { SC_ARRANGE, "Arrange something." }, + { SC_RESTORE, "Make the window noramally sized." }, + { SC_TASKLIST, "Put up the task list dialog." }, + { SC_SCREENSAVE, "Save the screen! Run for your life!" }, + { SC_HOTKEY, "Boy, is this key hot!" } +}; + +// Message type for popup messages. +typedef struct { + HMENU hmenu; + char string[MAX_MESSAGE]; +} STATPOPUP; + +// List of all popup messages. +static STATPOPUP PopupList[NUM_POPUP]; + +static UINT nCurrentPopup = 0; + + + +/* RegisterStatusClass + * ------------------- + * + * Creates classes for status window. + * + * HINSTANCE hInstance + * + * RETURNS: TRUE if class successfully registered. + * FALSE otherwise. + * + * CUSTOMIZATION: Change class name. + * + */ +BOOL RegisterStatusClass(HINSTANCE hInstance) +{ + WNDCLASS wc; + + wc.lpszClassName = "ObjStatus"; + wc.lpfnWndProc = StatusWndProc; + wc.style = 0; + wc.hInstance = hInstance; + wc.hIcon = NULL; + wc.cbClsExtra = 4; + wc.cbWndExtra = 0; + wc.lpszMenuName = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(LTGRAY_BRUSH); + + if (!RegisterClass(&wc)) + return FALSE; + + return TRUE; +} + + +/* CreateStatusWindow + * ------------------ + * + * Creates status window. + * + * HWND hwndMain + * + * RETURNS: HWND of status window if creation is successful. + * NULL otherwise. + * + * CUSTOMIZATION: Change class name. + * + */ +HWND CreateStatusWindow(HWND hWndApp, HINSTANCE hInst) +{ + RECT rect; + int width, height; + HWND hWndStatusBar; + + lpszStatusMessage = ControlList[0].string; + GetClientRect(hWndApp, &rect); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + hWndStatusBar = CreateWindow ( + "ObjStatus", + "SvrStatus", + WS_CHILD | + WS_CLIPSIBLINGS | + WS_VISIBLE, + 0, height - STATUS_HEIGHT, + width, + STATUS_HEIGHT, + hWndApp, + NULL, + hInst, + NULL + ); + + return hWndStatusBar; +} + + +/* DestroyStatusWindow + * ------------------- + * + * Destroys status window. + * + * CUSTOMIZATION: None. + * + */ +void DestroyStatusWindow(HWND hWndStatusBar) +{ + DestroyWindow(hWndStatusBar); +} + + +/* AssignPopupMessage + * ------------------ + * + * Associates a string with a popup menu handle. + * + * HMENU hmenuPopup + * char *szMessage + * + * CUSTOMIZATION: None. + * + */ +void AssignPopupMessage(HMENU hmenuPopup, char *szMessage) +{ + if (nCurrentPopup < NUM_POPUP) { + PopupList[nCurrentPopup].hmenu = hmenuPopup; + lstrcpy(PopupList[nCurrentPopup].string, szMessage); + ++nCurrentPopup; + } +} + + +/* SetStatusText + * ------------- + * + * Show the message in the status line. + */ +void SetStatusText(HWND hWndStatusBar, LPSTR lpszMessage) +{ + lpszStatusMessage = lpszMessage; + InvalidateRect (hWndStatusBar, (LPRECT)NULL, TRUE); + UpdateWindow (hWndStatusBar); +} + + +/* GetItemMessage + * -------------- + * + * Retrieve the message associated with the given menu command item number. + * + * UINT wIDItem + * LPVOID lpDoc + * + * CUSTOMIZATION: None. + * + */ +void GetItemMessage(UINT wIDItem, LPSTR FAR* lplpszMessage) +{ + UINT i; + + *lplpszMessage = ControlList[1].string; + for (i = 0; i < NUM_STATS; ++i) { + if (wIDItem == MesgList[i].wIDItem) { + *lplpszMessage = MesgList[i].string; + break; + } + } +} + + +/* GetPopupMessage + * --------------- + * + * Retrieve the message associated with the given popup menu. + * + * HMENU hmenuPopup + * LPVOID lpDoc + * + * CUSTOMIZATION: None. + * + */ +void GetPopupMessage(HMENU hmenuPopup, LPSTR FAR* lplpszMessage) +{ + UINT i; + + *lplpszMessage = ControlList[1].string; + for (i = 0; i < nCurrentPopup; ++i) { + if (hmenuPopup == PopupList[i].hmenu) { + *lplpszMessage = PopupList[i].string; + break; + } + } +} + + +/* GetSysMenuMessage + * ----------------- + * + * Retrieves the messages to correspond to items on the system menu. + * + * + * UINT wIDItem + * LPVOID lpDoc + * + * CUSTOMIZATION: None. + * + */ +void GetSysMenuMessage(UINT wIDItem, LPSTR FAR* lplpszMessage) +{ + UINT i; + + *lplpszMessage = ControlList[1].string; + for (i = 0; i < 16; ++i) { + if (wIDItem == SysMenuList[i].wIDItem) { + *lplpszMessage = SysMenuList[i].string; + break; + } + } +} + + +/* GetControlMessage + * ----------------- + * + * Retrieves the general system messages. + * + * + * STATCONTROL scCommand + * LPVOID lpDoc + * + * CUSTOMIZATION: Add new messages. + * + */ +void GetControlMessage(STATCONTROL scCommand, LPSTR FAR* lplpszMessage) +{ + UINT i; + + *lplpszMessage = ControlList[1].string; + for (i = 0; i < 2; ++i) { + if ((UINT)scCommand == ControlList[i].wIDItem) { + *lplpszMessage = ControlList[i].string; + break; + } + } +} + + + +/* StatusWndProc + * ------------- + * + * Message handler for the statusbar window. + * + * + * CUSTOMIZATION: None + * + */ +LRESULT FAR PASCAL StatusWndProc + (HWND hwnd, unsigned message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_PAINT) { + RECT rc; + HDC hdc; + PAINTSTRUCT paintstruct; + HPEN hpenOld; + HPEN hpen; + HFONT hfontOld; + HFONT hfont; + HPALETTE hpalOld = NULL; + POINT point; + + BeginPaint (hwnd, &paintstruct); + hdc = GetDC (hwnd); + + GetClientRect (hwnd, (LPRECT) &rc); + + hpenOld = SelectObject (hdc, GetStockObject (BLACK_PEN)); + + MoveToEx (hdc, 0, 0, &point); + LineTo (hdc, rc.right, 0); + + SelectObject (hdc, GetStockObject (WHITE_PEN)); + + MoveToEx (hdc, STATUS_RRIGHT, STATUS_RTOP, &point); + LineTo (hdc, STATUS_RRIGHT, STATUS_RBOTTOM); + LineTo (hdc, STATUS_RLEFT-1, STATUS_RBOTTOM); + + hpen = CreatePen (PS_SOLID, 1, /* DKGRAY */ 0x00808080); + SelectObject (hdc, hpen); + + MoveToEx (hdc, STATUS_RLEFT, STATUS_RBOTTOM-1, &point); + LineTo (hdc, STATUS_RLEFT, STATUS_RTOP); + LineTo (hdc, STATUS_RRIGHT, STATUS_RTOP); + + SetBkMode (hdc, TRANSPARENT); + SetTextAlign (hdc, TA_LEFT | TA_TOP); + hfont = CreateFont (STATUS_THEIGHT, 0, 0, 0, FW_NORMAL, FALSE, FALSE, + FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + DEFAULT_PITCH | FF_DONTCARE, "MS Sans Serif"); + + hfontOld = SelectObject(hdc, hfont); + + TextOut (hdc, STATUS_TLEFT, STATUS_TTOP, + lpszStatusMessage, + lstrlen(lpszStatusMessage)); + + // Restore original objects + SelectObject (hdc, hfontOld); + SelectObject (hdc, hpenOld); + DeleteObject (hpen); + DeleteObject (hfont); + + ReleaseDC (hwnd, hdc); + EndPaint (hwnd, &paintstruct); + + return 0; + } + else { + return DefWindowProc(hwnd, message, wParam, lParam); + } +} diff --git a/private/oleutest/letest/outline/status.h b/private/oleutest/letest/outline/status.h new file mode 100644 index 000000000..1a7bcd215 --- /dev/null +++ b/private/oleutest/letest/outline/status.h @@ -0,0 +1,47 @@ +/************************************************************************* +** +** OLE 2.0 Sample Code +** +** status.h +** +** This file contains typedefs, defines, global variable declarations, +** and function prototypes for the status bar window. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +// Sizes of statusbar items +#if defined( USE_STATUSBAR ) + #define STATUS_HEIGHT 23 +#else + #define STATUS_HEIGHT 0 +#endif +#define STATUS_RLEFT 8 +#define STATUS_RRIGHT 400 +#define STATUS_RTOP 3 +#define STATUS_RBOTTOM 20 +#define STATUS_TTOP 4 +#define STATUS_TLEFT 11 +#define STATUS_THEIGHT 18 + + +typedef enum { + STATUS_READY, + STATUS_BLANK +} STATCONTROL; + +// Window for status bar. +extern HWND hwndStatusbar; + +BOOL RegisterStatusClass(HINSTANCE hInstance); +HWND CreateStatusWindow(HWND hWndApp, HINSTANCE hInst); +void DestroyStatusWindow(HWND hWndStatusBar); + +void AssignPopupMessage(HMENU hmenuPopup, char *szMessage); + +void SetStatusText(HWND hWndStatusBar, LPSTR lpszMessage); +void GetItemMessage(UINT wIDItem, LPSTR FAR* lplpszMessage); +void GetPopupMessage(HMENU hmenuPopup, LPSTR FAR* lplpszMessage); +void GetSysMenuMessage(UINT wIDItem, LPSTR FAR* lplpszMessage); +void GetControlMessage(STATCONTROL scCommand, LPSTR FAR* lplpszMessage); diff --git a/private/oleutest/letest/outline/svrbase.c b/private/oleutest/letest/outline/svrbase.c new file mode 100644 index 000000000..30a4c4dbc --- /dev/null +++ b/private/oleutest/letest/outline/svrbase.c @@ -0,0 +1,2018 @@ +/************************************************************************* +** +** OLE 2 Server Sample Code +** +** svrbase.c +** +** This file contains all interfaces, methods and related support +** functions for the basic OLE Object (Server) application. The +** basic OLE Object application supports embedding an object and +** linking to a file-based or embedded object as a whole. The basic +** Object application includes the following implementation objects: +** +** ClassFactory (aka. ClassObject) Object (see file classfac.c) +** exposed interfaces: +** IClassFactory interface +** +** ServerDoc Object +** exposed interfaces: +** IUnknown +** IOleObject interface +** IPersistStorage interface +** IDataObject interface +** +** ServerApp Object +** exposed interfaces: +** IUnknown +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; +extern IOleObjectVtbl g_SvrDoc_OleObjectVtbl; +extern IPersistStorageVtbl g_SvrDoc_PersistStorageVtbl; + +#if defined( INPLACE_SVR ) +extern IOleInPlaceObjectVtbl g_SvrDoc_OleInPlaceObjectVtbl; +extern IOleInPlaceActiveObjectVtbl g_SvrDoc_OleInPlaceActiveObjectVtbl; +#endif // INPLACE_SVR + +#if defined( SVR_TREATAS ) +extern IStdMarshalInfoVtbl g_SvrDoc_StdMarshalInfoVtbl; +#endif // SVR_TREATAS + + +// REVIEW: should use string resource for messages +extern char ErrMsgSaving[]; +extern char ErrMsgFormatNotSupported[]; +static char ErrMsgPSSaveFail[] = "PSSave failed"; +static char ErrMsgLowMemNClose[] = "Warning OUT OF MEMORY! We must close down"; +extern char g_szUpdateCntrDoc[] = "&Update %s"; +extern char g_szExitNReturnToCntrDoc[] = "E&xit && Return to %s"; + + +/************************************************************************* +** ServerDoc::IOleObject interface implementation +*************************************************************************/ + +// IOleObject::QueryInterface method + +STDMETHODIMP SvrDoc_OleObj_QueryInterface( + LPOLEOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj); +} + + +// IOleObject::AddRef method + +STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OleDbgAddRefMethod(lpThis, "IOleObject"); + + return OleDoc_AddRef((LPOLEDOC)lpServerDoc); +} + + +// IOleObject::Release method + +STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OleDbgReleaseMethod(lpThis, "IOleObject"); + + return OleDoc_Release((LPOLEDOC)lpServerDoc); +} + + +// IOleObject::SetClientSite method + +STDMETHODIMP SvrDoc_OleObj_SetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE lpclientSite +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_SetClientSite\r\n") + + // SetClientSite is only valid to call on an embedded object + if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) { + OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED); + OLEDBG_END2 + return ResultFromScode(E_UNEXPECTED); + } + + /* if we currently have a client site ptr, then release it. */ + if (lpServerDoc->m_lpOleClientSite) + OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite); + + lpServerDoc->m_lpOleClientSite = (LPOLECLIENTSITE) lpclientSite; + // OLE2NOTE: to be able to hold onto clientSite pointer, we must AddRef it + if (lpclientSite) + lpclientSite->lpVtbl->AddRef(lpclientSite); + + OLEDBG_END2 + return NOERROR; +} + + +// IOleObject::GetClientSite method + +STDMETHODIMP SvrDoc_OleObj_GetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE FAR* lplpClientSite +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_OleObj_GetClientSite\r\n"); + + /* OLE2NOTE: we MUST AddRef this interface pointer to give the + ** caller a personal copy of the pointer + */ + lpServerDoc->m_lpOleClientSite->lpVtbl->AddRef( + lpServerDoc->m_lpOleClientSite + ); + *lplpClientSite = lpServerDoc->m_lpOleClientSite; + + return NOERROR; + +} + + +// IOleObject::SetHostNames method + +STDMETHODIMP SvrDoc_OleObj_SetHostNamesA( + LPOLEOBJECT lpThis, + LPCSTR szContainerApp, + LPCSTR szContainerObj +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + OleDbgOut2("SvrDoc_OleObj_SetHostNames\r\n"); + + LSTRCPYN((LPSTR)lpServerDoc->m_szContainerApp, szContainerApp, + sizeof(lpServerDoc->m_szContainerApp)); + LSTRCPYN((LPSTR)lpServerDoc->m_szContainerObj, szContainerObj, + sizeof(lpServerDoc->m_szContainerObj)); + + /* The Window title for an embedded object is constructed as + ** follows: + ** <server app name> - <obj short type> in <cont. doc name> + ** + ** here we construct the current document title portion of the + ** name which follows the '-'. OutlineDoc_SetTitle prepends the + ** "<server app name> - " to the document title. + */ + // REVIEW: this string should be loaded from string resource + wsprintf(lpOutlineDoc->m_szFileName, "%s in %s", + (LPSTR)SHORTUSERTYPENAME, (LPSTR)lpServerDoc->m_szContainerObj); + + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/); + + /* OLE2NOTE: update the application menus correctly for an embedded + ** object. the changes include: + ** 1 Remove File/New and File/Open (SDI ONLY) + ** 2 Change File/Save As.. to File/Save Copy As.. + ** 3 Change File menu so it contains "Update" instead of "Save" + ** 4 Change File/Exit to File/Exit & Return to <client doc>" + */ + ServerDoc_UpdateMenu(lpServerDoc); + + return NOERROR; +} + +STDMETHODIMP SvrDoc_OleObj_SetHostNames( + LPOLEOBJECT lpThis, + LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj +) +{ + CREATESTR(pstrApp, szContainerApp) + CREATESTR(pstrObj, szContainerObj) + + HRESULT hr = SvrDoc_OleObj_SetHostNamesA(lpThis, pstrApp, pstrObj); + + FREESTR(pstrApp) + FREESTR(pstrObj) + + return hr; +} + + + +// IOleObject::Close method + +STDMETHODIMP SvrDoc_OleObj_Close( + LPOLEOBJECT lpThis, + DWORD dwSaveOption +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + BOOL fStatus; + + OLEDBG_BEGIN2("SvrDoc_OleObj_Close\r\n") + + /* OLE2NOTE: the OLE 2.0 user model is that embedded objects should + ** always be saved when closed WITHOUT any prompting to the + ** user. this is the recommendation irregardless of whether the + ** object is activated in-place or open in its own window. + ** this is a CHANGE from the OLE 1.0 user model where it + ** was the guideline that servers always prompt to save changes. + ** thus OLE 2.0 compound document oriented container's should + ** always pass dwSaveOption==OLECLOSE_SAVEIFDIRTY. it is + ** possible that for programmatic uses a container may want to + ** specify a different dwSaveOption. the implementation of + ** various save options can be tricky, particularly considering + ** cases involving in-place activation. the following would be + ** reasonable behavior: + ** + ** (1) OLECLOSE_SAVEIFDIRTY: if dirty, save. close. + ** (2) OLECLOSE_NOSAVE: close. + ** (3) OLECLOSE_PROMPTSAVE: + ** (a) object visible, but not in-place: + ** if not dirty, close. + ** switch(prompt) + ** case IDYES: save. close. + ** case IDNO: close. + ** case IDCANCEL: return OLE_E_PROMPTSAVECANCELLED + ** (b) object invisible (includes UIDeactivated object) + ** if dirty, save. close. + ** NOTE: NO PROMPT. it is not appropriate to prompt + ** if the object is not visible. + ** (c) object is in-place active: + ** if dirty, save. close. + ** NOTE: NO PROMPT. it is not appropriate to prompt + ** if the object is active in-place. + */ + fStatus = OutlineDoc_Close((LPOUTLINEDOC)lpServerDoc, dwSaveOption); + OleDbgAssertSz(fStatus == TRUE, "SvrDoc_OleObj_Close failed\r\n"); + + OLEDBG_END2 + return (fStatus ? NOERROR : ResultFromScode(E_FAIL)); +} + + +// IOleObject::SetMoniker method + +STDMETHODIMP SvrDoc_OleObj_SetMoniker( + LPOLEOBJECT lpThis, + DWORD dwWhichMoniker, + LPMONIKER lpmk +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPMONIKER lpmkFull = NULL; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_SetMoniker\r\n") + + /* OLE2NOTE: if our full moniker is passed then we can use it, + ** otherwise we must call back to our ClientSite to get our full + ** moniker. + */ + if (dwWhichMoniker == OLEWHICHMK_OBJFULL) { + + /* Register the document as running with the new moniker and + ** notify any clients that our moniker has changed. + */ + OleDoc_DocRenamedUpdate(lpOleDoc, lpmk); + + if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) { + IBindCtx FAR *pbc = NULL; + LPSTR lpszName = NULL; + + /* OLE2NOTE: if this is a FILE-based or untitled document + ** then we should accept this new moniker as our document's + ** moniker. we will remember this moniker instead of the + ** FileMoniker that we have by default. this allows + ** systems that use special monikers to track the + ** location of documents to inform a document that is a + ** link source of its special moniker. this enables the + ** document to use this special moniker when building + ** composite monikers to identify contained objects and + ** pseudo objects (ranges). + ** + ** we should also use the DisplayName form of this + ** moniker as our document name in our window title. + */ + if (lpOleDoc->m_lpFileMoniker) { + lpOleDoc->m_lpFileMoniker->lpVtbl->Release( + lpOleDoc->m_lpFileMoniker); + } + lpOleDoc->m_lpFileMoniker = lpmk; + // we must AddRef the moniker to hold on to it + lpmk->lpVtbl->AddRef(lpmk); + + /* we should also use the DisplayName form of this + ** moniker as our document name in our window title. + */ + CreateBindCtx(0, (LPBC FAR*)&pbc); + CallIMonikerGetDisplayNameA(lpmk,pbc,NULL,&lpszName); + pbc->lpVtbl->Release(pbc); + if (lpszName) { + LSTRCPYN(lpOutlineDoc->m_szFileName, lpszName, + sizeof(lpOutlineDoc->m_szFileName)); + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/); + OleStdFreeString(lpszName, NULL); + } + } + + OLEDBG_END2 + return NOERROR; + } + + /* if the passed moniker was NOT a full moniker then we must call + ** back to our ClientSite to get our full moniker. this is + ** needed in order to register in the RunningObjectTable. if we + ** don't have a ClientSite then this is an error. + */ + if (lpServerDoc->m_lpOleClientSite == NULL) { + sc = E_FAIL; + goto error; + } + + hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker( + lpServerDoc->m_lpOleClientSite, + OLEGETMONIKER_ONLYIFTHERE, + OLEWHICHMK_OBJFULL, + &lpmkFull + ); + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + + /* Register the document as running with the new moniker and + ** notify any clients that our moniker has changed. + */ + OleDoc_DocRenamedUpdate(lpOleDoc, lpmkFull); + + if (lpmkFull) + OleStdRelease((LPUNKNOWN)lpmkFull); + + OLEDBG_END2 + return NOERROR; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleObject::GetMoniker method + +STDMETHODIMP SvrDoc_OleObj_GetMoniker( + LPOLEOBJECT lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_GetMoniker\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpmk = NULL; + + if (lpServerDoc->m_lpOleClientSite) { + + /* document is an embedded object. retrieve our moniker from + ** our container. + */ + OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n") + sc = GetScode( lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker( + lpServerDoc->m_lpOleClientSite, + dwAssign, + dwWhichMoniker, + lplpmk + ) ); + OLEDBG_END2 + + } else if (lpOleDoc->m_lpFileMoniker) { + + /* document is a top-level user document (either + ** file-based or untitled). return the FileMoniker stored + ** with the document; it uniquely identifies the document. + */ + if (dwWhichMoniker == OLEWHICHMK_CONTAINER) + sc = E_INVALIDARG; // file-based object has no CONTAINER moniker + else { + *lplpmk = lpOleDoc->m_lpFileMoniker; + (*lplpmk)->lpVtbl->AddRef(*lplpmk); // must AddRef to pass out ptr + sc = S_OK; + } + + } else { + // document is not yet fully initialized => no moniker + sc = E_FAIL; + } + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleObject::InitFromData method + +STDMETHODIMP SvrDoc_OleObj_InitFromData( + LPOLEOBJECT lpThis, + LPDATAOBJECT lpDataObject, + BOOL fCreation, + DWORD reserved +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_InitFromData\r\n") + + // REVIEW: NOT YET IMPLEMENTED + + OLEDBG_END2 + return ResultFromScode(E_NOTIMPL); +} + + +// IOleObject::GetClipboardData method + +STDMETHODIMP SvrDoc_OleObj_GetClipboardData( + LPOLEOBJECT lpThis, + DWORD reserved, + LPDATAOBJECT FAR* lplpDataObject +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_GetClipboardData\r\n") + + // REVIEW: NOT YET IMPLEMENTED + + OLEDBG_END2 + return ResultFromScode(E_NOTIMPL); +} + + +// IOleObject::DoVerb method + +STDMETHODIMP SvrDoc_OleObj_DoVerb( + LPOLEOBJECT lpThis, + LONG lVerb, + LPMSG lpmsg, + LPOLECLIENTSITE lpActiveSite, + LONG lindex, + HWND hwndParent, + LPCRECT lprcPosRect +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + SCODE sc = S_OK; + + OLEDBG_BEGIN2("SvrDoc_OleObj_DoVerb\r\n") + + switch (lVerb) { + + default: + /* OLE2NOTE: when an unknown verb number is given, the + ** server must take careful action: + ** 1. if it is one of the specially defined OLEIVERB + ** (negative numbered) verbs, the app should return an + ** error (E_NOTIMPL) and perform no action. + ** + ** 2. if the verb is a application specific verb + ** (positive numbered verb), then the app should + ** return the special scode (OLEOBJ_S_INVALIDVERB). BUT, + ** we should still perform our normal primary verb action. + */ + if (lVerb < 0) { + OLEDBG_END2 + return ResultFromScode(E_NOTIMPL); + } else { + sc = OLEOBJ_S_INVALIDVERB; + } + + // deliberatly fall through to Primary Verb + +#if !defined( INPLACE_SVR ) + case 0: + case OLEIVERB_SHOW: + case OLEIVERB_OPEN: + OutlineDoc_ShowWindow(lpOutlineDoc); + break; + + case OLEIVERB_HIDE: + OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/); + break; +#endif // ! INPLACE_SVR +#if defined( INPLACE_SVR ) + case 0: + case OLEIVERB_SHOW: + + /* OLE2NOTE: if our window is already open (visible) then + ** we should simply surface the open window. if not, + ** then we can do our primary action of in-place + ** activation. + */ + if ( lpServerDoc->m_lpOleClientSite + && ! (IsWindowVisible(lpOutlineDoc->m_hWndDoc) && + ! lpServerDoc->m_fInPlaceActive) ) { + ServerDoc_DoInPlaceActivate( + lpServerDoc, lVerb, lpmsg, lpActiveSite); + } + OutlineDoc_ShowWindow(lpOutlineDoc); + break; + + case 1: + case OLEIVERB_OPEN: + ServerDoc_DoInPlaceDeactivate(lpServerDoc); + OutlineDoc_ShowWindow(lpOutlineDoc); + break; + + + case OLEIVERB_HIDE: + if (lpServerDoc->m_fInPlaceActive) { + + SvrDoc_IPObj_UIDeactivate( + (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject); + +#if defined( SVR_INSIDEOUT ) + /* OLE2NOTE: an inside-out style in-place server will + ** NOT hide its window in UIDeactive (an outside-in + ** style object will hide its window in + ** UIDeactivate). thus we need to explicitly hide + ** our window now. + */ + ServerDoc_DoInPlaceHide(lpServerDoc); +#endif // INSIEDOUT + + } else { + OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/); + } + break; + + case OLEIVERB_UIACTIVATE: + +#if defined( SVR_INSIDEOUT ) + /* OLE2NOTE: only an inside-out style object supports + ** INPLACEACTIVATE verb + */ + case OLEIVERB_INPLACEACTIVATE: +#endif // SVR_INSIDEOUT + + /* OLE2NOTE: if our window is already open (visible) then + ** we can NOT activate in-place. + */ + if (IsWindowVisible(lpOutlineDoc->m_hWndDoc) && + ! lpServerDoc->m_fInPlaceActive ) { + sc = OLE_E_NOT_INPLACEACTIVE; + } else { + sc = GetScode( ServerDoc_DoInPlaceActivate( + lpServerDoc, lVerb, lpmsg, lpActiveSite) ); + if (SUCCEEDED(sc)) + OutlineDoc_ShowWindow(lpOutlineDoc); + } + break; +#endif // INPLACE_SVR + } + + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleObject::EnumVerbs method + +STDMETHODIMP SvrDoc_OleObj_EnumVerbs( + LPOLEOBJECT lpThis, + LPENUMOLEVERB FAR* lplpenumOleVerb +) +{ + OleDbgOut2("SvrDoc_OleObj_EnumVerbs\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumOleVerb = NULL; + + /* An object implemented as a server EXE (as this sample + ** is) may simply return OLE_S_USEREG to instruct the OLE + ** DefHandler to call the OleReg* helper API which uses info in + ** the registration database. Alternatively, the OleRegEnumVerbs + ** API may be called directly. Objects implemented as a server + ** DLL may NOT return OLE_S_USEREG; they must call the OleReg* + ** API or provide their own implementation. For EXE based + ** objects it is more efficient to return OLE_S_USEREG, because + ** in then the verb enumerator is instantiated in the callers + ** process space and no LRPC remoting is required. + */ + return ResultFromScode(OLE_S_USEREG); +} + + +// IOleObject::Update method + +STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis) +{ + OleDbgOut2("SvrDoc_OleObj_Update\r\n"); + + /* OLE2NOTE: a server-only app is always "up-to-date". + ** a container-app which contains links where the link source + ** has changed since the last update of the link would be + ** considered "out-of-date". the "Update" method instructs the + ** object to get an update from any out-of-date links. + */ + + return NOERROR; +} + + +// IOleObject::IsUpToDate method + +STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis) +{ + OleDbgOut2("SvrDoc_OleObj_IsUpToDate\r\n"); + + /* OLE2NOTE: a server-only app is always "up-to-date". + ** a container-app which contains links where the link source + ** has changed since the last update of the link would be + ** considered "out-of-date". + */ + return NOERROR; +} + + +// IOleObject::GetUserClassID method + +STDMETHODIMP SvrDoc_OleObj_GetUserClassID( + LPOLEOBJECT lpThis, + LPCLSID lpClassID +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_OleObj_GetClassID\r\n"); + + /* OLE2NOTE: we must be carefull to return the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the class of the object + ** written in the storage of the object. otherwise we would + ** return our own class id. + */ + return ServerDoc_GetClassID(lpServerDoc, lpClassID); +} + + +// IOleObject::GetUserType method + +STDMETHODIMP SvrDoc_OleObj_GetUserTypeA( + LPOLEOBJECT lpThis, + DWORD dwFormOfType, + LPSTR FAR* lpszUserType +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_OleObj_GetUserType\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lpszUserType = NULL; + + /* OLE2NOTE: we must be carefull to return the correct user type here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the user type name that + ** corresponds to the class of the object we are currently + ** emmulating. otherwise we should return our normal user type + ** name corresponding to our own class. This routine determines + ** the current clsid in effect. + ** + ** An object implemented as a server EXE (as this sample + ** is) may simply return OLE_S_USEREG to instruct the OLE + ** DefHandler to call the OleReg* helper API which uses info in + ** the registration database. Alternatively, the OleRegGetUserType + ** API may be called directly. Objects implemented as a server + ** DLL may NOT return OLE_S_USEREG; they must call the OleReg* + ** API or provide their own implementation. For EXE based + ** objects it is more efficient to return OLE_S_USEREG, because + ** in then the return string is instantiated in the callers + ** process space and no LRPC remoting is required. + */ +#if defined( SVR_TREATAS ) + if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) ) + return OleRegGetUserTypeA( + &lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType); + else +#endif // SVR_TREATAS + + return ResultFromScode(OLE_S_USEREG); +} + + + +STDMETHODIMP SvrDoc_OleObj_GetUserType( + LPOLEOBJECT lpThis, + DWORD dwFormOfType, + LPOLESTR FAR* lpszUserType +) +{ + LPSTR pstr; + + HRESULT hr = SvrDoc_OleObj_GetUserTypeA(lpThis, dwFormOfType, &pstr); + + CopyAndFreeSTR(pstr, lpszUserType); + + return hr; +} + + + +// IOleObject::SetExtent method + +STDMETHODIMP SvrDoc_OleObj_SetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lplgrc +) +{ + OleDbgOut2("SvrDoc_OleObj_SetExtent\r\n"); + + /* SVROUTL does NOT allow the object's size to be set by its + ** container. the size of the ServerDoc object is determined by + ** the data contained within the document. + */ + return ResultFromScode(E_FAIL); +} + + +// IOleObject::GetExtent method + +STDMETHODIMP SvrDoc_OleObj_GetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lpsizel +) +{ + LPOLEDOC lpOleDoc = + (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_OleObj_GetExtent\r\n"); + + /* OLE2NOTE: it is VERY important to check which aspect the caller + ** is asking about. an object implemented by a server EXE MAY + ** fail to return extents when asked for DVASPECT_ICON. + */ + if (dwDrawAspect == DVASPECT_CONTENT) { + OleDoc_GetExtent(lpOleDoc, lpsizel); + return NOERROR; + } + +#if defined( LATER ) + + else if (dwDrawAspect == DVASPECT_THUMBNAIL) + { + /* as our thumbnail we will render only the first page of the + ** document. calculate extents of our thumbnail rendering. + ** + ** OLE2NOTE: thumbnails are most often used by applications in + ** FindFile or FileOpen type dialogs to give the user a + ** quick view of the contents of the file or object. + */ + OleDoc_GetThumbnailExtent(lpOleDoc, lpsizel); + return NOERROR; + } +#endif + + else + { + return ResultFromScode(E_FAIL); + } +} + + +// IOleObject::Advise method + +STDMETHODIMP SvrDoc_OleObj_Advise( + LPOLEOBJECT lpThis, + LPADVISESINK lpAdvSink, + LPDWORD lpdwConnection +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_Advise\r\n"); + + if (lpServerDoc->m_OleDoc.m_fObjIsClosing) + { + // We don't accept any more Advise's once we're closing + sc = OLE_E_ADVISENOTSUPPORTED; + goto error; + } + + if (lpServerDoc->m_lpOleAdviseHldr == NULL && + CreateOleAdviseHolder(&lpServerDoc->m_lpOleAdviseHldr) != NOERROR) { + sc = E_OUTOFMEMORY; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n") + hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Advise( + lpServerDoc->m_lpOleAdviseHldr, + lpAdvSink, + lpdwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + *lpdwConnection = 0; + return ResultFromScode(sc); +} + + +// IOleObject::Unadvise method + +STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_Unadvise\r\n"); + + if (lpServerDoc->m_lpOleAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n") + hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Unadvise( + lpServerDoc->m_lpOleAdviseHldr, + dwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleObject::EnumAdvise method + +STDMETHODIMP SvrDoc_OleObj_EnumAdvise( + LPOLEOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_OleObj_EnumAdvise\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumAdvise = NULL; + + if (lpServerDoc->m_lpOleAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n") + hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->EnumAdvise( + lpServerDoc->m_lpOleAdviseHldr, + lplpenumAdvise + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IOleObject::GetMiscStatus method + +STDMETHODIMP SvrDoc_OleObj_GetMiscStatus( + LPOLEOBJECT lpThis, + DWORD dwAspect, + DWORD FAR* lpdwStatus +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + OleDbgOut2("SvrDoc_OleObj_GetMiscStatus\r\n"); + + /* Get our default MiscStatus for the given Aspect. this + ** information is registered in the RegDB. We query the RegDB + ** here to guarantee that the value returned from this method + ** agrees with the values in RegDB. in this way we only have to + ** maintain the info in one place (in the RegDB). Alternatively + ** we could have the values hard coded here. + */ + OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus); + + /* OLE2NOTE: check if the data copied is compatible to be + ** linked by an OLE 1.0 container. it is compatible if + ** either the data is an untitled document, a file, or a + ** selection of data within a file. if the data is part of + ** an embedded object, then it is NOT compatible to be + ** linked by an OLE 1.0 container. if it is compatible then + ** we must include OLEMISC_CANLINKBYOLE1 as part of the + ** dwStatus flags transfered via CF_OBJECTDESCRIPTOR or + ** CF_LINKSRCDESCRIPTOR. + */ + if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW || + lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) + *lpdwStatus |= OLEMISC_CANLINKBYOLE1; + +#if defined( INPLACE_SVR ) + if (dwAspect == DVASPECT_CONTENT) + *lpdwStatus |= (OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE); +#endif // INPLACE_SVR + return NOERROR; +} + + +// IOleObject::SetColorScheme method + +STDMETHODIMP SvrDoc_OleObj_SetColorScheme( + LPOLEOBJECT lpThis, + LPLOGPALETTE lpLogpal +) +{ + OleDbgOut2("SvrDoc_OleObj_SetColorScheme\r\n"); + + // REVIEW: NOT YET IMPLEMENTED + + return ResultFromScode(E_NOTIMPL); +} + + +/************************************************************************* +** ServerDoc::IPersistStorage interface implementation +*************************************************************************/ + +// IPersistStorage::QueryInterface method + +STDMETHODIMP SvrDoc_PStg_QueryInterface( + LPPERSISTSTORAGE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + + return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj); +} + + +// IPersistStorage::AddRef method + +STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + + OleDbgAddRefMethod(lpThis, "IPersistStorage"); + + return OleDoc_AddRef((LPOLEDOC)lpServerDoc); +} + + +// IPersistStorage::Release method + +STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + + OleDbgReleaseMethod(lpThis, "IPersistStorage"); + + return OleDoc_Release((LPOLEDOC)lpServerDoc); +} + + +// IPersistStorage::GetClassID method + +STDMETHODIMP SvrDoc_PStg_GetClassID( + LPPERSISTSTORAGE lpThis, + LPCLSID lpClassID +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_PStg_GetClassID\r\n"); + + /* OLE2NOTE: we must be carefull to return the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the class of the object + ** written in the storage of the object. otherwise we would + ** return our own class id. + */ + return ServerDoc_GetClassID(lpServerDoc, lpClassID); +} + + +// IPersistStorage::IsDirty method + +STDMETHODIMP SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_PStg_IsDirty\r\n"); + + if (OutlineDoc_IsModified((LPOUTLINEDOC)lpServerDoc)) + return NOERROR; + else + return ResultFromScode(S_FALSE); +} + + + +// IPersistStorage::InitNew method + +STDMETHODIMP SvrDoc_PStg_InitNew( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStg +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPSTR lpszUserType = (LPSTR)FULLUSERTYPENAME; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_PStg_InitNew\r\n") + +#if defined( SVR_TREATAS ) + { + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + CLSID clsid; + CLIPFORMAT cfFmt; + LPSTR lpszType; + + /* OLE2NOTE: if the Server is capable of supporting "TreatAs" + ** (aka. ActivateAs), it must read the class that is written + ** into the storage. if this class is NOT the app's own + ** class ID, then this is a TreatAs operation. the server + ** then must faithfully pretend to be the class that is + ** written into the storage. it must also faithfully write + ** the data back to the storage in the SAME format as is + ** written in the storage. + ** + ** SVROUTL and ISVROTL can emulate each other. they have the + ** simplification that they both read/write the identical + ** format. thus for these apps no actual conversion of the + ** native bits is actually required. + */ + lpServerDoc->m_clsidTreatAs = CLSID_NULL; + if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpStg, &clsid, + (CLIPFORMAT FAR*)&cfFmt, (LPSTR FAR*)&lpszType)) { + + if (cfFmt == lpOutlineApp->m_cfOutline) { + // We should perform TreatAs operation + if (lpServerDoc->m_lpszTreatAsType) + OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL); + + lpServerDoc->m_clsidTreatAs = clsid; + ((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt; + lpServerDoc->m_lpszTreatAsType = lpszType; + lpszUserType = lpServerDoc->m_lpszTreatAsType; + + OleDbgOut3("SvrDoc_PStg_InitNew: TreateAs ==> '"); + OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType); + OleDbgOutNoPrefix3("'\r\n"); + } else { + // ERROR: we ONLY support TreatAs for CF_OUTLINE format + OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Format\r\n"); + OleStdFreeString(lpszType, NULL); + } + } + } +#endif // SVR_TREATAS + + /* OLE2NOTE: a server EXE object should write its format tag to its + ** storage in InitNew so that the DefHandler can know the format + ** of the object. this is particularly important if the objects + ** uses CF_METATFILE or CF_DIB as its format. the DefHandler + ** automatically avoids separately storing presentation cache + ** data when the object's native data is a standard presentation + ** format. + */ + WriteFmtUserTypeStgA(lpStg,lpOutlineApp->m_cfOutline,lpszUserType); + + // set the doc to a new embedded object. + if (! ServerDoc_InitNewEmbed(lpServerDoc)) { + sc = E_FAIL; + goto error; + } + + /* OLE2NOTE: An embedded object must guarantee that it can save + ** even in low memory situations. it must be able to + ** successfully save itself without consuming any additional + ** memory. this means that a server is NOT supposed to open or + ** create any streams or storages when + ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an + ** embedded object should hold onto its storage and pre-open and + ** hold open any streams that it will need later when it is time + ** to save. + */ + hrErr = CallIStorageCreateStreamA( + lpStg, + "LineList", + STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, + 0, + &lpOleDoc->m_lpLLStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream"); + OleDbgOutHResult("LineList CreateStream returned", hrErr); + sc = GetScode(hrErr); + goto error; + } + + hrErr = CallIStorageCreateStreamA( + lpStg, + "NameTable", + STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, + 0, + &lpOleDoc->m_lpNTStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream"); + OleDbgOutHResult("NameTable CreateStream returned", hrErr); + sc = GetScode(hrErr); + goto error; + } + + lpOleDoc->m_lpStg = lpStg; + + // OLE2NOTE: to be able to hold onto IStorage* pointer, we must AddRef it + lpStg->lpVtbl->AddRef(lpStg); + + OLEDBG_END2 + return NOERROR; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IPersistStorage::Load method + +STDMETHODIMP SvrDoc_PStg_Load( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStg +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + SCODE sc; + HRESULT hrErr; + + OLEDBG_BEGIN2("SvrDoc_PStg_Load\r\n") + + if (OutlineDoc_LoadFromStg((LPOUTLINEDOC)lpServerDoc, lpStg)) { + + ((LPOUTLINEDOC)lpServerDoc)->m_docInitType = DOCTYPE_EMBEDDED; + + /* OLE2NOTE: we need to check if the ConvertStg bit is on. if + ** so, we need to clear the ConvertStg bit and mark the + ** document as dirty so as to force a save when the document + ** is closed. the actual conversion of the bits should be + ** performed when the data is loaded from the IStorage*. in + ** our case any conversion of data formats would be done in + ** OutlineDoc_LoadFromStg function. in reality both SVROUTL + ** and ISVROTL read and write the same format so no actual + ** conversion of data bits is necessary. + */ + if (GetConvertStg(lpStg) == NOERROR) { + SetConvertStg(lpStg, FALSE); + + OleDbgOut3("SvrDoc_PStg_Load: ConvertStg==TRUE\r\n"); + OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE); + } + + } else { + sc = E_FAIL; + goto error; + } + + /* OLE2NOTE: An embedded object must guarantee that it can save + ** even in low memory situations. it must be able to + ** successfully save itself without consuming any additional + ** memory. this means that a server is NOT supposed to open or + ** create any streams or storages when + ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an + ** embedded object should hold onto its storage and pre-open and + ** hold open any streams that it will need later when it is time + ** to save. + */ + if (lpOleDoc->m_lpLLStm) + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm); + hrErr = CallIStorageOpenStreamA( + lpStg, + "LineList", + NULL, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE, + 0, + &lpOleDoc->m_lpLLStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream"); + OleDbgOutHResult("LineList CreateStream returned", hrErr); + sc = GetScode(hrErr); + goto error; + } + + if (lpOleDoc->m_lpNTStm) + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm); + hrErr = CallIStorageOpenStreamA( + lpStg, + "NameTable", + NULL, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE, + 0, + &lpOleDoc->m_lpNTStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream"); + OleDbgOutHResult("NameTable CreateStream returned", hrErr); + sc = GetScode(hrErr); + goto error; + } + + lpOleDoc->m_lpStg = lpStg; + + // OLE2NOTE: to be able to hold onto IStorage* pointer, we must AddRef it + lpStg->lpVtbl->AddRef(lpStg); + + OLEDBG_END2 + return NOERROR; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +// IPersistStorage::Save method + +STDMETHODIMP SvrDoc_PStg_Save( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStg, + BOOL fSameAsLoad +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + BOOL fStatus; + SCODE sc; + + OLEDBG_BEGIN2("SvrDoc_PStg_Save\r\n") + + fStatus = OutlineDoc_SaveSelToStg( + (LPOUTLINEDOC)lpServerDoc, + NULL, + lpOutlineDoc->m_cfSaveFormat, + lpStg, + fSameAsLoad, + FALSE + ); + + if (! fStatus) { + OutlineApp_ErrorMessage(g_lpApp, ErrMsgPSSaveFail); + sc = E_FAIL; + goto error; + } + + lpServerDoc->m_fSaveWithSameAsLoad = fSameAsLoad; + lpServerDoc->m_fNoScribbleMode = TRUE; + + OLEDBG_END2 + return NOERROR; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +// IPersistStorage::SaveCompleted method + +STDMETHODIMP SvrDoc_PStg_SaveCompleted( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStgNew +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("SvrDoc_PStg_SaveCompleted\r\n") + + /* OLE2NOTE: this sample application is a pure server application. + ** a container/server application would have to call SaveCompleted + ** for each of its contained compound document objects. if a new + ** storage was given, then the container/server would have to + ** open the corresponding new sub-storage for each compound + ** document object and pass as an argument in the SaveCompleted + ** call. + */ + + /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation + ** on an embedded object. if the document is a file-based document + ** then we can not be changed to a IStorage-base object. + ** + ** fSameAsLoad lpStgNew Type of Save Send OnSave + ** --------------------------------------------------------- + ** TRUE NULL SAVE YES + ** TRUE ! NULL SAVE * YES + ** FALSE ! NULL SAVE AS YES + ** FALSE NULL SAVE COPY AS NO + ** + ** * this is a strange case that is possible. it is inefficient + ** for the caller; it would be better to pass lpStgNew==NULL for + ** the Save operation. + */ + if ( ((lpServerDoc->m_fSaveWithSameAsLoad && lpStgNew==NULL) || lpStgNew) + && (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) ) { + OLEDBG_END2 + return ResultFromScode(E_INVALIDARG); + } + + /* OLE2NOTE: inform any linking clients that the document has been + ** saved. in addition, any currently active pseudo objects + ** should also inform their clients. we should only broadcast an + ** OnSave notification if a Save or SaveAs operation was + ** performed. we do NOT want to send the notification if a + ** SaveCopyAs operation was performed. + */ + if (lpStgNew || lpServerDoc->m_fSaveWithSameAsLoad) { + + /* OLE2NOTE: if IPersistStorage::Save has been called, then we + ** need to clear the dirty bit and send OnSave notification. + ** if HandsOffStorage is called directly without first + ** calling Save, then we do NOT want to clear the dirty bit + ** and send OnSave when SaveCompleted is called. + */ + if (lpServerDoc->m_fNoScribbleMode) { + OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE); + + ServerDoc_SendAdvise ( + lpServerDoc, + OLE_ONSAVE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- not relevant here */ + ); + } + lpServerDoc->m_fSaveWithSameAsLoad = FALSE; + } + lpServerDoc->m_fNoScribbleMode = FALSE; + + /* OLE2NOTE: An embedded object must guarantee that it can save + ** even in low memory situations. it must be able to + ** successfully save itself without consuming any additional + ** memory. this means that a server is NOT supposed to open or + ** create any streams or storages when + ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an + ** embedded object should hold onto its storage and pre-open and + ** hold open any streams that it will need later when it is time + ** to save. if this is a SaveAs situtation, then we want to + ** pre-open and hold open our streams to guarantee that a + ** subsequent save will be successful in low-memory. if we fail + ** to open these streams then we want to force ourself to close + ** to make sure the can't make editing changes that can't be + ** later saved. + */ + if ( lpStgNew && !lpServerDoc->m_fSaveWithSameAsLoad ) { + + // release previous streams + if (lpOleDoc->m_lpLLStm) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm); + lpOleDoc->m_lpLLStm = NULL; + } + if (lpOleDoc->m_lpNTStm) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm); + lpOleDoc->m_lpNTStm = NULL; + } + if (lpOleDoc->m_lpStg) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg); + lpOleDoc->m_lpStg = NULL; + } + + hrErr = CallIStorageOpenStreamA( + lpStgNew, + "LineList", + NULL, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE, + 0, + &lpOleDoc->m_lpLLStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream"); + OleDbgOutHResult("LineList CreateStream returned", hrErr); + goto error; + } + + hrErr = CallIStorageOpenStreamA( + lpStgNew, + "NameTable", + NULL, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE, + 0, + &lpOleDoc->m_lpNTStm + ); + + if (hrErr != NOERROR) { + OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream"); + OleDbgOutHResult("NameTable CreateStream returned", hrErr); + goto error; + } + + lpOleDoc->m_lpStg = lpStgNew; + + // OLE2NOTE: to hold onto IStorage* pointer, we must AddRef it + lpStgNew->lpVtbl->AddRef(lpStgNew); + } + + OLEDBG_END2 + return NOERROR; + +error: + OLEDBG_END2 + return ResultFromScode(E_OUTOFMEMORY); +} + + +// IPersistStorage::HandsOffStorage method + +STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_PStg_HandsOffStorage\r\n") + + /* OLE2NOTE: An embedded object must guarantee that it can save + ** even in low memory situations. it must be able to + ** successfully save itself without consuming any additional + ** memory. this means that a server is NOT supposed to open or + ** create any streams or storages when + ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an + ** embedded object should hold onto its storage and pre-open and + ** hold open any streams that it will need later when it is time + ** to save. Now when HandsOffStorage is called the object must + ** release its storage and any streams that is holds open. + ** later when SaveCompleted is called, it will be given back its + ** storage. + */ + if (lpOleDoc->m_lpLLStm) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm); + lpOleDoc->m_lpLLStm = NULL; + } + if (lpOleDoc->m_lpNTStm) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm); + lpOleDoc->m_lpNTStm = NULL; + } + if (lpOleDoc->m_lpStg) { + OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg); + lpOleDoc->m_lpStg = NULL; + } + + OLEDBG_END2 + return NOERROR; +} + + + +#if defined( SVR_TREATAS ) + +/************************************************************************* +** ServerDoc::IStdMarshalInfo interface implementation +*************************************************************************/ + +// IStdMarshalInfo::QueryInterface method + +STDMETHODIMP SvrDoc_StdMshl_QueryInterface( + LPSTDMARSHALINFO lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc; + + return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj); +} + + +// IStdMarshalInfo::AddRef method + +STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc; + + OleDbgAddRefMethod(lpThis, "IStdMarshalInfo"); + + return OleDoc_AddRef((LPOLEDOC)lpServerDoc); +} + + +// IStdMarshalInfo::Release method + +STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc; + + OleDbgReleaseMethod(lpThis, "IStdMarshalInfo"); + + return OleDoc_Release((LPOLEDOC)lpServerDoc); +} + + +// IStdMarshalInfo::GetClassForHandler + +STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler( + LPSTDMARSHALINFO lpThis, + DWORD dwDestContext, + LPVOID pvDestContext, + LPCLSID lpClassID +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_StdMshl_GetClassForHandler\r\n"); + + // OLE2NOTE: we only handle LOCAL marshal context. + if (dwDestContext != MSHCTX_LOCAL || pvDestContext != NULL) + return ResultFromScode(E_INVALIDARG); + + /* OLE2NOTE: we must return our REAL clsid, NOT the clsid that we + ** are pretending to be if a "TreatAs" is in effect. + */ + *lpClassID = CLSID_APP; + return NOERROR; +} +#endif // SVR_TREATAS + + + +/************************************************************************* +** ServerDoc Support Functions +*************************************************************************/ + + +/* ServerDoc_Init + * -------------- + * + * Initialize the fields of a new ServerDoc object. The object is initially + * not associated with a file or an (Untitled) document. This function sets + * the docInitType to DOCTYPE_UNKNOWN. After calling this function the + * caller should call: + * 1.) OutlineDoc_InitNewFile to set the ServerDoc to (Untitled) + * 2.) OutlineDoc_LoadFromFile to associate the ServerDoc with a file. + * This function creates a new window for the document. + * + * NOTE: the window is initially created with a NIL size. it must be + * sized and positioned by the caller. also the document is initially + * created invisible. the caller must call OutlineDoc_ShowWindow + * after sizing it to make the document window visible. + */ +BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc) +{ + lpServerDoc->m_cPseudoObj = 0; + lpServerDoc->m_lpOleClientSite = NULL; + lpServerDoc->m_lpOleAdviseHldr = NULL; + lpServerDoc->m_lpDataAdviseHldr = NULL; + + // initialy doc does not have any storage + lpServerDoc->m_fNoScribbleMode = FALSE; + lpServerDoc->m_fSaveWithSameAsLoad = FALSE; + lpServerDoc->m_szContainerApp[0] = '\0'; + lpServerDoc->m_szContainerObj[0] = '\0'; + lpServerDoc->m_nNextRangeNo = 0L; + lpServerDoc->m_lrSrcSelOfCopy.m_nStartLine = -1; + lpServerDoc->m_lrSrcSelOfCopy.m_nEndLine = -1; + lpServerDoc->m_fDataChanged = FALSE; + lpServerDoc->m_fSizeChanged = FALSE; + lpServerDoc->m_fSendDataOnStop = FALSE; + +#if defined( SVR_TREATAS ) + lpServerDoc->m_clsidTreatAs = CLSID_NULL; + lpServerDoc->m_lpszTreatAsType = NULL; +#endif // SVR_TREATAS + +#if defined( INPLACE_SVR ) + lpServerDoc->m_hWndHatch = + CreateHatchWindow( + OutlineApp_GetWindow(g_lpApp), + OutlineApp_GetInstance(g_lpApp) + ); + if (!lpServerDoc->m_hWndHatch) + return FALSE; + + lpServerDoc->m_fInPlaceActive = FALSE; + lpServerDoc->m_fInPlaceVisible = FALSE; + lpServerDoc->m_fUIActive = FALSE; + lpServerDoc->m_lpIPData = NULL; + lpServerDoc->m_fMenuHelpMode = FALSE; // F1 pressed in menu + + INIT_INTERFACEIMPL( + &lpServerDoc->m_OleInPlaceObject, + &g_SvrDoc_OleInPlaceObjectVtbl, + lpServerDoc + ); + INIT_INTERFACEIMPL( + &lpServerDoc->m_OleInPlaceActiveObject, + &g_SvrDoc_OleInPlaceActiveObjectVtbl, + lpServerDoc + ); +#endif // INPLACE_SVR + + INIT_INTERFACEIMPL( + &lpServerDoc->m_OleObject, + &g_SvrDoc_OleObjectVtbl, + lpServerDoc + ); + + INIT_INTERFACEIMPL( + &lpServerDoc->m_PersistStorage, + &g_SvrDoc_PersistStorageVtbl, + lpServerDoc + ); + +#if defined( SVR_TREATAS ) + + INIT_INTERFACEIMPL( + &lpServerDoc->m_StdMarshalInfo, + &g_SvrDoc_StdMarshalInfoVtbl, + lpServerDoc + ); +#endif // SVR_TREATAS + return TRUE; +} + + +/* ServerDoc_InitNewEmbed + * ---------------------- + * + * Initialize the ServerDoc object to be a new embedded object document. + * This function sets the docInitType to DOCTYPE_EMBED. + */ +BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + + OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN); + + lpOutlineDoc->m_docInitType = DOCTYPE_EMBEDDED; + + /* The Window title for an embedded object is constructed as + ** follows: + ** <server app name> - <obj short type> in <cont. doc name> + ** + ** here we construct the current document title portion of the + ** name which follows the '-'. OutlineDoc_SetTitle prepends the + ** "<server app name> - " to the document title. + */ + // REVIEW: this string should be loaded from string resource + wsprintf(lpOutlineDoc->m_szFileName, "%s in %s", + (LPSTR)SHORTUSERTYPENAME, + (LPSTR)DEFCONTAINERNAME); + lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName; + + + /* OLE2NOTE: an embedding should be marked as initially dirty so + ** that on close we always call IOleClientSite::SaveObject. + */ + OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE); + + OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/); + + return TRUE; +} + + +/* ServerDoc_SendAdvise + * -------------------- + * + * This function sends an advise notification on behalf of a specific + * doc object to all its clients. + */ +void ServerDoc_SendAdvise( + LPSERVERDOC lpServerDoc, + WORD wAdvise, + LPMONIKER lpmkDoc, + DWORD dwAdvf +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + + switch (wAdvise) { + + case OLE_ONDATACHANGE: + + // inform clients that the data of the object has changed + + if (lpOutlineDoc->m_nDisableDraw == 0) { + /* drawing is currently enabled. inform clients that + ** the data of the object has changed + */ + + lpServerDoc->m_fDataChanged = FALSE; + + /* OLE2NOTE: we must note the time of last change + ** for our object in the RunningObjectTable. + ** this is used as the basis to answer + ** IOleObject::IsUpToDate. we only want to note + ** the change time when an actual change takes + ** place. we do NOT want to set it when we are + ** notifying clients of ADVF_DATAONSTOP + */ + if (dwAdvf == 0) + OleStdNoteObjectChangeTime(lpOleDoc->m_dwRegROT); + + if (lpServerDoc->m_lpDataAdviseHldr) { + OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n"); + lpServerDoc->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange( + lpServerDoc->m_lpDataAdviseHldr, + (LPDATAOBJECT)&lpOleDoc->m_DataObject, + 0, + dwAdvf + ); + OLEDBG_END2 + + } + +#if defined( INPLACE_SVR ) + /* OLE2NOTE: if the ServerDoc is currently in-place UI active, + ** then is it important to renegotiate the size for the + ** in-place document window BEFORE sending OnDataChange + ** (which will cause the window to repaint). + */ + if (lpServerDoc->m_fSizeChanged) { + lpServerDoc->m_fSizeChanged = FALSE; + if (lpServerDoc->m_fInPlaceActive) + ServerDoc_UpdateInPlaceWindowOnExtentChange(lpServerDoc); + } +#endif + + /* OLE2NOTE: we do NOT need to tell our pseudo objects to + ** broadcast OnDataChange notification because + ** they will do it automatically when an editing + ** change in the document affects a PseudoObj. + ** (see OutlineNameTable_AddLineUpdate, + ** OutlineNameTable_DeleteLineUpdate, + ** and ServerNameTable_EditLineUpdate) + */ + + } else { + /* drawing is currently disabled. do not send + ** notifications or call + ** IOleInPlaceObject::OnPosRectChange until drawing + ** is re-enabled. + */ + } + break; + + case OLE_ONCLOSE: + + // inform clients that the document is shutting down + + if (lpServerDoc->m_lpOleAdviseHldr) { + OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n"); + lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnClose( + lpServerDoc->m_lpOleAdviseHldr + ); + OLEDBG_END2 + } + + /* OLE2NOTE: we do NOT need to tell our pseudo objects to + ** broadcast OnClose notification because they will do + ** it automatically when the pseudo object is closed. + ** (see PseudoObj_Close) + */ + + break; + + case OLE_ONSAVE: + + // inform clients that the object has been saved + + OLEDBG_BEGIN3("ServerDoc_SendAdvise ONSAVE\r\n"); + + if (lpServerDoc->m_lpOleAdviseHldr) { + OLEDBG_BEGIN2("IOleAdviseHolder::SendOnSave called\r\n"); + lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnSave( + lpServerDoc->m_lpOleAdviseHldr + ); + OLEDBG_END2 + } + + /* OLE2NOTE: inform any clients of pseudo objects + ** within our document, that our document has been + ** saved. + */ + ServerNameTable_InformAllPseudoObjectsDocSaved( + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, + lpmkDoc + ); + OLEDBG_END3 + break; + + case OLE_ONRENAME: + + // inform clients that the object's name has changed + + OLEDBG_BEGIN3("ServerDoc_SendAdvise ONRENAME\r\n"); + + if (lpmkDoc && lpServerDoc->m_lpOleAdviseHldr) { + OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n"); + lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnRename( + lpServerDoc->m_lpOleAdviseHldr, + lpmkDoc + ); + OLEDBG_END2 + } + + OLEDBG_END3 + break; + } +} + + +/* ServerDoc_GetClassID +** -------------------- +** Return the class ID corresponding to the bits in the storage. +** normally this will be our application's given CLSID. but if a +** "TreateAs (aka. ActivateAs)" operation is taking place, then our +** application needs to pretend to be the class of the object that +** we are emulating. this is also the class that will be written +** into the storage. +*/ +HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid) +{ +#if defined( SVR_TREATAS ) + if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL)) + *lpclsid = lpServerDoc->m_clsidTreatAs; + else +#endif // SVR_TREATAS + *lpclsid = CLSID_APP; + + return NOERROR; +} + + + +/* ServerDoc_UpdateMenu + * -------------------- + * + * Update menu for embedding mode. the changes include: + * 1 Remove File/New and File/Open (SDI ONLY) + * 2 Change File/Save As.. to File/Save Copy As.. + * 3 Change File menu so it contains "Update" instead of "Save" + * 4 Change File/Exit to File/Exit & Return to <client doc>" + */ +void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc) +{ + char str[256]; + HWND hWndMain; + HMENU hMenu; + OleDbgOut2("ServerDoc_UpdateMenu\r\n"); + + hWndMain=g_lpApp->m_hWndApp; + hMenu=GetMenu(hWndMain); + +#if defined( SDI_VERSION ) + /* SDI ONLY: Remove File/New and File/Open */ + DeleteMenu(hMenu, IDM_F_NEW, MF_BYCOMMAND); + DeleteMenu(hMenu, IDM_F_OPEN, MF_BYCOMMAND); +#endif + + // Change File.Save As.. to File.Save Copy As.. */ + ModifyMenu(hMenu,IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save Copy As.."); + + // Change File.Save to "&Update <container doc>" + wsprintf(str, g_szUpdateCntrDoc, lpServerDoc->m_szContainerObj); + ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, str); + + // Change File/Exit to File/Exit & Return to <container doc>" */ + wsprintf(str, g_szExitNReturnToCntrDoc, lpServerDoc->m_szContainerObj); + ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, str); + + DrawMenuBar(hWndMain); +} + +#if defined( MDI_VERSION ) + +// NOTE: ServerDoc_RestoreMenu is actually redundant because the +// app is dying when the function is called. (In SDI, the +// app will terminate when the ref counter of the server doc +// is zero). However, it is important for MDI. + +/* ServerDoc_RestoreMenu + * --------------------- + * + * Reset the menu to non-embedding mode + */ +void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + HWND hWndMain; + HMENU hMenu; + OleDbgOut2("ServerDoc_RestoreMenu\r\n"); + + hWndMain = lpOutlineApp->m_hWndApp; + hMenu = GetMenu(hWndMain); + + /* Add back File/New, File/Open.. and File/Save */ + InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING, + IDM_F_NEW, "&New"); + InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING, + IDM_F_OPEN, "&Open..."); + + /* Change File menu so it contains "Save As..." instead of */ + /* "Save Copy As..." */ + ModifyMenu(hMenu, IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save &As.."); + + /* Change File menu so it contains "Save" instead of "Update" */ + ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, "&Save"); + + /* Change File menu so it contains "Exit" */ + /* instead of just "Exit & Return to <client doc>" */ + ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, "E&xit"); + + DrawMenuBar (hWndMain); +} + +#endif // MDI_VERSION diff --git a/private/oleutest/letest/outline/svrinpl.c b/private/oleutest/letest/outline/svrinpl.c new file mode 100644 index 000000000..fe4219d72 --- /dev/null +++ b/private/oleutest/letest/outline/svrinpl.c @@ -0,0 +1,1451 @@ +/************************************************************************* +** +** OLE 2 Server Sample Code +** +** svrinpl.c +** +** This file contains all interfaces, methods and related support +** functions for an In-Place Object (Server) application (aka. Visual +** Editing). The in-place Object application includes the following +** implementation objects: +** +** ServerDoc Object +** exposed interfaces: +** IOleInPlaceObject +** IOleInPlaceActiveObject +** +** ServerApp Object +** exposed interfaces: +** IUnknown +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + +/* OLE2NOTE: the object should compose a string that is used by +** in-place containers to be used for the window titles. this string +** is passed to the container application via +** IOleInPlaceUIWindow::SetActiveObject. the string should have the +** following form: +** <application name> - <object short type name> +** SDI containers can use the string directly to display in the +** frame window title. the container would concatenate the string +** " in <container doc name>". +** an MDI container with the MDI child window maximized can do the +** same as the SDI container. an MDI container with the MDI child +** windows NOT maximized can look for the " - " in the string from +** the object. the first part of the string (app name) would be put +** as the frame window title; the second part would be composed with +** " in <container doc name>" and used as the MDI child window +** title. +*/ + +// REVIEW: should use string resource for messages +char g_szIPObjectTitle[] = APPNAME " - " SHORTUSERTYPENAME; + +extern RECT g_rectNull; + + + +/************************************************************************* +** ServerDoc::IOleInPlaceObject interface implementation +*************************************************************************/ + +// IOleInPlaceObject::QueryInterface method + +STDMETHODIMP SvrDoc_IPObj_QueryInterface( + LPOLEINPLACEOBJECT lpThis, + REFIID riid, + LPVOID FAR * lplpvObj +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj); +} + + +// IOleInPlaceObject::AddRef method + +STDMETHODIMP_(ULONG) SvrDoc_IPObj_AddRef(LPOLEINPLACEOBJECT lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OleDbgAddRefMethod(lpThis, "IOleInPlaceObject"); + + return OleDoc_AddRef((LPOLEDOC)lpServerDoc); +} + + +// IOleInPlaceObject::Release method + +STDMETHODIMP_(ULONG) SvrDoc_IPObj_Release(LPOLEINPLACEOBJECT lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OleDbgReleaseMethod(lpThis, "IOleInPlaceObject"); + + return OleDoc_Release((LPOLEDOC)lpServerDoc); +} + + +// IOleInPlaceObject::GetWindow method + +STDMETHODIMP SvrDoc_IPObj_GetWindow( + LPOLEINPLACEOBJECT lpThis, + HWND FAR* lphwnd +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_IPObj_GetWindow\r\n") + + *lphwnd = ((LPOUTLINEDOC)lpServerDoc)->m_hWndDoc; + + OLEDBG_END2 + return S_OK; +} + + +// IOleInPlaceObject::ContextSensitiveHelp method + +STDMETHODIMP SvrDoc_IPObj_ContextSensitiveHelp( + LPOLEINPLACEOBJECT lpThis, + BOOL fEnable +) +{ + LPOLEDOC lpOleDoc = + (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_IPObj_ContextSensitiveHelp\r\n"); + + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC). + ** This method is called when SHIFT-F1 context sensitive help is + ** entered. the cursor should then change to a question mark + ** cursor and the app should enter a modal state where the next + ** mouse click does not perform its normal action but rather + ** gives help corresponding to the location clicked. if the app + ** does not implement a help system, it should at least eat the + ** click and do nothing. + */ + lpOleDoc->m_fCSHelpMode = fEnable; + + return S_OK; +} + + +// IOleInPlaceObject::InPlaceDeactivate method + +STDMETHODIMP SvrDoc_IPObj_InPlaceDeactivate(LPOLEINPLACEOBJECT lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("SvrDoc_IPObj_InPlaceDeactivate\r\n") + + hrErr = ServerDoc_DoInPlaceDeactivate(lpServerDoc); + + OLEDBG_END2 + return hrErr; +} + + +// IOleInPlaceObject::UIDeactivate method + +STDMETHODIMP SvrDoc_IPObj_UIDeactivate(LPOLEINPLACEOBJECT lpThis) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpServerDoc)->m_LineList; + HWND hWndApp = OutlineApp_GetWindow(g_lpApp); + + OLEDBG_BEGIN2("SvrDoc_IPObj_UIDeactivate\r\n"); + + if (!lpServerDoc->m_fUIActive) { + OLEDBG_END2 + return NOERROR; + } + + lpServerDoc->m_fUIActive = FALSE; + + // Clip the hatch window to the size of pos rect so, that the object + // adornments and hatch border will not be visible. + ServerDoc_ResizeInPlaceWindow(lpServerDoc, + (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect), + (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect) + ); + + if (lpIPData->lpDoc) + lpIPData->lpDoc->lpVtbl->SetActiveObject(lpIPData->lpDoc, NULL, NULL); + + if (lpIPData->lpFrame) { + lpIPData->lpFrame->lpVtbl->SetActiveObject( + lpIPData->lpFrame, + NULL, + NULL + ); + } + +#if defined( USE_FRAMETOOLS ) + /* OLE2NOTE: we must hide our frame tools here but NOT call + ** IOleInPlaceFrame::SetBorderSpace(NULL) or SetMenu(NULL). + ** we must hide our tools BEFORE calling + ** IOleInPlaceSite::OnUIDeactivate. the container will put + ** his menus and tools back when OnUIDeactivate is called. + */ + ServerDoc_RemoveFrameLevelTools(lpServerDoc); +#endif + + OLEDBG_BEGIN2("IOleInPlaceSite::OnUIDeactivate called\r\n"); + lpIPData->lpSite->lpVtbl->OnUIDeactivate(lpIPData->lpSite, FALSE); + OLEDBG_END2 + + /* Reset to use our normal app's accelerator table */ + g_lpApp->m_hAccelApp = lpServerApp->m_hAccelBaseApp; + g_lpApp->m_hAccel = lpServerApp->m_hAccelBaseApp; + g_lpApp->m_hWndAccelTarget = hWndApp; + + OLEDBG_END2 + +#if !defined( SVR_INSIDEOUT ) + /* OLE2NOTE: an "outside-in" style in-place server would hide its + ** window here. an "inside-out" style server leaves its window + ** visible when it is UIDeactivated. it would only hide its + ** window when InPlaceDeactivated. this app is an "inside-out" + ** style server. it is recommended for most server to support + ** inside-out behavior if possible. + */ + ServerDoc_DoInPlaceHide(lpServerDoc); +#endif // INSIEDOUT + + return NOERROR; +} + + +// IOleInPlaceObject::SetObjectRects method + +STDMETHODIMP SvrDoc_IPObj_SetObjectRects( + LPOLEINPLACEOBJECT lpThis, + LPCRECT lprcPosRect, + LPCRECT lprcClipRect +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + LPLINELIST lpLL = OutlineDoc_GetLineList((LPOUTLINEDOC)lpServerDoc); + OLEDBG_BEGIN2("SvrDoc_IPObj_SetObjectRects\r\n") + +#if defined( _DEBUG ) + OleDbgOutRect3("SvrDoc_IPObj_SetObjectRects (PosRect)", + (LPRECT)lprcPosRect); + OleDbgOutRect3("SvrDoc_IPObj_SetObjectRects (ClipRect)", + (LPRECT)lprcClipRect); +#endif + // save the current PosRect and ClipRect + lpIPData->rcPosRect = *lprcPosRect; + lpIPData->rcClipRect = *lprcClipRect; + + if (! lpServerDoc->m_fUIActive) // hatch and adornaments must not be drawn + lprcClipRect = lprcPosRect; + + ServerDoc_ResizeInPlaceWindow( + lpServerDoc, (LPRECT)lprcPosRect, (LPRECT)lprcClipRect); + + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceObject::ReactivateAndUndo method + +STDMETHODIMP SvrDoc_IPObj_ReactivateAndUndo(LPOLEINPLACEOBJECT lpThis) +{ + OLEDBG_BEGIN2("SvrDoc_IPObj_ReactivateAndUndo\r\n") + + // We do not support support UNDO. + + /* REVIEW: for debugging purposes it would be useful to give a + ** message box indicating that this method has been called. + */ + + OLEDBG_END2 + return NOERROR; +} + + +/************************************************************************* +** ServerDoc::IOleInPlaceActiveObject interface implementation +*************************************************************************/ + +// IOleInPlaceActiveObject::QueryInterface method + +STDMETHODIMP SvrDoc_IPActiveObj_QueryInterface( + LPOLEINPLACEACTIVEOBJECT lpThis, + REFIID riid, + LPVOID FAR * lplpvObj +) +{ + SCODE sc = E_NOINTERFACE; + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + /* The container should not be able to access the other interfaces + ** of our object by doing QI on this interface. + */ + + *lplpvObj = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IOleWindow) || + IsEqualIID(riid, &IID_IOleInPlaceActiveObject)) { + OleDbgOut4("OleDoc_QueryInterface: IOleInPlaceActiveObject* RETURNED\r\n"); + + *lplpvObj = lpThis; + OleDoc_AddRef((LPOLEDOC)lpServerDoc); + sc = NOERROR; + } + + OleDbgQueryInterfaceMethod(*lplpvObj); + + return ResultFromScode(sc); +} + + +// IOleInPlaceActiveObject::AddRef method + +STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_AddRef( + LPOLEINPLACEACTIVEOBJECT lpThis +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OleDbgAddRefMethod(lpThis, "IOleInPlaceActiveObject"); + + return OleDoc_AddRef((LPOLEDOC)lpServerDoc); +} + + +// IOleInPlaceActiveObject::Release method + +STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_Release( + LPOLEINPLACEACTIVEOBJECT lpThis +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OleDbgReleaseMethod(lpThis, "IOleInPlaceActiveObject"); + + return OleDoc_Release((LPOLEDOC)lpServerDoc); +} + + +// IOleInPlaceActiveObject::GetWindow method + +STDMETHODIMP SvrDoc_IPActiveObj_GetWindow( + LPOLEINPLACEACTIVEOBJECT lpThis, + HWND FAR* lphwnd +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_IPActiveObj_GetWindow\r\n") + + *lphwnd = ((LPOUTLINEDOC)lpServerDoc)->m_hWndDoc; + + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceActiveObject::ContextSensitiveHelp method + +STDMETHODIMP SvrDoc_IPActiveObj_ContextSensitiveHelp( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fEnterMode +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + OleDbgOut2("SvrDoc_IPActiveObj_ContextSensitiveHelp\r\n"); + + /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC) + ** This method is called when F1 is pressed when a menu item is + ** selected. this tells the in-place server application to give + ** help rather than execute the next menu command. at a minimum, + ** even if the in-place server application does not implement a + ** help system, it should NOT execute the next command when + ** fEnable==TRUE. We set the active object's m_fMenuMode flag here. + ** later, in WM_COMMAND processing in the DocWndProc, if this + ** flag is set then the command is NOT executed (and help could + ** be given if we had a help system....but we don't.) + */ + lpServerDoc->m_fMenuHelpMode = fEnterMode; + +#if !defined( HACK ) + ((LPOLEDOC)lpServerDoc)->m_fCSHelpMode = fEnterMode; +#endif + return NOERROR; +} + + +// IOleInPlaceActiveObject::TranslateAccelerator method + +STDMETHODIMP SvrDoc_IPActiveObj_TranslateAccelerator( + LPOLEINPLACEACTIVEOBJECT lpThis, + LPMSG lpmsg +) +{ + // This will never be called because this server is implemented as an EXE + return NOERROR; +} + + +// IOleInPlaceActiveObject::OnFrameWindowActivate method + +STDMETHODIMP SvrDoc_IPActiveObj_OnFrameWindowActivate( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fActivate +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC) + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + HWND hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc); +#if defined( _DEBUG ) + if (fActivate) + OleDbgOut2("SvrDoc_IPActiveObj_OnFrameWindowActivate(TRUE)\r\n"); + else + OleDbgOut2("SvrDoc_IPActiveObj_OnFrameWindowActivate(FALSE)\r\n"); +#endif // _DEBUG + + /* OLE2NOTE: this is a notification of the container application's + ** WM_ACTIVATEAPP status. some applications may find this + ** important. we need to update the enable/disable status of our + ** tool bar buttons. + */ + + // OLE2NOTE: We can't call OutlineDoc_UpdateFrameToolButtons + // right away which + // would generate some OLE calls and eventually + // WM_ACTIVATEAPP and a loop was formed. Therefore, we + // should delay the frame tool initialization until + // WM_ACTIVATEAPP is finished by posting a message + // to ourselves. + + /* Update enable/disable state of buttons in toolbar */ + if (fActivate) + PostMessage(hWndDoc, WM_U_INITFRAMETOOLS, 0, 0L); + + return NOERROR; +} + + +// IOleInPlaceActiveObject::OnDocWindowActivate method + +STDMETHODIMP SvrDoc_IPActiveObj_OnDocWindowActivate( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fActivate +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; +#if defined( _DEBUG ) + if (fActivate) + OleDbgOut2("SvrDoc_IPActiveObj_OnDocWindowActivate(TRUE)\r\n"); + else + OleDbgOut2("SvrDoc_IPActiveObj_OnDocWindowActivate(FALSE)\r\n"); +#endif + + if (fActivate) { + ServerDoc_AddFrameLevelUI(lpServerDoc); + } + else { +#if defined( USE_FRAMETOOLS ) + /* OLE2NOTE: we must NOT call IOleInPlaceFrame::SetBorderSpace(NULL) + ** or SetMenu(NULL) here. we should simply hide our tools. + */ + ServerDoc_RemoveFrameLevelTools(lpServerDoc); +#endif + } + + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceActiveObject::ResizeBorder method + +STDMETHODIMP SvrDoc_IPActiveObj_ResizeBorder( + LPOLEINPLACEACTIVEOBJECT lpThis, + LPCRECT lprectBorder, + LPOLEINPLACEUIWINDOW lpIPUiWnd, + BOOL fFrameWindow +) +{ + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + + OLEDBG_BEGIN2("SvrDoc_IPActiveObj_ResizeBorder\r\n") + + +#if defined( USE_FRAMETOOLS ) + + if (fFrameWindow) { + FrameTools_NegotiateForSpaceAndShow( + lpOutlineDoc->m_lpFrameTools, + (LPRECT)lprectBorder, + (LPOLEINPLACEFRAME)lpIPUiWnd + ); + } + +#endif + + OLEDBG_END2 + return NOERROR; +} + + +// IOleInPlaceActiveObject::EnableModeless method + +STDMETHODIMP SvrDoc_IPActiveObj_EnableModeless( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fEnable +) +{ +#if defined( USE_FRAMETOOLS ) + LPSERVERDOC lpServerDoc = + ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPFRAMETOOLS lptb; + + /* OLE2NOTE: we must enable/disable mouse and keyboard input to our + ** floating tool palette + */ + if (lpOutlineDoc) { + lptb = lpOutlineDoc->m_lpFrameTools; + if (lptb) + FrameTools_EnableWindow(lptb, fEnable); + } +#endif // USE_FRAMETOOLS + +#if defined( _DEBUG ) + if (fEnable) + OleDbgOut2("SvrDoc_IPActiveObj_EnableModeless(TRUE)\r\n"); + else + OleDbgOut2("SvrDoc_IPActiveObj_EnableModeless(FALSE)\r\n"); +#endif // _DEBUG + + /* OLE2NOTE: this method is called when the top-level, in-place + ** container puts up a modal dialog. it tells the UIActive + ** object to disable it modeless dialogs for the duration that + ** the container is displaying a modal dialog. + ** + ** ISVROTL does not use any modeless dialogs, thus we can + ** ignore this method. + */ + return NOERROR; +} + + +/************************************************************************* +** Support Functions +*************************************************************************/ + + +HRESULT ServerDoc_DoInPlaceActivate( + LPSERVERDOC lpServerDoc, + LONG lVerb, + LPMSG lpmsg, + LPOLECLIENTSITE lpActiveSite +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + SCODE sc = E_FAIL; + RECT rcPos; + RECT rcClip; + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + LPOUTLINEDOC lpOutlineDoc=(LPOUTLINEDOC)lpServerDoc; + HWND hWndDoc = lpOutlineDoc->m_hWndDoc; + HWND hWndHatch = lpServerDoc->m_hWndHatch; + HRESULT hrErr; + LPLINELIST lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList; + LPOLEINPLACESITE lpIPSite = NULL; + + /* OLE2NOTE: lpActiveSite should be used only for InPlace PLAYing. + ** This app does not do inplace PLAYing, so it never uses + ** lpActiveSite. + */ + + /* InPlace activation can only be done if the ClientSite is non-NULL. */ + if (! lpServerDoc->m_lpOleClientSite) + return NOERROR; + + if (! lpServerDoc->m_fInPlaceActive) { + + // if the object is in open mode then we do not want to do inplace + // activation. + if (IsWindowVisible(lpOutlineDoc->m_hWndDoc)) + return NOERROR; + + lpIPSite = (LPOLEINPLACESITE)OleStdQueryInterface( + (LPUNKNOWN)lpServerDoc->m_lpOleClientSite, + &IID_IOleInPlaceSite + ); + + if (! lpIPSite) + goto errActivate; + + OLEDBG_BEGIN2("IOleInPlaceSite::CanInPlaceActivate called\r\n"); + hrErr = lpIPSite->lpVtbl->CanInPlaceActivate(lpIPSite); + OLEDBG_END2 + if (hrErr != NOERROR) + goto errActivate; + + lpServerDoc->m_fInPlaceActive = TRUE; + OLEDBG_BEGIN2("IOleInPlaceSite::OnInPlaceActivate called\r\n"); + hrErr = lpIPSite->lpVtbl->OnInPlaceActivate(lpIPSite); + OLEDBG_END2 + if (hrErr != NOERROR) + goto errActivate; + + if (! ServerDoc_AllocInPlaceData(lpServerDoc)) { + sc = E_OUTOFMEMORY; + OLEDBG_BEGIN2("IOleInPlaceSite::OnInPlaceDeactivate called\r\n"); + lpIPSite->lpVtbl->OnInPlaceDeactivate(lpIPSite); + OLEDBG_END2 + goto errActivate; + } + + (lpIPData = lpServerDoc->m_lpIPData)->lpSite = lpIPSite; + goto InPlaceActive; + + errActivate: + lpServerDoc->m_fInPlaceActive = FALSE; + if (lpIPSite) + OleStdRelease((LPUNKNOWN)lpIPSite); + return ResultFromScode(sc); + } + + +InPlaceActive: + + if (! lpServerDoc->m_fInPlaceVisible) { + lpServerDoc->m_fInPlaceVisible = TRUE; + + OLEDBG_BEGIN2("IOleInPlaceSite::GetWindow called\r\n"); + hrErr = lpIPData->lpSite->lpVtbl->GetWindow( + lpIPData->lpSite, &lpServerDoc->m_hWndParent); + OLEDBG_END2 + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto errRtn; + } + + if (! lpServerDoc->m_hWndParent) + goto errRtn; + + /* OLE2NOTE: The server should fill in the "cb" field so that the + ** container can tell what size structure the server is + ** expecting. this enables this structure to be easily extended + ** in future releases of OLE. the container should check this + ** field so that it doesn't try to use fields that do not exist + ** since the server may be using an old structure definition. + */ + _fmemset( + (LPOLEINPLACEFRAMEINFO)&lpIPData->frameInfo, + 0, + sizeof(OLEINPLACEFRAMEINFO) + ); + lpIPData->frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + + OLEDBG_BEGIN2("IOleInPlaceSite::GetWindowContext called\r\n"); + hrErr = lpIPData->lpSite->lpVtbl->GetWindowContext(lpIPData->lpSite, + (LPOLEINPLACEFRAME FAR*) &lpIPData->lpFrame, + (LPOLEINPLACEUIWINDOW FAR*)&lpIPData->lpDoc, + (LPRECT)&rcPos, + (LPRECT)&rcClip, + (LPOLEINPLACEFRAMEINFO)&lpIPData->frameInfo); + OLEDBG_END2 + + if (hrErr != NOERROR) { + sc = GetScode(hrErr); + goto errRtn; + } + + lpServerApp->m_lpIPData = lpIPData; + ShowWindow(hWndDoc, SW_HIDE); // make sure we are hidden + + /* OLE2NOTE: reparent in-place server document's window to the + ** special in-place hatch border window. set the in-place site's + ** window as the parent of the hatch window. position the + ** in-place and hatch border windows using the PosRect and + ** ClipRect. + ** it is important to properly parent and position the in-place + ** server window BEFORE calling IOleInPlaceFrame::SetMenu and + ** SetBorderSpace. + */ + ShowWindow(lpServerDoc->m_hWndHatch, SW_SHOW); + // make sure App busy/blocked dialogs are parented to our + // new hWndFrame + OleStdMsgFilter_SetParentWindow( + lpOleApp->m_lpMsgFilter,lpIPData->frameInfo.hwndFrame); + SetParent(lpServerDoc->m_hWndHatch, lpServerDoc->m_hWndParent); + SetParent(hWndDoc, lpServerDoc->m_hWndHatch); + +#if defined( _DEBUG ) + OleDbgOutRect3("IOleInPlaceSite::GetWindowContext (PosRect)", + (LPRECT)&rcPos); + OleDbgOutRect3("IOleInPlaceSite::GetWindowContext (ClipRect)", + (LPRECT)&rcClip); +#endif + // save the current PosRect and ClipRect + lpIPData->rcPosRect = rcPos; + lpIPData->rcClipRect = rcClip; + + /* OLE2NOTE: build the shared menu for the in-place container and + ** the server. + */ + if (ServerDoc_AssembleMenus (lpServerDoc) != NOERROR) + goto errRtn; + +#if defined( SVR_INSIDEOUT ) + if (lVerb == OLEIVERB_INPLACEACTIVATE) { + // Clip the hatch window to the size of pos rect so, that + // hatch and object adornments will not be visible. + ServerDoc_ResizeInPlaceWindow(lpServerDoc, + (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect), + (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect) + ); + } +#endif // SVR_INSIDEOUT + } + +#if defined( SVR_INSIDEOUT ) + // OLE2NOTE: if verb is OLEIVERB_INPLACEACTIVATE we do NOT want to + // show our UI + if (lVerb == OLEIVERB_INPLACEACTIVATE) { + return NOERROR; + } +#endif // SVR_INSIDEOUT + + if (! lpServerDoc->m_fUIActive) { + lpServerDoc->m_fUIActive = TRUE; + OLEDBG_BEGIN2("IOleInPlaceSite::OnUIActivate called\r\n"); + hrErr = lpIPData->lpSite->lpVtbl->OnUIActivate(lpIPData->lpSite); + OLEDBG_END2 + if (hrErr != NOERROR) { + lpServerDoc->m_fUIActive = FALSE; + goto errRtn; + } + + SetFocus(hWndDoc); + + // Show the object adornments and hacth border around them. + ServerDoc_ResizeInPlaceWindow(lpServerDoc, + (LPRECT)&lpIPData->rcPosRect, + (LPRECT)&lpIPData->rcClipRect + ); + + /* OLE2NOTE: IOleInPlaceFrame::SetActiveObject must be called BEFORE + ** IOleInPlaceFrame::SetMenu. + */ + OLEDBG_BEGIN2("IOleInPlaceSite::SetActiveObject called\r\n"); + CallIOleInPlaceUIWindowSetActiveObjectA( + (struct IOleInPlaceUIWindow *) lpIPData->lpFrame, + (LPOLEINPLACEACTIVEOBJECT) &lpServerDoc->m_OleInPlaceActiveObject, + (LPSTR)g_szIPObjectTitle + ); + OLEDBG_END2 + + /* OLE2NOTE: If the container wants to give ownership of the + ** palette then he would sendmessage WM_QUEYNEWPALETTE to + ** the object window proc, before returning from + ** IOleInPlaceFrame::SetActiveObject. Those objects which + ** want to be edited inplace only if they have the ownership of + ** the palette, can check at this point in the code whether + ** they got WM_QUERYNEWPALETTE or not. If they didn't get + ** the message, then they can inplace deactivate and do open + ** editing instead. + */ + + + + if (lpIPData->lpDoc) { + CallIOleInPlaceUIWindowSetActiveObjectA( + lpIPData->lpDoc, + (LPOLEINPLACEACTIVEOBJECT)&lpServerDoc->m_OleInPlaceActiveObject, + (LPSTR)g_szIPObjectTitle + ); + } + + /* OLE2NOTE: install the menu and frame-level tools on the in-place + ** frame. + */ + ServerDoc_AddFrameLevelUI(lpServerDoc); + } + + return NOERROR; + +errRtn: + ServerDoc_DoInPlaceDeactivate(lpServerDoc); + return ResultFromScode(sc); +} + + + +HRESULT ServerDoc_DoInPlaceDeactivate(LPSERVERDOC lpServerDoc) +{ + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + + if (!lpServerDoc->m_fInPlaceActive) + return S_OK; + + lpServerDoc->m_fInPlaceActive = FALSE; + + SvrDoc_IPObj_UIDeactivate( + (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject); + + /* OLE2NOTE: an inside-out style in-place server will + ** NOT hide its window in UIDeactive (an outside-in + ** style object will hide its window in UIDeactivate). + ** thus, an inside-out server must explicitly hide + ** its window in InPlaceDeactivate. it is ALSO important for an + ** outside-in style object to call ServerDoc_DoInPlaceHide here + ** BEFORE freeing the InPlaceData structure. it will be common + ** for in-place containers to call IOleInPlaceObject:: + ** InPlaceDeactivate in their IOleInPlaceSite::OnUIDeactiate + ** implementation. + */ + ServerDoc_DoInPlaceHide(lpServerDoc); + + OLEDBG_BEGIN2("IOleInPlaceSite::OnInPlaceDeactivate called\r\n"); + lpIPData->lpSite->lpVtbl->OnInPlaceDeactivate(lpIPData->lpSite); + OLEDBG_END2 + + OleStdRelease((LPUNKNOWN)lpIPData->lpSite); + lpIPData->lpSite = NULL; + + ServerDoc_FreeInPlaceData(lpServerDoc); + + return NOERROR; +} + + +HRESULT ServerDoc_DoInPlaceHide(LPSERVERDOC lpServerDoc) +{ + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + HWND hWndApp = OutlineApp_GetWindow(g_lpApp); + + if (! lpServerDoc->m_fInPlaceVisible) + return NOERROR; + + // Set the parent back to server app's window + OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /* fShutdown */); + + /* we need to enusure that our window is set to normal 100% zoom. + ** if the window is next shown in open mode it should start out + ** at normal zoom factor. our window may have been set to a + ** different zoom factor while it was in-place active. + */ + OutlineDoc_SetCurrentZoomCommand(lpOutlineDoc,IDM_V_ZOOM_100); + + lpServerDoc->m_fInPlaceVisible = FALSE; + + lpServerDoc->m_hWndParent = hWndApp; + SetParent( + lpOutlineDoc->m_hWndDoc, + lpServerDoc->m_hWndParent + ); + + // make sure App busy/blocked dialogs are parented to our own hWndApp + OleStdMsgFilter_SetParentWindow(lpOleApp->m_lpMsgFilter, hWndApp); + + // Hide the in-place hatch border window. + ShowWindow(lpServerDoc->m_hWndHatch, SW_HIDE); + + ServerDoc_DisassembleMenus(lpServerDoc); + + /* we no longer need the IOleInPlaceFrame* or the doc's + ** IOleInPlaceWindow* interface pointers. + */ + if (lpIPData->lpDoc) { + OleStdRelease((LPUNKNOWN)lpIPData->lpDoc); + lpIPData->lpDoc = NULL; + } + + if (lpIPData->lpFrame) { + OleStdRelease((LPUNKNOWN)lpIPData->lpFrame); + lpIPData->lpFrame = NULL; + } + + ((LPSERVERAPP)g_lpApp)->m_lpIPData = NULL; + + return NOERROR; +} + + +BOOL ServerDoc_AllocInPlaceData(LPSERVERDOC lpServerDoc) +{ + LPINPLACEDATA lpIPData; + + if (!(lpIPData = (LPINPLACEDATA) New(sizeof(INPLACEDATA)))) + return FALSE; + + lpIPData->lpFrame = NULL; + lpIPData->lpDoc = NULL; + lpIPData->lpSite = NULL; + lpIPData->hOlemenu = NULL; + lpIPData->hMenuShared = NULL; + + lpServerDoc->m_lpIPData = lpIPData; + return TRUE; +} + + +void ServerDoc_FreeInPlaceData(LPSERVERDOC lpServerDoc) +{ + Delete(lpServerDoc->m_lpIPData); + lpServerDoc->m_lpIPData = NULL; +} + + +HRESULT ServerDoc_AssembleMenus(LPSERVERDOC lpServerDoc) +{ + HMENU hMenuShared; + LONG FAR* lpWidths; + UINT uPosition; + UINT uPositionStart; + LPSERVERAPP lpServerApp = (LPSERVERAPP) g_lpApp; + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + HRESULT hresult; + BOOL fNoError = TRUE; + + lpWidths = lpIPData->menuGroupWidths.width; + hMenuShared = CreateMenu(); + + if (hMenuShared && + (hresult = lpIPData->lpFrame->lpVtbl->InsertMenus( + lpIPData->lpFrame, hMenuShared, + &lpIPData->menuGroupWidths)) == NOERROR) { + + /* Insert EDIT group menus */ + + uPosition = (UINT)lpWidths[0]; /* # of menus in the FILE group */ + uPositionStart = uPosition; + + fNoError &= InsertMenu( + hMenuShared, + (UINT)uPosition, + (UINT)(MF_BYPOSITION | MF_POPUP), + (UINT)lpServerApp->m_hMenuEdit, + (LPCSTR)"&Edit" + ); + uPosition++; + + lpWidths[1] = uPosition - uPositionStart; + + /* Insert OBJECT group menus */ + + uPosition += (UINT)lpWidths[2]; + uPositionStart = uPosition; + + fNoError &= InsertMenu( + hMenuShared, + (UINT)uPosition, + (UINT)(MF_BYPOSITION | MF_POPUP), + (UINT)lpServerApp->m_hMenuLine, + (LPCSTR)"&Line" + ); + uPosition++; + + fNoError &= InsertMenu( + hMenuShared, + (UINT)uPosition, + (UINT)(MF_BYPOSITION | MF_POPUP), + (UINT)lpServerApp->m_hMenuName, + (LPCSTR)"&Name" + ); + uPosition++; + + fNoError &= InsertMenu( + hMenuShared, + (UINT)uPosition, + (UINT)(MF_BYPOSITION | MF_POPUP), + (UINT)lpServerApp->m_hMenuOptions, + (LPCSTR)"&Options" + ); + uPosition++; + + fNoError &= InsertMenu( + hMenuShared, + (UINT)uPosition, + (UINT)(MF_BYPOSITION | MF_POPUP), + (UINT)lpServerApp->m_hMenuDebug, + (LPCSTR)"DbgI&Svr" + ); + uPosition++; + + lpWidths[3] = uPosition - uPositionStart; + + /* Insert HELP group menus */ + + uPosition += (UINT) lpWidths[4]; /* # of menus in WINDOW group */ + uPositionStart = uPosition; + + fNoError &= InsertMenu( + hMenuShared, + (UINT)uPosition, + (UINT)(MF_BYPOSITION | MF_POPUP), + (UINT)lpServerApp->m_hMenuHelp, + (LPCSTR)"&Help" + ); + uPosition++; + + lpWidths[5] = uPosition - uPositionStart; + + OleDbgAssert(fNoError == TRUE); + + } else { + /* In-place container does not allow us to add menus to the + ** frame. + ** OLE2NOTE: even when the in-place container does NOT allow + ** the building of a merged menu bar, it is CRITICAL that + ** the in-place server still call OleCreateMenuDescriptor + ** passing NULL for hMenuShared. + */ + if (hMenuShared) { + DestroyMenu(hMenuShared); + hMenuShared = NULL; + } + } + + lpIPData->hMenuShared = hMenuShared; + + if (!(lpIPData->hOlemenu = OleCreateMenuDescriptor(hMenuShared, + &lpIPData->menuGroupWidths))) + return ResultFromScode(E_OUTOFMEMORY); + + return NOERROR; +} + + +void ServerDoc_DisassembleMenus(LPSERVERDOC lpServerDoc) +{ + UINT uCount; + UINT uGroup; + UINT uDeleteAt; + LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData; + LONG FAR* lpWidths = lpIPData->menuGroupWidths.width; + BOOL fNoError = TRUE; + + /* OLE2NOTE: even when hMenuShared is NULL (ie. the server has no + ** Menu), there is still an hOleMenu created that must be destroyed. + */ + if (lpIPData->hOlemenu) { + OleDestroyMenuDescriptor (lpIPData->hOlemenu); + lpIPData->hOlemenu = NULL; + } + + if (! lpIPData->hMenuShared) + return; // no menus to be destroyed + + /* Remove server group menus. */ + uDeleteAt = 0; + for (uGroup = 0; uGroup < 6; uGroup++) { + uDeleteAt += (UINT)lpWidths[uGroup++]; + for (uCount = 0; uCount < (UINT)lpWidths[uGroup]; uCount++) + fNoError &= RemoveMenu(lpIPData->hMenuShared, uDeleteAt, + MF_BYPOSITION); + } + + /* Remove container group menus */ + fNoError &= (lpIPData->lpFrame->lpVtbl->RemoveMenus( + lpIPData->lpFrame, + lpIPData->hMenuShared) == NOERROR); + + OleDbgAssert(fNoError == TRUE); + + DestroyMenu(lpIPData->hMenuShared); + lpIPData->hMenuShared = NULL; +} + + +/* ServerDoc_UpdateInPlaceWindowOnExtentChange +** ------------------------------------------- +** The size of the in-place window needs to be changed. +** calculate the size required in Client coordinates (taking into +** account the current scale factor imposed by the in-place +** container) and ask our in-place container to allow us to resize. +** our container must call us back via +** IOleInPlaceObject::SetObjectRects for the actual sizing to take +** place. +** +** OLE2NOTE: the rectangle that we ask for from our in-place +** container is always the rectangle required for the object display +** itself (in our case the size of the LineList contents). it does +** NOT include the space we require for object frame adornments. +*/ +void ServerDoc_UpdateInPlaceWindowOnExtentChange(LPSERVERDOC lpServerDoc) +{ + SIZEL sizelHim; + SIZEL sizelPix; + RECT rcPosRect; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPLINELIST lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList; + HWND hWndLL = lpLL->m_hWndListBox; + LPSCALEFACTOR lpscale = (LPSCALEFACTOR)&lpOutlineDoc->m_scale; + + if (!lpServerDoc->m_fInPlaceActive) + return; + + OleDoc_GetExtent((LPOLEDOC)lpServerDoc, (LPSIZEL)&sizelHim); + + // apply current scale factor + sizelHim.cx = sizelHim.cx * lpscale->dwSxN / lpscale->dwSxD; + sizelHim.cy = sizelHim.cy * lpscale->dwSxN / lpscale->dwSxD; + XformSizeInHimetricToPixels(NULL, (LPSIZEL)&sizelHim, (LPSIZEL)&sizelPix); + + GetWindowRect(hWndLL, (LPRECT)&rcPosRect); + ScreenToClient(lpServerDoc->m_hWndParent, (POINT FAR *)&rcPosRect); + + rcPosRect.right = rcPosRect.left + (int) sizelPix.cx; + rcPosRect.bottom = rcPosRect.top + (int) sizelPix.cy; + OleDbgOutRect3("ServerDoc_UpdateInPlaceWindowOnExtentChange: (PosRect)", (LPRECT)&rcPosRect); + + OLEDBG_BEGIN2("IOleInPlaceSite::OnPosRectChange called\r\n"); + lpServerDoc->m_lpIPData->lpSite->lpVtbl->OnPosRectChange( + lpServerDoc->m_lpIPData->lpSite, + (LPRECT) &rcPosRect + ); + OLEDBG_END2 +} + + +/* ServerDoc_CalcInPlaceWindowPos + * ------------------------------ + * + * Move (and re-scale) the ServerDoc to the specified rectangle. + * + * Parameters: + * lprcListBox - rect in client coordinate in which the listbox will fit + * lprcDoc - corresponding size of the Doc in client coordinate + * + */ +void ServerDoc_CalcInPlaceWindowPos( + LPSERVERDOC lpServerDoc, + LPRECT lprcListBox, + LPRECT lprcDoc, + LPSCALEFACTOR lpscale +) +{ + SIZEL sizelHim; + SIZEL sizelPix; + LPLINELIST lpLL; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPHEADING lphead; + + if (!lpServerDoc || !lprcListBox || !lprcDoc) + return; + + lphead = (LPHEADING)&lpOutlineDoc->m_heading; + + lpLL = OutlineDoc_GetLineList(lpOutlineDoc); + OleDoc_GetExtent((LPOLEDOC)lpServerDoc, (LPSIZEL)&sizelHim); + XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix); + + if (sizelHim.cx == 0 || sizelPix.cx == 0) { + lpscale->dwSxN = 1; + lpscale->dwSxD = 1; + } else { + lpscale->dwSxN = lprcListBox->right - lprcListBox->left; + lpscale->dwSxD = sizelPix.cx; + } + + if (sizelHim.cy == 0 || sizelPix.cy == 0) { + lpscale->dwSyN = 1; + lpscale->dwSyD = 1; + } else { + lpscale->dwSyN = lprcListBox->bottom - lprcListBox->top; + lpscale->dwSyD = sizelPix.cy; + } + + lprcDoc->left = lprcListBox->left - Heading_RH_GetWidth(lphead,lpscale); + lprcDoc->right = lprcListBox->right; + lprcDoc->top = lprcListBox->top - Heading_CH_GetHeight(lphead,lpscale); + lprcDoc->bottom = lprcListBox->bottom; +} + + +/* ServerDoc_ResizeInPlaceWindow +** ----------------------------- +** Actually resize the in-place ServerDoc windows according to the +** PosRect and ClipRect allowed by our in-place container. +** +** OLE2NOTE: the PosRect rectangle that our in-place container tells +** us is always the rectangle required for the object display +** itself (in our case the size of the LineList contents). it does +** NOT include the space we require for object frame adornments. +*/ +void ServerDoc_ResizeInPlaceWindow( + LPSERVERDOC lpServerDoc, + LPCRECT lprcPosRect, + LPCRECT lprcClipRect +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPLINELIST lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList; + SCALEFACTOR scale; + RECT rcDoc; + POINT ptOffset; + + /* OLE2NOTE: calculate the space needed for our object frame + ** adornments. our in-place container tells us the size that our + ** object should take in window client coordinates + ** (lprcPosRect). the rectangle cooresponds to the size that our + ** LineList ListBox should be. our Doc window must the correct + ** amount larger to accomodate our row/column headings. + ** then move all windows into position. + */ + ServerDoc_CalcInPlaceWindowPos( + lpServerDoc, + (LPRECT)lprcPosRect, + (LPRECT)&rcDoc, + (LPSCALEFACTOR)&scale + ); + + /* OLE2NOTE: we need to honor the lprcClipRect specified by our + ** in-place container. we must NOT draw outside of the ClipRect. + ** in order to achieve this, we will size the hatch window to be + ** exactly the size that should be visible (rcVisRect). the + ** rcVisRect is defined as the intersection of the full size of + ** the in-place server window and the lprcClipRect. + ** the ClipRect could infact clip the HatchRect on the + ** right/bottom and/or on the top/left. if it is clipped on the + ** right/bottom then it is sufficient to simply resize the hatch + ** window. but if the HatchRect is clipped on the top/left then + ** we must "move" the ServerDoc window (child of HatchWindow) by + ** the delta that was clipped. the window origin of the + ** ServerDoc window will then have negative coordinates relative + ** to its parent HatchWindow. + */ + SetHatchWindowSize( + lpServerDoc->m_hWndHatch, + (LPRECT)&rcDoc, + (LPRECT)lprcClipRect, + (LPPOINT)&ptOffset + ); + + // shift Doc window to account for hatch frame being drawn + OffsetRect((LPRECT)&rcDoc, ptOffset.x, ptOffset.y); + + // move/size/set scale factor of ServerDoc window. + OutlineDoc_SetScaleFactor( + lpOutlineDoc, (LPSCALEFACTOR)&scale, (LPRECT)&rcDoc); + + /* reset the horizontal extent of the listbox. this makes + ** the listbox realize that a scroll bar is not needed. + */ + SendMessage( + lpLL->m_hWndListBox, + LB_SETHORIZONTALEXTENT, + (int) 0, + 0L + ); + SendMessage( + lpLL->m_hWndListBox, + LB_SETHORIZONTALEXTENT, + (int) (lprcPosRect->right - lprcPosRect->left), + 0L + ); +} + + +/* ServerDoc_SetStatusText +** Tell the active in-place frame to display a status message. +*/ +void ServerDoc_SetStatusText(LPSERVERDOC lpServerDoc, LPSTR lpszMessage) +{ + if (lpServerDoc && lpServerDoc->m_fUIActive && + lpServerDoc->m_lpIPData != NULL) { + + OLEDBG_BEGIN2("IOleInPlaceFrame::SetStatusText called\r\n") + CallIOleInPlaceFrameSetStatusTextA + (lpServerDoc->m_lpIPData->lpFrame, lpszMessage); + OLEDBG_END2 + } +} + + +/* ServerDoc_GetTopInPlaceFrame +** ---------------------------- +** returns NON-AddRef'ed pointer to Top In-Place Frame interface +*/ +LPOLEINPLACEFRAME ServerDoc_GetTopInPlaceFrame(LPSERVERDOC lpServerDoc) +{ + if (lpServerDoc->m_lpIPData) + return lpServerDoc->m_lpIPData->lpFrame; + else + return NULL; +} + +void ServerDoc_GetSharedMenuHandles( + LPSERVERDOC lpServerDoc, + HMENU FAR* lphSharedMenu, + HOLEMENU FAR* lphOleMenu +) +{ + if (lpServerDoc->m_lpIPData) { + *lphSharedMenu = lpServerDoc->m_lpIPData->hMenuShared; + *lphOleMenu = lpServerDoc->m_lpIPData->hOlemenu; + } else { + *lphSharedMenu = NULL; + *lphOleMenu = NULL; + } +} + + +void ServerDoc_AddFrameLevelUI(LPSERVERDOC lpServerDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPOLEINPLACEFRAME lpTopIPFrame=ServerDoc_GetTopInPlaceFrame(lpServerDoc); + HMENU hSharedMenu; // combined obj/cntr menu + HOLEMENU hOleMenu; // returned by OleCreateMenuDesc. + + ServerDoc_GetSharedMenuHandles( + lpServerDoc, + &hSharedMenu, + &hOleMenu + ); + + lpTopIPFrame->lpVtbl->SetMenu( + lpTopIPFrame, + hSharedMenu, + hOleMenu, + lpOutlineDoc->m_hWndDoc + ); + + // save normal accelerator table + lpServerApp->m_hAccelBaseApp = lpOutlineApp->m_hAccelApp; + + // install accelerator table for UIActive server (w/ active editor cmds) + lpOutlineApp->m_hAccel = lpServerApp->m_hAccelIPSvr; + lpOutlineApp->m_hAccelApp = lpServerApp->m_hAccelIPSvr; + lpOutlineApp->m_hWndAccelTarget = lpOutlineDoc->m_hWndDoc; + +#if defined( USE_FRAMETOOLS ) + ServerDoc_AddFrameLevelTools(lpServerDoc); + + // update toolbar button enable states + OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc); +#endif +} + + +void ServerDoc_AddFrameLevelTools(LPSERVERDOC lpServerDoc) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPOLEINPLACEFRAME lpTopIPFrame=ServerDoc_GetTopInPlaceFrame(lpServerDoc); + +#if defined( USE_FRAMETOOLS ) + HWND hWndFrame; + + FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE); + + // if not in-place UI active, add our tools to our own frame. + if (! lpServerDoc->m_fUIActive) { + OutlineDoc_AddFrameLevelTools(lpOutlineDoc); + return; + } + + if ((hWndFrame = OutlineApp_GetFrameWindow(lpOutlineApp)) == NULL) { + /* we could NOT get a valid frame window, so POP our tools up. */ + + /* OLE2NOTE: since we are poping up our tools, we MUST inform + ** the top in-place frame window that we need NO tool space + ** BUT that it should NOT put its own tools up. if we were + ** to pass NULL instead of (0,0,0,0), then the container + ** would have the option to leave its own tools up. + */ + lpTopIPFrame->lpVtbl->SetBorderSpace( + lpTopIPFrame, + (LPCBORDERWIDTHS)&g_rectNull + ); + FrameTools_PopupTools(lpOutlineDoc->m_lpFrameTools); + } else { + + /* OLE2NOTE: we need to negotiate for space and attach our frame + ** level tools to the top-level in-place container's frame window. + */ + FrameTools_AttachToFrame(lpOutlineDoc->m_lpFrameTools, hWndFrame); + + FrameTools_NegotiateForSpaceAndShow( + lpOutlineDoc->m_lpFrameTools, + NULL, + lpTopIPFrame + ); + } + +#else // ! USE_FRAMETOOLS + /* OLE2NOTE: if you do NOT use frame tools, you MUST inform the top + ** in-place frame window so that it can put back its own tools. + */ + lpTopIPFrame->lpVtbl->SetBorderSpace(lpIPData->lpFrame, NULL); +#endif // ! USE_FRAMETOOLS +} + + +#if defined( USE_FRAMETOOLS ) + +void ServerDoc_RemoveFrameLevelTools(LPSERVERDOC lpServerDoc) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + OleDbgAssert(lpOutlineDoc->m_lpFrameTools != NULL); + + // Reparent our tools back to one of our own windows + FrameTools_AttachToFrame(lpOutlineDoc->m_lpFrameTools,g_lpApp->m_hWndApp); + + FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, FALSE); +} +#endif // USE_FRAMETOOLS + + + +void ServerDoc_UIActivate (LPSERVERDOC lpServerDoc) +{ + if (lpServerDoc->m_fInPlaceActive && !lpServerDoc->m_fUIActive) { + ServerDoc_DoInPlaceActivate(lpServerDoc, + OLEIVERB_UIACTIVATE, + NULL /*lpmsg*/, + lpServerDoc->m_lpOleClientSite + ); + OutlineDoc_ShowWindow((LPOUTLINEDOC)lpServerDoc); + } +} diff --git a/private/oleutest/letest/outline/svroutl.h b/private/oleutest/letest/outline/svroutl.h new file mode 100644 index 000000000..478149eae --- /dev/null +++ b/private/oleutest/letest/outline/svroutl.h @@ -0,0 +1,888 @@ +/************************************************************************* +** +** OLE 2.0 Server Sample Code +** +** svroutl.h +** +** This file contains file contains data structure defintions, +** function prototypes, constants, etc. used by the OLE 2.0 server +** app version of the Outline series of sample applications: +** Outline -- base version of the app (without OLE functionality) +** SvrOutl -- OLE 2.0 Server sample app +** CntrOutl -- OLE 2.0 Containter sample app +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#if !defined( _SVROUTL_H_ ) +#define _SVROUTL_H_ + +#ifndef RC_INVOKED +#pragma message ("INCLUDING SVROUTL.H from " __FILE__) +#endif /* RC_INVOKED */ + +#include "oleoutl.h" + +/* Defines */ + +// Enable SVROUTL and ISVROTL to emulate each other (TreatAs aka. ActivateAs) +#define SVR_TREATAS 1 + +// Enable SVROUTL and ISVROTL to convert each other (TreatAs aka. ActivateAs) +#define SVR_CONVERTTO 1 + +// Enable ISVROTL to operate as in inside-out style in-place object +#define SVR_INSIDEOUT 1 + +/* Default name used for container of the embedded object. used if +** container forgets to call IOleObject::SetHostNames +*/ +// REVIEW: should load from string resource +#define DEFCONTAINERNAME "Unknown Document" + +/* Default prefix for auto-generated range names. This is used with +** links to unnamed ranges (pseudo objects). +*/ +// REVIEW: should load from string resource +#define DEFRANGENAMEPREFIX "Range" + +// Maximum length of strings accepted through IOleObject::SetHostNames +// (note: this is rather arbitrary; a better strategy would be to +// dynamically allocated buffers for these strings.) +#define MAXAPPNAME 80 +#define MAXCONTAINERNAME 80 + +// Menu option in embedding mode +#define IDM_F_UPDATE 1151 + +/* Types */ + +/* Codes for CallBack events */ +typedef enum tagOLE_NOTIFICATION { + OLE_ONDATACHANGE, // 0 + OLE_ONSAVE, // 1 + OLE_ONRENAME, // 2 + OLE_ONCLOSE // 3 +} OLE_NOTIFICATION; + +/* Codes to indicate mode of storage for an object. +** Mode of the storage is modified by the IPersistStorage methods: +** Save, HandsOffStorage, and SaveCompleted. +*/ +typedef enum tagSTGMODE { + STGMODE_NORMAL = 0, + STGMODE_NOSCRIBBLE = 1, + STGMODE_HANDSOFF = 2 +} STGMODE; + + +/* Forward type definitions */ +typedef struct tagSERVERAPP FAR* LPSERVERAPP; +typedef struct tagSERVERDOC FAR* LPSERVERDOC; +typedef struct tagPSEUDOOBJ FAR* LPPSEUDOOBJ; + +typedef struct tagINPLACEDATA { + OLEMENUGROUPWIDTHS menuGroupWidths; + HOLEMENU hOlemenu; + HMENU hMenuShared; + LPOLEINPLACESITE lpSite; + LPOLEINPLACEUIWINDOW lpDoc; + LPOLEINPLACEFRAME lpFrame; + OLEINPLACEFRAMEINFO frameInfo; + HWND hWndFrame; + BOOL fBorderOn; + RECT rcPosRect; + RECT rcClipRect; +} INPLACEDATA, FAR* LPINPLACEDATA; + + +/************************************************************************* +** class SERVERDOC : OLEDOC +** SERVERDOC is an extention to the abstract base OLEDOC class. +** The OLEDOC class defines the fields, methods and interfaces that +** are common to both server and client implementations. The +** SERVERDOC class adds the fields, methods and interfaces that are +** specific to OLE 2.0 Server functionality. There is one instance +** of SERVERDOC object created per document open in the app. The SDI +** version of the app supports one SERVERDOC at a time. The MDI +** version of the app can manage multiple documents at one time. +** The SERVERDOC class inherits all fields from the OLEDOC class. +** This inheritance is achieved by including a member variable of +** type OLEDOC as the first field in the SERVERDOC structure. Thus a +** pointer to a SERVERDOC object can be cast to be a pointer to a +** OLEDOC object or an OUTLINEDOC object +*************************************************************************/ + +typedef struct tagSERVERDOC { + OLEDOC m_OleDoc; // ServerDoc inherits from OleDoc + ULONG m_cPseudoObj; // total count of pseudo obj's + LPOLECLIENTSITE m_lpOleClientSite; // Client associated with the obj + LPOLEADVISEHOLDER m_lpOleAdviseHldr; // helper obj to hold ole advises + LPDATAADVISEHOLDER m_lpDataAdviseHldr; // helper obj to hold data advises + BOOL m_fNoScribbleMode; // was IPS::Save called + BOOL m_fSaveWithSameAsLoad; // was IPS::Save called with + // fSameAsLoad==TRUE. + char m_szContainerApp[MAXAPPNAME]; + char m_szContainerObj[MAXCONTAINERNAME]; + ULONG m_nNextRangeNo; // next no. for unnamed range + LINERANGE m_lrSrcSelOfCopy; // src sel if doc created for copy + BOOL m_fDataChanged; // data changed when draw disabled + BOOL m_fSizeChanged; // size changed when draw disabled + BOOL m_fSendDataOnStop; // did data ever change? +#if defined( SVR_TREATAS ) + CLSID m_clsidTreatAs; // clsid to pretend to be + LPSTR m_lpszTreatAsType; // user type name to pretend to be +#endif // SVR_TREATAS + +#if defined( LATER ) + // REVIEW: is it necessary to register a WildCard Moniker + DWORD m_dwWildCardRegROT; // key if wildcard reg'ed in ROT +#endif + +#if defined( INPLACE_SVR ) + BOOL m_fInPlaceActive; + BOOL m_fInPlaceVisible; + BOOL m_fUIActive; + HWND m_hWndParent; + HWND m_hWndHatch; + LPINPLACEDATA m_lpIPData; + BOOL m_fMenuHelpMode;// is F1 pressed in menu, give help + + struct CDocOleInPlaceObjectImpl { + IOleInPlaceObjectVtbl FAR* lpVtbl; + LPSERVERDOC lpServerDoc; + int cRef; // interface specific ref count. + } m_OleInPlaceObject; + + struct CDocOleInPlaceActiveObjectImpl { + IOleInPlaceActiveObjectVtbl FAR* lpVtbl; + LPSERVERDOC lpServerDoc; + int cRef;// interface specific ref count. + } m_OleInPlaceActiveObject; +#endif // INPLACE_SVR + + struct CDocOleObjectImpl { + IOleObjectVtbl FAR* lpVtbl; + LPSERVERDOC lpServerDoc; + int cRef; // interface specific ref count. + } m_OleObject; + + struct CDocPersistStorageImpl { + IPersistStorageVtbl FAR* lpVtbl; + LPSERVERDOC lpServerDoc; + int cRef; // interface specific ref count. + } m_PersistStorage; + +#if defined( SVR_TREATAS ) + struct CDocStdMarshalInfoImpl { + IStdMarshalInfoVtbl FAR* lpVtbl; + LPSERVERDOC lpServerDoc; + int cRef; // interface specific ref count. + } m_StdMarshalInfo; +#endif // SVR_TREATAS + +} SERVERDOC; + +/* ServerDoc methods (functions) */ +BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc); +BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc); +void ServerDoc_PseudoObjUnlockDoc( + LPSERVERDOC lpServerDoc, + LPPSEUDOOBJ lpPseudoObj +); +void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc); +BOOL ServerDoc_PasteFormatFromData( + LPSERVERDOC lpServerDoc, + CLIPFORMAT cfFormat, + LPDATAOBJECT lpSrcDataObj, + BOOL fLocalDataObj, + BOOL fLink +); +BOOL ServerDoc_QueryPasteFromData( + LPSERVERDOC lpServerDoc, + LPDATAOBJECT lpSrcDataObj, + BOOL fLink +); +HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid); +void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc); +void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc); +HRESULT ServerDoc_GetData ( + LPSERVERDOC lpServerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +); +HRESULT ServerDoc_GetDataHere ( + LPSERVERDOC lpServerDoc, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +); +HRESULT ServerDoc_QueryGetData(LPSERVERDOC lpServerDoc,LPFORMATETC lpformatetc); +HRESULT ServerDoc_EnumFormatEtc( + LPSERVERDOC lpServerDoc, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +); +HANDLE ServerDoc_GetMetafilePictData( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel +); +void ServerDoc_SendAdvise( + LPSERVERDOC lpServerDoc, + WORD wAdvise, + LPMONIKER lpmkDoc, + DWORD dwAdvf +); +HRESULT ServerDoc_GetObject( + LPSERVERDOC lpServerDoc, + LPOLESTR lpszItem, + REFIID riid, + LPVOID FAR* lplpvObject +); +HRESULT ServerDoc_IsRunning(LPSERVERDOC lpServerDoc, LPOLESTR lpszItem); +LPMONIKER ServerDoc_GetSelRelMoniker( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel, + DWORD dwAssign +); +LPMONIKER ServerDoc_GetSelFullMoniker( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel, + DWORD dwAssign +); + + +#if defined( INPLACE_SVR ) +HRESULT ServerDoc_DoInPlaceActivate( + LPSERVERDOC lpServerDoc, + LONG lVerb, + LPMSG lpmsg, + LPOLECLIENTSITE lpActiveSite +); +HRESULT ServerDoc_DoInPlaceDeactivate(LPSERVERDOC lpServerDoc); +HRESULT ServerDoc_DoInPlaceHide(LPSERVERDOC lpServerDoc); +BOOL ServerDoc_AllocInPlaceData(LPSERVERDOC lpServerDoc); +void ServerDoc_FreeInPlaceData(LPSERVERDOC lpServerDoc); + +HRESULT ServerDoc_AssembleMenus(LPSERVERDOC lpServerDoc); +void ServerDoc_DisassembleMenus(LPSERVERDOC lpServerDoc); +void ServerDoc_CalcInPlaceWindowPos( + LPSERVERDOC lpServerDoc, + LPRECT lprcListBox, + LPRECT lprcDoc, + LPSCALEFACTOR lpscale +); +void ServerDoc_UpdateInPlaceWindowOnExtentChange(LPSERVERDOC lpServerDoc); +void ServerDoc_ResizeInPlaceWindow( + LPSERVERDOC lpServerDoc, + LPCRECT lprcPosRect, + LPCRECT lprcClipRect +); +void ServerDoc_ShadeInPlaceBorder(LPSERVERDOC lpServerDoc, BOOL fShadeOn); +void ServerDoc_SetStatusText(LPSERVERDOC lpServerDoc, LPSTR lpszMessage); +LPOLEINPLACEFRAME ServerDoc_GetTopInPlaceFrame(LPSERVERDOC lpServerDoc); +void ServerDoc_GetSharedMenuHandles( + LPSERVERDOC lpServerDoc, + HMENU FAR* lphSharedMenu, + HOLEMENU FAR* lphOleMenu +); +void ServerDoc_AddFrameLevelUI(LPSERVERDOC lpServerDoc); +void ServerDoc_AddFrameLevelTools(LPSERVERDOC lpServerDoc); +void ServerDoc_UIActivate (LPSERVERDOC lpServerDoc); + +#if defined( USE_FRAMETOOLS ) +void ServerDoc_RemoveFrameLevelTools(LPSERVERDOC lpServerDoc); +#endif // USE_FRAMETOOLS + +#endif // INPLACE_SVR + + +/* ServerDoc::IOleObject methods (functions) */ +STDMETHODIMP SvrDoc_OleObj_QueryInterface( + LPOLEOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis); +STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis); +STDMETHODIMP SvrDoc_OleObj_SetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE lpclientSite +); +STDMETHODIMP SvrDoc_OleObj_GetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE FAR* lplpClientSite +); +STDMETHODIMP SvrDoc_OleObj_SetHostNames( + LPOLEOBJECT lpThis, + LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj +); +STDMETHODIMP SvrDoc_OleObj_Close( + LPOLEOBJECT lpThis, + DWORD dwSaveOption +); +STDMETHODIMP SvrDoc_OleObj_SetMoniker( + LPOLEOBJECT lpThis, + DWORD dwWhichMoniker, + LPMONIKER lpmk +); +STDMETHODIMP SvrDoc_OleObj_GetMoniker( + LPOLEOBJECT lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +); +STDMETHODIMP SvrDoc_OleObj_InitFromData( + LPOLEOBJECT lpThis, + LPDATAOBJECT lpDataObject, + BOOL fCreation, + DWORD reserved +); +STDMETHODIMP SvrDoc_OleObj_GetClipboardData( + LPOLEOBJECT lpThis, + DWORD reserved, + LPDATAOBJECT FAR* lplpDataObject +); +STDMETHODIMP SvrDoc_OleObj_DoVerb( + LPOLEOBJECT lpThis, + LONG lVerb, + LPMSG lpmsg, + LPOLECLIENTSITE lpActiveSite, + LONG lindex, + HWND hwndParent, + LPCRECT lprcPosRect +); +STDMETHODIMP SvrDoc_OleObj_EnumVerbs( + LPOLEOBJECT lpThis, + LPENUMOLEVERB FAR* lplpenumOleVerb +); +STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis); +STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis); +STDMETHODIMP SvrDoc_OleObj_GetUserClassID( + LPOLEOBJECT lpThis, + LPCLSID lpclsid +); +STDMETHODIMP SvrDoc_OleObj_GetUserType( + LPOLEOBJECT lpThis, + DWORD dwFormOfType, + LPOLESTR FAR* lpszUserType +); +STDMETHODIMP SvrDoc_OleObj_SetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lplgrc +); +STDMETHODIMP SvrDoc_OleObj_GetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lplgrc +); +STDMETHODIMP SvrDoc_OleObj_Advise( + LPOLEOBJECT lpThis, + LPADVISESINK lpAdvSink, + LPDWORD lpdwConnection +); +STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection); +STDMETHODIMP SvrDoc_OleObj_EnumAdvise( + LPOLEOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +); +STDMETHODIMP SvrDoc_OleObj_GetMiscStatus( + LPOLEOBJECT lpThis, + DWORD dwAspect, + DWORD FAR* lpdwStatus +); +STDMETHODIMP SvrDoc_OleObj_SetColorScheme( + LPOLEOBJECT lpThis, + LPLOGPALETTE lpLogpal +); +STDMETHODIMP SvrDoc_OleObj_LockObject( + LPOLEOBJECT lpThis, + BOOL fLock +); + +/* ServerDoc::IPersistStorage methods (functions) */ +STDMETHODIMP SvrDoc_PStg_QueryInterface( + LPPERSISTSTORAGE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis); +STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis); +STDMETHODIMP SvrDoc_PStg_GetClassID( + LPPERSISTSTORAGE lpThis, + LPCLSID lpClassID +); +STDMETHODIMP SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE lpThis); +STDMETHODIMP SvrDoc_PStg_InitNew( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStg +); +STDMETHODIMP SvrDoc_PStg_Load( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStg +); +STDMETHODIMP SvrDoc_PStg_Save( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStg, + BOOL fSameAsLoad +); +STDMETHODIMP SvrDoc_PStg_SaveCompleted( + LPPERSISTSTORAGE lpThis, + LPSTORAGE lpStgNew +); +STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis); + + +#if defined( SVR_TREATAS ) + +/* ServerDoc::IStdMarshalInfo methods (functions) */ +STDMETHODIMP SvrDoc_StdMshl_QueryInterface( + LPSTDMARSHALINFO lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis); +STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis); +STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler( + LPSTDMARSHALINFO lpThis, + DWORD dwDestContext, + LPVOID pvDestContext, + LPCLSID lpClassID +); +#endif // SVR_TREATAS + +/************************************************************************* +** class SERVERAPP : OLEAPP +** SERVERAPP is an extention to the abstract base OLEAPP class. +** The OLEAPP class defines the fields, methods and interfaces that +** are common to both server and client implementations. The +** SERVERAPP class adds the fields and methods that are specific to +** OLE 2.0 Server functionality. There is one instance of +** SERVERAPP object created per running application instance. This +** object holds many fields that could otherwise be organized as +** global variables. The SERVERAPP class inherits all fields +** from the OLEAPP class. This inheritance is achieved by including a +** member variable of type OLEAPP as the first field in the SERVERAPP +** structure. OLEAPP inherits from OLEAPP. This inheritance is +** achieved in the same manner. Thus a pointer to a SERVERAPP object +** can be cast to be a pointer to an OLEAPP or an OUTLINEAPP object +*************************************************************************/ + +typedef struct tagSERVERAPP { + OLEAPP m_OleApp; // ServerApp inherits all fields of OleApp + +#if defined( INPLACE_SVR ) + HACCEL m_hAccelIPSvr; // accelerators for server's active object commands + HACCEL m_hAccelBaseApp; // normal accel for non-inplace server mode + HMENU m_hMenuEdit; // handle to Edit menu of the server app + HMENU m_hMenuLine; // handle to Line menu of the server app + HMENU m_hMenuName; // handle to Name menu of the server app + HMENU m_hMenuOptions; // handle to Options menu of the server app + HMENU m_hMenuDebug; // handle to Debug menu of the server app + HMENU m_hMenuHelp; // handle to Help menu of the server app + LPINPLACEDATA m_lpIPData; +#endif + +} SERVERAPP; + +/* ServerApp methods (functions) */ +BOOL ServerApp_InitInstance( + LPSERVERAPP lpServerApp, + HINSTANCE hInst, + int nCmdShow +); +BOOL ServerApp_InitVtbls (LPSERVERAPP lpServerApp); + + + +/************************************************************************* +** class SERVERNAME : OUTLINENAME +** SERVERNAME class is an extension to the OUTLINENAME base class that +** adds functionallity required to support linking to ranges (pseudo +** objects). Pseudo objects are used to allow linking to a range +** (sub-selection) of a SERVERDOC document. The base class OUTLINENAME +** stores a particular named selection in the document. The +** NAMETABLE class holds all of the names defined in a particular +** document. Each OUTLINENAME object has a string as its key and a +** starting line index and an ending line index for the named range. +** The SERVERNAME class, also, stores a pointer to a PSEUDOOBJ if one +** has been allocated that corresponds to the named selection. +** The SERVERNAME class inherits all fields from the OUTLINENAME class. +** This inheritance is achieved by including a member variable of +** type OUTLINENAME as the first field in the SERVERNAME +** structure. Thus a pointer to an SERVERNAME object can be cast to be +** a pointer to a OUTLINENAME object. +*************************************************************************/ + +typedef struct tagSERVERNAME { + OUTLINENAME m_Name; // ServerName inherits all fields of Name + LPPSEUDOOBJ m_lpPseudoObj; // ptr to pseudo object if allocated +} SERVERNAME, FAR* LPSERVERNAME; + +/* ServerName methods (functions) */ +void ServerName_SetSel( + LPSERVERNAME lpServerName, + LPLINERANGE lplrSel, + BOOL fRangeModified +); +void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName); +LPPSEUDOOBJ ServerName_GetPseudoObj( + LPSERVERNAME lpServerName, + LPSERVERDOC lpServerDoc +); +void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName); + + +/************************************************************************* +** class PSEUDOOBJ +** The PSEUDOOBJ (pseudo object) is a concrete class. A pseudo object +** is created when a link is made to a range of lines within an +** SERVERDOC document. A pseudo object is dependent on the existance +** of the SERVERDOC which represents the whole document. +*************************************************************************/ + +typedef struct tagPSEUDOOBJ { + ULONG m_cRef; // total ref count for obj + BOOL m_fObjIsClosing; // flag to guard recursive close + LPSERVERNAME m_lpName; // named range for this pseudo obj + LPSERVERDOC m_lpDoc; // ptr to whole document + LPOLEADVISEHOLDER m_lpOleAdviseHldr; // helper obj to hold ole advises + LPDATAADVISEHOLDER m_lpDataAdviseHldr; // helper obj to hold data advises + BOOL m_fDataChanged; // data changed when draw disabled + + struct CPseudoObjUnknownImpl { + IUnknownVtbl FAR* lpVtbl; + LPPSEUDOOBJ lpPseudoObj; + int cRef; // interface specific ref count. + } m_Unknown; + + struct CPseudoObjOleObjectImpl { + IOleObjectVtbl FAR* lpVtbl; + LPPSEUDOOBJ lpPseudoObj; + int cRef; // interface specific ref count. + } m_OleObject; + + struct CPseudoObjDataObjectImpl { + IDataObjectVtbl FAR* lpVtbl; + LPPSEUDOOBJ lpPseudoObj; + int cRef; // interface specific ref count. + } m_DataObject; + +} PSEUDOOBJ; + +/* PseudoObj methods (functions) */ +void PseudoObj_Init( + LPPSEUDOOBJ lpPseudoObj, + LPSERVERNAME lpServerName, + LPSERVERDOC lpServerDoc +); +ULONG PseudoObj_AddRef(LPPSEUDOOBJ lpPseudoObj); +ULONG PseudoObj_Release(LPPSEUDOOBJ lpPseudoObj); +HRESULT PseudoObj_QueryInterface( + LPPSEUDOOBJ lpPseudoObj, + REFIID riid, + LPVOID FAR* lplpUnk +); +BOOL PseudoObj_Close(LPPSEUDOOBJ lpPseudoObj); +void PseudoObj_Destroy(LPPSEUDOOBJ lpPseudoObj); +void PseudoObj_GetSel(LPPSEUDOOBJ lpPseudoObj, LPLINERANGE lplrSel); +void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel); +void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel); +void PseudoObj_SendAdvise( + LPPSEUDOOBJ lpPseudoObj, + WORD wAdvise, + LPMONIKER lpmkObj, + DWORD dwAdvf +); +LPMONIKER PseudoObj_GetFullMoniker(LPPSEUDOOBJ lpPseudoObj, LPMONIKER lpmkDoc); + +/* PseudoObj::IUnknown methods (functions) */ +STDMETHODIMP PseudoObj_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) PseudoObj_Unk_AddRef(LPUNKNOWN lpThis); +STDMETHODIMP_(ULONG) PseudoObj_Unk_Release (LPUNKNOWN lpThis); + +/* PseudoObj::IOleObject methods (functions) */ +STDMETHODIMP PseudoObj_OleObj_QueryInterface( + LPOLEOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) PseudoObj_OleObj_AddRef(LPOLEOBJECT lpThis); +STDMETHODIMP_(ULONG) PseudoObj_OleObj_Release(LPOLEOBJECT lpThis); +STDMETHODIMP PseudoObj_OleObj_SetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE lpClientSite +); +STDMETHODIMP PseudoObj_OleObj_GetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE FAR* lplpClientSite +); +STDMETHODIMP PseudoObj_OleObj_SetHostNames( + LPOLEOBJECT lpThis, + LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj +); +STDMETHODIMP PseudoObj_OleObj_Close( + LPOLEOBJECT lpThis, + DWORD dwSaveOption +); +STDMETHODIMP PseudoObj_OleObj_SetMoniker( + LPOLEOBJECT lpThis, + DWORD dwWhichMoniker, + LPMONIKER lpmk +); +STDMETHODIMP PseudoObj_OleObj_GetMoniker( + LPOLEOBJECT lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +); +STDMETHODIMP PseudoObj_OleObj_InitFromData( + LPOLEOBJECT lpThis, + LPDATAOBJECT lpDataObject, + BOOL fCreation, + DWORD reserved +); +STDMETHODIMP PseudoObj_OleObj_GetClipboardData( + LPOLEOBJECT lpThis, + DWORD reserved, + LPDATAOBJECT FAR* lplpDataObject +); +STDMETHODIMP PseudoObj_OleObj_DoVerb( + LPOLEOBJECT lpThis, + LONG lVerb, + LPMSG lpmsg, + LPOLECLIENTSITE lpActiveSite, + LONG lindex, + HWND hwndParent, + LPCRECT lprcPosRect +); +STDMETHODIMP PseudoObj_OleObj_EnumVerbs( + LPOLEOBJECT lpThis, + LPENUMOLEVERB FAR* lplpenumOleVerb +); +STDMETHODIMP PseudoObj_OleObj_Update(LPOLEOBJECT lpThis); +STDMETHODIMP PseudoObj_OleObj_IsUpToDate(LPOLEOBJECT lpThis); +STDMETHODIMP PseudoObj_OleObj_GetUserClassID( + LPOLEOBJECT lpThis, + LPCLSID lpclsid +); +STDMETHODIMP PseudoObj_OleObj_GetUserType( + LPOLEOBJECT lpThis, + DWORD dwFormOfType, + LPOLESTR FAR* lpszUserType +); +STDMETHODIMP PseudoObj_OleObj_SetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lplgrc +); +STDMETHODIMP PseudoObj_OleObj_GetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lplgrc +); +STDMETHODIMP PseudoObj_OleObj_Advise( + LPOLEOBJECT lpThis, + LPADVISESINK lpAdvSink, + LPDWORD lpdwConnection +); +STDMETHODIMP PseudoObj_OleObj_Unadvise(LPOLEOBJECT lpThis,DWORD dwConnection); +STDMETHODIMP PseudoObj_OleObj_EnumAdvise( + LPOLEOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +); +STDMETHODIMP PseudoObj_OleObj_GetMiscStatus( + LPOLEOBJECT lpThis, + DWORD dwAspect, + DWORD FAR* lpdwStatus +); +STDMETHODIMP PseudoObj_OleObj_SetColorScheme( + LPOLEOBJECT lpThis, + LPLOGPALETTE lpLogpal +); +STDMETHODIMP PseudoObj_OleObj_LockObject( + LPOLEOBJECT lpThis, + BOOL fLock +); + +/* PseudoObj::IDataObject methods (functions) */ +STDMETHODIMP PseudoObj_DataObj_QueryInterface ( + LPDATAOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +); +STDMETHODIMP_(ULONG) PseudoObj_DataObj_AddRef(LPDATAOBJECT lpThis); +STDMETHODIMP_(ULONG) PseudoObj_DataObj_Release (LPDATAOBJECT lpThis); +STDMETHODIMP PseudoObj_DataObj_GetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +); +STDMETHODIMP PseudoObj_DataObj_GetDataHere ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +); +STDMETHODIMP PseudoObj_DataObj_QueryGetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc +); +STDMETHODIMP PseudoObj_DataObj_GetCanonicalFormatEtc ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPFORMATETC lpformatetcOut +); +STDMETHODIMP PseudoObj_DataObj_SetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpmedium, + BOOL fRelease +); +STDMETHODIMP PseudoObj_DataObj_EnumFormatEtc( + LPDATAOBJECT lpThis, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +); +STDMETHODIMP PseudoObj_DataObj_DAdvise( + LPDATAOBJECT lpThis, + FORMATETC FAR* lpFormatetc, + DWORD advf, + LPADVISESINK lpAdvSink, + DWORD FAR* lpdwConnection +); +STDMETHODIMP PseudoObj_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection); +STDMETHODIMP PseudoObj_DataObj_EnumAdvise( + LPDATAOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +); + + +/************************************************************************* +** class SERVERNAMETABLE : OUTLINENAMETABLE +** SERVERNAMETABLE class is an extension to the OUTLINENAMETABLE +** base class that adds functionallity required to support linking +** to ranges (pseudo objects). The name table manages the table of +** named selections in the document. Each name table entry has a +** string as its key and a starting line index and an ending line +** index for the named range. The SERVERNAMETABLE entries, in +** addition, maintain a pointer to a PSEUDOOBJ pseudo object if one +** has been already allocated. There is always one instance of +** SERVERNAMETABLE for each SERVERDOC object created. +** The SERVERNAME class inherits all fields from the NAME class. +** This inheritance is achieved by including a member variable of +** type NAME as the first field in the SERVERNAME +** structure. Thus a pointer to an SERVERNAME object can be cast to be +** a pointer to a NAME object. +*************************************************************************/ + +typedef struct tagSERVERNAMETABLE { + OUTLINENAMETABLE m_NameTable; // we inherit from OUTLINENAMETABLE + + // ServerNameTable does NOT add any fields + +} SERVERNAMETABLE, FAR* LPSERVERNAMETABLE; + +/* ServerNameTable methods (functions) */ +void ServerNameTable_EditLineUpdate( + LPSERVERNAMETABLE lpServerNameTable, + int nEditIndex +); +void ServerNameTable_InformAllPseudoObjectsDocRenamed( + LPSERVERNAMETABLE lpServerNameTable, + LPMONIKER lpmkDoc +); +void ServerNameTable_InformAllPseudoObjectsDocSaved( + LPSERVERNAMETABLE lpServerNameTable, + LPMONIKER lpmkDoc +); +void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable); +LPPSEUDOOBJ ServerNameTable_GetPseudoObj( + LPSERVERNAMETABLE lpServerNameTable, + LPSTR lpszItem, + LPSERVERDOC lpServerDoc +); +void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable); + + +#if defined( INPLACE_SVR) + +/* ServerDoc::IOleInPlaceObject methods (functions) */ + +STDMETHODIMP SvrDoc_IPObj_QueryInterface( + LPOLEINPLACEOBJECT lpThis, + REFIID riid, + LPVOID FAR * lplpvObj +); +STDMETHODIMP_(ULONG) SvrDoc_IPObj_AddRef(LPOLEINPLACEOBJECT lpThis); +STDMETHODIMP_(ULONG) SvrDoc_IPObj_Release(LPOLEINPLACEOBJECT lpThis); +STDMETHODIMP SvrDoc_IPObj_GetWindow( + LPOLEINPLACEOBJECT lpThis, + HWND FAR* lphwnd +); +STDMETHODIMP SvrDoc_IPObj_ContextSensitiveHelp( + LPOLEINPLACEOBJECT lpThis, + BOOL fEnable +); +STDMETHODIMP SvrDoc_IPObj_InPlaceDeactivate(LPOLEINPLACEOBJECT lpThis); +STDMETHODIMP SvrDoc_IPObj_UIDeactivate(LPOLEINPLACEOBJECT lpThis); +STDMETHODIMP SvrDoc_IPObj_SetObjectRects( + LPOLEINPLACEOBJECT lpThis, + LPCRECT lprcPosRect, + LPCRECT lprcClipRect +); +STDMETHODIMP SvrDoc_IPObj_ReactivateAndUndo(LPOLEINPLACEOBJECT lpThis); + +/* ServerDoc::IOleInPlaceActiveObject methods (functions) */ + +STDMETHODIMP SvrDoc_IPActiveObj_QueryInterface( + LPOLEINPLACEACTIVEOBJECT lpThis, + REFIID riidReq, + LPVOID FAR * lplpUnk +); +STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_AddRef( + LPOLEINPLACEACTIVEOBJECT lpThis +); +STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_Release( + LPOLEINPLACEACTIVEOBJECT lpThis +); +STDMETHODIMP SvrDoc_IPActiveObj_GetWindow( + LPOLEINPLACEACTIVEOBJECT lpThis, + HWND FAR* lphwnd +); +STDMETHODIMP SvrDoc_IPActiveObj_ContextSensitiveHelp( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fEnable +); +STDMETHODIMP SvrDoc_IPActiveObj_TranslateAccelerator( + LPOLEINPLACEACTIVEOBJECT lpThis, + LPMSG lpmsg +); +STDMETHODIMP SvrDoc_IPActiveObj_OnFrameWindowActivate( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fActivate +); +STDMETHODIMP SvrDoc_IPActiveObj_OnDocWindowActivate( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fActivate +); +STDMETHODIMP SvrDoc_IPActiveObj_ResizeBorder( + LPOLEINPLACEACTIVEOBJECT lpThis, + LPCRECT lprectBorder, + LPOLEINPLACEUIWINDOW lpIPUiWnd, + BOOL fFrameWindow +); +STDMETHODIMP SvrDoc_IPActiveObj_EnableModeless( + LPOLEINPLACEACTIVEOBJECT lpThis, + BOOL fEnable +); + +#endif // INPLACE_SVR + +#endif // _SVROUTL_H_ diff --git a/private/oleutest/letest/outline/svroutl.ico b/private/oleutest/letest/outline/svroutl.ico Binary files differnew file mode 100644 index 000000000..b674fc61d --- /dev/null +++ b/private/oleutest/letest/outline/svroutl.ico diff --git a/private/oleutest/letest/outline/svroutl/daytona/makefile b/private/oleutest/letest/outline/svroutl/daytona/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/oleutest/letest/outline/svroutl/daytona/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/oleutest/letest/outline/svroutl/daytona/makefile.inc b/private/oleutest/letest/outline/svroutl/daytona/makefile.inc new file mode 100644 index 000000000..462f38133 --- /dev/null +++ b/private/oleutest/letest/outline/svroutl/daytona/makefile.inc @@ -0,0 +1,2 @@ +copyfiles: + xcopy ..\..\*.c . /D diff --git a/private/oleutest/letest/outline/svroutl/daytona/sources b/private/oleutest/letest/outline/svroutl/daytona/sources new file mode 100644 index 000000000..40df009b7 --- /dev/null +++ b/private/oleutest/letest/outline/svroutl/daytona/sources @@ -0,0 +1,106 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Kenneth MacLeod (Kennethm) 9-Mar-1994 + +!ENDIF + +MAJORCOMP = oleutest +MINORCOMP = letest + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= svroutl + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= PROGRAM + +INCLUDES= ..\..\..\ole2ui; \ + ..\..\..\bttncur; \ + ..\..\..\gizmobar; \ + ..\..\..\..\inc; \ + ..\.. + +C_DEFINES= \ + $(C_DEFINES) \ + -DFLAT \ + -DWIN32=100 \ + -D_NT1X_=100 \ + -DNOEXCEPTIONS \ + -DOLE_SERVER + +SOURCES= \ + ..\svroutl.rc \ + classfac.c \ + clipbrd.c \ + debug.c \ + debug2.c \ + dialogs.c \ + dragdrop.c \ + frametls.c \ + heading.c \ + linking.c \ + main.c \ + memmgr.c \ + oleapp.c \ + oledoc.c \ + outlapp.c \ + outldoc.c \ + outlline.c \ + outllist.c \ + outlname.c \ + outlntbl.c \ + outltxtl.c \ + svrbase.c \ + svrpsobj.c \ + status.c \ + tests.c + +UMTYPE= windows +UMENTRY= winmain + +USE_CRTDLL=1 +TARGETLIBS= \ + ..\..\..\ole2ui\daytona\obj\*\ole2u32a.lib \ + ..\..\..\gizmobar\daytona\obj\*\gizmobar.lib \ + ..\..\..\bttncur\daytona\obj\*\bttncur.lib \ + $(BASEDIR)\public\sdk\lib\*\ole32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\gdi32.lib \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\uuid.lib + +NTTARGETFILE0=copyfiles diff --git a/private/oleutest/letest/outline/svroutl/dirs b/private/oleutest/letest/outline/svroutl/dirs new file mode 100644 index 000000000..515c134a8 --- /dev/null +++ b/private/oleutest/letest/outline/svroutl/dirs @@ -0,0 +1,37 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + \ + daytona diff --git a/private/oleutest/letest/outline/svroutl/svroutl.rc b/private/oleutest/letest/outline/svroutl/svroutl.rc new file mode 100644 index 000000000..224009f2b --- /dev/null +++ b/private/oleutest/letest/outline/svroutl/svroutl.rc @@ -0,0 +1,187 @@ +/************************************************************************* +** +** OLE 2.0 Server Sample Code +** +** svroutl.rc +** +** Resource file for svroutl.exe +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "windows.h" +#include "outlrc.h" + +SelCur CURSOR selcross.cur +DragMoveCur CURSOR dragmove.cur + +#if defined( IF_SPECIAL_DD_CURSORS_NEEDED ) +DragNoneCur CURSOR dragnone.cur +DragCopyCur CURSOR dragcopy.cur +DragLinkCur CURSOR draglink.cur +#endif // IF_SPECIAL_DD_CURSORS_NEEDED + +SvrOutlMenu MENU + BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", IDM_F_NEW + MENUITEM "&Open...\t Ctrl+F12", IDM_F_OPEN + MENUITEM "&Save\t Shift+F12", IDM_F_SAVE + MENUITEM "Save &As...\t F12", IDM_F_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print...\t Ctrl+Shift+F12", IDM_F_PRINT + MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP + MENUITEM SEPARATOR + MENUITEM "E&xit\t Alt+F4", IDM_F_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", IDM_E_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\t Ctrl+X", IDM_E_CUT + MENUITEM "&Copy\t Ctrl+C", IDM_E_COPY + MENUITEM "&Paste\t Ctrl+V", IDM_E_PASTE + MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL + MENUITEM "Cl&ear\t Del", IDM_E_CLEAR + MENUITEM SEPARATOR + MENUITEM "Select A&ll\t Ctrl+A", IDM_E_SELECTALL + END + POPUP "O&utline" + BEGIN + POPUP "&Zoom" + BEGIN + MENUITEM "&400%", IDM_V_ZOOM_400 + MENUITEM "&300%", IDM_V_ZOOM_300 + MENUITEM "&200%", IDM_V_ZOOM_200 + MENUITEM "&100%", IDM_V_ZOOM_100 + MENUITEM "&75%", IDM_V_ZOOM_75 + MENUITEM "&50%", IDM_V_ZOOM_50 + MENUITEM "&25%", IDM_V_ZOOM_25 + END + POPUP "&Left and Right margins" + BEGIN + MENUITEM "&nil", IDM_V_SETMARGIN_0 + MENUITEM "&1 cm", IDM_V_SETMARGIN_1 + MENUITEM "&2 cm", IDM_V_SETMARGIN_2 + MENUITEM "&3 cm", IDM_V_SETMARGIN_3 + MENUITEM "&4 cm", IDM_V_SETMARGIN_4 + END + POPUP "Add &Top Line" + BEGIN + MENUITEM "&1 cm", IDM_V_ADDTOP_1 + MENUITEM "&2 cm", IDM_V_ADDTOP_2 + MENUITEM "&3 cm", IDM_V_ADDTOP_3 + MENUITEM "&4 cm", IDM_V_ADDTOP_4 + END + END + POPUP "&Line" + BEGIN + MENUITEM "&Add Line\t Enter", IDM_L_ADDLINE + MENUITEM "E&dit Line\t Alt+Enter", IDM_L_EDITLINE + MENUITEM SEPARATOR + MENUITEM "&Indent Line\t Tab", IDM_L_INDENTLINE + MENUITEM "U&nindent Line\t Shift+Tab", IDM_L_UNINDENTLINE + MENUITEM SEPARATOR + MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT + END + POPUP "&Name" + BEGIN + MENUITEM "&Define Name...", IDM_N_DEFINENAME + MENUITEM "&Goto Name...", IDM_N_GOTONAME + END + POPUP "&Options" + BEGIN + POPUP "&Button Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_BB_TOP + MENUITEM "At &Bottom", IDM_O_BB_BOTTOM + MENUITEM "&Popup", IDM_O_BB_POPUP + MENUITEM "&Hide", IDM_O_BB_HIDE + END + POPUP "&Formula Bar Display" + BEGIN + MENUITEM "At &Top", IDM_O_FB_TOP + MENUITEM "At &Bottom", IDM_O_FB_BOTTOM + MENUITEM "&Popup", IDM_O_FB_POPUP + END + POPUP "&Row and Column Heading" + BEGIN + MENUITEM "&Show", IDM_O_HEAD_SHOW + MENUITEM "&Hide", IDM_O_HEAD_HIDE + END + END + POPUP "Dbg&Svr" + BEGIN + MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL + MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER + MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING + END + POPUP "&Help" + BEGIN + MENUITEM "&About...", IDM_H_ABOUT + END + END + +SvrOutlAccel ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CLEAR, VIRTKEY + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + + VK_F2, IDM_F2, VIRTKEY + END + +; Same as SvrOutlAccel but without Delete and Backspace +; used when edit control of Formula Bar in focus +; +SvrOutlAccelFocusEdit ACCELERATORS + BEGIN + VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL + VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT + VK_F12, IDM_F_SAVEAS, VIRTKEY + VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT + + "x", IDM_E_CUT, VIRTKEY, CONTROL + "c", IDM_E_COPY, VIRTKEY, CONTROL + "v", IDM_E_PASTE, VIRTKEY, CONTROL + VK_RETURN, IDM_L_ADDLINE, VIRTKEY + VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT + VK_TAB, IDM_L_INDENTLINE, VIRTKEY + VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT + "a", IDM_E_SELECTALL, VIRTKEY, CONTROL + + VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY + + ; old conventions for editing + VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL + VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT + VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT + END + + +SvrOutlIcon ICON svroutl.ico + +Image72 BITMAP image72.bmp +Image96 BITMAP image96.bmp +Image120 BITMAP image120.bmp +LogoBitmap BITMAP ole2.bmp + +#include "DIALOGS.DLG" diff --git a/private/oleutest/letest/outline/svrpsobj.c b/private/oleutest/letest/outline/svrpsobj.c new file mode 100644 index 000000000..c73f16c89 --- /dev/null +++ b/private/oleutest/letest/outline/svrpsobj.c @@ -0,0 +1,1538 @@ +/************************************************************************* +** +** OLE 2 Server Sample Code +** +** svrpsobj.c +** +** This file contains all PseudoObj methods and related support +** functions. +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; +extern IUnknownVtbl g_PseudoObj_UnknownVtbl; +extern IOleObjectVtbl g_PseudoObj_OleObjectVtbl; +extern IDataObjectVtbl g_PseudoObj_DataObjectVtbl; + + +/* PseudoObj_Init +** -------------- +** Initialize fields in a newly constructed PseudoObj. +** NOTE: ref cnt of PseudoObj initialized to 0 +*/ +void PseudoObj_Init( + LPPSEUDOOBJ lpPseudoObj, + LPSERVERNAME lpServerName, + LPSERVERDOC lpServerDoc +) +{ + OleDbgOut2("++PseudoObj Created\r\n"); + + lpPseudoObj->m_cRef = 0; + lpPseudoObj->m_lpName = lpServerName; + lpPseudoObj->m_lpDoc = lpServerDoc; + lpPseudoObj->m_lpOleAdviseHldr = NULL; + lpPseudoObj->m_lpDataAdviseHldr = NULL; + lpPseudoObj->m_fObjIsClosing = FALSE; + + INIT_INTERFACEIMPL( + &lpPseudoObj->m_Unknown, + &g_PseudoObj_UnknownVtbl, + lpPseudoObj + ); + + INIT_INTERFACEIMPL( + &lpPseudoObj->m_OleObject, + &g_PseudoObj_OleObjectVtbl, + lpPseudoObj + ); + + INIT_INTERFACEIMPL( + &lpPseudoObj->m_DataObject, + &g_PseudoObj_DataObjectVtbl, + lpPseudoObj + ); + + /* OLE2NOTE: Increment the refcnt of the Doc on behalf of the + ** PseudoObj. the Document should not shut down unless all + ** pseudo objects are closed. when a pseudo object is destroyed, + ** it calls ServerDoc_PseudoObjUnlockDoc to release this hold on + ** the document. + */ + ServerDoc_PseudoObjLockDoc(lpServerDoc); +} + + + +/* PseudoObj_AddRef +** ---------------- +** +** increment the ref count of the PseudoObj object. +** +** Returns the new ref count on the object +*/ +ULONG PseudoObj_AddRef(LPPSEUDOOBJ lpPseudoObj) +{ + ++lpPseudoObj->m_cRef; + +#if defined( _DEBUG ) + OleDbgOutRefCnt4( + "PseudoObj_AddRef: cRef++\r\n", + lpPseudoObj, + lpPseudoObj->m_cRef + ); +#endif + return lpPseudoObj->m_cRef; +} + + +/* PseudoObj_Release +** ----------------- +** +** decrement the ref count of the PseudoObj object. +** if the ref count goes to 0, then the PseudoObj is destroyed. +** +** Returns the remaining ref count on the object +*/ +ULONG PseudoObj_Release(LPPSEUDOOBJ lpPseudoObj) +{ + ULONG cRef; + + /********************************************************************* + ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. ** + ** otherwise the object is still in use. ** + *********************************************************************/ + + cRef = --lpPseudoObj->m_cRef; + +#if defined( _DEBUG ) + OleDbgAssertSz(lpPseudoObj->m_cRef >= 0,"Release called with cRef == 0"); + + OleDbgOutRefCnt4( + "PseudoObj_Release: cRef--\r\n", lpPseudoObj,cRef); +#endif + + if (cRef == 0) + PseudoObj_Destroy(lpPseudoObj); + + return cRef; +} + + +/* PseudoObj_QueryInterface +** ------------------------ +** +** Retrieve a pointer to an interface on the PseudoObj object. +** +** Returns S_OK if interface is successfully retrieved. +** E_NOINTERFACE if the interface is not supported +*/ +HRESULT PseudoObj_QueryInterface( + LPPSEUDOOBJ lpPseudoObj, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + SCODE sc = E_NOINTERFACE; + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) { + OleDbgOut4("PseudoObj_QueryInterface: IUnknown* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpPseudoObj->m_Unknown; + PseudoObj_AddRef(lpPseudoObj); + sc = S_OK; + } + else if (IsEqualIID(riid, &IID_IOleObject)) { + OleDbgOut4("PseudoObj_QueryInterface: IOleObject* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpPseudoObj->m_OleObject; + PseudoObj_AddRef(lpPseudoObj); + sc = S_OK; + } + else if (IsEqualIID(riid, &IID_IDataObject)) { + OleDbgOut4("PseudoObj_QueryInterface: IDataObject* RETURNED\r\n"); + + *lplpvObj = (LPVOID) &lpPseudoObj->m_DataObject; + PseudoObj_AddRef(lpPseudoObj); + sc = S_OK; + } + + OleDbgQueryInterfaceMethod(*lplpvObj); + + return ResultFromScode(sc); +} + + +/* PseudoObj_Close + * --------------- + * + * Close the pseudo object. Force all external connections to close + * down. This causes link clients to release this PseudoObj. when + * the refcount actually reaches 0, then the PseudoObj will be + * destroyed. + * + * Returns: + * FALSE -- user canceled the closing of the doc. + * TRUE -- the doc was successfully closed + */ + +BOOL PseudoObj_Close(LPPSEUDOOBJ lpPseudoObj) +{ + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc; + LPSERVERNAME lpServerName = (LPSERVERNAME)lpPseudoObj->m_lpName; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + BOOL fStatus = TRUE; + + if (lpPseudoObj->m_fObjIsClosing) + return TRUE; // Closing is already in progress + + lpPseudoObj->m_fObjIsClosing = TRUE; // guard against recursive call + + OLEDBG_BEGIN3("PseudoObj_Close\r\n") + + /* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object + ** during the process of closing, we intially AddRef the App, + ** Doc, and PseudoObj ref counts and later Release them. These + ** initial AddRefs are artificial; they are simply done to + ** guarantee that these objects do not get destroyed until the + ** end of this routine. + */ + OleApp_AddRef(lpOleApp); + OleDoc_AddRef(lpOleDoc); + PseudoObj_AddRef(lpPseudoObj); + + if (lpPseudoObj->m_lpDataAdviseHldr) { + /* OLE2NOTE: send last OnDataChange notification to clients + ** that have registered for data notifications when object + ** stops running (ADVF_DATAONSTOP) + */ + PseudoObj_SendAdvise( + lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkObj -- not relevant here */ + ADVF_DATAONSTOP + ); + + /* OLE2NOTE: we just sent the last data notification that we + ** need to send; release our DataAdviseHolder. we SHOULD be + ** the only one using it. + */ + OleStdVerifyRelease( + (LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr, + "DataAdviseHldr not released properly" + ); + lpPseudoObj->m_lpDataAdviseHldr = NULL; + } + + if (lpPseudoObj->m_lpOleAdviseHldr) { + // OLE2NOTE: inform all of our linking clients that we are closing. + PseudoObj_SendAdvise( + lpPseudoObj, + OLE_ONCLOSE, + NULL, /* lpmkObj -- not relevant here */ + 0 /* advf -- not relevant here */ + ); + + /* OLE2NOTE: OnClose is the last notification that we need to + ** send; release our OleAdviseHolder. we SHOULD be the only + ** one using it. this will make our destructor realize that + ** OnClose notification has already been sent. + */ + OleStdVerifyRelease( + (LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr, + "OleAdviseHldr not released properly" + ); + lpPseudoObj->m_lpOleAdviseHldr = NULL; + } + + /* OLE2NOTE: this call forces all external connections to our + ** object to close down and therefore guarantees that we receive + ** all releases associated with those external connections. + */ + OLEDBG_BEGIN2("CoDisconnectObject called\r\n") + CoDisconnectObject((LPUNKNOWN)&lpPseudoObj->m_Unknown, 0); + OLEDBG_END2 + + PseudoObj_Release(lpPseudoObj); // release artificial AddRef above + OleDoc_Release(lpOleDoc); // release artificial AddRef above + OleApp_Release(lpOleApp); // release artificial AddRef above + + OLEDBG_END3 + return fStatus; +} + + +/* PseudoObj_Destroy +** ----------------- +** Destroy (Free) the memory used by a PseudoObj structure. +** This function is called when the ref count of the PseudoObj goes +** to zero. the ref cnt goes to zero after PseudoObj_Delete forces +** the OleObject to unload and release its pointers to the +** PseudoObj IOleClientSite and IAdviseSink interfaces. +*/ + +void PseudoObj_Destroy(LPPSEUDOOBJ lpPseudoObj) +{ + LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + + OLEDBG_BEGIN3("PseudoObj_Destroy\r\n") + + /* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object + ** during the process of closing, we intially AddRef the App, + ** Doc ref counts and later Release them. These + ** initial AddRefs are artificial; they are simply done to + ** guarantee that these objects do not get destroyed until the + ** end of this routine. + */ + OleApp_AddRef(lpOleApp); + OleDoc_AddRef(lpOleDoc); + + /****************************************************************** + ** OLE2NOTE: we no longer need the advise and enum holder objects, + ** so release them. + ******************************************************************/ + + if (lpPseudoObj->m_lpDataAdviseHldr) { + /* release DataAdviseHldr; we SHOULD be the only one using it. */ + OleStdVerifyRelease( + (LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr, + "DataAdviseHldr not released properly" + ); + lpPseudoObj->m_lpDataAdviseHldr = NULL; + } + + if (lpPseudoObj->m_lpOleAdviseHldr) { + /* release OleAdviseHldr; we SHOULD be the only one using it. */ + OleStdVerifyRelease( + (LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr, + "OleAdviseHldr not released properly" + ); + lpPseudoObj->m_lpOleAdviseHldr = NULL; + } + + /* forget the pointer to destroyed PseudoObj in NameTable */ + if (lpPseudoObj->m_lpName) + lpPseudoObj->m_lpName->m_lpPseudoObj = NULL; + + /* OLE2NOTE: release the lock on the Doc held on behalf of the + ** PseudoObj. the Document should not shut down unless all + ** pseudo objects are closed. when a pseudo object is first + ** created, it calls ServerDoc_PseudoObjLockDoc to guarantee + ** that the document stays alive (called from PseudoObj_Init). + */ + ServerDoc_PseudoObjUnlockDoc(lpServerDoc, lpPseudoObj); + + Delete(lpPseudoObj); // Free the memory for the structure itself + + OleDoc_Release(lpOleDoc); // release artificial AddRef above + OleApp_Release(lpOleApp); // release artificial AddRef above + + OLEDBG_END3 +} + + +/* PseudoObj_GetSel +** ---------------- +** Return the line range for the pseudo object +*/ +void PseudoObj_GetSel(LPPSEUDOOBJ lpPseudoObj, LPLINERANGE lplrSel) +{ + LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName; + lplrSel->m_nStartLine = lpOutlineName->m_nStartLine; + lplrSel->m_nEndLine = lpOutlineName->m_nEndLine; +} + + +/* PseudoObj_GetExtent + * ------------------- + * + * Get the extent (width, height) of the entire document. + */ +void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc; + LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; + LINERANGE lrSel; + + PseudoObj_GetSel(lpPseudoObj, (LPLINERANGE)&lrSel); + + LineList_CalcSelExtentInHimetric(lpLL, (LPLINERANGE)&lrSel, lpsizel); +} + + +/* PseudoObj_SendAdvise + * -------------------- + * + * This function sends an advise notification on behalf of a specific + * doc object to all its clients. + */ +void PseudoObj_SendAdvise( + LPPSEUDOOBJ lpPseudoObj, + WORD wAdvise, + LPMONIKER lpmkObj, + DWORD dwAdvf +) +{ + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc; + + switch (wAdvise) { + + case OLE_ONDATACHANGE: + + // inform clients that the data of the object has changed + + if (lpOutlineDoc->m_nDisableDraw == 0) { + /* drawing is currently enabled. inform clients that + ** the data of the object has changed + */ + + lpPseudoObj->m_fDataChanged = FALSE; + if (lpPseudoObj->m_lpDataAdviseHldr) { + + OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n"); + lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange( + lpPseudoObj->m_lpDataAdviseHldr, + (LPDATAOBJECT)&lpPseudoObj->m_DataObject, + 0, + dwAdvf + ); + OLEDBG_END2 + } + + } else { + /* drawing is currently disabled. do not send + ** notifications until drawing is re-enabled. + */ + lpPseudoObj->m_fDataChanged = TRUE; + } + break; + + case OLE_ONCLOSE: + + // inform clients that the object is shutting down + + if (lpPseudoObj->m_lpOleAdviseHldr) { + + OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n"); + lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnClose( + lpPseudoObj->m_lpOleAdviseHldr + ); + OLEDBG_END2 + } + break; + + case OLE_ONSAVE: + + // inform clients that the object has been saved + + if (lpPseudoObj->m_lpOleAdviseHldr) { + + OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n"); + lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnSave( + lpPseudoObj->m_lpOleAdviseHldr + ); + OLEDBG_END2 + } + break; + + case OLE_ONRENAME: + + // inform clients that the object's name has changed + if (lpmkObj && lpPseudoObj->m_lpOleAdviseHldr) { + + OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n"); + if (lpPseudoObj->m_lpOleAdviseHldr) + lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnRename( + lpPseudoObj->m_lpOleAdviseHldr, + lpmkObj + ); + OLEDBG_END2 + } + break; + } +} + + +/* PseudoObj_GetFullMoniker + * ------------------------ + * + * Returns the Full, absolute Moniker which identifies this pseudo object. + */ +LPMONIKER PseudoObj_GetFullMoniker(LPPSEUDOOBJ lpPseudoObj, LPMONIKER lpmkDoc) +{ + LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName; + LPMONIKER lpmkItem = NULL; + LPMONIKER lpmkPseudoObj = NULL; + + if (lpmkDoc != NULL) { + CreateItemMonikerA(OLESTDDELIM,lpOutlineName->m_szName,&lpmkItem); + + /* OLE2NOTE: create an absolute moniker which identifies the + ** pseudo object. this moniker is created as a composite of + ** the absolute moniker for the entire document appended + ** with an item moniker which identifies the selection of + ** the pseudo object relative to the document. + */ + CreateGenericComposite(lpmkDoc, lpmkItem, &lpmkPseudoObj); + + if (lpmkItem) + OleStdRelease((LPUNKNOWN)lpmkItem); + + return lpmkPseudoObj; + } else { + return NULL; + } +} + + +/************************************************************************* +** PseudoObj::IUnknown interface implementation +*************************************************************************/ + +STDMETHODIMP PseudoObj_Unk_QueryInterface( + LPUNKNOWN lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj; + + return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) PseudoObj_Unk_AddRef(LPUNKNOWN lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj; + + OleDbgAddRefMethod(lpThis, "IUnknown"); + + return PseudoObj_AddRef(lpPseudoObj); +} + + +STDMETHODIMP_(ULONG) PseudoObj_Unk_Release (LPUNKNOWN lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj; + + OleDbgReleaseMethod(lpThis, "IUnknown"); + + return PseudoObj_Release(lpPseudoObj); +} + + +/************************************************************************* +** PseudoObj::IOleObject interface implementation +*************************************************************************/ + +STDMETHODIMP PseudoObj_OleObj_QueryInterface( + LPOLEOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + + return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) PseudoObj_OleObj_AddRef(LPOLEOBJECT lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + + OleDbgAddRefMethod(lpThis, "IOleObject"); + + return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj); +} + + +STDMETHODIMP_(ULONG) PseudoObj_OleObj_Release(LPOLEOBJECT lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + + OleDbgReleaseMethod(lpThis, "IOleObject"); + + return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj); +} + + +STDMETHODIMP PseudoObj_OleObj_SetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE lpClientSite +) +{ + OleDbgOut2("PseudoObj_OleObj_SetClientSite\r\n"); + + // OLE2NOTE: a pseudo object does NOT support SetExtent + + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP PseudoObj_OleObj_GetClientSite( + LPOLEOBJECT lpThis, + LPOLECLIENTSITE FAR* lplpClientSite +) +{ + OleDbgOut2("PseudoObj_OleObj_GetClientSite\r\n"); + + *lplpClientSite = NULL; + + // OLE2NOTE: a pseudo object does NOT support SetExtent + + return ResultFromScode(E_FAIL); +} + + + +STDMETHODIMP PseudoObj_OleObj_SetHostNamesA( + LPOLEOBJECT lpThis, + LPCSTR szContainerApp, + LPCSTR szContainerObj +) +{ + OleDbgOut2("PseudoObj_OleObj_SetHostNamesA\r\n"); + + // OLE2NOTE: a pseudo object does NOT support SetExtent + + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP PseudoObj_OleObj_SetHostNames( + LPOLEOBJECT lpThis, + LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj +) +{ + OleDbgOut2("PseudoObj_OleObj_SetHostNames\r\n"); + + // OLE2NOTE: a pseudo object does NOT support SetExtent + + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP PseudoObj_OleObj_Close( + LPOLEOBJECT lpThis, + DWORD dwSaveOption +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + BOOL fStatus; + + OLEDBG_BEGIN2("PseudoObj_OleObj_Close\r\n") + + /* OLE2NOTE: a pseudo object's implementation of IOleObject::Close + ** should ignore the dwSaveOption parameter. it is NOT + ** applicable to pseudo objects. + */ + + fStatus = PseudoObj_Close(lpPseudoObj); + OleDbgAssertSz(fStatus == TRUE, "PseudoObj_OleObj_Close failed\r\n"); + + OLEDBG_END2 + return NOERROR; +} + + +STDMETHODIMP PseudoObj_OleObj_SetMoniker( + LPOLEOBJECT lpThis, + DWORD dwWhichMoniker, + LPMONIKER lpmk +) +{ + OleDbgOut2("PseudoObj_OleObj_SetMoniker\r\n"); + + // OLE2NOTE: a pseudo object does NOT support SetMoniker + + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP PseudoObj_OleObj_GetMoniker( + LPOLEOBJECT lpThis, + DWORD dwAssign, + DWORD dwWhichMoniker, + LPMONIKER FAR* lplpmk +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc; + LPMONIKER lpmkDoc; + + OLEDBG_BEGIN2("PseudoObj_OleObj_GetMoniker\r\n") + + lpmkDoc = OleDoc_GetFullMoniker(lpOleDoc, GETMONIKER_ONLYIFTHERE); + *lplpmk = PseudoObj_GetFullMoniker(lpPseudoObj, lpmkDoc); + + OLEDBG_END2 + + if (*lplpmk != NULL) + return NOERROR; + else + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP PseudoObj_OleObj_InitFromData( + LPOLEOBJECT lpThis, + LPDATAOBJECT lpDataObject, + BOOL fCreation, + DWORD reserved +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + OleDbgOut2("PseudoObj_OleObj_InitFromData\r\n"); + + // REVIEW: NOT YET IMPLEMENTED + + return ResultFromScode(E_NOTIMPL); +} + + +STDMETHODIMP PseudoObj_OleObj_GetClipboardData( + LPOLEOBJECT lpThis, + DWORD reserved, + LPDATAOBJECT FAR* lplpDataObject +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + OleDbgOut2("PseudoObj_OleObj_GetClipboardData\r\n"); + + // REVIEW: NOT YET IMPLEMENTED + + return ResultFromScode(E_NOTIMPL); +} + + +STDMETHODIMP PseudoObj_OleObj_DoVerb( + LPOLEOBJECT lpThis, + LONG lVerb, + LPMSG lpmsg, + LPOLECLIENTSITE lpActiveSite, + LONG lindex, + HWND hwndParent, + LPCRECT lprcPosRect +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc; + LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; + LINERANGE lrSel; + HRESULT hrErr; + + OLEDBG_BEGIN2("PseudoObj_OleObj_DoVerb\r\n"); + + /* OLE2NOTE: we must first ask our Document to perform the same + ** verb. then if the verb is NOT OLEIVERB_HIDE we should also + ** select the range of our pseudo object. + ** however, we must give our document its own embedding site as + ** its active site. + */ + hrErr = SvrDoc_OleObj_DoVerb( + (LPOLEOBJECT)&lpServerDoc->m_OleObject, + lVerb, + lpmsg, + lpServerDoc->m_lpOleClientSite, + lindex, + NULL, /* we have no hwndParent to give */ + NULL /* we have no lprcPosRect to give */ + ); + if (FAILED(hrErr)) { + OLEDBG_END2 + return hrErr; + } + + if (lVerb != OLEIVERB_HIDE) { + PseudoObj_GetSel(lpPseudoObj, &lrSel); + OutlineDoc_SetSel(lpOutlineDoc, &lrSel); + } + + OLEDBG_END2 + return NOERROR; +} + + + +STDMETHODIMP PseudoObj_OleObj_EnumVerbs( + LPOLEOBJECT lpThis, + LPENUMOLEVERB FAR* lplpenumOleVerb +) +{ + OleDbgOut2("PseudoObj_OleObj_EnumVerbs\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumOleVerb = NULL; + + /* A pseudo object may NOT return OLE_S_USEREG; they must call the + ** OleReg* API or provide their own implementation. Because this + ** pseudo object does NOT implement IPersist, simply a low-level + ** remoting handler (ProxyManager) object as opposed to a + ** DefHandler object is used as the handler for the pseudo + ** object in a clients process space. The ProxyManager does NOT + ** handle the OLE_S_USEREG return values. + */ + return OleRegEnumVerbs((REFCLSID)&CLSID_APP, lplpenumOleVerb); +} + + +STDMETHODIMP PseudoObj_OleObj_Update(LPOLEOBJECT lpThis) +{ + OleDbgOut2("PseudoObj_OleObj_Update\r\n"); + + /* OLE2NOTE: a server-only app is always "up-to-date". + ** a container-app which contains links where the link source + ** has changed since the last update of the link would be + ** considered "out-of-date". the "Update" method instructs the + ** object to get an update from any out-of-date links. + */ + + return NOERROR; +} + + +STDMETHODIMP PseudoObj_OleObj_IsUpToDate(LPOLEOBJECT lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + OleDbgOut2("PseudoObj_OleObj_IsUpToDate\r\n"); + + /* OLE2NOTE: a server-only app is always "up-to-date". + ** a container-app which contains links where the link source + ** has changed since the last update of the link would be + ** considered "out-of-date". + */ + return NOERROR; +} + + +STDMETHODIMP PseudoObj_OleObj_GetUserClassID( + LPOLEOBJECT lpThis, + LPCLSID lpclsid +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc; + OleDbgOut2("PseudoObj_OleObj_GetUserClassID\r\n"); + + /* OLE2NOTE: we must be carefull to return the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the class of the object + ** written in the storage of the object. otherwise we would + ** return our own class id. + */ + return ServerDoc_GetClassID(lpServerDoc, lpclsid); +} + + +STDMETHODIMP PseudoObj_OleObj_GetUserTypeA( + LPOLEOBJECT lpThis, + DWORD dwFormOfType, + LPSTR FAR* lpszUserType +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc; + OleDbgOut2("PseudoObj_OleObj_GetUserType\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lpszUserType = NULL; + + /* OLE2NOTE: we must be carefull to return the correct user type here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the user type name that + ** corresponds to the class of the object we are currently + ** emmulating. otherwise we should return our normal user type + ** name corresponding to our own class. This routine determines + ** the current clsid in effect. + ** + ** A pseudo object may NOT return OLE_S_USEREG; they must call the + ** OleReg* API or provide their own implementation. Because this + ** pseudo object does NOT implement IPersist, simply a low-level + ** remoting handler (ProxyManager) object as opposed to a + ** DefHandler object is used as the handler for the pseudo + ** object in a clients process space. The ProxyManager does NOT + ** handle the OLE_S_USEREG return values. + */ +#if defined( SVR_TREATAS ) + if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) ) + return OleRegGetUserTypeA( + &lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType); + else +#endif // SVR_TREATAS + + return OleRegGetUserTypeA(&CLSID_APP, dwFormOfType, lpszUserType); +} + +STDMETHODIMP PseudoObj_OleObj_GetUserType( + LPOLEOBJECT lpThis, + DWORD dwFormOfType, + LPOLESTR FAR* lpszUserType +) +{ + LPSTR pstr; + + HRESULT hr = PseudoObj_OleObj_GetUserTypeA(lpThis, dwFormOfType, &pstr); + + CopyAndFreeSTR(pstr, lpszUserType); + + return hr; +} + + + +STDMETHODIMP PseudoObj_OleObj_SetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lplgrc +) +{ + OleDbgOut2("PseudoObj_OleObj_SetExtent\r\n"); + + // OLE2NOTE: a pseudo object does NOT support SetExtent + + return ResultFromScode(E_FAIL); +} + + +STDMETHODIMP PseudoObj_OleObj_GetExtent( + LPOLEOBJECT lpThis, + DWORD dwDrawAspect, + LPSIZEL lpsizel +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + OleDbgOut2("PseudoObj_OleObj_GetExtent\r\n"); + + /* OLE2NOTE: it is VERY important to check which aspect the caller + ** is asking about. an object implemented by a server EXE MAY + ** fail to return extents when asked for DVASPECT_ICON. + */ + if (dwDrawAspect == DVASPECT_CONTENT) { + PseudoObj_GetExtent(lpPseudoObj, lpsizel); + return NOERROR; + } + else + { + return ResultFromScode(E_FAIL); + } +} + + +STDMETHODIMP PseudoObj_OleObj_Advise( + LPOLEOBJECT lpThis, + LPADVISESINK lpAdvSink, + LPDWORD lpdwConnection +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + HRESULT hrErr; + SCODE sc; + OLEDBG_BEGIN2("PseudoObj_OleObj_Advise\r\n"); + + if (lpPseudoObj->m_lpOleAdviseHldr == NULL && + CreateOleAdviseHolder(&lpPseudoObj->m_lpOleAdviseHldr) != NOERROR) { + sc = E_OUTOFMEMORY; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n") + hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Advise( + lpPseudoObj->m_lpOleAdviseHldr, + lpAdvSink, + lpdwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("PseudoObj_OleObj_Unadvise\r\n"); + + if (lpPseudoObj->m_lpOleAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n") + hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Unadvise( + lpPseudoObj->m_lpOleAdviseHldr, + dwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_OleObj_EnumAdvise( + LPOLEOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("PseudoObj_OleObj_EnumAdvise\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumAdvise = NULL; + + if (lpPseudoObj->m_lpOleAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n") + hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->EnumAdvise( + lpPseudoObj->m_lpOleAdviseHldr, + lplpenumAdvise + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_OleObj_GetMiscStatus( + LPOLEOBJECT lpThis, + DWORD dwAspect, + DWORD FAR* lpdwStatus +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc; + OleDbgOut2("PseudoObj_OleObj_GetMiscStatus\r\n"); + + /* Get our default MiscStatus for the given Aspect. this + ** information is registered in the RegDB. We query the RegDB + ** here to guarantee that the value returned from this method + ** agrees with the values in RegDB. in this way we only have to + ** maintain the info in one place (in the RegDB). Alternatively + ** we could have the values hard coded here. + ** + ** OLE2NOTE: A pseudo object may NOT return OLE_S_USEREG; they must + ** call the + ** OleReg* API or provide their own implementation. Because this + ** pseudo object does NOT implement IPersist, simply a low-level + ** remoting handler (ProxyManager) object as opposed to a + ** DefHandler object is used as the handler for the pseudo + ** object in a clients process space. The ProxyManager does NOT + ** handle the OLE_S_USEREG return values. + */ + OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus); + + /* OLE2NOTE: check if the pseudo object is compatible to be + ** linked by an OLE 1.0 container. it is compatible if + ** either the pseudo object is an untitled document or a + ** file-based document. if the pseudo object is part of + ** an embedded object, then it is NOT compatible to be + ** linked by an OLE 1.0 container. if it is compatible then + ** we should include OLEMISC_CANLINKBYOLE1 as part of the + ** dwStatus flags. + */ + if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW || + lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) + *lpdwStatus |= OLEMISC_CANLINKBYOLE1; + + return NOERROR; +} + + +STDMETHODIMP PseudoObj_OleObj_SetColorScheme( + LPOLEOBJECT lpThis, + LPLOGPALETTE lpLogpal +) +{ + OleDbgOut2("PseudoObj_OleObj_SetColorScheme\r\n"); + + // REVIEW: NOT YET IMPLEMENTED + + return ResultFromScode(E_NOTIMPL); +} + + +/************************************************************************* +** PseudoObj::IDataObject interface implementation +*************************************************************************/ + +STDMETHODIMP PseudoObj_DataObj_QueryInterface ( + LPDATAOBJECT lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + + return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj); +} + + +STDMETHODIMP_(ULONG) PseudoObj_DataObj_AddRef(LPDATAOBJECT lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + + OleDbgAddRefMethod(lpThis, "IDataObject"); + + return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj); +} + + +STDMETHODIMP_(ULONG) PseudoObj_DataObj_Release (LPDATAOBJECT lpThis) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + + OleDbgReleaseMethod(lpThis, "IDataObject"); + + return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj); +} + + +STDMETHODIMP PseudoObj_DataObj_GetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + LINERANGE lrSel; + SCODE sc = S_OK; + OLEDBG_BEGIN2("PseudoObj_DataObj_GetData\r\n") + + PseudoObj_GetSel(lpPseudoObj, &lrSel); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + lpMedium->tymed = TYMED_NULL; + lpMedium->pUnkForRelease = NULL; // we transfer ownership to caller + lpMedium->hGlobal = NULL; + + if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DATA_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,&lrSel); + if (! lpMedium->hGlobal) return ResultFromScode(E_OUTOFMEMORY); + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_OUTLINE\r\n"); + + } else if(lpformatetc->cfFormat == CF_METAFILEPICT && + (lpformatetc->dwAspect & DVASPECT_CONTENT) ) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_MFPICT)) { + sc = DATA_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal=ServerDoc_GetMetafilePictData(lpServerDoc,&lrSel); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + lpMedium->tymed = TYMED_MFPICT; + OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT\r\n"); + + } else if (lpformatetc->cfFormat == CF_METAFILEPICT && + (lpformatetc->dwAspect & DVASPECT_ICON) ) { + CLSID clsid; + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_MFPICT)) { + sc = DATA_E_FORMATETC; + goto error; + } + + /* OLE2NOTE: we should return the default icon for our class. + ** we must be carefull to use the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to use the class of the object + ** written in the storage of the object. otherwise we would + ** use our own class id. + */ + if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) { + sc = DATA_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal=GetIconOfClass( + g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + + lpMedium->tymed = TYMED_MFPICT; + OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT (icon)\r\n"); + return NOERROR; + + } else if (lpformatetc->cfFormat == CF_TEXT) { + // Verify caller asked for correct medium + if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { + sc = DATA_E_FORMATETC; + goto error; + } + + lpMedium->hGlobal = OutlineDoc_GetTextData (lpOutlineDoc, &lrSel); + if (! lpMedium->hGlobal) { + sc = E_OUTOFMEMORY; + goto error; + } + lpMedium->tymed = TYMED_HGLOBAL; + OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_TEXT\r\n"); + + } else { + sc = DATA_E_FORMATETC; + goto error; + } + + OLEDBG_END2 + return NOERROR; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_DataObj_GetDataHere ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpMedium +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + OleDbgOut("PseudoObj_DataObj_GetDataHere\r\n"); + + /* Caller is requesting data to be returned in Caller allocated + ** medium, but we do NOT support this. we only support + ** global memory blocks that WE allocate for the caller. + */ + return ResultFromScode(DATA_E_FORMATETC); +} + + +STDMETHODIMP PseudoObj_DataObj_QueryGetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; + OleDbgOut2("PseudoObj_DataObj_QueryGetData\r\n"); + + /* Caller is querying if we support certain format but does not + ** want any data actually returned. + */ + if (lpformatetc->cfFormat == CF_METAFILEPICT && + (lpformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)) ) { + return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT); + + } else if (lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline || + lpformatetc->cfFormat == CF_TEXT) { + return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL); + } + + return ResultFromScode(DATA_E_FORMATETC); +} + + +STDMETHODIMP PseudoObj_DataObj_GetCanonicalFormatEtc( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPFORMATETC lpformatetcOut +) +{ + HRESULT hrErr; + OleDbgOut2("PseudoObj_DataObj_GetCanonicalFormatEtc\r\n"); + + if (!lpformatetcOut) + return ResultFromScode(E_INVALIDARG); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + lpformatetcOut->ptd = NULL; + + if (!lpformatetc) + return ResultFromScode(E_INVALIDARG); + + // OLE2NOTE: we must validate that the format requested is supported + if ((hrErr=lpThis->lpVtbl->QueryGetData(lpThis,lpformatetc)) != NOERROR) + return hrErr; + + /* OLE2NOTE: an app that is insensitive to target device (as the + ** Outline Sample is) should fill in the lpformatOut parameter + ** but NULL out the "ptd" field; it should return NOERROR if the + ** input formatetc->ptd what non-NULL. this tells the caller + ** that it is NOT necessary to maintain a separate screen + ** rendering and printer rendering. if should return + ** DATA_S_SAMEFORMATETC if the input and output formatetc's are + ** identical. + */ + + *lpformatetcOut = *lpformatetc; + if (lpformatetc->ptd == NULL) + return ResultFromScode(DATA_S_SAMEFORMATETC); + else { + lpformatetcOut->ptd = NULL; + return NOERROR; + } +} + + +STDMETHODIMP PseudoObj_DataObj_SetData ( + LPDATAOBJECT lpThis, + LPFORMATETC lpformatetc, + LPSTGMEDIUM lpmedium, + BOOL fRelease +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; + + OleDbgOut2("PseudoObj_DataObj_SetData\r\n"); + + // REVIEW: NOT-YET-IMPLEMENTED + return ResultFromScode(E_NOTIMPL); +} + + +STDMETHODIMP PseudoObj_DataObj_EnumFormatEtc( + LPDATAOBJECT lpThis, + DWORD dwDirection, + LPENUMFORMATETC FAR* lplpenumFormatEtc +) +{ + SCODE sc; + OleDbgOut2("PseudoObj_DataObj_EnumFormatEtc\r\n"); + + /* OLE2NOTE: a pseudo object only needs to enumerate the static list + ** of formats that are registered for our app in the + ** registration database. it is NOT + ** required that a pseudo object (ie. non-DataTransferDoc) + ** enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or + ** CF_EMBEDDEDOBJECT. we do NOT use pseudo objects for data + ** transfers. + ** + ** A pseudo object may NOT return OLE_S_USEREG; they must call the + ** OleReg* API or provide their own implementation. Because this + ** pseudo object does NOT implement IPersist, simply a low-level + ** remoting handler (ProxyManager) object as opposed to a + ** DefHandler object is used as the handler for the pseudo + ** object in a clients process space. The ProxyManager does NOT + ** handle the OLE_S_USEREG return values. + */ + if (dwDirection == DATADIR_GET) + return OleRegEnumFormatEtc( + (REFCLSID)&CLSID_APP, dwDirection, lplpenumFormatEtc); + else if (dwDirection == DATADIR_SET) + sc = E_NOTIMPL; + else + sc = E_INVALIDARG; + + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_DataObj_DAdvise( + LPDATAOBJECT lpThis, + FORMATETC FAR* lpFormatetc, + DWORD advf, + LPADVISESINK lpAdvSink, + DWORD FAR* lpdwConnection +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("PseudoObj_DataObj_DAdvise\r\n") + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lpdwConnection = 0; + + /* OLE2NOTE: we should validate if the caller is setting up an + ** Advise for a data type that we support. we must + ** explicitly allow an advise for the "wildcard" advise. + */ + if ( !( lpFormatetc->cfFormat == 0 && + lpFormatetc->ptd == NULL && + lpFormatetc->dwAspect == -1L && + lpFormatetc->lindex == -1L && + lpFormatetc->tymed == -1L) && + (hrErr = PseudoObj_DataObj_QueryGetData(lpThis, lpFormatetc)) + != NOERROR) { + sc = GetScode(hrErr); + goto error; + } + + if (lpPseudoObj->m_lpDataAdviseHldr == NULL && + CreateDataAdviseHolder(&lpPseudoObj->m_lpDataAdviseHldr) != NOERROR) { + sc = E_OUTOFMEMORY; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n") + hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Advise( + lpPseudoObj->m_lpDataAdviseHldr, + (LPDATAOBJECT)&lpPseudoObj->m_DataObject, + lpFormatetc, + advf, + lpAdvSink, + lpdwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("PseudoObj_DataObj_Unadvise\r\n"); + + // no one registered + if (lpPseudoObj->m_lpDataAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::DUnadvise called\r\n") + hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Unadvise( + lpPseudoObj->m_lpDataAdviseHldr, + dwConnection + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} + + +STDMETHODIMP PseudoObj_DataObj_EnumAdvise( + LPDATAOBJECT lpThis, + LPENUMSTATDATA FAR* lplpenumAdvise +) +{ + LPPSEUDOOBJ lpPseudoObj = + ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; + HRESULT hrErr; + SCODE sc; + + OLEDBG_BEGIN2("PseudoObj_DataObj_EnumAdvise\r\n"); + + /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ + *lplpenumAdvise = NULL; + + if (lpPseudoObj->m_lpDataAdviseHldr == NULL) { + sc = E_FAIL; + goto error; + } + + OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n") + hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->EnumAdvise( + lpPseudoObj->m_lpDataAdviseHldr, + lplpenumAdvise + ); + OLEDBG_END2 + + OLEDBG_END2 + return hrErr; + +error: + OLEDBG_END2 + return ResultFromScode(sc); +} diff --git a/private/oleutest/letest/outline/tests.c b/private/oleutest/letest/outline/tests.c new file mode 100644 index 000000000..ce8f99a09 --- /dev/null +++ b/private/oleutest/letest/outline/tests.c @@ -0,0 +1,134 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: tests.c +// +// Contents: unit tests for 32bit OLE +// +// Classes: +// +// Functions: StartClipboardTest1 +// +// History: dd-mmm-yy Author Comment +// 16-Jun-94 alexgo author +// +//-------------------------------------------------------------------------- + +#include "outline.h" + +//+------------------------------------------------------------------------- +// +// Function: StartClipboardTest1 +// +// Synopsis: copies the loaded object to the clipboard +// +// Effects: +// +// Arguments: void +// +// Requires: +// +// Returns: void +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 16-Jun-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +void StartClipboardTest1( LPOUTLINEAPP lpOutlineApp) +{ + static char FileName[] = "letest12.olc"; + BOOL fStatus; + HRESULT hresult = ResultFromScode(E_FAIL); + + lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); + if (! lpOutlineApp->m_lpDoc) + { + goto errRtn; + } + + fStatus = OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, + FileName); + + if( !fStatus ) + { + hresult = ResultFromScode(STG_E_FILENOTFOUND); + goto errRtn; + } + + + + // position and size the new doc window + OutlineApp_ResizeWindows(lpOutlineApp); + OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); + + + // we post a message here to give outline a chance to setup its + // UI before we do the copy. + + UpdateWindow(lpOutlineApp->m_hWndApp); + OutlineDoc_SelectAllCommand(lpOutlineApp->m_lpDoc); + + PostMessage(lpOutlineApp->m_hWndApp, WM_TEST2, 0, 0); + + return; + +errRtn: + + // we should abort if error + PostMessage(g_hwndDriver, WM_TESTEND, TEST_FAILURE, hresult); + PostMessage(lpOutlineApp->m_hWndApp, WM_SYSCOMMAND, SC_CLOSE, 0L); + + +} + +//+------------------------------------------------------------------------- +// +// Function: ContinueClipboardTest1 +// +// Synopsis: finishes up the clipboard test +// +// Effects: +// +// Arguments: +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 16-Jun-94 alexgo author +// Notes: +// +//-------------------------------------------------------------------------- + +void ContinueClipboardTest1( LPOUTLINEAPP lpOutlineApp ) +{ + OutlineDoc_CopyCommand(lpOutlineApp->m_lpDoc); + + OleApp_FlushClipboard((LPOLEAPP)lpOutlineApp); + + //flushing will make the app dirty, just reset that here ;-) + + lpOutlineApp->m_lpDoc->m_fModified = FALSE; + + PostMessage(g_hwndDriver, WM_TEST1, NOERROR, 0); + PostMessage(lpOutlineApp->m_hWndApp, WM_SYSCOMMAND, SC_CLOSE, 0L); +} + |