summaryrefslogtreecommitdiffstats
path: root/private/oleutest/letest/outline
diff options
context:
space:
mode:
Diffstat (limited to 'private/oleutest/letest/outline')
-rw-r--r--private/oleutest/letest/outline/classfac.c219
-rw-r--r--private/oleutest/letest/outline/classfac.h219
-rw-r--r--private/oleutest/letest/outline/clipbrd.c3401
-rw-r--r--private/oleutest/letest/outline/cntrbase.c2002
-rw-r--r--private/oleutest/letest/outline/cntrinpl.c1940
-rw-r--r--private/oleutest/letest/outline/cntrline.c3540
-rw-r--r--private/oleutest/letest/outline/cntrline.h3584
-rw-r--r--private/oleutest/letest/outline/cntroutl.h855
-rw-r--r--private/oleutest/letest/outline/cntroutl.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/letest/outline/cntroutl/cntroutl.rc179
-rw-r--r--private/oleutest/letest/outline/cntroutl/daytona/makefile6
-rw-r--r--private/oleutest/letest/outline/cntroutl/daytona/makefile.inc2
-rw-r--r--private/oleutest/letest/outline/cntroutl/daytona/sources114
-rw-r--r--private/oleutest/letest/outline/cntroutl/dirs37
-rw-r--r--private/oleutest/letest/outline/cntrrc.h30
-rw-r--r--private/oleutest/letest/outline/debug.c100
-rw-r--r--private/oleutest/letest/outline/debug.rc142
-rw-r--r--private/oleutest/letest/outline/debug2.c329
-rw-r--r--private/oleutest/letest/outline/defguid.h44
-rw-r--r--private/oleutest/letest/outline/dialogs.c659
-rw-r--r--private/oleutest/letest/outline/dialogs.dlg92
-rw-r--r--private/oleutest/letest/outline/dirs32
-rw-r--r--private/oleutest/letest/outline/dragcopy.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/outline/dragdrop.c674
-rw-r--r--private/oleutest/letest/outline/draglink.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/outline/dragmove.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/outline/dragnone.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/outline/frametls.c1075
-rw-r--r--private/oleutest/letest/outline/frametls.h102
-rw-r--r--private/oleutest/letest/outline/heading.c451
-rw-r--r--private/oleutest/letest/outline/heading.h59
-rw-r--r--private/oleutest/letest/outline/icntrotl.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/letest/outline/icntrotl/daytona/makefile6
-rw-r--r--private/oleutest/letest/outline/icntrotl/daytona/makefile.inc2
-rw-r--r--private/oleutest/letest/outline/icntrotl/daytona/sources108
-rw-r--r--private/oleutest/letest/outline/icntrotl/dirs37
-rw-r--r--private/oleutest/letest/outline/icntrotl/icntrotl.rc210
-rw-r--r--private/oleutest/letest/outline/image120.bmpbin0 -> 1498 bytes
-rw-r--r--private/oleutest/letest/outline/image72.bmpbin0 -> 558 bytes
-rw-r--r--private/oleutest/letest/outline/image96.bmpbin0 -> 758 bytes
-rw-r--r--private/oleutest/letest/outline/install.bat7
-rw-r--r--private/oleutest/letest/outline/isvrotl.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/letest/outline/isvrotl/daytona/makefile6
-rw-r--r--private/oleutest/letest/outline/isvrotl/daytona/makefile.inc2
-rw-r--r--private/oleutest/letest/outline/isvrotl/daytona/sources108
-rw-r--r--private/oleutest/letest/outline/isvrotl/dirs37
-rw-r--r--private/oleutest/letest/outline/isvrotl/isvrotl.rc211
-rw-r--r--private/oleutest/letest/outline/linking.c2157
-rw-r--r--private/oleutest/letest/outline/main.c2488
-rw-r--r--private/oleutest/letest/outline/memmgr.c38
-rw-r--r--private/oleutest/letest/outline/message.h109
-rw-r--r--private/oleutest/letest/outline/ole2.bmpbin0 -> 14862 bytes
-rw-r--r--private/oleutest/letest/outline/oleapp.c2989
-rw-r--r--private/oleutest/letest/outline/oledoc.c1179
-rw-r--r--private/oleutest/letest/outline/oleoutl.h734
-rw-r--r--private/oleutest/letest/outline/outlapp.c1514
-rw-r--r--private/oleutest/letest/outline/outldoc.c3247
-rw-r--r--private/oleutest/letest/outline/outline.h790
-rw-r--r--private/oleutest/letest/outline/outline.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/letest/outline/outline.mst469
-rw-r--r--private/oleutest/letest/outline/outline.rc173
-rw-r--r--private/oleutest/letest/outline/outlline.c731
-rw-r--r--private/oleutest/letest/outline/outllist.c1183
-rw-r--r--private/oleutest/letest/outline/outlname.c112
-rw-r--r--private/oleutest/letest/outline/outlntbl.c460
-rw-r--r--private/oleutest/letest/outline/outlrc.h164
-rw-r--r--private/oleutest/letest/outline/outltxtl.c408
-rw-r--r--private/oleutest/letest/outline/precomp.c13
-rw-r--r--private/oleutest/letest/outline/selcross.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/outline/state.rst12
-rw-r--r--private/oleutest/letest/outline/status.c369
-rw-r--r--private/oleutest/letest/outline/status.h47
-rw-r--r--private/oleutest/letest/outline/svrbase.c2018
-rw-r--r--private/oleutest/letest/outline/svrinpl.c1451
-rw-r--r--private/oleutest/letest/outline/svroutl.h888
-rw-r--r--private/oleutest/letest/outline/svroutl.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/letest/outline/svroutl/daytona/makefile6
-rw-r--r--private/oleutest/letest/outline/svroutl/daytona/makefile.inc2
-rw-r--r--private/oleutest/letest/outline/svroutl/daytona/sources106
-rw-r--r--private/oleutest/letest/outline/svroutl/dirs37
-rw-r--r--private/oleutest/letest/outline/svroutl/svroutl.rc187
-rw-r--r--private/oleutest/letest/outline/svrpsobj.c1538
-rw-r--r--private/oleutest/letest/outline/tests.c134
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
new file mode 100644
index 000000000..313a0000f
--- /dev/null
+++ b/private/oleutest/letest/outline/cntroutl.ico
Binary files differ
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
new file mode 100644
index 000000000..89c7c960d
--- /dev/null
+++ b/private/oleutest/letest/outline/dragcopy.cur
Binary files differ
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
new file mode 100644
index 000000000..fca1fc090
--- /dev/null
+++ b/private/oleutest/letest/outline/draglink.cur
Binary files differ
diff --git a/private/oleutest/letest/outline/dragmove.cur b/private/oleutest/letest/outline/dragmove.cur
new file mode 100644
index 000000000..a9a9bd636
--- /dev/null
+++ b/private/oleutest/letest/outline/dragmove.cur
Binary files differ
diff --git a/private/oleutest/letest/outline/dragnone.cur b/private/oleutest/letest/outline/dragnone.cur
new file mode 100644
index 000000000..b002e96b3
--- /dev/null
+++ b/private/oleutest/letest/outline/dragnone.cur
Binary files differ
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
new file mode 100644
index 000000000..7bd2931c5
--- /dev/null
+++ b/private/oleutest/letest/outline/icntrotl.ico
Binary files differ
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
new file mode 100644
index 000000000..663f5234c
--- /dev/null
+++ b/private/oleutest/letest/outline/image120.bmp
Binary files differ
diff --git a/private/oleutest/letest/outline/image72.bmp b/private/oleutest/letest/outline/image72.bmp
new file mode 100644
index 000000000..dd096bb2c
--- /dev/null
+++ b/private/oleutest/letest/outline/image72.bmp
Binary files differ
diff --git a/private/oleutest/letest/outline/image96.bmp b/private/oleutest/letest/outline/image96.bmp
new file mode 100644
index 000000000..34af2948e
--- /dev/null
+++ b/private/oleutest/letest/outline/image96.bmp
Binary files differ
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
new file mode 100644
index 000000000..406bab9d8
--- /dev/null
+++ b/private/oleutest/letest/outline/isvrotl.ico
Binary files differ
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
new file mode 100644
index 000000000..f1d0cbbf7
--- /dev/null
+++ b/private/oleutest/letest/outline/ole2.bmp
Binary files differ
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
new file mode 100644
index 000000000..bb5d483ee
--- /dev/null
+++ b/private/oleutest/letest/outline/outline.ico
Binary files differ
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
new file mode 100644
index 000000000..de3d14703
--- /dev/null
+++ b/private/oleutest/letest/outline/selcross.cur
Binary files differ
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
new file mode 100644
index 000000000..b674fc61d
--- /dev/null
+++ b/private/oleutest/letest/outline/svroutl.ico
Binary files differ
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);
+}
+