summaryrefslogtreecommitdiffstats
path: root/private/oleutest/letest
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/oleutest/letest
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/oleutest/letest')
-rw-r--r--private/oleutest/letest/bttncur/bttncur.c1070
-rw-r--r--private/oleutest/letest/bttncur/bttncur.h201
-rw-r--r--private/oleutest/letest/bttncur/bttncur.rc39
-rw-r--r--private/oleutest/letest/bttncur/bttncur.rcv48
-rw-r--r--private/oleutest/letest/bttncur/bttncuri.h88
-rw-r--r--private/oleutest/letest/bttncur/changes.txt314
-rw-r--r--private/oleutest/letest/bttncur/cursors.c150
-rw-r--r--private/oleutest/letest/bttncur/daytona/bttncur.src39
-rw-r--r--private/oleutest/letest/bttncur/daytona/makefile6
-rw-r--r--private/oleutest/letest/bttncur/daytona/makefile.inc1
-rw-r--r--private/oleutest/letest/bttncur/daytona/sources39
-rw-r--r--private/oleutest/letest/bttncur/dirs4
-rw-r--r--private/oleutest/letest/bttncur/dllentry.c55
-rw-r--r--private/oleutest/letest/bttncur/makefile12
-rw-r--r--private/oleutest/letest/bttncur/msvc.pdbbin0 -> 49152 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/harrows.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/help.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/larrows.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/magnify.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/neswarrs.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/nodrop.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/nwsearrs.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/rarrow.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/sarrows.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/sizebarh.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/sizebarv.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/splith.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/splitv.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/stdim120.bmpbin0 -> 2602 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/stdim72.bmpbin0 -> 910 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/stdim96.bmpbin0 -> 1198 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/tabletop.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/bttncur/res/varrows.curbin0 -> 326 bytes
-rw-r--r--private/oleutest/letest/data/letest12.olcbin0 -> 5120 bytes
-rw-r--r--private/oleutest/letest/data/tiger.bmpbin0 -> 438198 bytes
-rw-r--r--private/oleutest/letest/data/tigernph.wmfbin0 -> 185288 bytes
-rw-r--r--private/oleutest/letest/dirs7
-rw-r--r--private/oleutest/letest/gizmobar/api.c846
-rw-r--r--private/oleutest/letest/gizmobar/book1632.h154
-rw-r--r--private/oleutest/letest/gizmobar/daytona/gizmobar.src51
-rw-r--r--private/oleutest/letest/gizmobar/daytona/makefile6
-rw-r--r--private/oleutest/letest/gizmobar/daytona/makefile.inc1
-rw-r--r--private/oleutest/letest/gizmobar/daytona/sources50
-rw-r--r--private/oleutest/letest/gizmobar/dirs37
-rw-r--r--private/oleutest/letest/gizmobar/dllentry.c55
-rw-r--r--private/oleutest/letest/gizmobar/gizmo.c766
-rw-r--r--private/oleutest/letest/gizmobar/gizmo.h103
-rw-r--r--private/oleutest/letest/gizmobar/gizmobar.c467
-rw-r--r--private/oleutest/letest/gizmobar/gizmobar.h178
-rw-r--r--private/oleutest/letest/gizmobar/gizmobar.rc20
-rw-r--r--private/oleutest/letest/gizmobar/gizmobar.rcv53
-rw-r--r--private/oleutest/letest/gizmobar/gizmoint.h105
-rw-r--r--private/oleutest/letest/gizmobar/init.c233
-rw-r--r--private/oleutest/letest/gizmobar/paint.c132
-rw-r--r--private/oleutest/letest/ole2ui/bang.icobin0 -> 1846 bytes
-rw-r--r--private/oleutest/letest/ole2ui/busy.c551
-rw-r--r--private/oleutest/letest/ole2ui/busy.dlg13
-rw-r--r--private/oleutest/letest/ole2ui/busy.h45
-rw-r--r--private/oleutest/letest/ole2ui/common.c423
-rw-r--r--private/oleutest/letest/ole2ui/common.h166
-rw-r--r--private/oleutest/letest/ole2ui/convert.c1802
-rw-r--r--private/oleutest/letest/ole2ui/convert.dlg32
-rw-r--r--private/oleutest/letest/ole2ui/convert.h63
-rw-r--r--private/oleutest/letest/ole2ui/daytona/makefile6
-rw-r--r--private/oleutest/letest/ole2ui/daytona/ole2u32a.src200
-rw-r--r--private/oleutest/letest/ole2ui/daytona/ole2ui.src199
-rw-r--r--private/oleutest/letest/ole2ui/daytona/sources64
-rw-r--r--private/oleutest/letest/ole2ui/dballoc.cpp900
-rw-r--r--private/oleutest/letest/ole2ui/dballoc.h36
-rw-r--r--private/oleutest/letest/ole2ui/dbgutil.c419
-rw-r--r--private/oleutest/letest/ole2ui/debug.h69
-rw-r--r--private/oleutest/letest/ole2ui/default.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/letest/ole2ui/defuimak.ini20
-rw-r--r--private/oleutest/letest/ole2ui/depend87
-rw-r--r--private/oleutest/letest/ole2ui/depend.mk569
-rw-r--r--private/oleutest/letest/ole2ui/dirs3
-rw-r--r--private/oleutest/letest/ole2ui/dllentry.c55
-rw-r--r--private/oleutest/letest/ole2ui/dllfuncs.c110
-rw-r--r--private/oleutest/letest/ole2ui/drawicon.c729
-rw-r--r--private/oleutest/letest/ole2ui/edlinks.h135
-rw-r--r--private/oleutest/letest/ole2ui/egares.bmpbin0 -> 6838 bytes
-rw-r--r--private/oleutest/letest/ole2ui/enumfetc.c308
-rw-r--r--private/oleutest/letest/ole2ui/enumfetc.h13
-rw-r--r--private/oleutest/letest/ole2ui/enumstat.c336
-rw-r--r--private/oleutest/letest/ole2ui/filelist.mk75
-rw-r--r--private/oleutest/letest/ole2ui/fileopen.dlg33
-rw-r--r--private/oleutest/letest/ole2ui/geticon.c1177
-rw-r--r--private/oleutest/letest/ole2ui/geticon.h18
-rw-r--r--private/oleutest/letest/ole2ui/hatch.c325
-rw-r--r--private/oleutest/letest/ole2ui/hivgares.bmpbin0 -> 20326 bytes
-rw-r--r--private/oleutest/letest/ole2ui/icon.c857
-rw-r--r--private/oleutest/letest/ole2ui/icon.dlg48
-rw-r--r--private/oleutest/letest/ole2ui/icon.h59
-rw-r--r--private/oleutest/letest/ole2ui/iconbox.c253
-rw-r--r--private/oleutest/letest/ole2ui/iconbox.h31
-rw-r--r--private/oleutest/letest/ole2ui/insobj.c1724
-rw-r--r--private/oleutest/letest/ole2ui/insobj.dlg51
-rw-r--r--private/oleutest/letest/ole2ui/insobj.h52
-rw-r--r--private/oleutest/letest/ole2ui/links.c2146
-rw-r--r--private/oleutest/letest/ole2ui/links.dlg35
-rw-r--r--private/oleutest/letest/ole2ui/makefile12
-rw-r--r--private/oleutest/letest/ole2ui/makefile.32590
-rw-r--r--private/oleutest/letest/ole2ui/makefile.old607
-rw-r--r--private/oleutest/letest/ole2ui/makelib503
-rw-r--r--private/oleutest/letest/ole2ui/msgfiltr.c809
-rw-r--r--private/oleutest/letest/ole2ui/msgfiltr.h64
-rw-r--r--private/oleutest/letest/ole2ui/objfdbk.c246
-rw-r--r--private/oleutest/letest/ole2ui/ole2ui.c971
-rw-r--r--private/oleutest/letest/ole2ui/ole2ui.h958
-rw-r--r--private/oleutest/letest/ole2ui/ole2ui.mak272
-rw-r--r--private/oleutest/letest/ole2ui/ole2ui.rc65
-rw-r--r--private/oleutest/letest/ole2ui/olestd.c3048
-rw-r--r--private/oleutest/letest/ole2ui/olestd.h852
-rw-r--r--private/oleutest/letest/ole2ui/olestr.c32
-rw-r--r--private/oleutest/letest/ole2ui/olestr.h21
-rw-r--r--private/oleutest/letest/ole2ui/olethunk.c649
-rw-r--r--private/oleutest/letest/ole2ui/olethunk.h193
-rw-r--r--private/oleutest/letest/ole2ui/oleutl.c660
-rw-r--r--private/oleutest/letest/ole2ui/outlui.d32138
-rw-r--r--private/oleutest/letest/ole2ui/pastespl.c1713
-rw-r--r--private/oleutest/letest/ole2ui/pastespl.dlg40
-rw-r--r--private/oleutest/letest/ole2ui/pastespl.h110
-rw-r--r--private/oleutest/letest/ole2ui/precomp.c23
-rw-r--r--private/oleutest/letest/ole2ui/prompt.dlg80
-rw-r--r--private/oleutest/letest/ole2ui/regdb.c401
-rw-r--r--private/oleutest/letest/ole2ui/regdb.h8
-rw-r--r--private/oleutest/letest/ole2ui/resimage.c363
-rw-r--r--private/oleutest/letest/ole2ui/resimage.h61
-rw-r--r--private/oleutest/letest/ole2ui/stdpal.c94
-rw-r--r--private/oleutest/letest/ole2ui/stdpal.h292
-rw-r--r--private/oleutest/letest/ole2ui/strings.rc124
-rw-r--r--private/oleutest/letest/ole2ui/suminfo.cpp1371
-rw-r--r--private/oleutest/letest/ole2ui/suminfo.h331
-rw-r--r--private/oleutest/letest/ole2ui/targtdev.c328
-rw-r--r--private/oleutest/letest/ole2ui/template.c243
-rw-r--r--private/oleutest/letest/ole2ui/template.h119
-rw-r--r--private/oleutest/letest/ole2ui/uiclass.h2
-rw-r--r--private/oleutest/letest/ole2ui/uimake.cmd1
-rw-r--r--private/oleutest/letest/ole2ui/uimake.ini24
-rw-r--r--private/oleutest/letest/ole2ui/utility.c1039
-rw-r--r--private/oleutest/letest/ole2ui/utility.h37
-rw-r--r--private/oleutest/letest/ole2ui/verlocal.h54
-rw-r--r--private/oleutest/letest/ole2ui/vgares.bmpbin0 -> 9078 bytes
-rw-r--r--private/oleutest/letest/ole2ui/wn_dos.h174
-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
-rw-r--r--private/oleutest/letest/readme.txt11
228 files changed, 83674 insertions, 0 deletions
diff --git a/private/oleutest/letest/bttncur/bttncur.c b/private/oleutest/letest/bttncur/bttncur.c
new file mode 100644
index 000000000..4e5dee40f
--- /dev/null
+++ b/private/oleutest/letest/bttncur/bttncur.c
@@ -0,0 +1,1070 @@
+/*
+ * BTTNCUR.C
+ * Buttons & Cursors Version 1.1, Win32 version August 1993
+ *
+ * Public functions to generate different states of toolbar buttons from
+ * a single bitmap. States are normal, pressed, checked, and disabled.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+#ifdef WIN32
+#define _INC_OLE
+#define __RPC_H__
+#endif
+
+#include <windows.h>
+#include <memory.h>
+#include "bttncur.h"
+#include "bttncuri.h"
+
+
+//Display sensitive information
+TOOLDISPLAYDATA tdd;
+
+//Library instance
+HINSTANCE ghInst;
+
+
+//Cache GDI objects to speed drawing.
+HDC hDCGlyphs = NULL;
+HDC hDCMono = NULL;
+HBRUSH hBrushDither = NULL;
+
+// Common clean up code
+void FAR PASCAL WEP(int bSystemExit);
+
+
+//Standard images to use in case caller doesn't provide them
+HBITMAP rghBmpStandardImages[3];
+
+//Standard button colors.
+const COLORREF crStandard[4]={ RGB(0, 0, 0) //STDCOLOR_BLACK
+ , RGB(128, 128, 128) //STDCOLOR_DKGRAY
+ , RGB(192, 192, 192) //STDCOLOR_LTGRAY
+ , RGB(255, 255, 255)}; //STDCOLOR_WHITE
+
+
+/*
+ * Mapping from image identifier to button type (command/attribute).
+ * Version 1.00 of this DLL has no attribute images defined, so
+ * the code will only support three states for each command
+ * button. Any state is, however, valid for an application
+ * defined image.
+ */
+
+UINT mpButtonType[TOOLIMAGE_MAX-TOOLIMAGE_MIN+1]=
+ {
+ BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND,
+ BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND,
+ BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND
+ };
+
+
+
+/*
+ * LibMain
+ *
+ * Purpose:
+ * Entry point conditionally compiled for Windows NT and Windows
+ * 3.1. Provides the proper structure for each environment
+ * and calls InternalLibMain for real initialization.
+ */
+
+#ifdef WIN32
+BOOL _cdecl LibMain(
+ HINSTANCE hDll,
+ DWORD dwReason,
+ LPVOID lpvReserved)
+ {
+ if (DLL_PROCESS_ATTACH == dwReason)
+ {
+ return FInitialize(hDll);
+ }
+ else if (DLL_PROCESS_DETACH == dwReason)
+ {
+ WEP(0);
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
+#else
+HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg
+ , WORD cbHeapSize, LPSTR lpCmdLine)
+ {
+ //Perform global initialization.
+ if (FInitialize(hInstance))
+ {
+ if (0!=cbHeapSize)
+ UnlockData(0);
+ }
+
+ return hInstance;
+ }
+#endif
+
+
+
+
+/*
+ * FInitialize
+ *
+ * Purpose:
+ * Initialization function for the DLL.
+ *
+ * Parameters:
+ * hInstance HANDLE instance of the DLL.
+ *
+ * Return Value:
+ * BOOL TRUE if the function was successful, FALSE otherwise.
+ */
+
+BOOL FInitialize(HANDLE hInstance)
+ {
+ UINT i;
+
+ /*
+ * To remain backwards compatible with 1.0 we'll default to 96DPI
+ * like we forced in the older version. If the application calls
+ * UIToolButtonDraw we use the values here. If the application
+ * calls UIToolButtonDrawTDD then we use the pointer to the
+ * application-provided TOOLDISPLAYDATA structure.
+ */
+ tdd.uDPI =96;
+ tdd.cyBar =CYBUTTONBAR96;
+ tdd.cxButton =TOOLBUTTON_STD96WIDTH;
+ tdd.cyButton =TOOLBUTTON_STD96HEIGHT;
+ tdd.cxImage =TOOLBUTTON_STD96IMAGEWIDTH;
+ tdd.cyImage =TOOLBUTTON_STD96IMAGEHEIGHT;
+ tdd.uIDImages=IDB_STANDARDIMAGES96;
+
+ for (i=0; i < 3; i++)
+ {
+ rghBmpStandardImages[i]=LoadBitmap(hInstance
+ , MAKEINTRESOURCE(IDB_STANDARDIMAGESMIN+i));
+
+ if (NULL==rghBmpStandardImages[i])
+ return FALSE;
+ }
+
+ ghInst=hInstance;
+
+ //Perform global initialization.
+ if (ToolButtonInit())
+ {
+ CursorsCache(hInstance);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+
+
+/*
+ * WEP
+ *
+ * Purpose:
+ * Required DLL Exit function. Does nothing.
+ *
+ * Parameters:
+ * bSystemExit BOOL indicating if the system is being shut
+ * down or the DLL has just been unloaded.
+ *
+ * Return Value:
+ * void
+ *
+ */
+
+void FAR PASCAL WEP(int bSystemExit)
+ {
+ /*
+ * **Developers: Note that WEP is called AFTER Windows does any
+ * automatic task cleanup. You may see warnings for
+ * that two DCs, a bitmap, and a brush, were not
+ * deleted before task termination. THIS IS NOT A
+ * PROBLEM WITH THIS CODE AND IT IS NOT A BUG. This
+ * WEP function is properly called and performs the
+ * cleanup as appropriate. The fact that Windows is
+ * calling WEP after checking task cleanup is not
+ * something we can control. Just to prove it, the
+ * OutputDebugStrings in this and ToolButtonFree
+ * show that the code is exercised.
+ */
+
+ #ifdef DEBUG
+ OutputDebugString("BTTNCUR.DLL: WEP Entry\r\n");
+ OutputDebugString("BTTNCUR.DLL: The two DC's, the brush, and the three\r\n");
+ OutputDebugString("BTTNCUR.DLL: bitmaps that Debug Windows shows\r\n");
+ OutputDebugString("BTTNCUR.DLL: above were detected BEFORE this WEP\r\n");
+ OutputDebugString("BTTNCUR.DLL: had a chance to do it! NOT A BUG!\r\n");
+ #endif
+
+ CursorsFree();
+ ToolButtonFree();
+
+ #ifdef DEBUG
+ OutputDebugString("BTTNCUR.DLL: WEP Exit\r\n");
+ #endif
+ return;
+ }
+
+
+
+
+
+/*
+ * UIToolConfigureForDisplay
+ * Public API
+ *
+ * Purpose:
+ * Initializes the library to scale button images for the display type.
+ * Without calling this function the library defaults to 96 DPI (VGA).
+ * By calling this function an application acknowledges that it must
+ * use the data returned from this function to configure itself for
+ * the display.
+ *
+ * Parameters:
+ * lpDD LPTOOLDISPLAYDATA to fill with the display-sensitive
+ * size values.
+ *
+ * Return Value:
+ * BOOL TRUE if the sizes were obtained, FALSE otherwise.
+ */
+
+BOOL WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA lpDD)
+ {
+ int cy;
+ HDC hDC;
+
+
+ if (NULL==lpDD || IsBadWritePtr(lpDD, sizeof(TOOLDISPLAYDATA)))
+ return FALSE;
+
+ /*
+ * Determine the aspect ratio of the display we're currently
+ * running on and calculate the necessary information.
+ *
+ * By retrieving the logical Y extent of the display driver, you
+ * only have limited possibilities:
+ * LOGPIXELSY Display
+ * ----------------------------------------
+ * 48 CGA (unsupported)
+ * 72 EGA
+ * 96 VGA
+ * 120 8514/a (i.e. HiRes VGA)
+ */
+
+ hDC=GetDC(NULL);
+
+ if (NULL==hDC)
+ return FALSE;
+
+ cy=GetDeviceCaps(hDC, LOGPIXELSY);
+ ReleaseDC(NULL, hDC);
+
+ /*
+ * Instead of single comparisons, check ranges instead, so in case
+ * we get something funky, we'll act reasonable.
+ */
+ if (72 >=cy)
+ {
+ lpDD->uDPI =72;
+ lpDD->cyBar =CYBUTTONBAR72;
+ lpDD->cxButton =TOOLBUTTON_STD72WIDTH;
+ lpDD->cyButton =TOOLBUTTON_STD72HEIGHT;
+ lpDD->cxImage =TOOLBUTTON_STD72IMAGEWIDTH;
+ lpDD->cyImage =TOOLBUTTON_STD72IMAGEHEIGHT;
+ lpDD->uIDImages=IDB_STANDARDIMAGES72;
+ }
+ else
+ {
+ if (72 < cy && 120 > cy)
+ {
+ lpDD->uDPI =96;
+ lpDD->cyBar =CYBUTTONBAR96;
+ lpDD->cxButton =TOOLBUTTON_STD96WIDTH;
+ lpDD->cyButton =TOOLBUTTON_STD96HEIGHT;
+ lpDD->cxImage =TOOLBUTTON_STD96IMAGEWIDTH;
+ lpDD->cyImage =TOOLBUTTON_STD96IMAGEHEIGHT;
+ lpDD->uIDImages=IDB_STANDARDIMAGES96;
+ }
+ else
+ {
+ lpDD->uDPI =120;
+ lpDD->cyBar =CYBUTTONBAR120;
+ lpDD->cxButton =TOOLBUTTON_STD120WIDTH;
+ lpDD->cyButton =TOOLBUTTON_STD120HEIGHT;
+ lpDD->cxImage =TOOLBUTTON_STD120IMAGEWIDTH;
+ lpDD->cyImage =TOOLBUTTON_STD120IMAGEHEIGHT;
+ lpDD->uIDImages=IDB_STANDARDIMAGES120;
+ }
+ }
+
+ return TRUE;
+ }
+
+
+
+
+
+
+
+
+/*
+ * ToolButtonInit
+ * Internal
+ *
+ * Purpose:
+ * Initializes GDI objects for drawing images through UIToolButtonDraw.
+ * If the function fails, the function has already performed proper
+ * cleanup.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * BOOL TRUE if initialization succeeded. FALSE otherwise.
+ */
+
+static BOOL ToolButtonInit(void)
+ {
+ COLORREF rgbHi;
+
+ //DC for BitBltting the image (the glyph)
+ hDCGlyphs=CreateCompatibleDC(NULL);
+
+ //Create a monochrome DC and a brush for doing pattern dithering.
+ hDCMono=CreateCompatibleDC(NULL);
+
+ //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white.
+ if (0x0300 < (UINT)GetVersion())
+ rgbHi=GetSysColor(COLOR_BTNHIGHLIGHT);
+ else
+ rgbHi=crStandard[STDCOLOR_WHITE];
+
+ hBrushDither=HBrushDitherCreate(GetSysColor(COLOR_BTNFACE), rgbHi);
+
+ if (NULL==hDCGlyphs || NULL==hDCMono || NULL==hBrushDither)
+ {
+ //On failure, cleanup whatever might have been allocated.
+ ToolButtonFree();
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+
+
+
+
+/*
+ * ToolButtonFree
+ * Internal
+ *
+ * Purpose:
+ * Free all GDI allocations made during initialization. Note that the
+ * DEBUG output included here shows that WEP is called and cleanup actually
+ * occurs. However, if you watch debug output in DBWIN or on a terminal,
+ * the debugging version of Windows does automatic app cleanup before WEP
+ * is called, leading some to believe that this code is buggy. The
+ * debug output below shows that we do perform all necessary cleanup.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * None
+ */
+
+static void ToolButtonFree(void)
+ {
+ UINT i;
+
+ if (NULL!=hDCMono)
+ DeleteDC(hDCMono);
+
+ hDCMono=NULL;
+
+ if (NULL!=hDCGlyphs)
+ DeleteDC(hDCGlyphs);
+
+ hDCGlyphs=NULL;
+
+ if (NULL!=hBrushDither)
+ DeleteObject(hBrushDither);
+
+ hBrushDither=NULL;
+
+ for (i=0; i < 3; i++)
+ {
+ if (NULL!=rghBmpStandardImages[i])
+ DeleteObject(rghBmpStandardImages[i]);
+ rghBmpStandardImages[i]=NULL;
+ }
+
+ return;
+ }
+
+
+
+
+
+/*
+ * HBrushDitherCreate
+ * Internal
+ *
+ * Purpose:
+ * Creates and returns a handle to a pattern brush created from
+ * an 8*8 monochrome pattern bitmap. We use the button face and
+ * highlight colors to indicate the resulting colors of a PatBlt
+ * using this brush.
+ *
+ * Parameters:
+ * rgbFace COLORREF of the button face color.
+ * rgbHilight COLORREF of the button highlight color.
+ *
+ * Return Value:
+ * HBITMAP Handle to the dither bitmap.
+ */
+
+static HBRUSH HBrushDitherCreate(COLORREF rgbFace, COLORREF rgbHilight)
+ {
+ struct //BITMAPINFO with 16 colors
+ {
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[16];
+ } bmi;
+
+ HBRUSH hBrush=NULL;
+ DWORD patGray[8];
+ HDC hDC;
+ HBITMAP hBmp;
+ static COLORREF rgbFaceOld =0xFFFFFFFF; //Initially an impossible color
+ static COLORREF rgbHilightOld=0xFFFFFFFF; //so at first we always create
+
+ /*
+ * If the colors haven't changed from last time, just return the
+ * existing brush.
+ */
+ if (rgbFace==rgbFaceOld && rgbHilight==rgbHilightOld)
+ return hBrushDither;
+
+ rgbFaceOld=rgbFace;
+ rgbHilightOld=rgbHilight;
+
+ /*
+ * We're going to create an 8*8 brush for PatBlt using the
+ * button face color and button highlight color. We use this
+ * brush to affect the pressed state and the disabled state.
+ */
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = 8;
+ bmi.bmiHeader.biHeight = 8;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 1;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter= 0;
+ bmi.bmiHeader.biYPelsPerMeter= 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+
+ bmi.bmiColors[0].rgbBlue = GetBValue(rgbFace);
+ bmi.bmiColors[0].rgbGreen = GetGValue(rgbFace);
+ bmi.bmiColors[0].rgbRed = GetRValue(rgbFace);
+ bmi.bmiColors[0].rgbReserved = 0;
+
+ bmi.bmiColors[1].rgbBlue = GetBValue(rgbHilight);
+ bmi.bmiColors[1].rgbGreen = GetGValue(rgbHilight);
+ bmi.bmiColors[1].rgbRed = GetRValue(rgbHilight);
+ bmi.bmiColors[1].rgbReserved = 0;
+
+ //Create the byte array for CreateDIBitmap.
+ patGray[6]=patGray[4]=patGray[2]=patGray[0]=0x5555AAAAL;
+ patGray[7]=patGray[5]=patGray[3]=patGray[1]=0xAAAA5555L;
+
+ //Create the bitmap
+ hDC=GetDC(NULL);
+ hBmp=CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT, patGray
+ , (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
+ ReleaseDC(NULL, hDC);
+
+ //Create the brush from the bitmap
+ if (NULL!=hBmp)
+ {
+ hBrush=CreatePatternBrush(hBmp);
+ DeleteObject(hBmp);
+ }
+
+ /*
+ * If we could recreate a brush, clean up and make it the current
+ * pattern. Otherwise the best we can do it return the old one,
+ * which will be colored wrong, but at least it works.
+ */
+ if (NULL!=hBrush)
+ {
+ if (NULL!=hBrushDither)
+ DeleteObject(hBrushDither);
+
+ hBrushDither=hBrush;
+ }
+
+ return hBrushDither;
+ }
+
+
+
+
+
+/*
+ * UIToolButtonDraw
+ * Public API
+ *
+ * Purpose:
+ * Draws the complete image of a toolbar-style button with a given
+ * image in the center and in a specific state. The button is drawn
+ * on a specified hDC at a given location, so this function is useful
+ * on standard owner-draw buttons as well as on toolbar controls that
+ * have only one window but show images of multiple buttons.
+ *
+ * Parameters:
+ * hDC HDC on which to draw.
+ * x, y int coordinates at which to draw.
+ * dx, dy int dimensions of the *button*, not necessarily the image.
+ * hBmp HBITMAP from which to draw the image.
+ * bmx, bmy int dimensions of each bitmap in hBmp. If hBmp is NULL
+ * then these are forced to the standard sizes.
+ * iImage int index to the image to draw in the button
+ * uStateIn UINT containing the state index for the button and the
+ * color control bits.
+ *
+ * Return Value:
+ * BOOL TRUE if drawing succeeded, FALSE otherwise meaning that
+ * hDC is NULL or hBmp is NULL and iImage is not a valid
+ * index for a standard image.
+ */
+
+BOOL WINAPI UIToolButtonDraw(HDC hDC, int x, int y, int dx, int dy
+ , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn)
+ {
+ return UIToolButtonDrawTDD(hDC, x, y, dx, dy, hBmp, bmx, bmy, iImage
+ , uStateIn, &tdd);
+ }
+
+
+
+
+
+
+/*
+ * UIToolButtonDrawTDD
+ * Public API
+ *
+ * Purpose:
+ * Draws the complete image of a toolbar-style button with a given
+ * image in the center and in a specific state. The button is drawn
+ * on a specified hDC at a given location, so this function is useful
+ * on standard owner-draw buttons as well as on toolbar controls that
+ * have only one window but show images of multiple buttons.
+ *
+ * This is the same as UIToolButtonDraw but adds the pTDD configuration
+ * structure. UIToolButtonDraw calls us with that pointing to the
+ * default 96dpi structure.
+ *
+ * Parameters:
+ * hDC HDC on which to draw.
+ * x, y int coordinates at which to draw.
+ * dx, dy int dimensions of the *button*, not necessarily the image.
+ * hBmp HBITMAP from which to draw the image.
+ * bmx, bmy int dimensions of each bitmap in hBmp. If hBmp is NULL
+ * then these are forced to the standard sizes.
+ * iImage int index to the image to draw in the button
+ * uStateIn UINT containing the state index for the button and the
+ * color control bits.
+ * pTDD LPTOOLDISPLAYDATA containing display configuration.
+ * Can be NULL if hBmp is non-NULL.
+ *
+ * Return Value:
+ * BOOL TRUE if drawing succeeded, FALSE otherwise meaning that
+ * hDC is NULL or hBmp is NULL and iImage is not a valid
+ * index for a standard image.
+ */
+
+BOOL WINAPI UIToolButtonDrawTDD(HDC hDC, int x, int y, int dx, int dy
+ , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn
+ , LPTOOLDISPLAYDATA pTDD)
+ {
+ static COLORREF crSys[5]; //Avoid stack arrays in DLLs: use static
+ UINT uState=(UINT)LOBYTE((WORD)uStateIn);
+ UINT uColors=(UINT)HIBYTE((WORD)uStateIn & PRESERVE_ALL);
+ int xOffsetGlyph, yOffsetGlyph;
+ int i, iSaveDC;
+ HDC hMemDC;
+ HGDIOBJ hObj;
+ HBRUSH hBR;
+ HBITMAP hBmpT;
+ HBITMAP hBmpMono;
+ HBITMAP hBmpMonoOrg;
+ HBITMAP hBmpSave=NULL;
+
+ if (NULL==hDC)
+ return FALSE;
+
+ /*
+ * If we're given no image bitmap, then use the standard and validate the
+ * image index. We also enforce the standard bitmap size and the size of
+ * the button (as requested by User Interface designers).
+ */
+ if (NULL==hBmp && !(uState & BUTTONGROUP_BLANK))
+ {
+ hBmp=rghBmpStandardImages[pTDD->uIDImages-IDB_STANDARDIMAGESMIN];
+
+ bmx=pTDD->cxImage; //Force bitmap dimensions
+ bmy=pTDD->cyImage;
+
+ dx=pTDD->cxButton; //Force button dimensions
+ dy=pTDD->cyButton;
+
+ if (iImage > TOOLIMAGE_MAX)
+ return FALSE;
+
+ /*
+ * If we are using a standard command button, verify that the state
+ * does not contain the LIGHTFACE group which only applies to
+ * attribute buttons.
+ */
+ if (BUTTONTYPE_COMMAND==mpButtonType[iImage]
+ && (uState & BUTTONGROUP_LIGHTFACE))
+ return FALSE;
+ }
+
+ //Create a dithered bitmap.
+ hBmpMono=CreateBitmap(dx-2, dy-2, 1, 1, NULL);
+
+ if (NULL==hBmpMono)
+ return FALSE;
+
+ hBmpMonoOrg=(HBITMAP)SelectObject(hDCMono, hBmpMono);
+
+
+ //Save the DC state before we munge on it.
+ iSaveDC=SaveDC(hDC);
+
+ /*
+ * Draw a button sans image. This also fills crSys with the system
+ * colors for us which has space for five colors. We don't use the
+ * fifth, the frame color, in this function.
+ */
+ DrawBlankButton(hDC, x, y, dx, dy, (BOOL)(uState & BUTTONGROUP_DOWN), crSys);
+
+ //Shift coordinates to account for the button's border
+ x++;
+ y++;
+ dx-=2;
+ dy-=2;
+
+ /*
+ * Determine the offset necessary to center the image but also reflect
+ * the pushed-in state, which means just adding 1 to the up state.
+ */
+ i=(uState & BUTTONGROUP_DOWN) ? 1 : 0;
+ xOffsetGlyph=((dx-bmx) >> 1)+i;
+ yOffsetGlyph=((dy-bmy) >> 1)+i;
+
+
+ //Select the given image bitmap into the glyph DC before calling MaskCreate
+ if (NULL!=hBmp)
+ hBmpSave=(HBITMAP)SelectObject(hDCGlyphs, hBmp);
+
+
+ /*
+ * Draw the face on the button. If we have an up or [mouse]down
+ * button then we can just draw it as-is. For indeterminate,
+ * disabled, or down disabled we have to gray the image and possibly
+ * add a white shadow to it (disabled/down disabled).
+ *
+ * Also note that for the intermediate state we first draw the normal
+ * up state, then proceed to add disabling looking highlights.
+ */
+
+ //Up, mouse down, down, indeterminate
+ if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK))
+ {
+ BOOL fColorsSame=TRUE;
+
+ /*
+ * In here we pay close attention to the system colors. Where
+ * the source image is black, we paint COLOR_BTNTEXT. Where
+ * light gray, we paint COLOR_BTNFACE. Where dark gray we paint
+ * COLOR_BTNSHADOW, and where white we paint COLOR_BTNHILIGHT.
+ *
+ * The uColors variable contains flags to prevent color
+ * conversion. To do a little optimization, we just do a
+ * single BitBlt if we're preserving all colors or if no colors
+ * are different than the standards, which is by far the most
+ * common case. Otherwise, cycle through the four colors we can
+ * convert and do a BitBlt that converts it to the system color.
+ */
+
+ //See what colors are different.
+ for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++)
+ fColorsSame &= (crSys[i]==crStandard[i]);
+
+ if (PRESERVE_ALL==uColors || fColorsSame)
+ {
+ BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, bmx, bmy
+ , hDCGlyphs, iImage*bmx, 0, SRCCOPY);
+ }
+ else
+ {
+ /*
+ * Cycle through hard-coded colors and create a mask that has all
+ * regions of that color in white and all other regions black.
+ * Then we select a pattern brush of the color to convert to:
+ * if we aren't converting the color then we use a brush of
+ * the standard hard-coded color, otherwise we use the actual
+ * system color. The ROP_DSPDxax means that anything that's
+ * 1's in the mask get the pattern, anything that's 0 is unchanged
+ * in the destination.
+ *
+ * To prevent too many Blts to the screen, we use an intermediate
+ * bitmap and DC.
+ */
+
+ hMemDC=CreateCompatibleDC(hDC);
+
+ //Make sure conversion of monochrome to color stays B&W
+ SetTextColor(hMemDC, 0L); //0's in mono -> 0
+ SetBkColor(hMemDC, (COLORREF)0x00FFFFFF); //1's in mono -> 1
+
+ hBmpT=CreateCompatibleBitmap(hDC, bmx, bmy);
+ SelectObject(hMemDC, hBmpT);
+
+ //Copy the unmodified bitmap to the temporary bitmap
+ BitBlt(hMemDC, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);
+
+ for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++)
+ {
+ //Convert pixels of the color to convert to 1's in the mask
+ SetBkColor(hDCGlyphs, crStandard[i]);
+ BitBlt(hDCMono, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);
+
+ //Preserve or modify the color depending on the flag.
+ hBR=CreateSolidBrush((uColors & (1 << i))
+ ? crStandard[i] : crSys[i]);
+
+ if (NULL!=hBR)
+ {
+ hObj=SelectObject(hMemDC, hBR);
+
+ if (NULL!=hObj)
+ {
+ BitBlt(hMemDC, 0, 0, dx-1, dy-1, hDCMono, 0, 0, ROP_DSPDxax);
+ SelectObject(hMemDC, hObj);
+ }
+
+ DeleteObject(hBR);
+ }
+ }
+
+ //Now put the final version on the display and clean up
+ BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, dx-1, dy-1
+ , hMemDC, 0, 0, SRCCOPY);
+
+ DeleteDC(hMemDC);
+ DeleteObject(hBmpT);
+
+ }
+ }
+
+
+ //Disabled and indeterminate states (unless we're blank)
+ if ((uState & BUTTONGROUP_DISABLED || ATTRIBUTEBUTTON_INDETERMINATE==uState)
+ && !(uState & BUTTONGROUP_BLANK))
+ {
+ //Grayed state (up or down, no difference)
+ MaskCreate(iImage, dx, dy, bmx, bmy, xOffsetGlyph, yOffsetGlyph, 0);
+
+ //Make sure conversion of monochrome to color stays B&W
+ SetTextColor(hDC, 0L); //0's in mono -> 0
+ SetBkColor(hDC, (COLORREF)0x00FFFFFF); //1's in mono -> 1
+
+ //If we're disabled, up or down, draw the highlighted shadow.
+ if (uState & BUTTONGROUP_DISABLED)
+ {
+ hBR=CreateSolidBrush(crSys[SYSCOLOR_HILIGHT]);
+
+ if (NULL!=hBR)
+ {
+ hObj=SelectObject(hDC, hBR);
+
+ if (NULL!=hObj)
+ {
+ //Draw hilight color where we have 0's in the mask
+ BitBlt(hDC, x+1, y+1, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax);
+ SelectObject(hDC, hObj);
+ }
+ DeleteObject(hBR);
+ }
+ }
+
+ //Draw the gray image.
+ hBR=CreateSolidBrush(crSys[SYSCOLOR_SHADOW]);
+
+ if (NULL!=hBR)
+ {
+ hObj=SelectObject(hDC, hBR);
+
+ if (NULL!=hObj)
+ {
+ //Draw the shadow color where we have 0's in the mask
+ BitBlt(hDC, x, y, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax);
+ SelectObject(hDC, hObj);
+ }
+
+ DeleteObject(hBR);
+ }
+ }
+
+ //If the button is selected do the dither brush avoiding the glyph
+ if (uState & BUTTONGROUP_LIGHTFACE)
+ {
+ HBRUSH hBRDither;
+
+ /*
+ * Get the dither brush. This function will recreate it if
+ * necessary or return the global one if the colors already match.
+ */
+ hBRDither=HBrushDitherCreate(crSys[SYSCOLOR_FACE], crSys[SYSCOLOR_HILIGHT]);
+ hObj=SelectObject(hDC, hBRDither);
+
+ if (NULL!=hObj)
+ {
+ /*
+ * The mask we create now determines where the dithering
+ * ends up. In the down disabled state, we have to preserve
+ * the highlighted shadow, so the mask we create must have
+ * two masks of the original glyph, one of them offset by
+ * one pixel in both x & y. For the indeterminate state,
+ * we have to mask all highlighted areas. The state passed
+ * to MaskCreate matters here (we've used zero before).
+ */
+ MaskCreate(iImage, dx, dy, bmx, bmy
+ , xOffsetGlyph-1, yOffsetGlyph-1, uState);
+
+ //Convert monochrome masks to B&W color bitmap in the BitBlt.
+ SetTextColor(hDC, 0L);
+ SetBkColor(hDC, (COLORREF)0x00FFFFFF);
+
+ /*
+ * Only draw the dither brush where the mask is 1's. For
+ * the indeterminate state we have to not overdraw the
+ * shadow highlight so we use dx-3, dy-3 instead of dx-1
+ * and dy-1. We do this whether or not we're blank.
+ */
+ i=(ATTRIBUTEBUTTON_INDETERMINATE==uState
+ || BLANKBUTTON_INDETERMINATE==uState) ? 3 : 1;
+
+ BitBlt(hDC, x+1, y+1, dx-i, dy-i, hDCMono, 0, 0, ROP_DSPDxax);
+ SelectObject(hDC, hObj);
+ }
+
+ //DO NOT delete hBRDither! It's a reference to a shared global.
+ }
+
+ //Cleanup hDCGlyphs: Must do AFTER calling MaskCreate
+ if (NULL!=hBmpSave)
+ SelectObject(hDCGlyphs, hBmpSave);
+
+ SelectObject(hDCMono, hBmpMonoOrg);
+ DeleteObject(hBmpMono);
+
+ //Restore everything in the DC.
+ RestoreDC(hDC, iSaveDC);
+ return TRUE;
+ }
+
+
+
+
+
+
+/*
+ * DrawBlankButton
+ *
+ * Purpose:
+ * Draws a button with no face using the current system colors in either
+ * an up or down state.
+ *
+ * Parameters:
+ * hDC HDC on which to draw
+ * x, y int coordinates where we start drawing
+ * dx,dy int size of the button
+ * fDown BOOL indicating the up or down state of the button
+ * pcr COLORREF FAR * to five colors in which we store text,
+ * shadow, face, highlight, and frame colors. This is
+ * a matter of convenience for the caller, since we have
+ * to load these colors anyway we might as well send them
+ * back.
+ *
+ * Return Value:
+ * None
+ */
+
+static void DrawBlankButton(HDC hDC, int x, int y, int dx, int dy
+ , BOOL fDown, COLORREF FAR *pcr)
+ {
+ //Get the current system colors for buttons.
+ pcr[0]=GetSysColor(COLOR_BTNTEXT);
+ pcr[1]=GetSysColor(COLOR_BTNSHADOW);
+ pcr[2]=GetSysColor(COLOR_BTNFACE);
+
+ //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white.
+ if (0x0300 < (UINT)GetVersion())
+ pcr[3]=GetSysColor(COLOR_BTNHIGHLIGHT);
+ else
+ pcr[3]=crStandard[STDCOLOR_WHITE];
+
+ pcr[4]=GetSysColor(COLOR_WINDOWFRAME);
+
+ //Draw the border around the button.
+ PatB(hDC, x+1, y, dx-2, 1, pcr[4]);
+ PatB(hDC, x+1, y+dy-1, dx-2, 1, pcr[4]);
+ PatB(hDC, x, y+1, 1, dy-2, pcr[4]);
+ PatB(hDC, x+dx-1, y+1, 1, dy-2, pcr[4]);
+
+ //Shift coordinates to account for the border we just drew
+ x++;
+ y++;
+ dx-=2;
+ dy-=2;
+
+ //Paint the interior grey as a default.
+ PatB(hDC, x, y, dx, dy, pcr[2]);
+
+ /*
+ * Draw shadows and highlights. The DOWN grouping that contains
+ * down, mouse down, and down disabled are drawn depressed. Up,
+ * indeterminate, and disabled are drawn up.
+ */
+
+ if (fDown)
+ {
+ PatB(hDC, x, y, 1, dy, pcr[1]);
+ PatB(hDC, x, y, dx, 1, pcr[1]);
+ }
+ else
+ {
+ //Normal button look.
+ PatB(hDC, x, y, 1, dy-1, pcr[3]);
+ PatB(hDC, x, y, dx-1, 1, pcr[3]);
+
+ PatB(hDC, x+dx-1, y, 1, dy, pcr[1]);
+ PatB(hDC, x, y+dy-1, dx, 1, pcr[1]);
+
+ PatB(hDC, x+1+dx-3, y+1, 1, dy-2, pcr[1]);
+ PatB(hDC, x+1, y+dy-2, dx-2, 1, pcr[1]);
+ }
+
+ return;
+ }
+
+
+
+
+
+
+/*
+ * PatB
+ * Internal
+ *
+ * Purpose:
+ * A more convenient PatBlt operation for drawing button borders and
+ * highlights.
+ *
+ * Parameters:
+ * hDC HDC on which to paint.
+ * x, y int coordinates at which to paint.
+ * dx, dy int dimensions of rectangle to paint.
+ * rgb COLORREF to use as the background color.
+ *
+ * Return Value:
+ * None
+ */
+
+static void PatB(HDC hDC, int x, int y, int dx, int dy, COLORREF rgb)
+ {
+ RECT rc;
+
+ SetBkColor(hDC, rgb);
+ SetRect(&rc, x, y, x+dx, y+dy);
+ ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
+ }
+
+
+
+
+/*
+ * MaskCreate
+ * Internal
+ *
+ * Purpose:
+ * Creates a monochrome mask bitmap of the given image at the given offset
+ * in the global hDCMono. Anywhere in the image that you have the light
+ * gray (STDCOLOR_LTGRAY) or the white highlight (STDCOLOR_WHITE) you get
+ * get 1's. All other pixels are 0's
+ *
+ * Parameters:
+ * iImage UINT index of the image for which to create a mask.
+ * dx, dy int dimensions of the button.
+ * bmx, bmy int dimensions of the bitmap to use.
+ * xOffset int offset for x inside hDCMono where we paint.
+ * yOffset int offset for y inside hDCMono where we paint.
+ * uState UINT state of the image. Special cases are made
+ * for ATTRIBUTEBUTTON_DOWNDISABLED and
+ * ATTRIBUTEBUTTON_INDETERMINATE. In any case where you
+ * do not want a special case, pass zero here, regardless
+ * of the true button state.
+ *
+ * Return Value:
+ * None
+ */
+
+static void MaskCreate(UINT iImage, int dx, int dy, int bmx, int bmy
+ ,int xOffset, int yOffset, UINT uState)
+ {
+ //Initalize whole area with zeros
+ PatBlt(hDCMono, 0, 0, dx, dy, WHITENESS);
+
+ if (uState & BUTTONGROUP_BLANK)
+ return;
+
+ //Convert face colored pixels to 1's. all others to black.
+ SetBkColor(hDCGlyphs, crStandard[STDCOLOR_LTGRAY]);
+ BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);
+
+ //In the indeterminate state, don't turn highlight's to 1's. Leave black.
+ if (ATTRIBUTEBUTTON_INDETERMINATE!=uState)
+ {
+ //Convert highlight colored pixels to 1's and OR them with the previous.
+ SetBkColor(hDCGlyphs, crStandard[STDCOLOR_WHITE]);
+ BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCPAINT);
+ }
+
+ /*
+ * For the down disabled state, AND this same mask with itself at an
+ * offset of 1, which accounts for the highlight shadow.
+ */
+ if (ATTRIBUTEBUTTON_DOWNDISABLED==uState)
+ BitBlt(hDCMono, 1, 1, dx-1, dy-1, hDCMono, 0, 0, SRCAND);
+
+ return;
+ }
diff --git a/private/oleutest/letest/bttncur/bttncur.h b/private/oleutest/letest/bttncur/bttncur.h
new file mode 100644
index 000000000..a9685c971
--- /dev/null
+++ b/private/oleutest/letest/bttncur/bttncur.h
@@ -0,0 +1,201 @@
+/*
+ * BTTNCUR.H
+ * Buttons & Cursors Version 1.1, March 1993
+ *
+ * Public include file for the Button Images and Cursor DLL, including
+ * structures, definitions, and function prototypes.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+
+#ifndef _BTTNCUR_H_
+#define _BTTNCUR_H_
+
+#ifdef __cplusplus
+extern "C"
+ {
+#endif
+
+
+//Standard image bitmap
+
+//WARNING: Obsolete. Use the return from UIToolDisplayData
+#define IDB_STANDARDIMAGES 400
+
+//New values for display types
+#define IDB_STANDARDIMAGESMIN 400
+#define IDB_STANDARDIMAGES96 400
+#define IDB_STANDARDIMAGES72 401
+#define IDB_STANDARDIMAGES120 402
+
+
+
+//Image indices inside the standard bitmap.
+#define TOOLIMAGE_MIN 0
+#define TOOLIMAGE_EDITCUT 0
+#define TOOLIMAGE_EDITCOPY 1
+#define TOOLIMAGE_EDITPASTE 2
+#define TOOLIMAGE_FILENEW 3
+#define TOOLIMAGE_FILEOPEN 4
+#define TOOLIMAGE_FILESAVE 5
+#define TOOLIMAGE_FILEPRINT 6
+#define TOOLIMAGE_HELP 7
+#define TOOLIMAGE_HELPCONTEXT 8
+#define TOOLIMAGE_MAX 8
+
+
+//Additional Standard Cursors as defined in the UI Design Guide.
+#define IDC_NEWUICURSORMIN 500
+#define IDC_RIGHTARROW 500
+#define IDC_CONTEXTHELP 501
+#define IDC_MAGNIFY 502
+#define IDC_NODROP 503
+#define IDC_TABLETOP 504
+#define IDC_HSIZEBAR 505
+#define IDC_VSIZEBAR 506
+#define IDC_HSPLITBAR 507
+#define IDC_VSPLITBAR 508
+#define IDC_SMALLARROWS 509
+#define IDC_LARGEARROWS 510
+#define IDC_HARROWS 511
+#define IDC_VARROWS 512
+#define IDC_NESWARROWS 513
+#define IDC_NWSEARROWS 514
+#define IDC_NEWUICURSORMAX 514
+
+
+
+//Standard sizes for toolbar buttons and bitmaps on display types
+
+//WARNING: These are obsolete for version 1.0 compatibility/
+#define TOOLBUTTON_STDWIDTH 24
+#define TOOLBUTTON_STDHEIGHT 22
+#define TOOLBUTTON_STDIMAGEWIDTH 16
+#define TOOLBUTTON_STDIMAGEHEIGHT 15
+
+/*
+ * Applications can call UIToolDisplayData to get the particular
+ * values to use for the current display instead of using these values
+ * directly. However, if the application has the aspect ratio already
+ * then these are available for them.
+ */
+
+//Sizes for 72 DPI (EGA)
+#define TOOLBUTTON_STD72WIDTH 24
+#define TOOLBUTTON_STD72HEIGHT 16
+#define TOOLBUTTON_STD72IMAGEWIDTH 16
+#define TOOLBUTTON_STD72IMAGEHEIGHT 11
+
+//Sizes for 96 DPI (VGA)
+#define TOOLBUTTON_STD96WIDTH 24
+#define TOOLBUTTON_STD96HEIGHT 22
+#define TOOLBUTTON_STD96IMAGEWIDTH 16
+#define TOOLBUTTON_STD96IMAGEHEIGHT 15
+
+//Sizes for 120 DPI (8514/a)
+#define TOOLBUTTON_STD120WIDTH 32
+#define TOOLBUTTON_STD120HEIGHT 31
+#define TOOLBUTTON_STD120IMAGEWIDTH 24
+#define TOOLBUTTON_STD120IMAGEHEIGHT 23
+
+
+//Sizes of a standard button bar depending on the display
+#define CYBUTTONBAR72 23
+#define CYBUTTONBAR96 29
+#define CYBUTTONBAR120 38
+
+
+
+/*
+ * The low-word of the state contains the display state where each
+ * value is mutually exclusive and contains one or more grouping bits.
+ * Each group represents buttons that share some sub-state in common.
+ *
+ * The high-order byte controls which colors in the source bitmap,
+ * black, white, gray, and dark gray, are to be converted into the
+ * system colors COLOR_BTNTEXT, COLOR_HILIGHT, COLOR_BTNFACE, and
+ * COLOR_BTNSHADOW. Any or all of these bits may be set to allow
+ * the application control over specific colors.
+ *
+ * The actual state values are split into a command group and an
+ * attribute group. Up, mouse down, and disabled states are identical,
+ * but only attributes can have down, down disabled, and indeterminate
+ * states.
+ *
+ * BUTTONGROUP_BLANK is defined so an application can draw only the button
+ * without an image in the up, down, mouse down, or indeterminate
+ * state, that is, BUTTONGROUP_BLANK is inclusive with BUTTONGROUP_DOWN
+ * and BUTTONGROUP_LIGHTFACE.
+ */
+
+
+#define BUTTONGROUP_DOWN 0x0001
+#define BUTTONGROUP_ACTIVE 0x0002
+#define BUTTONGROUP_DISABLED 0x0004
+#define BUTTONGROUP_LIGHTFACE 0x0008
+#define BUTTONGROUP_BLANK 0x0010
+
+//Command buttons only
+#define COMMANDBUTTON_UP (BUTTONGROUP_ACTIVE)
+#define COMMANDBUTTON_MOUSEDOWN (BUTTONGROUP_ACTIVE | BUTTONGROUP_DOWN)
+#define COMMANDBUTTON_DISABLED (BUTTONGROUP_DISABLED)
+
+//Attribute buttons only
+#define ATTRIBUTEBUTTON_UP (BUTTONGROUP_ACTIVE)
+#define ATTRIBUTEBUTTON_MOUSEDOWN (BUTTONGROUP_ACTIVE | BUTTONGROUP_DOWN)
+#define ATTRIBUTEBUTTON_DISABLED (BUTTONGROUP_DISABLED)
+#define ATTRIBUTEBUTTON_DOWN (BUTTONGROUP_ACTIVE | BUTTONGROUP_DOWN | BUTTONGROUP_LIGHTFACE)
+#define ATTRIBUTEBUTTON_INDETERMINATE (BUTTONGROUP_ACTIVE | BUTTONGROUP_LIGHTFACE)
+#define ATTRIBUTEBUTTON_DOWNDISABLED (BUTTONGROUP_DISABLED | BUTTONGROUP_DOWN | BUTTONGROUP_LIGHTFACE)
+
+//Blank buttons only
+#define BLANKBUTTON_UP (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK)
+#define BLANKBUTTON_DOWN (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK | BUTTONGROUP_DOWN | BUTTONGROUP_LIGHTFACE)
+#define BLANKBUTTON_MOUSEDOWN (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK | BUTTONGROUP_DOWN)
+#define BLANKBUTTON_INDETERMINATE (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK | BUTTONGROUP_LIGHTFACE)
+
+
+/*
+ * Specific bits to prevent conversions of specific colors to system
+ * colors. If an application uses this newer library and never specified
+ * any bits, then they benefit from color conversion automatically.
+ */
+#define PRESERVE_BLACK 0x0100
+#define PRESERVE_DKGRAY 0x0200
+#define PRESERVE_LTGRAY 0x0400
+#define PRESERVE_WHITE 0x0800
+
+#define PRESERVE_ALL (PRESERVE_BLACK | PRESERVE_DKGRAY | PRESERVE_LTGRAY | PRESERVE_WHITE)
+#define PRESERVE_NONE 0 //Backwards compatible
+
+
+
+//Structure for UIToolConfigureForDisplay
+typedef struct tagTOOLDISPLAYDATA
+ {
+ UINT uDPI; //Display driver DPI
+ UINT cyBar; //Vertical size for a bar containing buttons.
+ UINT cxButton; //Dimensions of a button.
+ UINT cyButton;
+ UINT cxImage; //Dimensions of bitmap image
+ UINT cyImage;
+ UINT uIDImages; //Standard resource ID for display-sensitive images
+ } TOOLDISPLAYDATA, FAR *LPTOOLDISPLAYDATA;
+
+
+
+//Public functions in BTTNCUR.DLL
+HCURSOR WINAPI UICursorLoad(UINT);
+BOOL WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA);
+BOOL WINAPI UIToolButtonDraw(HDC, int, int, int, int, HBITMAP, int, int, int, UINT);
+BOOL WINAPI UIToolButtonDrawTDD(HDC, int, int, int, int, HBITMAP, int, int, int, UINT, LPTOOLDISPLAYDATA);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif //_BTTNCUR_H_
diff --git a/private/oleutest/letest/bttncur/bttncur.rc b/private/oleutest/letest/bttncur/bttncur.rc
new file mode 100644
index 000000000..38ddfc2a9
--- /dev/null
+++ b/private/oleutest/letest/bttncur/bttncur.rc
@@ -0,0 +1,39 @@
+/*
+ * BTTNCUR.RC
+ * Buttons & Cursors Version 1.1, March 1993
+ *
+ * Resource file for the Button Image & Cursors DLL, including cursors and
+ * standard bitmaps.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+#include <windows.h>
+#include "bttncur.h"
+#include "bttncuri.h"
+
+IDB_STANDARDIMAGES72 BITMAP res\stdim72.bmp
+IDB_STANDARDIMAGES96 BITMAP res\stdim96.bmp
+IDB_STANDARDIMAGES120 BITMAP res\stdim120.bmp
+
+IDC_RIGHTARROW CURSOR res\rarrow.cur
+IDC_CONTEXTHELP CURSOR res\help.cur
+IDC_MAGNIFY CURSOR res\magnify.cur
+IDC_NODROP CURSOR res\nodrop.cur
+IDC_TABLETOP CURSOR res\tabletop.cur
+IDC_HSIZEBAR CURSOR res\sizebarh.cur
+IDC_VSIZEBAR CURSOR res\sizebarv.cur
+IDC_HSPLITBAR CURSOR res\splith.cur
+IDC_VSPLITBAR CURSOR res\splitv.cur
+IDC_SMALLARROWS CURSOR res\sarrows.cur
+IDC_LARGEARROWS CURSOR res\larrows.cur
+IDC_HARROWS CURSOR res\harrows.cur
+IDC_VARROWS CURSOR res\varrows.cur
+IDC_NESWARROWS CURSOR res\neswarrs.cur
+IDC_NWSEARROWS CURSOR res\nwsearrs.cur
+
+
+//Include the version information
+rcinclude bttncur.rcv
diff --git a/private/oleutest/letest/bttncur/bttncur.rcv b/private/oleutest/letest/bttncur/bttncur.rcv
new file mode 100644
index 000000000..7e3fcea4b
--- /dev/null
+++ b/private/oleutest/letest/bttncur/bttncur.rcv
@@ -0,0 +1,48 @@
+/*
+ * BTTNCUR.RCV
+ * Buttons & Cursors Version 1.1, Win32 version August 1993
+ *
+ * Version resource file for the Button Images and Cursors DLL.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+//Default is nodebug
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,1,0,0
+ PRODUCTVERSION 1,1,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VER_DEBUG
+ FILEOS VOS_DOS_WINDOWS16
+ FILETYPE VFT_DLL
+ FILESUBTYPE VFT_UNKNOWN
+
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0", "\0"
+ VALUE "FileDescription", "Microsoft Windows(TM) Standard Button Images and Cursors", "\0"
+ VALUE "FileVersion", "1.10\0", "\0"
+ VALUE "InternalName", "BTTNCUR.DLL", "\0"
+ VALUE "LegalCopyright", "Copyright \251 1993 Microsoft Corp.", "\0"
+ VALUE "OriginalFilename","BTTNCUR.DLL", "\0"
+ VALUE "ProductName", "Microsoft Windows(TM) Standard Button Images and Cursors", "\0"
+ VALUE "ProductVersion", "1.10\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x04E4
+ END
+ END
diff --git a/private/oleutest/letest/bttncur/bttncuri.h b/private/oleutest/letest/bttncur/bttncuri.h
new file mode 100644
index 000000000..53d088712
--- /dev/null
+++ b/private/oleutest/letest/bttncur/bttncuri.h
@@ -0,0 +1,88 @@
+/*
+ * BTTNCURI.H
+ *
+ * Private include file for the Button Images and Cursors DLL.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Right Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+#ifdef __cplusplus
+extern "C"
+ {
+#endif
+
+//Function prototypes.
+
+//BTTNCUR.C
+#ifdef WIN32
+ extern BOOL WINAPI _CRT_INIT(HINSTANCE, DWORD, LPVOID);
+ extern _cexit(void);
+#else
+ HANDLE FAR PASCAL LibMain(HANDLE, WORD, WORD, LPSTR);
+#endif
+
+BOOL FInitialize(HANDLE);
+void FAR PASCAL WEP(int);
+static BOOL ToolButtonInit(void);
+static void ToolButtonFree(void);
+static HBRUSH HBrushDitherCreate(COLORREF, COLORREF);
+static void DrawBlankButton(HDC, int, int, int, int, BOOL, COLORREF FAR *);
+static void PatB(HDC, int, int, int, int, COLORREF);
+static void MaskCreate(UINT, int, int, int, int, int, int, UINT);
+
+
+//CURSORS.C
+void CursorsCache(HINSTANCE);
+void CursorsFree(void);
+
+
+
+/*
+ * Wierd Wild Wooly Waster (raster) Ops for special bltting. See the
+ * Windows SDK reference on Raster Operation Codes for explanation of
+ * these. The DSPDxax and PSDPxax is a reverse-polish notation for
+ * operations where D==Destination, S==Source, P==Patterm, a==AND,
+ * x==XOR. Both of these codes are actually described in Programming
+ * Windows by Charles Petzold, Second Edition, pages 622-624.
+ */
+#define ROP_DSPDxax 0x00E20746
+#define ROP_PSDPxax 0x00B8074A
+
+
+/*
+ * Color indices into an array of standard hard-coded black, white, and
+ * gray colors.
+ */
+
+#define STDCOLOR_BLACK 0
+#define STDCOLOR_DKGRAY 1
+#define STDCOLOR_LTGRAY 2
+#define STDCOLOR_WHITE 3
+
+/*
+ * Color indices into an array of system colors, matching those in
+ * the hard-coded array for the colors they replace.
+ */
+
+#define SYSCOLOR_TEXT 0
+#define SYSCOLOR_SHADOW 1
+#define SYSCOLOR_FACE 2
+#define SYSCOLOR_HILIGHT 3
+
+
+/*
+ * Button types, used internally to distinguish command buttons from
+ * attribute buttons to enforce three-state or six-state possibilities.
+ * Command buttons can only have three states (up, mouse down, disabled)
+ * while attribute buttons add (down, down disabled, and indeterminate).
+ */
+
+#define BUTTONTYPE_COMMAND 0
+#define BUTTONTYPE_ATTRIBUTE 1
+
+
+#ifdef __cplusplus
+ }
+#endif
diff --git a/private/oleutest/letest/bttncur/changes.txt b/private/oleutest/letest/bttncur/changes.txt
new file mode 100644
index 000000000..ef945130f
--- /dev/null
+++ b/private/oleutest/letest/bttncur/changes.txt
@@ -0,0 +1,314 @@
+NOTE: This DLL is the same as that shipped with the OLE 2.0 SDK
+but is updated from that shipped with "The Windows Interface" book
+from Microsoft Press. It is now compatible with Windows NT.
+
+
+----------
+
+
+Changes in BTTNCUR.DLL Source Code and Documentation from Version 1.00b
+to Version 1.1. See also below for 1.00 to 1.00b changes.
+
+BTTNCUR.DLL version 1.1 is now fully compatible and tested under Windows
+3.0. Previously the demo application crashed under Windows 3.0
+on calls to the non-existent MoveToEx (Win32 compatible). Version 1.1 only
+uses MoveToEx for builds where the symbol WINVER < 0x030a.
+
+Windows NT changes are surrounded by #ifdef WIN32. The largest change
+is the DLL entry point: LibMain. Both Win3.1 and Win32 versions
+call FInitialize now.
+
+The images have been updated slightly and are now provided for 72dpi
+(ega), 96dpi (vga), and 120dpi (super vga)
+
+Version 1.1 completely handles system color changes unlike version 1.00x.
+This new version will dynamically convert black, light gray, dark gray,
+and white pixels in the image bitmap into system colors set for the
+button text, button shadow, button face, and button highlight, respectively.
+If you have blue, red, yellow, and green button colors, BTTNCUR.DLL will
+now work perfectly with all of them.
+
+BTTNCUR.DLL Version 1.1 also supports color images better by allowing
+you to control which colors in the image bitmap are converted to system
+colors. By default, any black, gray, or white colors are converted
+into system button colors as decribed in the last paragraph. BTTNCUR.H
+defines new PRESERVE_* flags for each of the four colors that are liable
+to be converted. By specifing one or more flags you prevent BTTNCUR
+from changing that color to a system color. For example, if you
+want to preserve all black pixels in your image, specify PRESERVE_BLACK
+when calling UIToolButtonDraw.
+
+Applications should obtain configuration data for the current display
+through UIToolConfigureForDisplay. With this data the application can
+configure itself for the correct toolbar size and button sizes and load
+the appropriate application supplied bitmaps.
+
+Applications using UIToolConfigureForDisplay should now use
+UIToolButtonDrawTDD instead of UIToolButtonDraw, passing one extra
+parameter, a pointer to the TOOLDISPLAYDATA. Applications that
+still call UIToolButtonDraw will always use 96dpi.
+
+
+------------------------
+BTTNCUR.H changes
+ Added PRESERVE_ flags to allow application to control color conversions
+ from black, dark gray, light gray, and white into the
+ file compatible with C++.
+
+ Added prototype for UIToolConfigureForDisplay, TOOLDISPLAYDATA structure,
+ and definitions for button and image sizes on 72dpi, 96dpi, and 120dpi.
+
+------------------------
+BTTNCUR.RCV version changes
+ FILEVERSION and PRODUCTVERSION changed from 1,0,0,2 to 1,0,1,0
+
+ VALUE "FileVersion" and VALUE "ProductVersion" changed from
+ "1.00b\0","\0" to "1.1\0","\0"
+
+
+------------------------
+BTTNCURI.H changes
+ Defined STDCOLOR_* values as indices into an array in BTTNCUR.C
+ that holds hard-coded default button color that never change
+ regardless of the system colors. Also defined SYSCOLOR_*
+ flags that matched STDCOLOR_* flags for uniform array indices.
+
+ Removed NEAR, FAR, and PASCAL from any function that didn't need it
+ so we can port to Windows NT cleanly.
+
+------------------------
+BTTNCUR.C source code changes. There are significant modifications.
+
+Overall:
+ Updated header comment
+
+ Removed NEAR, FAR, and PASCAL from any function that didn't need it
+ so we can port to Windows NT cleanly.
+
+Globals:
+ Eliminated the COLORREFs prefixed with RGB. Only a few are needed
+ statically and were moved to HBrushDitherCreate.
+
+ Also added an array of standard colors used in the standard images:
+
+ static const
+ COLORREF crStandard[4]={ RGB(0, 0, 0) //STDCOLOR_BLACK
+ , RGB(128, 128, 128) //STDCOLOR_DKGRAY
+ , RGB(192, 192, 192) //STDCOLOR_LTGRAY
+ , RGB(255, 255, 255)}; //STDCOLOR_WHITE
+
+ Added an array of standard images instead of just 96dpi versions.
+
+UIToolConfigureForDisplay:
+ Added function to return the resolution of the display and
+ size information about button and image sizes.
+
+
+ToolButtonInit():
+ Call to CreatePatternBrush moved into HBrushDitherCreate.
+ Conditionally sets the highlight color for HDitherBrushCreate
+ depending on Windows 3.x or Windows 3.0 (3.0 did not support
+ COLOR_BTNHIGHLIGHT).
+
+
+ToolButtonFree():
+ Removed some old debug output no longer useful.
+
+
+HDitherBitmapCreate()
+ Renamed to HBrushDitherCreate.
+ Moved CreatePatterBrush code from ToolButtonInit into this
+ function.
+
+ To support changing system colors, this function maintains
+ static variables for the face and highlight colors that we
+ use to create the brush. If the function is called and the
+ current colors in the global hBrushDither are different than
+ the system colors, we recreate the brush and update the global
+ hBrushDither, deleting the old brush. Otherwise we just return
+ hBrushDither.
+
+ Note that if we fail to create the new brush we just maintain
+ the old. We'll paint something, albeit not in the right colors,
+ but something nontheless.
+
+
+UIToolButtonDraw():
+ Calls UIToolButtonDrawTDD with default display configuration.
+
+UIToolButtonDrawTDD():
+ This is the function that was overhauled the most, specifically
+ to handle variable colors.
+
+ First, we added several local variables of which two are important.
+ crSys is an array of system colors for the text, shadow, face,
+ highlight, and frame, declared as static to keep references to
+ it off DS instead of SS; if it's in SS things will crash. The second
+ important variable is uColor, which receives the color preservation
+ flags passed in the hibyte of the uState parameter to UIToolButtonDraw.
+
+ All the code to draw a blank button outline was moved into a separate
+ function DrawBlankButton. Since this procedure needs all the system
+ colors to do it's thing, I've set it up to take an array of five
+ COLORREFs (exactly crSys) in which it stores those color (it also
+ uses it as its color variables). This way we only have to call
+ GetSysColor once for each system color.
+
+ Anything dealing with the dithered brush is moved to the
+ BUTTONGROUP_LIGHTFACE case where we just get the current brush
+ by calling HBrushDitherCreate, passing it the current face
+ and highlight colors. Remember that is these colors match those
+ used in the currently held global hBrushDither, this function just
+ returns that global, so it's quite fast. We have to be very careful
+ not to delete this brush where we're done with it since it is global.
+
+ The largest amount of new code is under the line:
+
+ if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK))
+
+ This has changed from a single BitBlt call to a much more complex
+ operation to handle specific color conversions and preservations.
+ A little optimization was done to detect when the system colors
+ for buttons match the defaults, that is, black, dark gray, light gray,
+ and white for text, shadow, face, and highlight. If these colors
+ all match, or if the caller requested preservation of all colors,
+ the we just do the single BitBlt of old.
+
+ Otherwise we loop through each of the black/white/gray colors
+ that need possible conversion. For each one we create a mask
+ that contains 1's where the converting color exists in the image
+ and 0's everywhere else. For each color then we BitBlt the
+ mask, a brush matching the system color we're converting to,
+ and the destination bitmap (which we initialize with the unmodified
+ image itself) using ROP_DSPDxax. This leaves any color but the
+ one under conversion alone and replaces the converted color with
+ the system color.
+
+ If the caller set a specific flag to preserve one or more specific
+ colors, then we replace the standard color with the standard color,
+ resulting in a no-op.
+
+ Finally, to reduce flicker for this four Blt operation we create
+ and build the final image in a temporary bitmap, making it 6 total
+ Blts to handle the color changes. But since we optimized for the
+ 99% case where the system colors are the standard colors, this isn't
+ too much of a consideration.
+
+ color conversions.
+
+
+DrawBlankButton():
+ New internal function. Moved code from UIToolButtonDraw here.
+
+
+
+
+------------------------
+CURSORS.C
+ Updated header comment
+
+ Removed PASCAL on both internal functions.
+
+
+ CursorsFree
+ Eliminated all the code inside this function as it was unnecessary.
+
+ UICursorLoad
+ Eliminated code to revalidate a cursor in the array. Unnecessary.
+
+
+------------------------
+BCDEMO.C
+
+ Tested for running under Windows 3.0 and avoided MoveToEx calls,
+ using MoveTo instead. Calling MoveToEx in a Windows 3.1 app
+ marked as 3.0 compatible under 3.0 causes an unknown GP fault.
+
+ Uses UIToolButtonConfigureForDisplay and UIToolButtonDrawTDD.
+
+
+------------------------------------------------------------------------------
+
+Changes in BTTNCUR.DLL Source Code and Documentation from Version 1.00
+to Version 1.00b
+
+------------------------
+BTTNCUR.H changes
+ Added #ifdef __cplusplus to include extern "C" making the
+ file compatible with C++.
+
+
+------------------------
+BTTNCURI.H changes
+ Added #ifdef __cplusplus to include extern "C" making the
+ file compatible with C++.
+
+ Removed code contained between a #ifdef NEVER that is unused.
+
+
+------------------------
+BTTNCUR.RCV version changes
+ FILEVERSION and PRODUCTVERSION changed from 1,0,0,0 to 1,0,0,2
+
+ VALUE "FileVersion" and VALUE "ProductVersion" changed from
+ "1.00\0","\0" to "1.00b\0","\0"
+
+
+------------------------
+BTTNCUR.C source code changes.
+
+ Added a global for the frame color
+ static COLORREF rgbFrame =RGB(0, 0, 0);
+
+WEP():
+ Added comment about resource cleanup messages in DEBUG mode.
+
+
+ToolButtonInit():
+ Added the line below just before the assignment of hDCGlyphs:
+
+ rgbFrame=GetSysColor(COLOR_WINDOWFRAME);
+
+ This insures that the frame color is properly shown on plasma
+ displays.
+
+
+ToolButtonFree():
+ Added the following lines just before return:
+
+ if (NULL!=hBmpStandardImages)
+ DeleteObject(hBmpStandardImages);
+ hBmpStandardImages=NULL;
+
+
+UIToolButtonDraw():
+ The image centering is one too high. The line
+
+ yOffsetGlyph=((dy-bmy) >> 1)-1;
+
+ now reads:
+
+ yOffsetGlyph=(dy-bmy) >> 1;
+
+
+ The declaration HBITMAP hBmp; now read HBITMAP hBmp=NULL;
+
+ The line hBmpT=SelectObject(hDCGlyphs, hBmp); is now two:
+
+ if (NULL!=hBmp)
+ SelectObject(hDCGlyphs, hBmp);
+
+ The line SelectObject(hDCGlyphs, hBmpT); is now two:
+
+ if (NULL!=hBmpT)
+ SelectObject(hDCGlyphs, hBmpT);
+
+
+
+------------------------
+BTTNCUR.BMP
+ Fixed the images to be 16*15 (the standard) instead of 16*16
+ as they originally were. Changed the label "16x16" to "16x15".
+
+ Copied an image of the disabled state of Context-Sensitive Help
+ to this bitmap as it was previously missing.
diff --git a/private/oleutest/letest/bttncur/cursors.c b/private/oleutest/letest/bttncur/cursors.c
new file mode 100644
index 000000000..625f6e5ed
--- /dev/null
+++ b/private/oleutest/letest/bttncur/cursors.c
@@ -0,0 +1,150 @@
+/*
+ * CURSORS.C
+ * Buttons & Cursors Version 1.1, Win32 version August 1993
+ *
+ * Public functions to retrieve new cursors from the BTTNCUR DLL based
+ * on ordinal to prevent applications from necessarily calling LoadCursor
+ * directly on the DLL.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+#ifdef WIN32
+#define _INC_OLE
+#define __RPC_H__
+#endif
+
+#include <windows.h>
+#include "bttncur.h"
+#include "bttncuri.h"
+
+
+/*
+ * The +1 is because MAX is the highest allowable number and MIN is not
+ * necessarily zero.
+ */
+HCURSOR rgHCursors[IDC_NEWUICURSORMAX-IDC_NEWUICURSORMIN+1];
+
+
+
+/*
+ * CursorsCache
+ * Internal
+ *
+ * Purpose:
+ * Loads all the cursors available through NewUICursorLoad into
+ * a global array. This way we can clean up all the cursors without
+ * placing the burden on the application.
+ *
+ * Parameters:
+ * hInst HANDLE of the DLL instance.
+ *
+ * Return Value:
+ * None. If any of the LoadCursor calls fail, then the corresponding
+ * array entry is NULL and NewUICursorLoad will fail. Better to fail
+ * an app getting a cursor than failing to load the app just for that
+ * reason; and app can attempt to load the cursor on startup if it's
+ * that important, and fail itself.
+ */
+
+void CursorsCache(HINSTANCE hInst)
+ {
+ UINT i;
+
+ for (i=IDC_NEWUICURSORMIN; i<=IDC_NEWUICURSORMAX; i++)
+ rgHCursors[i-IDC_NEWUICURSORMIN]=LoadCursor(hInst, MAKEINTRESOURCE(i));
+
+ return;
+ }
+
+
+
+
+/*
+ * CursorsFree
+ * Internal
+ *
+ * Purpose:
+ * Frees all the cursors previously loaded through CursorsCache.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * None
+ */
+
+void CursorsFree(void)
+ {
+ /*
+ * Note that since cursors are discardable resources and should
+ * not be used with DestroyCursor, there's nothing to do here.
+ * We still provide this API for compatibility and to maintain
+ * symmetry.
+ */
+ return;
+ }
+
+
+
+
+
+/*
+ * UICursorLoad
+ * Public API
+ *
+ * Purpose:
+ * Loads and returns a handle to one of the new standard UI cursors
+ * contained in UITOOLS.DLL. The application must not call DestroyCursor
+ * on this cursor as it is managed by the DLL.
+ *
+ * Parameters:
+ * iCursor UINT index to the cursor to load which must be one
+ * of the following values:
+ *
+ * IDC_RIGHTARROW Right pointing standard arrow
+ * IDC_CONTEXTHELP Arrow with a ? (context help)
+ * IDC_MAGNIFY Magnifying glass for zooming
+ * IDC_NODROP Circle with a slash
+ * IDC_TABLETOP Small arrow pointing down
+ *
+ * IDC_SMALLARROWS Thin four-headed arrow
+ * IDC_LARGEARROWS Wide four-headed arrow
+ * IDC_HARROWS Horizontal two-headed arrow
+ * IDC_VARROWS Vertical two-headed arrow
+ * IDC_NESWARROWS Two-headed arrow pointing NE<->SW
+ * IDC_NWSEHARROWS Two-headed arrow pointing NW<->SE
+ *
+ * IDC_HSIZEBAR Horizontal two-headed arrow with
+ * a single vertical bar down the
+ * middle
+ *
+ * IDC_VSIZEBAR Vertical two-headed arrow with a
+ * single horizontal bar down the
+ * middle
+ *
+ * IDC_HSPLITBAR Horizontal two-headed arrow with
+ * split double vertical bars down the
+ * middle
+ *
+ * IDC_VSPLITBAR Vertical two-headed arrow with split
+ * double horizontal bars down the
+ * middle
+ *
+ * Return Value:
+ * HCURSOR Handle to the loaded cursor if successful, NULL
+ * if iCursor is out of range or the function could not
+ * load the cursor.
+ */
+
+HCURSOR WINAPI UICursorLoad(UINT iCursor)
+ {
+ HCURSOR hCur=NULL;
+
+ if ((iCursor >= IDC_NEWUICURSORMIN) && (iCursor <= IDC_NEWUICURSORMAX))
+ hCur=rgHCursors[iCursor-IDC_NEWUICURSORMIN];
+
+ return hCur;
+ }
diff --git a/private/oleutest/letest/bttncur/daytona/bttncur.src b/private/oleutest/letest/bttncur/daytona/bttncur.src
new file mode 100644
index 000000000..12c011464
--- /dev/null
+++ b/private/oleutest/letest/bttncur/daytona/bttncur.src
@@ -0,0 +1,39 @@
+#if 0
+
+ Microsoft Windows
+ Copyright (C) Microsoft Corporation, 1992 - 1992.
+ All rights reserved.
+
+ This .def file is preprocessed by the compiler to create the version for
+ the current build in the appropriate subdir. Basically, whatever you
+ would have used in your code to control what is compiled when can be
+ used in this file for the same purpose. The following defines are in
+ use at the time this file was written:
+
+ FLAT - Used to indicate a NT/DOS7 build
+ i386 - Intel i386/i486 build
+ MIPS - MIPS R3000/R4000 build
+ ALPHA - DEC Alpha build
+ DBG - Used to control Debug/Retail. Set to 1 if Debug,
+ 0 if Retail.
+ WIN31 - Win16 build
+ __OS2__ - OS/2 build (used by CT mostly)
+
+ If none of these are used, it is assumed the entire file can be used
+ for all builds.
+
+#endif
+
+#ifdef FLAT
+
+LIBRARY bttncur
+
+DESCRIPTION 'BTTNCUR'
+
+EXPORTS
+ UICursorLoad
+ UIToolConfigureForDisplay
+ UIToolButtonDraw
+ UIToolButtonDrawTDD
+
+#endif // FLAT
diff --git a/private/oleutest/letest/bttncur/daytona/makefile b/private/oleutest/letest/bttncur/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/letest/bttncur/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/bttncur/daytona/makefile.inc b/private/oleutest/letest/bttncur/daytona/makefile.inc
new file mode 100644
index 000000000..fc473f167
--- /dev/null
+++ b/private/oleutest/letest/bttncur/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\*\bttncur.def: bttncur.src
diff --git a/private/oleutest/letest/bttncur/daytona/sources b/private/oleutest/letest/bttncur/daytona/sources
new file mode 100644
index 000000000..6beeb9661
--- /dev/null
+++ b/private/oleutest/letest/bttncur/daytona/sources
@@ -0,0 +1,39 @@
+
+TARGETNAME=bttncur
+
+TARGETPATH=obj
+
+TARGETTYPE=DYNLINK
+
+DLLDEF= obj\*\bttncur.def
+
+TARGETLIBS=$(GUI32_LIBS) $(WIN32_LIBS)
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+DLLENTRY= DllEntryPoint
+
+UMTYPE=windows
+
+INCLUDES=..;..\res
+
+C_DEFINES=-DWIN32 -DFLAT
+
+BLDCRT=1
+
+SOURCES=..\bttncur.rc \
+ ..\bttncur.c \
+ ..\dllentry.c \
+ ..\cursors.c
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/letest/bttncur/dirs b/private/oleutest/letest/bttncur/dirs
new file mode 100644
index 000000000..d0b57ca11
--- /dev/null
+++ b/private/oleutest/letest/bttncur/dirs
@@ -0,0 +1,4 @@
+DIRS=
+OPTIONAL_DIRS= \
+ daytona \
+
diff --git a/private/oleutest/letest/bttncur/dllentry.c b/private/oleutest/letest/bttncur/dllentry.c
new file mode 100644
index 000000000..1cd1159e4
--- /dev/null
+++ b/private/oleutest/letest/bttncur/dllentry.c
@@ -0,0 +1,55 @@
+//+-------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: dllentry.c
+//
+// Contents: Dll Entry point code. Calls the appropriate run-time
+// init/term code and then defers to LibMain for further
+// processing.
+//
+// Classes: <none>
+//
+// Functions: DllEntryPoint - Called by loader
+//
+// History: 10-May-92 BryanT Created
+// 22-Jul-92 BryanT Switch to calling _cexit/_mtdeletelocks
+// on cleanup.
+// 06-Oct-92 BryanT Call RegisterWithCommnot on entry
+// and DeRegisterWithCommnot on exit.
+// This should fix the heap dump code.
+// 27-Dec-93 AlexT Post 543 builds don't need special code.
+//
+//--------------------------------------------------------------------
+
+#define USE_CRTDLL
+#include <windows.h>
+
+BOOL WINAPI _CRT_INIT (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL _CRTAPI1 LibMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+ BOOL fRc = FALSE;
+
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ _CRT_INIT(hDll, dwReason, lpReserved);
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ _CRT_INIT(hDll, dwReason, lpReserved);
+ }
+
+ return(fRc);
+}
diff --git a/private/oleutest/letest/bttncur/makefile b/private/oleutest/letest/bttncur/makefile
new file mode 100644
index 000000000..21eedcbe0
--- /dev/null
+++ b/private/oleutest/letest/bttncur/makefile
@@ -0,0 +1,12 @@
+#
+# 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
+#
+!ifdef NTMAKEENV
+all:
+ echo $(BUILDMSG)
+clean: all
+!else
+!INCLUDE $(NTMAKEENV)\makefile.def
+!endif
diff --git a/private/oleutest/letest/bttncur/msvc.pdb b/private/oleutest/letest/bttncur/msvc.pdb
new file mode 100644
index 000000000..917b59b09
--- /dev/null
+++ b/private/oleutest/letest/bttncur/msvc.pdb
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/harrows.cur b/private/oleutest/letest/bttncur/res/harrows.cur
new file mode 100644
index 000000000..571dd0ef7
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/harrows.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/help.cur b/private/oleutest/letest/bttncur/res/help.cur
new file mode 100644
index 000000000..d0a2aa307
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/help.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/larrows.cur b/private/oleutest/letest/bttncur/res/larrows.cur
new file mode 100644
index 000000000..8574ffb2d
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/larrows.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/magnify.cur b/private/oleutest/letest/bttncur/res/magnify.cur
new file mode 100644
index 000000000..0d3289422
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/magnify.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/neswarrs.cur b/private/oleutest/letest/bttncur/res/neswarrs.cur
new file mode 100644
index 000000000..c38501ee1
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/neswarrs.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/nodrop.cur b/private/oleutest/letest/bttncur/res/nodrop.cur
new file mode 100644
index 000000000..b002e96b3
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/nodrop.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/nwsearrs.cur b/private/oleutest/letest/bttncur/res/nwsearrs.cur
new file mode 100644
index 000000000..570cbbb57
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/nwsearrs.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/rarrow.cur b/private/oleutest/letest/bttncur/res/rarrow.cur
new file mode 100644
index 000000000..5691efbaf
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/rarrow.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/sarrows.cur b/private/oleutest/letest/bttncur/res/sarrows.cur
new file mode 100644
index 000000000..a407a1298
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/sarrows.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/sizebarh.cur b/private/oleutest/letest/bttncur/res/sizebarh.cur
new file mode 100644
index 000000000..dda3483bb
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/sizebarh.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/sizebarv.cur b/private/oleutest/letest/bttncur/res/sizebarv.cur
new file mode 100644
index 000000000..a87811cb4
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/sizebarv.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/splith.cur b/private/oleutest/letest/bttncur/res/splith.cur
new file mode 100644
index 000000000..f2f0be363
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/splith.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/splitv.cur b/private/oleutest/letest/bttncur/res/splitv.cur
new file mode 100644
index 000000000..a4260808f
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/splitv.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/stdim120.bmp b/private/oleutest/letest/bttncur/res/stdim120.bmp
new file mode 100644
index 000000000..89d1be7d1
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/stdim120.bmp
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/stdim72.bmp b/private/oleutest/letest/bttncur/res/stdim72.bmp
new file mode 100644
index 000000000..57bcbe029
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/stdim72.bmp
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/stdim96.bmp b/private/oleutest/letest/bttncur/res/stdim96.bmp
new file mode 100644
index 000000000..eef487dbd
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/stdim96.bmp
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/tabletop.cur b/private/oleutest/letest/bttncur/res/tabletop.cur
new file mode 100644
index 000000000..b61fec41a
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/tabletop.cur
Binary files differ
diff --git a/private/oleutest/letest/bttncur/res/varrows.cur b/private/oleutest/letest/bttncur/res/varrows.cur
new file mode 100644
index 000000000..76449be89
--- /dev/null
+++ b/private/oleutest/letest/bttncur/res/varrows.cur
Binary files differ
diff --git a/private/oleutest/letest/data/letest12.olc b/private/oleutest/letest/data/letest12.olc
new file mode 100644
index 000000000..4d82e7069
--- /dev/null
+++ b/private/oleutest/letest/data/letest12.olc
Binary files differ
diff --git a/private/oleutest/letest/data/tiger.bmp b/private/oleutest/letest/data/tiger.bmp
new file mode 100644
index 000000000..3eaedbcdf
--- /dev/null
+++ b/private/oleutest/letest/data/tiger.bmp
Binary files differ
diff --git a/private/oleutest/letest/data/tigernph.wmf b/private/oleutest/letest/data/tigernph.wmf
new file mode 100644
index 000000000..99f176cff
--- /dev/null
+++ b/private/oleutest/letest/data/tigernph.wmf
Binary files differ
diff --git a/private/oleutest/letest/dirs b/private/oleutest/letest/dirs
new file mode 100644
index 000000000..55c391db6
--- /dev/null
+++ b/private/oleutest/letest/dirs
@@ -0,0 +1,7 @@
+DIRS= \
+ bttncur \
+ ole2ui \
+ gizmobar \
+ outline
+
+
diff --git a/private/oleutest/letest/gizmobar/api.c b/private/oleutest/letest/gizmobar/api.c
new file mode 100644
index 000000000..526d66a5f
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/api.c
@@ -0,0 +1,846 @@
+/*
+ * API.C
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * API functions affecting a GizmoBar and a message processing function to
+ * handle the equivalent called through messages.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+
+
+/*
+ * GBMessageHandler
+ *
+ * Purpose:
+ * Processes control messages that are equivalents of available
+ * control API. The data passed with these messages is simply
+ * extracted from structures and passed as parameters to their
+ * equivalent function.
+ *
+ * Parameters:
+ * <Standard Message Parameters> plus
+ * pGB LPGIZMOBAR providing control-specific data.
+ *
+ * Return Value:
+ * LRESULT Return value from equivalent API function.
+ */
+
+LRESULT GBMessageHandler(HWND hWnd, UINT iMsg, WPARAM wParam
+ , LPARAM lParam, LPGIZMOBAR pGB)
+ {
+ LRESULT lRet=0L;
+ LPCREATEGIZMO pCG;
+ LPGBMSG pMsg;
+ LPGBGETTEXT pGT;
+ LPGBGETINT pGI;
+ LPGBSETINT pSI;
+
+ if (NULL==pGB)
+ return 0L;
+
+ switch (iMsg)
+ {
+ case GBM_HWNDASSOCIATESET:
+ lRet=(LRESULT)(UINT)GBHwndAssociateSet(hWnd, (HWND)wParam);
+ break;
+
+ case GBM_HWNDASSOCIATEGET:
+ lRet=(LRESULT)(UINT)GBHwndAssociateGet(hWnd);
+ break;
+
+ case GBM_GIZMOADD:
+ pCG=(LPCREATEGIZMO)lParam;
+ lRet=(LRESULT)GBGizmoAdd(pCG->hWndParent, pCG->iType, pCG->iGizmo
+ , pCG->uID, pCG->dx, pCG->dy, pCG->pszText, pCG->hBmp
+ , pCG->iImage, pCG->uState);
+ break;
+
+ case GBM_GIZMOREMOVE:
+ lRet=(LRESULT)GBGizmoRemove(hWnd, wParam);
+ break;
+
+ case GBM_GIZMOSENDMESSAGE:
+ pMsg=(LPGBMSG)lParam;
+ lRet=GBGizmoSendMessage(hWnd, wParam, pMsg->iMsg, pMsg->wParam, pMsg->lParam);
+ break;
+
+ case GBM_GIZMOSHOW:
+ lRet=(LRESULT)GBGizmoShow(hWnd, wParam, (BOOL)LOWORD(lParam));
+ break;
+
+ case GBM_GIZMOENABLE:
+ lRet=(LRESULT)GBGizmoEnable(hWnd, wParam, (BOOL)LOWORD(lParam));
+ break;
+
+ case GBM_GIZMOCHECK:
+ lRet=(LRESULT)GBGizmoCheck(hWnd, wParam, (BOOL)LOWORD(lParam));
+ break;
+
+ case GBM_GIZMOFOCUSSET:
+ lRet=(LRESULT)GBGizmoFocusSet(hWnd, wParam);
+ break;
+
+ case GBM_GIZMOEXIST:
+ lRet=(LRESULT)GBGizmoExist(hWnd, wParam);
+ break;
+
+ case GBM_GIZMOTYPEGET:
+ lRet=(LRESULT)GBGizmoTypeGet(hWnd, wParam);
+ break;
+
+ case GBM_GIZMODATASET:
+ lRet=(LRESULT)GBGizmoDataSet(hWnd, wParam, (DWORD)lParam);
+ break;
+
+ case GBM_GIZMODATAGET:
+ lRet=(LRESULT)GBGizmoDataGet(hWnd, wParam);
+ break;
+
+ case GBM_GIZMONOTIFYSET:
+ lRet=(LRESULT)GBGizmoNotifySet(hWnd, wParam, (BOOL)LOWORD(lParam));
+ break;
+
+ case GBM_GIZMONOTIFYGET:
+ lRet=(LRESULT)GBGizmoNotifyGet(hWnd, wParam);
+ break;
+
+ case GBM_GIZMOTEXTGET:
+ pGT=(LPGBGETTEXT)lParam;
+ lRet=(LRESULT)GBGizmoTextGet(hWnd, wParam, pGT->psz, pGT->cch);
+ break;
+
+ case GBM_GIZMOTEXTSET:
+ GBGizmoTextSet(hWnd, wParam, (LPTSTR)lParam);
+ break;
+
+ case GBM_GIZMOINTGET:
+ pGI=(LPGBGETINT)lParam;
+ lRet=(LRESULT)GBGizmoIntGet(hWnd, wParam, &pGI->fSuccess, pGI->fSigned);
+ break;
+
+
+ case GBM_GIZMOINTSET:
+ pSI=(LPGBSETINT)lParam;
+ GBGizmoIntSet(hWnd, wParam, pSI->uValue, pSI->fSigned);
+ break;
+
+ default:
+ break;
+ }
+
+ return lRet;
+ }
+
+
+
+
+
+
+
+
+
+
+/*
+ * PGizmoFromHwndID
+ *
+ * Purpose:
+ * Retrieves the pGizmo for the given GizmoBar and the gizmo ID.
+ *
+ * Parameters:
+ * hWnd HWND of a GizmoBar.
+ * uID UINT gizmo identifier.
+ *
+ * Return Value:
+ * LPGIZMO NULL if the gizmo does not exist or hWnd is invalid.
+ * non-NULL LPGIZMO otherwise.
+ */
+
+LPGIZMO PGizmoFromHwndID(HWND hWnd, UINT uID)
+ {
+ LPGIZMOBAR pGB;
+
+ if (!IsWindow(hWnd))
+ return FALSE;
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ if (NULL==pGB)
+ return FALSE;
+
+ return GizmoPFind(&pGB->pGizmos, uID);
+ }
+
+
+
+
+
+
+/*
+ * GBHwndAssociateSet
+ *
+ * Purpose:
+ * Changes the associate window of a GizmoBar.
+ *
+ * Parameters:
+ * hWnd HWND of the control window.
+ *
+ * Set Parameters:
+ * hWndAssociate HWND of new associate.
+ *
+ * Return Value:
+ * HWND Handle of previous associate.
+ */
+
+HWND WINAPI GBHwndAssociateSet(HWND hWnd, HWND hWndNew)
+ {
+ HWND hWndOld=NULL;
+ LPGIZMOBAR pGB;
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ if (NULL!=pGB)
+ {
+ hWndOld=pGB->hWndAssociate;
+ pGB->hWndAssociate=hWndNew;
+
+ if (NULL!=hWndOld)
+ SendCommand(hWndOld, pGB->uID, GBN_ASSOCIATELOSS, hWnd);
+
+ if (NULL!=hWndNew)
+ SendCommand(hWndNew, pGB->uID, GBN_ASSOCIATEGAIN, hWnd);
+ }
+
+ return hWndOld;
+ }
+
+
+
+
+
+/*
+ * GBHwndAssociateGet
+ *
+ * Purpose:
+ * Retrieves the associate window of a GizmoBar
+ *
+ * Parameters:
+ * hWnd HWND of the control window.
+ *
+ * Set Parameters:
+ * hWndAssociate HWND of new associate.
+ *
+ * Return Value:
+ * HWND Handle of current associate.
+ */
+
+HWND WINAPI GBHwndAssociateGet(HWND hWnd)
+ {
+ HWND hWndOld=NULL;
+ LPGIZMOBAR pGB;
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ if (NULL!=pGB)
+ hWndOld=pGB->hWndAssociate;
+
+ return hWndOld;
+ }
+
+
+
+
+
+/*
+ * GBGizmoAdd
+ *
+ * Purpose:
+ * Creates a new gizmo on the GizmoBar. Subsequent operations should
+ * be done using the identifier, uID, for this gizmo.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * iType UINT type of the gizmo to create.
+ * iGizmo UINT position (zero-based) at which to place the gizmo.
+ * uID UINT identifier for WM_COMMAND from this gizmo.
+ * dx, dy UINT dimensions of the gizmo.
+ * pszText LPTSTR initial text for edit, list, combo, and text gizmos.
+ * hBitmap HBITMAP for gizmos of the button types (COMMAND or
+ * ATTRIBUTE) specifies a source bitmap from which the
+ * button image is taken.
+ * iImage UINT index into hBitmap for the image for this button.
+ * uState UINT initial state of the gizmo.
+ *
+ * Return Value:
+ * BOOL TRUE if creation succeeded, FALSE otherwise.
+ */
+
+BOOL WINAPI GBGizmoAdd(HWND hWnd, UINT iType, UINT iGizmo, UINT uID
+ , UINT dx, UINT dy, LPTSTR pszText, HBITMAP hBmp, UINT iImage, UINT uState)
+ {
+ BOOL fSuccess;
+ LPGIZMOBAR pGB;
+ LPGIZMO pGizmo;
+
+ if (!IsWindow(hWnd))
+ return FALSE;
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ if (NULL==pGB)
+ return FALSE;
+
+ /*
+ * This automatically creates the windows, allocates structures, includes
+ * the gizmo in pGB->pGizmos, and so forth.
+ */
+ pGizmo=GizmoPAllocate((LPINT)&fSuccess, &pGB->pGizmos, hWnd, iType
+ , iGizmo, uID, dx, dy, pszText, hBmp, iImage, uState);
+
+ if (fSuccess)
+ {
+ if (NULL!=pGB->hWndAssociate)
+ SendCommand(pGB->hWndAssociate,GBN_GIZMOADDED, pGB->uID, hWnd);
+
+ InvalidateRect(hWnd, NULL, TRUE);
+ UpdateWindow(hWnd);
+ }
+ else
+ GizmoPFree(&pGB->pGizmos, pGizmo);
+
+ return fSuccess;
+ }
+
+
+
+
+
+/*
+ * GBGizmoRemove
+ *
+ * Purpose:
+ * Removes an existing gizmo from the GizmoBar.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier for this gizmo.
+ *
+ * Return Value:
+ * BOOL TRUE if deletion succeeded, FALSE otherwise.
+ */
+
+BOOL WINAPI GBGizmoRemove(HWND hWnd, UINT uID)
+ {
+ LPGIZMOBAR pGB;
+ LPGIZMO pGizmo;
+
+ if (!IsWindow(hWnd))
+ return FALSE;
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ if (NULL==pGB)
+ return FALSE;
+
+ pGizmo=GizmoPFind(&pGB->pGizmos, uID);
+
+ if (NULL==pGizmo)
+ return FALSE;
+
+ GizmoPFree(&pGB->pGizmos, pGizmo);
+
+ if (NULL!=pGB->hWndAssociate)
+ SendCommand(pGB->hWndAssociate, GBN_GIZMOREMOVED, pGB->uID, hWnd);
+
+ InvalidateRect(hWnd, NULL, TRUE);
+ UpdateWindow(hWnd);
+ return TRUE;
+ }
+
+
+
+
+
+
+/*
+ * GBGizmoSendMessage
+ *
+ * Purpose:
+ * Implements the equivalent of SendMessage to a gizmo in the
+ * GizmoBar. Separators, command buttons, and attribute buttons
+ * do not accept messages.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo to affect.
+ * iMsg UINT message to send.
+ * wParam WPARAM of the message.
+ * lParam LPARAM of the message.
+ *
+ * Return Value:
+ * LRESULT Return value from the message. 0L if the
+ * gizmo does not accept messages.
+ */
+
+LRESULT WINAPI GBGizmoSendMessage(HWND hWnd, UINT uID, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ LPGIZMO pGizmo;
+ LONG lRet=0L;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo && NULL!=pGizmo->hWnd)
+ lRet=SendMessage(pGizmo->hWnd, iMsg, wParam, lParam);
+
+ return lRet;
+ }
+
+
+
+
+
+
+/*
+ * GBGizmoShow
+ *
+ * Purpose:
+ * Shows or hides a control, adjusting the positions of all others
+ * to make room for or reuse the space for this control.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo to affect.
+ * fShow BOOL TRUE to show the gizmo, FALSE to hide it.
+ *
+ * Return Value:
+ * BOOL TRUE if the function was successful, FALSE otherwise.
+ */
+
+BOOL WINAPI GBGizmoShow(HWND hWnd, UINT uID, BOOL fShow)
+ {
+ BOOL fRet=FALSE;
+ LPGIZMO pGizmo;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo)
+ {
+ if (fShow && pGizmo->fHidden)
+ {
+ if (NULL!=pGizmo->hWnd)
+ ShowWindow(pGizmo->hWnd, SW_SHOWNORMAL);
+
+ GizmosExpand(pGizmo);
+ }
+
+ if (!fShow && !pGizmo->fHidden)
+ {
+ if (NULL!=pGizmo->hWnd)
+ ShowWindow(pGizmo->hWnd, SW_HIDE);
+
+ GizmosCompact(pGizmo);
+ }
+
+ //This will be right even if we didn't change anything.
+ pGizmo->fHidden=!fShow;
+ }
+
+ InvalidateRect(hWnd, NULL, TRUE);
+ UpdateWindow(hWnd);
+ return fRet;
+ }
+
+
+
+
+
+
+/*
+ * GBGizmoEnable
+ *
+ * Purpose:
+ * Enables or disables a control on the GizmoBar.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo to affect.
+ * fEnable BOOL TRUE to enable the gizmo, FALSE otherwise.
+ *
+ * Return Value:
+ * BOOL TRUE if the gizmo was previously disabled, FALSE
+ * otherwise.
+ */
+
+BOOL WINAPI GBGizmoEnable(HWND hWnd, UINT uID, BOOL fEnable)
+ {
+ LPGIZMO pGizmo;
+ BOOL fRet=FALSE;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL==pGizmo)
+ return FALSE;
+
+ fRet=(BOOL)(BUTTONGROUP_DISABLED & pGizmo->uState);
+
+ //Use windows to enable or disable window gizmos
+ if (NULL!=pGizmo->hWnd)
+ EnableWindow(pGizmo->hWnd, fEnable);
+ else
+ {
+ //If we're not down, command and attribute buttons act the same.
+ if (!(BUTTONGROUP_DOWN & pGizmo->uState))
+ GizmoPStateSet(hWnd, pGizmo, fEnable ? COMMANDBUTTON_UP : COMMANDBUTTON_DISABLED);
+ else
+ {
+ //Attribute buttons are a little more sensitive with DOWNDISABLED
+ GizmoPStateSet(hWnd, pGizmo
+ , fEnable ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_DOWNDISABLED);
+ }
+ }
+
+ return fRet;
+ }
+
+
+
+
+
+
+
+/*
+ * GBGizmoCheck
+ *
+ * Purpose:
+ * Checks or unchecks an attribute button in the GizmoBar. If the
+ * gizmo is part of a group of mutually exclusive attributes, then
+ * other gizmos are unchecked when this one is checked. If this is
+ * the only one checked in these circumstances, this function is a NOP.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo to affect.
+ * fCheck BOOL TRUE to check this gizmo, FALSE to uncheck.
+ *
+ * Return Value:
+ * BOOL TRUE if the change took place. FALSE otherwise.
+ */
+
+BOOL WINAPI GBGizmoCheck(HWND hWnd, UINT uID, BOOL fCheck)
+ {
+ LPGIZMOBAR pGB;
+ LPGIZMO pGizmo;
+
+ if (!IsWindow(hWnd))
+ return FALSE;
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ if (NULL==pGB)
+ return FALSE;
+
+ pGizmo=GizmoPFind(&pGB->pGizmos, uID);
+
+ if (NULL!=pGizmo)
+ GizmoPCheck(hWnd, pGizmo, fCheck);
+
+ return TRUE;
+ }
+
+
+
+
+
+
+/*
+ * GBGizmoFocusSet
+ *
+ * Purpose:
+ * Sets the focus to a partuclar gizmo in the gizmo if that gizmo
+ * can accept the focus. Separators, attribute buttons, text,
+ * and command buttons cannot have the focus.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo to affect.
+ *
+ * Return Value:
+ * BOOL TRUE if the focus was set. FALSE otherwise, such as
+ * when uID identifies a control that cannot have focus.
+ */
+
+UINT WINAPI GBGizmoFocusSet(HWND hWnd, UINT uID)
+ {
+ LPGIZMO pGizmo;
+ BOOL fRet=FALSE;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo && NULL!=pGizmo->hWnd)
+ {
+ fRet=TRUE;
+ SetFocus(pGizmo->hWnd);
+ }
+
+ return fRet;
+ }
+
+
+
+
+
+/*
+ * GBGizmoExist
+ *
+ * Purpose:
+ * Determines if a gizmo of a given identifier exists in the GizmoBar.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier to verify.
+ *
+ * Return Value:
+ * BOOL TRUE if the gizmo exists, FALSE otherwise.
+ */
+
+BOOL WINAPI GBGizmoExist(HWND hWnd, UINT uID)
+ {
+ return (NULL!=PGizmoFromHwndID(hWnd, uID));
+ }
+
+
+
+
+
+/*
+ * GBGizmoTypeGet
+ *
+ * Purpose:
+ * Returns the type of the gizmo specified by the given identifer.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier to find.
+ *
+ * Return Value:
+ * int A GIZMOTYPE_* value if the function is successful,
+ * otherwise -1.
+ */
+
+int WINAPI GBGizmoTypeGet(HWND hWnd, UINT uID)
+ {
+ int iRet=-1;
+ LPGIZMO pGizmo;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo)
+ iRet=pGizmo->iType;
+
+ return iRet;
+ }
+
+
+
+
+
+/*
+ * GBGizmoDataSet
+ * GBGizmoDataGet
+ *
+ * Purpose:
+ * Sets or retrieves an extra DWORD value associated with the given gizmo.
+ * Applications can store any information here they please.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo.
+ * dwData (Set only) DWORD data to store with the gizmo.
+ *
+ * Return Value:
+ * DWORD Set: Previous value
+ * Get: Current value
+ */
+
+DWORD WINAPI GBGizmoDataSet(HWND hWnd, UINT uID, DWORD dwData)
+ {
+ LPGIZMO pGizmo;
+ DWORD dw=0L;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo)
+ {
+ dw=pGizmo->dwData;
+ pGizmo->dwData=dwData;
+ }
+
+ return dw;
+ }
+
+
+
+DWORD WINAPI GBGizmoDataGet(HWND hWnd, UINT uID)
+ {
+ LPGIZMO pGizmo;
+ DWORD dw=0L;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo)
+ dw=pGizmo->dwData;
+
+ return dw;
+ }
+
+
+
+
+
+
+/*
+ * GBGizmoNotifySet
+ * GBGizmoNotifyGet
+ *
+ * Purpose:
+ * Sets or retrieves the notify status of a gizmo. If notify is FALSE,
+ * the no WM_COMMAND messages are sent from the GizmoBar to the parent
+ * window when this gizmo is used.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifier of the gizmo.
+ * fNotify (Set only) BOOL new notify status to set.
+ *
+ * Return Value:
+ * BOOL Set: Previous value of the notify flag.
+ * Get: Current value of the notify flag.
+ */
+
+BOOL WINAPI GBGizmoNotifySet(HWND hWnd, UINT uID, BOOL fNotify)
+ {
+ LPGIZMO pGizmo;
+ BOOL fRet=FALSE;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo)
+ {
+ fRet=pGizmo->fNotify;
+ pGizmo->fNotify=fNotify;
+ }
+
+ return fRet;
+ }
+
+
+BOOL WINAPI GBGizmoNotifyGet(HWND hWnd, UINT uID)
+ {
+ LPGIZMO pGizmo;
+ BOOL fRet=FALSE;
+
+ pGizmo=PGizmoFromHwndID(hWnd, uID);
+
+ if (NULL!=pGizmo)
+ fRet=pGizmo->fNotify;
+
+ return fRet;
+ }
+
+
+
+
+
+
+
+/*
+ * GBGizmoTextSet
+ * GBGizmoTextGet
+ *
+ * Purpose:
+ * Retrieves or sets text in a GizmoBar gizmo. Separators, command buttons,
+ * and attribute buttons are not affected by this call.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifying the gizmo.
+ * psz LPTSTR (Set) providing the text to show in the window
+ * or (Get) pointing to a buffer to receive the text.
+ * cch (Get only) UINT maximum number of chars to copy to psz.
+ *
+ * Return Value:
+ * int Number of characters copied to psz.
+ */
+
+void WINAPI GBGizmoTextSet(HWND hWnd, UINT uID, LPTSTR psz)
+ {
+ //This fails on non-windowed gizmos anyway, so we don't check.
+ SetDlgItemText(hWnd, uID, psz);
+ return;
+ }
+
+
+int WINAPI GBGizmoTextGet(HWND hWnd, UINT uID, LPTSTR psz, UINT cch)
+ {
+ //This fails on non-windowed gizmos anyway, so we don't check.
+ return GetDlgItemText(hWnd, uID, psz, cch);
+ }
+
+
+
+
+
+
+
+
+/*
+ * GBGizmoIntSet
+ * GBGizmoIntGet
+ *
+ * Purpose:
+ * Retrieves or sets an integer in a GizmoBar gizmo. Separators, command
+ * buttons, and attribute buttons are not affected by this call.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * uID UINT identifying the gizmo.
+ *
+ * (Set only)
+ * u UINT value to set in the gizmo.
+ * fSigned BOOL TRUE to indicate if the value is signed.
+ *
+ * (Get only)
+ * pfTrans BOOL FAR * in which the success of the function is returned.
+ * fSigned BOOL TRUE to indicate if the value is signed.
+ *
+ * Return Value:
+ * (Set): None
+ * (Get): UINT Integer translation of the gizmo's text.
+ */
+
+void WINAPI GBGizmoIntSet(HWND hWnd, UINT uID, UINT u, BOOL fSigned)
+ {
+ //This fails on non-windowed gizmos anyway, so we don't check.
+ SetDlgItemInt(hWnd, uID, u, fSigned);
+ return;
+ }
+
+
+
+UINT WINAPI GBGizmoIntGet(HWND hWnd, UINT uID, BOOL FAR *pfTrans, BOOL fSigned)
+ {
+ //This fails on non-windowed gizmos anyway, so we don't check.
+ return GetDlgItemInt(hWnd, uID, pfTrans, fSigned);
+ }
diff --git a/private/oleutest/letest/gizmobar/book1632.h b/private/oleutest/letest/gizmobar/book1632.h
new file mode 100644
index 000000000..435fb200c
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/book1632.h
@@ -0,0 +1,154 @@
+/*
+ * WIN1632.H
+ *
+ * Macros and other definitions that assist in porting between Win16
+ * and Win32 applications. Define WIN32 to enable 32-bit versions.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: INTERNET>kraigb@microsoft.com
+ */
+
+
+#ifndef _BOOK1632_H_
+#define _BOOK1632_H_
+
+//Macros to handle control message packing between Win16 and Win32
+#ifdef WIN32
+
+#define MAKEPOINT MAKEPOINTS
+
+#ifndef COMMANDPARAMS
+#define COMMANDPARAMS(wID, wCode, hWndMsg) \
+ WORD wID = LOWORD(wParam); \
+ WORD wCode = HIWORD(wParam); \
+ HWND hWndMsg = (HWND)(UINT)lParam;
+#endif //COMMANDPARAMS
+
+#ifndef SendCommand
+#define SendCommand(hWnd, wID, wCode, hControl) \
+ SendMessage(hWnd, WM_COMMAND, MAKELONG(wID, wCode) \
+ , (LPARAM)hControl)
+#endif //SendCommand
+
+#ifndef MENUSELECTPARAMS
+#define MENUSELECTPARAMS(wID, wFlags, hMenu) \
+ WORD wID = LOWORD(wParam); \
+ WORD wFlags = HIWORD(wParam); \
+ HMENU hMenu = (HMENU)lParam;
+#endif //MENUSELECTPARAMS
+
+
+#ifndef SendMenuSelect
+#define SendMenuSelect(hWnd, wID, wFlags, hMenu) \
+ SendMessage(hWnd, WM_MENUSELECT, MAKELONG(wID, wFlags) \
+ , (LPARAM)hMenu)
+#endif //SendMenuSelect
+
+#ifndef SendScrollPosition
+#define SendScrollPosition(hWnd, iMsg, iPos) \
+ SendMessage(hWnd, iMsg, MAKELONG(SB_THUMBPOSITION, iPos), 0)
+#endif //SendScrollPosition
+
+#ifndef ScrollThumbPosition
+#define ScrollThumbPosition(w, l) HIWORD(w)
+#endif //ScrollThumbPosition
+
+#ifndef GETWINDOWINSTANCE
+#define GETWINDOWINSTANCE(h) (HINSTANCE)GetWindowLong(h, GWL_HINSTANCE)
+#endif //GETWINDOWINSTANCE
+
+#ifndef GETWINDOWID
+#define GETWINDOWID(h) (UINT)GetWindowLong(h, GWW_ID)
+#endif //GETWINDOWID
+
+#ifndef POINTFROMLPARAM
+#define POINTFROMLPARAM(p, l) {p.x=(LONG)(SHORT)LOWORD(l); \
+ p.y=(LONG)(SHORT)HIWORD(l);}
+#endif //POINTEFROMLPARAM
+
+#ifndef EXPORT
+#define EXPORT
+#endif //EXPORT
+
+#ifndef MDIREFRESHMENU
+#define MDIREFRESHMENU(h) SendMessage(h, WM_MDIREFRESHMENU, 0, 0L)
+#endif //MDIREFRESHMENU
+
+
+//****END WIN32
+
+
+
+#else
+
+
+
+//****START !WIN32
+
+#ifndef COMMANDPARAMS
+#define COMMANDPARAMS(wID, wCode, hWndMsg) \
+ WORD wID = LOWORD(wParam); \
+ WORD wCode = HIWORD(lParam); \
+ HWND hWndMsg = (HWND)(UINT)lParam;
+#endif //COMMANDPARAMS
+
+#ifndef SendCommand
+#define SendCommand(hWnd, wID, wCode, hControl) \
+ SendMessage(hWnd, WM_COMMAND, wID \
+ , MAKELONG(hControl, wCode))
+#endif //SendCommand
+
+#ifndef MENUSELECTPARAMS
+#define MENUSELECTPARAMS(wID, wFlags, hMenu) \
+ WORD wID = LOWORD(wParam); \
+ WORD wFlags = LOWORD(lParam); \
+ HMENU hMenu = (HMENU)HIWORD(lParam);
+#endif //MENUSELECTPARAMS
+
+#ifndef SendMenuSelect
+#define SendMenuSelect(hWnd, wID, wFlags, hMenu) \
+ SendMessage(hWnd, WM_MENUSELECT, wID \
+ , MAKELONG(wFlags, hMenu))
+#endif //SendMenuSelect
+
+#ifndef SendScrollPosition
+#define SendScrollPosition(hWnd, iMsg, iPos) \
+ SendMessage(hWnd, iMsg, SB_THUMBPOSITION, MAKELONG(iPos, 0))
+#endif //Send ScrollPosition
+
+#ifndef ScrollThumbPosition
+#define ScrollThumbPosition(w, l) LOWORD(l)
+#endif //ScrollThumbPosition
+
+#ifndef GETWINDOWINSTANCE
+#define GETWINDOWINSTANCE(h) (HINSTANCE)GetWindowWord(h, GWW_HINSTANCE)
+#endif //GETWINDOWINSTANCE
+
+#ifndef GETWINDOWID
+#define GETWINDOWID(h) (UINT)GetWindowWord(h, GWW_ID)
+#endif //GETWINDOWID
+
+#ifndef POINTFROMLPARAM
+#define POINTFROMLPARAM(p, l) {p.x=LOWORD(l); p.y=HIWORD(l);}
+#endif //POINTEFROMLPARAM
+
+#ifndef EXPORT
+#define EXPORT __export
+#endif //EXPORT
+
+
+#ifndef MDIREFRESHMENU
+#define MDIREFRESHMENU(h) SendMessage(h, WM_MDISETMENU, TRUE, 0L)
+#endif //MDIREFRESHMENU
+
+
+
+
+#endif //!WIN32
+
+#endif //_BOOK1632_H_
diff --git a/private/oleutest/letest/gizmobar/daytona/gizmobar.src b/private/oleutest/letest/gizmobar/daytona/gizmobar.src
new file mode 100644
index 000000000..b59771e9a
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/daytona/gizmobar.src
@@ -0,0 +1,51 @@
+#if 0
+
+ Microsoft Windows
+ Copyright (C) Microsoft Corporation, 1992 - 1992.
+ All rights reserved.
+
+ This .def file is preprocessed by the compiler to create the version for
+ the current build in the appropriate subdir. Basically, whatever you
+ would have used in your code to control what is compiled when can be
+ used in this file for the same purpose. The following defines are in
+ use at the time this file was written:
+
+ FLAT - Used to indicate a NT/DOS7 build
+ i386 - Intel i386/i486 build
+ MIPS - MIPS R3000/R4000 build
+ ALPHA - DEC Alpha build
+ DBG - Used to control Debug/Retail. Set to 1 if Debug,
+ 0 if Retail.
+ WIN31 - Win16 build
+ __OS2__ - OS/2 build (used by CT mostly)
+
+ If none of these are used, it is assumed the entire file can be used
+ for all builds.
+
+#endif
+
+#ifdef FLAT
+
+LIBRARY gizmobar
+
+DESCRIPTION 'GIZMOBAR'
+
+EXPORTS
+ GizmoPAllocate
+ GizmosExpand
+ GizmoPFree
+ GizmosCompact
+ GizmoPFind
+ GizmoPEnum
+ GizmoPStateSet
+ GizmoPCheck
+ GBGizmoAdd
+ GBGizmoEnable
+ GBGizmoFocusSet
+ GBGizmoSendMessage
+ GBGizmoTextGet
+ GBGizmoTextSet
+ GBHwndAssociateSet
+
+
+#endif // FLAT
diff --git a/private/oleutest/letest/gizmobar/daytona/makefile b/private/oleutest/letest/gizmobar/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/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/gizmobar/daytona/makefile.inc b/private/oleutest/letest/gizmobar/daytona/makefile.inc
new file mode 100644
index 000000000..afd853b6b
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\*\gizmobar.def: gizmobar.src
diff --git a/private/oleutest/letest/gizmobar/daytona/sources b/private/oleutest/letest/gizmobar/daytona/sources
new file mode 100644
index 000000000..bbce019a8
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/daytona/sources
@@ -0,0 +1,50 @@
+# This links against bttncur.lib so block all threads to assure that
+# bttncur is built.
+SYNCHRONIZE_BLOCK=1
+SYNCHRONIZE_DRAIN=1
+
+TARGETNAME=gizmobar
+
+TARGETPATH=obj
+
+TARGETTYPE=DYNLINK
+
+DLLDEF= obj\*\gizmobar.def
+
+TARGETLIBS=$(GUI32_LIBS) \
+ $(WIN32_LIBS) \
+ ..\..\bttncur\daytona\obj\*\bttncur.lib
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+DLLENTRY= DllEntryPoint
+
+UMTYPE=windows
+
+C_DEFINES=-DWIN32 -DFLAT
+
+INCLUDES=..\..\bttncur; \
+ ..
+
+BLDCRT=1
+
+SOURCES= \
+ ..\gizmobar.rc \
+ ..\api.c \
+ ..\init.c \
+ ..\dllentry.c \
+ ..\paint.c \
+ ..\gizmo.c \
+ ..\gizmobar.c
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/letest/gizmobar/dirs b/private/oleutest/letest/gizmobar/dirs
new file mode 100644
index 000000000..c33a3de9b
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/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:
+
+ JohannP 01/11/95
+
+!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/gizmobar/dllentry.c b/private/oleutest/letest/gizmobar/dllentry.c
new file mode 100644
index 000000000..1cd1159e4
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/dllentry.c
@@ -0,0 +1,55 @@
+//+-------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: dllentry.c
+//
+// Contents: Dll Entry point code. Calls the appropriate run-time
+// init/term code and then defers to LibMain for further
+// processing.
+//
+// Classes: <none>
+//
+// Functions: DllEntryPoint - Called by loader
+//
+// History: 10-May-92 BryanT Created
+// 22-Jul-92 BryanT Switch to calling _cexit/_mtdeletelocks
+// on cleanup.
+// 06-Oct-92 BryanT Call RegisterWithCommnot on entry
+// and DeRegisterWithCommnot on exit.
+// This should fix the heap dump code.
+// 27-Dec-93 AlexT Post 543 builds don't need special code.
+//
+//--------------------------------------------------------------------
+
+#define USE_CRTDLL
+#include <windows.h>
+
+BOOL WINAPI _CRT_INIT (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL _CRTAPI1 LibMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+ BOOL fRc = FALSE;
+
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ _CRT_INIT(hDll, dwReason, lpReserved);
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ _CRT_INIT(hDll, dwReason, lpReserved);
+ }
+
+ return(fRc);
+}
diff --git a/private/oleutest/letest/gizmobar/gizmo.c b/private/oleutest/letest/gizmobar/gizmo.c
new file mode 100644
index 000000000..c763c3bba
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmo.c
@@ -0,0 +1,766 @@
+/*
+ * GIZMO.C
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Allocate, free, find, and enumerate functions for the GIZMO structure
+ * and a generic subclass procedure to handle tabbing between gizmos.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+
+/*
+ * In order to control tabbing in the gizmos, we need to subclass
+ * real pushbuttons, edit controls, listboxes, and comboboxes. So
+ * we keep an array of the four original procs for such controls.
+ */
+WNDPROC pfnOrg[CSUBGIZMOS]={NULL, NULL, NULL, NULL};
+
+
+TCHAR szStatic[]=TEXT("static");
+TCHAR szEdit[]=TEXT("edit");
+TCHAR szCombobox[]=TEXT("combobox");
+TCHAR szListbox[]=TEXT("listbox");
+TCHAR szButton[]=TEXT("button");
+
+
+//Here so PAINT.C can get at it.
+TOOLDISPLAYDATA tdd;
+
+
+
+/*
+ * GizmoPAllocate
+ *
+ * Purpose:
+ * Allocates and initializes a GIZMO data structure.
+ *
+ * Parameters:
+ * pfSuccess LPINT flag indicating success of failure.
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * hWndParent HWND of the parent of this gizmo. Can be NULL for
+ * iType==GIZMOTYPE_BUTTON* or GIZMOTYPE_SEPARATOR.
+ * iType UINT gizmo control type.
+ * iGizmo UINT index of this gizmo in the GizmoBar.
+ * uID UINT identifier to send with WM_COMMAND for this control.
+ * dx, dy UINT width and height of the gizmo.
+ * pszText LPTSTR to the text for edits, listboxes, combobox, and text.
+ * dwStyle DWORD style for edits, lists, and combos, and texts.
+ * hBmp HBITMAP for button gizmos, is applicable.
+ * iImage UINT index into hBmp for the button image, if applicable.
+ * uState UINT initial state of the control.
+ *
+ * Return Value:
+ * LPGIZMO If NULL returned then GizmoPAllocate could not allocate
+ * memory. If a non-NULL pointer is returned with
+ * *pfSuccess, then call GizmoPFree immediately. If you
+ * get a non-NULL pointer and *pfSuccess==TRUE then the
+ * function succeeded.
+ */
+
+LPGIZMO GizmoPAllocate(LPINT pfSuccess, LPLPGIZMO ppFirst, HWND hWndParent
+ , UINT iType, UINT iGizmo, UINT uID, UINT dx, UINT dy, LPTSTR pszText
+ , HBITMAP hBmp, UINT iImage, UINT uState)
+ {
+ LPGIZMO pGizmo;
+ LPGIZMO pCur, pPrev;
+ LPTSTR pszClass;
+ HINSTANCE hInst;
+ UINT i;
+ DWORD dwStyle;
+ HWND hWndE;
+
+ if (NULL==pfSuccess)
+ return NULL;
+
+ //Make sure we know of this gizmo type.
+ if (GIZMOTYPE_MIN > iType || GIZMOTYPE_MAX < iType)
+ return NULL;
+
+ *pfSuccess=FALSE;
+
+ //Allocate the structure
+ pGizmo=(LPGIZMO)LocalAlloc(LPTR, CBGIZMO);
+
+ if (NULL==pGizmo)
+ return NULL;
+
+
+ //Store the necessary information for this gizmo.
+ pGizmo->iType =iType;
+ pGizmo->uID =uID;
+ pGizmo->hBmp =hBmp;
+ pGizmo->iBmp =iImage;
+ pGizmo->uState =uState;
+ pGizmo->fNotify =TRUE;
+
+
+ /*
+ * Insert this structure into our gizmo list. Each time we scan
+ * we increment the index counter (starting at zero) comparing it
+ * to the desired index of insertion. We then know exactly where
+ * to insert this new gizmo. Note that we insert the new gizmo in
+ * the list appropriately for the given owner, so enumerations will
+ * come out ordered in the same way for that owner.
+ */
+
+ i=0;
+ pCur=*ppFirst;
+ pPrev=NULL;
+
+ while (NULL!=pCur && i++ < iGizmo)
+ {
+ pPrev=pCur;
+ pCur =pCur->pNext;
+ }
+
+ //Point to our neighbors
+ pGizmo->pPrev=pPrev;
+ pGizmo->pNext=pCur;
+
+
+ //Point out neighbors to us.
+ if (NULL==pPrev)
+ *ppFirst=pGizmo;
+ else
+ pPrev->pNext=pGizmo;
+
+ if (NULL!=pCur)
+ pCur->pPrev=pGizmo;
+
+
+ //Our x-coordinate is the x of the previous gizmo plus its width.
+ if (NULL!=pPrev)
+ pGizmo->x=pGizmo->pPrev->x+pGizmo->pPrev->dx;
+ else
+ pGizmo->x=4; //First gizmo is at x=4
+
+
+ //If we're a separator or image button, force standards on dx.
+ UIToolConfigureForDisplay(&tdd);
+ pGizmo->cxImage=tdd.cxImage;
+ pGizmo->cyImage=tdd.cyImage;
+
+ if ((GIZMOTYPE_DRAWN & iType) && NULL==hBmp)
+ dx=tdd.cxButton;
+
+ if (GIZMOTYPE_SEPARATOR==iType)
+ dx=6;
+
+ /*
+ * Now create windows for edits, texts, lists, and comboboxes.
+ * First calculate the most often defaults used in the switch.
+ */
+ pGizmo->dx=dx+6;
+ pGizmo->dy=min(dy, tdd.cyButton);
+ pGizmo->y=2;
+ pszClass=NULL;
+
+ //If this is new gizmo is a window, create it.
+ switch (iType)
+ {
+ case GIZMOTYPE_TEXT:
+ pGizmo->dx=dx;
+ pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1; //Center vertically.
+ pszClass=szStatic;
+ dwStyle=SS_LEFT;
+ break;
+
+ case GIZMOTYPE_EDIT:
+ pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1; //Center vertically.
+ pszClass=szEdit;
+ dwStyle=ES_LEFT | WS_BORDER | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_LISTBOX:
+ pGizmo->dy=dy;
+ pszClass=szCombobox;
+ dwStyle=CBS_DROPDOWNLIST | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_COMBOBOX:
+ pGizmo->dy=dy;
+ pszClass=szCombobox;
+ dwStyle=CBS_DROPDOWN | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_BUTTONNORMAL:
+ pGizmo->dy=dy;
+ pszClass=szButton;
+ dwStyle=BS_PUSHBUTTON | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_SEPARATOR:
+ pGizmo->dx=dx;
+ pGizmo->y=3;
+ break;
+
+ case GIZMOTYPE_BUTTONATTRIBUTEIN:
+ case GIZMOTYPE_BUTTONATTRIBUTEEX:
+ case GIZMOTYPE_BUTTONCOMMAND:
+ pGizmo->dx=dx;
+ pGizmo->y=3;
+ break;
+ }
+
+
+ //If we matched a classname, create a window.
+ if (GIZMOTYPE_WINDOWS & iType)
+ {
+ if (!IsWindow(hWndParent))
+ return pGizmo;
+
+ hInst=(HINSTANCE) GetWindowLong(hWndParent, GWL_HINSTANCE);
+
+ pGizmo->hWnd=CreateWindow(pszClass, pszText
+ , dwStyle | WS_CHILD | WS_VISIBLE, pGizmo->x, pGizmo->y
+ , dx, pGizmo->dy, hWndParent, (HMENU)uID, hInst, NULL);
+
+ if (NULL==pGizmo->hWnd)
+ return pGizmo;
+
+ /*
+ * Subclass comboboxes, listboxes, edits, and windowed buttons.
+ * We use iType to index the original proc array so we can use
+ * a single subclass procedure for all controls. If you mess
+ * with the gizmo type definitions, this is going to break.
+ */
+
+ if (GIZMOTYPE_WINDOWS & iType && GIZMOTYPE_TEXT!=iType)
+ {
+ //Give the window its type.
+ BITPOSITION(iType, i);
+ SetProp(pGizmo->hWnd, SZTYPEPROP, (HANDLE)i);
+
+ if (NULL==pfnOrg[i])
+ pfnOrg[i]=(WNDPROC)GetWindowLong(pGizmo->hWnd, GWL_WNDPROC);
+
+ SetWindowLong(pGizmo->hWnd, GWL_WNDPROC, (LONG)GenericSubProc);
+
+ //If we're a combobox, get the edit control and subclass it.
+ if (GIZMOTYPE_COMBOBOX==iType)
+ {
+ hWndE=GetDlgItem(pGizmo->hWnd, ID_COMBOEDIT);
+ SetProp(hWndE, SZTYPEPROP, (HANDLE)-1); //Special flag.
+
+ if (NULL==pfnOrg[0])
+ pfnOrg[0]=(WNDPROC)GetWindowLong(pGizmo->hWnd, GWL_WNDPROC);
+
+ SetWindowLong(hWndE, GWL_WNDPROC, (LONG)GenericSubProc);
+ }
+ }
+ }
+
+
+ //Finally, move all our neighbors to the right over to accomodate us.
+ GizmosExpand(pGizmo);
+
+ *pfSuccess=TRUE;
+ return pGizmo;
+ }
+
+
+
+
+
+
+/*
+ * GizmoPFree
+ *
+ * Purpose:
+ * Reverses all initialization done by GizmoPAllocate, cleaning up
+ * any allocations including the application structure itself.
+ *
+ * Parameters:
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * pGizmo LPGIZMO to the structure
+ *
+ * Return Value:
+ * LPGIZMO NULL if successful, pGizmo if not, meaning we couldn't
+ * free something.
+ */
+
+LPGIZMO GizmoPFree(LPLPGIZMO ppFirst, LPGIZMO pGizmo)
+ {
+ int i;
+
+ if (NULL==pGizmo)
+ return NULL;
+
+ //Move other gizmos to fill in this gap.
+ GizmosCompact(pGizmo);
+
+ //Unsubclass
+ if (GIZMOTYPE_WINDOWS & pGizmo->iType && GIZMOTYPE_TEXT!=pGizmo->iType)
+ {
+ i=(int)GetProp(pGizmo->hWnd, SZTYPEPROP);
+ RemoveProp(pGizmo->hWnd, SZTYPEPROP);
+
+ SetWindowLong(pGizmo->hWnd, GWL_WNDPROC, (LONG)pfnOrg[i]);
+ }
+
+ //If this was a window gizmo, destroy the window.
+ if (NULL!=pGizmo->hWnd && IsWindow(pGizmo->hWnd))
+ DestroyWindow(pGizmo->hWnd);
+
+ //Unlink ourselves.
+ if (NULL!=pGizmo->pNext)
+ pGizmo->pNext->pPrev=pGizmo->pPrev;
+
+ if (NULL!=pGizmo->pPrev)
+ pGizmo->pPrev->pNext=pGizmo->pNext;
+ else
+ *ppFirst=pGizmo->pNext;
+
+ return (LPGIZMO)LocalFree((HLOCAL)(UINT)(LONG)pGizmo);
+ }
+
+
+
+
+
+
+/*
+ * GizmosExpand
+ *
+ * Purpose:
+ * Given a starting gizmo and a width, moves it and all gizmos to its
+ * right to the right by the width to make space for showing or creating
+ * a new gizmo.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO specifying the gizmo that was inserted.
+ *
+ * Return Value:
+ * None
+ */
+
+void GizmosExpand(LPGIZMO pGizmo)
+ {
+ int cx;
+
+ cx=(int)pGizmo->dx;
+
+ /*
+ * If we and the next control are buttons, use our width-1 to
+ * expand so we overlap borders with our neighboring button.
+ */
+
+ if (NULL!=pGizmo->pNext)
+ {
+ if ((GIZMOTYPE_BUTTONS & pGizmo->pNext->iType)
+ && (GIZMOTYPE_BUTTONS & pGizmo->iType))
+ cx-=1;
+ }
+
+ //Walk the gizmo list moving them right by our width.
+ pGizmo=pGizmo->pNext;
+
+ while (NULL!=pGizmo)
+ {
+ pGizmo->x+=cx;
+
+ //hWnd is NULL for buttons and separators.
+ if (NULL!=pGizmo->hWnd)
+ SetWindowPos(pGizmo->hWnd, NULL, pGizmo->x, pGizmo->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+
+ pGizmo=pGizmo->pNext;
+ }
+
+ return;
+ }
+
+
+
+
+
+
+
+/*
+ * GizmosCompact
+ *
+ * Purpose:
+ * Given a gizmo, moves all other gizmos to the right of it to the
+ * left by its width on the GizmoBar. Used when removing or hiding
+ * the gizmo.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO that is going away, visibly or physically.
+ *
+ * Return Value:
+ * None
+ */
+
+void GizmosCompact(LPGIZMO pGizmo)
+ {
+ UINT cx;
+ LPGIZMO pCur;
+
+ //Move all the gizmos beyond us on the GizmoBar back by our width.
+ if (NULL!=pGizmo->pNext)
+ {
+ cx=pGizmo->pNext->x - pGizmo->x;
+ pCur=pGizmo->pNext;
+
+ while (NULL!=pCur)
+ {
+ pCur->x-=cx;
+
+ if (NULL!=pCur->hWnd)
+ {
+ SetWindowPos(pCur->hWnd, NULL, pCur->x, pCur->y
+ , 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ }
+
+ pCur=pCur->pNext;
+ }
+ }
+
+ return;
+ }
+
+
+
+
+
+
+/*
+ * GizmoPFind
+ *
+ * Purpose:
+ * Given a GIZMO identifier, locates and returns a pointer to the structure
+ * for that position.
+ *
+ * Parameters:
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * uID UINT identifier to find.
+ *
+ * Return Value:
+ * LPGIZMO A pointer to a GIZMO structure allocated through
+ * GizmoPAllocate, NULL if iGizmo is out of range.
+ */
+
+LPGIZMO GizmoPFind(LPLPGIZMO ppFirst, UINT uID)
+ {
+ LPGIZMO pGizmo;
+
+ pGizmo=*ppFirst;
+
+ /*
+ * Yep, linear search, but a better search algorithm won't improve
+ * things appreciably. The better thing to optimize is what the
+ * caller passes as ppFirst.
+ */
+ while (NULL!=pGizmo && uID!=pGizmo->uID)
+ pGizmo=pGizmo->pNext;
+
+ return pGizmo;
+ }
+
+
+
+
+
+
+/*
+ * GizmoFEnum
+ *
+ * Purpose:
+ * Enumerates the list of GIZMO structures, passing each one to
+ * an application-defined callback.
+ *
+ * Parameters:
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * pfnEnum LPFNGIZMOENUM to call for each enumerated structure.
+ * dw DWORD extra data to pass to the enumeration function.
+ *
+ * Return Value:
+ * LPGIZMO NULL if the enumeration completed. Otherwise a pointer
+ * to the gizmo that enumeration stopped on.
+ */
+
+LPGIZMO GizmoPEnum(LPLPGIZMO ppFirst, LPFNGIZMOENUM pfnEnum, DWORD dw)
+ {
+ LPGIZMO pGizmo;
+ UINT i=0;
+
+ pGizmo=*ppFirst;
+
+ while (NULL!=pGizmo)
+ {
+ if (!(*pfnEnum)(pGizmo, i++, dw))
+ break;
+
+ pGizmo=pGizmo->pNext;
+ }
+
+ return pGizmo;
+ }
+
+
+
+
+/*
+ * GizmoPStateSet
+ *
+ * Purpose:
+ * State maniuplation functions. Set and Clear also invalidate
+ * this gizmo's rectangle on the given window and forces a repaint.
+ *
+ * Parameters:
+ * hWnd HWND of the window to repaint.
+ * pGizmo LPGIZMO affected.
+ * dwNew DWORD new state flags.
+ *
+ * Return Value:
+ * UINT Previous state.
+ */
+
+UINT GizmoPStateSet(HWND hWnd, LPGIZMO pGizmo, UINT uNew)
+ {
+ UINT uRet;
+ RECT rc;
+
+ if (GIZMOTYPE_SEPARATOR==pGizmo->iType)
+ return pGizmo->uState;
+
+ //Preserve the color conversion flags across this state change.
+ uRet=pGizmo->uState;
+ pGizmo->uState=(uNew & 0x00FF) | (uRet & 0xFF00);
+
+ //Adjust the rectangle by one to avoid repainting borders.
+ SetRect(&rc, pGizmo->x+1, pGizmo->y+1, pGizmo->x+pGizmo->dx-1, pGizmo->y+pGizmo->dy-1);
+ InvalidateRect(hWnd, &rc, FALSE);
+ UpdateWindow(hWnd);
+
+ return uRet;
+ }
+
+
+
+
+
+
+
+
+/*
+ * GizmoPCheck
+ *
+ * Purpose:
+ * Handles checking a single button in a group of attribute buttons.
+ * If the gizmo belongs to a group of mutually exclusive buttons then
+ * the others surrounding it are unchecked appropriately.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * pGizmo LPGIZMO of the gizmo affected.
+ * fCheck BOOL TRUE to check the button, FALSE to uncheck.
+ *
+ * Return Value:
+ * BOOL TRUE if the gizmo was previously checked, FALSE
+ * otherwise.
+ */
+
+BOOL GizmoPCheck(HWND hWnd, LPGIZMO pGizmo, BOOL fCheck)
+ {
+ BOOL fPrevCheck;
+ LPGIZMO pCur;
+
+
+ //Ignore command buttons.
+ if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType)
+ return FALSE;
+
+ //Get the previous state
+ fPrevCheck=(BOOL)(BUTTONGROUP_DOWN & pGizmo->uState);
+
+
+ //Simply set the state for inclusive attribute buttons.
+ if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType)
+ {
+ if (pGizmo->fDisabled)
+ {
+ GizmoPStateSet(hWnd, pGizmo
+ , fCheck ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DISABLED);
+ }
+ else
+ {
+ GizmoPStateSet(hWnd, pGizmo
+ , fCheck ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_UP);
+ }
+ }
+
+
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType)
+ {
+ //We cannot uncheck an exclusive attribute
+ if (!fCheck)
+ return fPrevCheck;
+
+ /*
+ * For exclusive buttons we have to do more work. First, if we're
+ * already checked (incliding DOWN and MOUSEDOWN) then we set DOWN
+ * and exit. If we're not already checked, then we look for the
+ * gizmo around us, backwards and forwards, that is checked and
+ * uncheck him.
+ */
+
+ //Search backwards.
+ pCur=pGizmo->pPrev;
+
+ while (NULL!=pCur)
+ {
+ //Stop at any non-exclusive attribute.
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)
+ {
+ pCur=NULL;
+ break;
+ }
+
+ //If it's down, set it up and we've finished.
+ if (BUTTONGROUP_DOWN & pCur->uState)
+ break;
+
+ pCur=pCur->pPrev;
+ }
+
+
+ //If we didn't find a previous one, pCur is NULL, so look ahead.
+ if (NULL==pCur)
+ {
+ pCur=pGizmo->pNext;
+
+ while (NULL!=pCur)
+ {
+ //Stop at any non-exclusive attribute.
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)
+ {
+ pCur=NULL;
+ break;
+ }
+
+ //If it's down, set it up and we've finished.
+ if (BUTTONGROUP_DOWN & pCur->uState)
+ break;
+
+ pCur=pCur->pNext;
+ }
+ }
+
+ //If pCur is non-NULL, the we found a neighbor, so uncheck him
+ if (NULL!=pCur)
+ {
+ GizmoPStateSet(hWnd, pCur
+ , (pGizmo->fDisabled) ? ATTRIBUTEBUTTON_DISABLED : ATTRIBUTEBUTTON_UP);
+ }
+
+ //Always set ourselves down
+ GizmoPStateSet(hWnd, pGizmo
+ , (pGizmo->fDisabled) ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DOWN);
+ }
+
+ return fPrevCheck;
+ }
+
+
+
+
+
+
+
+/*
+ * GenericSubProc
+ *
+ * Purpose:
+ * Subclasses window controls in Gizmos so we can trap the tab key and
+ * tab to the next control. We can have one shared generic subclass
+ * procedure because we save the type index for this control in the
+ * property "iType." This allows us to look up the original procedure
+ * in the pfnOrg array.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+//LRESULT FAR PASCAL EXPORT GenericSubProc(HWND hWnd, UINT iMsg
+LRESULT FAR PASCAL GenericSubProc(HWND hWnd, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ LONG lRet;
+ RECT rc;
+ RECT rcE;
+ HWND hWndE;
+ HBRUSH hBr;
+ HDC hDC;
+ UINT dx;
+ UINT iType, i;
+
+ i=(int)GetProp(hWnd, SZTYPEPROP);
+ iType=POSITIONBIT(i);
+
+ //Special: paint the gap in drop-down comboboxes.
+ if (GIZMOTYPE_COMBOBOX==iType && WM_PAINT==iMsg)
+ {
+ //Do default painting.
+ lRet=(*pfnOrg[i])(hWnd, iMsg, wParam, lParam);
+
+ hWndE=GetDlgItem(hWnd, ID_COMBOEDIT);
+
+ GetClientRect(hWnd, &rc);
+ GetClientRect(hWndE, &rcE);
+
+ //The width of the button is the scroll bar width.
+ dx=GetSystemMetrics(SM_CXVSCROLL);
+
+ //Calculate the rectangle
+ rc.right -=dx;
+ rc.left =rcE.right;
+ rc.bottom+=1;
+
+ //Paint the gap
+ hDC=GetDC(hWnd); //Already did BeginPaint and EndPaint
+
+ hBr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+ FillRect(hDC, &rc, hBr);
+ DeleteObject(hBr);
+
+ ReleaseDC(hWnd, hDC);
+ return lRet;
+ }
+
+ //Control tabbing to the next or previous control in the GizmoBar.
+ if (WM_KEYDOWN==iMsg && VK_TAB==wParam)
+ {
+ hWndE=hWnd;
+
+ if (-1==i)
+ hWndE=GetParent(hWnd);
+
+ hWndE=GetNextDlgTabItem(GetParent(hWndE), hWnd, (BOOL)(GetKeyState(VK_SHIFT)));
+ SetFocus(hWndE);
+ return 0L;
+ }
+
+ if (-1==i) i=0;
+
+ //Eat tab chars in edit controls to prevent beeping.
+ if (0==i && WM_CHAR==iMsg && VK_TAB==wParam)
+ return 0L;
+
+
+ //Do this or edit controls bomb big-time.
+ return CallWindowProc(pfnOrg[i], hWnd, iMsg, wParam, lParam);
+ }
diff --git a/private/oleutest/letest/gizmobar/gizmo.h b/private/oleutest/letest/gizmobar/gizmo.h
new file mode 100644
index 000000000..e99e06379
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmo.h
@@ -0,0 +1,103 @@
+/*
+ * GIZMO.H
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Data structure and type definitions for the GIZMO data structure. Each
+ * gizmo on a gizmobar has one of these structures associated with it.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#ifndef _GIZMO_H_
+#define _GIZMO_H_
+
+#ifdef __cplusplus
+extern "C"
+ {
+#endif
+
+
+typedef struct tagGIZMO
+ {
+ struct tagGIZMO FAR *pPrev;
+ struct tagGIZMO FAR *pNext;
+ UINT iType;
+ HWND hWnd; //Texts, edits, lists, and combos only.
+ UINT uID;
+ UINT x, y;
+ UINT dx, dy;
+ UINT cxImage; //From UIToolConfigureForDisplay
+ UINT cyImage;
+ HBITMAP hBmp; //Buttons only.
+ UINT iBmp;
+ BOOL fNotify; //Indicates whether we send WM_COMMANDs
+ BOOL fHidden; //Independent of state
+ BOOL fDisabled;
+ UINT uState;
+ UINT uStateOrg;
+ DWORD dwData; //Application-supplied data.
+ } GIZMO, FAR * LPGIZMO;
+
+typedef LPGIZMO FAR *LPLPGIZMO;
+#define CBGIZMO sizeof(GIZMO)
+
+//Property name we attach to controls in a gizmo to identify control type
+#define SZTYPEPROP TEXT("iType")
+
+//Number of controls we subclass
+#define CSUBGIZMOS 4
+
+//ID of edit controls in comboboxes
+#define ID_COMBOEDIT 1001
+
+
+/*
+ * Conversion of iType (a positioned bit) into its position.
+ * The BITPOSITION macro does not need to be fast because we only
+ * use it once when creating a gizmo. POSITIONBIT does, however, since
+ * we use it in subclass procedures.
+ */
+#define BITPOSITION(i, j) {int k=i; for (j=0; k>>=1; j++);}
+#define POSITIONBIT(i) (1 << i)
+
+//Control classifications. GIZMOBAR.H must be included first.
+#define GIZMOTYPE_WINDOWS (GIZMOTYPE_TEXT | GIZMOTYPE_EDIT | GIZMOTYPE_LISTBOX | GIZMOTYPE_COMBOBOX | GIZMOTYPE_BUTTONNORMAL)
+#define GIZMOTYPE_BUTTONS (GIZMOTYPE_BUTTONATTRIBUTEIN | GIZMOTYPE_BUTTONATTRIBUTEEX | GIZMOTYPE_BUTTONCOMMAND | GIZMOTYPE_BUTTONNORMAL)
+#define GIZMOTYPE_DRAWN (GIZMOTYPE_BUTTONATTRIBUTEIN | GIZMOTYPE_BUTTONATTRIBUTEEX | GIZMOTYPE_BUTTONCOMMAND)
+
+
+//These must stay in sync with GIZMOBAR.H
+#define GIZMOTYPE_MIN GIZMOTYPE_EDIT
+#define GIZMOTYPE_MAX GIZMOTYPE_BUTTONCOMMAND
+
+
+//Enumeration callback
+typedef BOOL (FAR PASCAL *LPFNGIZMOENUM)(LPGIZMO, UINT, DWORD);
+
+
+//GIZMO.C
+LPGIZMO GizmoPAllocate(LPINT, LPLPGIZMO, HWND, UINT, UINT, UINT, UINT, UINT, LPTSTR, HBITMAP, UINT, UINT);
+void GizmosExpand(LPGIZMO);
+LPGIZMO GizmoPFree(LPLPGIZMO, LPGIZMO);
+void GizmosCompact(LPGIZMO);
+LPGIZMO GizmoPFind(LPLPGIZMO, UINT);
+LPGIZMO GizmoPEnum(LPLPGIZMO, LPFNGIZMOENUM, DWORD);
+UINT GizmoPStateSet(HWND, LPGIZMO, UINT);
+BOOL GizmoPCheck(HWND, LPGIZMO, BOOL);
+
+//LRESULT FAR PASCAL EXPORT GenericSubProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT FAR PASCAL GenericSubProc(HWND, UINT, WPARAM, LPARAM);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif //_GIZMO_H_
diff --git a/private/oleutest/letest/gizmobar/gizmobar.c b/private/oleutest/letest/gizmobar/gizmobar.c
new file mode 100644
index 000000000..78b4fafd0
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmobar.c
@@ -0,0 +1,467 @@
+/*
+ * GIZMOBAR.C
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Contains the main window procedure of the GizmoBar control
+ * that handles mouse logic and Windows messages.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+
+
+/*
+ * GizmoBarWndProc
+ *
+ * Purpose:
+ * Window Procedure for the GizmoBar custom control. Handles all
+ * messages like WM_PAINT just as a normal application window would.
+ * Any message not processed here should go to DefWindowProc.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+LRESULT FAR PASCAL GizmoBarWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+ {
+ BOOL fSuccess;
+ BOOL fTemp;
+ LPCREATESTRUCT pCreate;
+ LPGIZMOBAR pGB;
+ LPGIZMO pGizmo;
+ RECT rc;
+ POINT pt;
+ short x, y;
+ COLORREF cr;
+
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);
+
+ //Pass control messages onto another function for processing.
+ if (iMsg >= WM_USER)
+ return GBMessageHandler(hWnd, iMsg, wParam, lParam, pGB);
+
+ switch (iMsg)
+ {
+ case WM_NCCREATE:
+ pCreate=(LPCREATESTRUCT)lParam;
+
+ pGB=GizmoBarPAllocate((LPINT)&fSuccess, hWnd, pCreate->hInstance
+ , pCreate->hwndParent, pCreate->style, 0
+ , (UINT)pCreate->hMenu);
+
+ if (!fSuccess)
+ {
+ GizmoBarPFree(pGB);
+ return -1L;
+ }
+ else
+ SetWindowLong(hWnd, GBWL_STRUCTURE, (LONG)pGB);
+
+ return DefWindowProc(hWnd, iMsg, wParam, lParam);
+
+
+ case WM_DESTROY:
+ /*
+ * We want to clean up before DestroyWindow nukes all the
+ * children, so WM_DESTROY is a better to do it than
+ * WM_NCDESTROY.
+ */
+ GizmoBarPFree(pGB);
+ break;
+
+
+ case WM_ERASEBKGND:
+ /*
+ * Eat this message to avoid erasing portions that
+ * we are going to repaint in WM_PAINT. Part of a
+ * change-state-and-repaint strategy is to rely on
+ * WM_PAINT to do anything visual, which includes
+ * erasing invalid portions. Letting WM_ERASEBKGND
+ * erase the background is redundant.
+ */
+ return TRUE;
+
+ #ifdef WIN32
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSTATIC:
+ fTemp=TRUE;
+ #else
+ case WM_CTLCOLOR:
+ //Change the color of static text on the GizmoBar.
+ fTemp=(HIWORD(lParam)==CTLCOLOR_STATIC
+ || HIWORD(lParam)==CTLCOLOR_BTN);
+ #endif
+
+ if (fTemp)
+ {
+ cr=GetSysColor(COLOR_BTNFACE);
+ SetTextColor((HDC)wParam, GetSysColor(COLOR_BTNTEXT));
+ SetBkColor((HDC)wParam, cr);
+
+ /*
+ * If the system colors have changed, then crFace will
+ * not be equal to COLOR_BTNFACE, so we reinitialize the
+ * background brush. This scheme handles system color
+ * changes appropriately without processing WM_WININICHANGE
+ * and without blindly creating a new brush on every
+ * WM_CTLCOLOR message.
+ */
+ if (cr!=pGB->crFace)
+ {
+ pGB->crFace=cr;
+
+ if (NULL!=pGB->hBrFace)
+ DeleteObject(pGB->hBrFace);
+
+ pGB->hBrFace=CreateSolidBrush(pGB->crFace);
+ }
+
+ return (LONG)(UINT)pGB->hBrFace;
+ }
+
+ return DefWindowProc(hWnd, iMsg, wParam, lParam);
+
+
+ case WM_PAINT:
+ GizmoBarPaint(hWnd, pGB);
+ break;
+
+
+ case WM_SETFONT:
+ /*
+ * wParam has the new font that we now send to all other
+ * windows controls in us. We control repaints here to
+ * prevent a lot of repainting for each control.
+ */
+ DefWindowProc(hWnd, WM_SETREDRAW, FALSE, 0L);
+
+ if ((WPARAM)NULL!=wParam)
+ {
+ pGB->hFont=(HFONT)wParam;
+ GizmoPEnum(&pGB->pGizmos, FEnumChangeFont, (DWORD)(LPSTR)pGB);
+
+ DefWindowProc(hWnd, WM_SETREDRAW, TRUE, 0L);
+ InvalidateRect(hWnd, NULL, FALSE);
+ UpdateWindow(hWnd);
+ }
+
+ break;
+
+
+ case WM_GETFONT:
+ return (LRESULT)(UINT)pGB->hFont;
+
+
+ case WM_ENABLE:
+ /*
+ * wParam has the new enable flag that we use to enable
+ * or disable ALL controls in us at one time. We also turn
+ * the redraw off to prevent a lot of flicker.
+ */
+ DefWindowProc(hWnd, WM_SETREDRAW, FALSE, 0L);
+
+ pGB->fEnabled=(BOOL)wParam;
+ GizmoPEnum(&pGB->pGizmos, FEnumEnable, (DWORD)(LPSTR)pGB);
+
+ DefWindowProc(hWnd, WM_SETREDRAW, TRUE, 0L);
+ InvalidateRect(hWnd, NULL, FALSE);
+ UpdateWindow(hWnd);
+ break;
+
+
+ case WM_CANCELMODE:
+ pGizmo=pGB->pGizmoTrack;
+
+ pGB->fTracking=FALSE;
+ pGB->fMouseOut=FALSE;
+
+ if (NULL!=pGizmo)
+ GizmoPStateSet(hWnd, pGizmo, COMMANDBUTTON_UP);
+
+ ReleaseCapture();
+ break;
+
+
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ //Get the mouse coordinates.
+ x=LOWORD(lParam);
+ y=HIWORD(lParam);
+
+
+ /*
+ * See if we hit a command or attribute gizmo or not. Anything
+ * else that is a control will get the message instead of
+ * us anyway, so we don't have to check. FEnumHitTest also
+ * validates drawn gizmos, enabled, and visible, so we don't.
+ */
+ pGizmo=GizmoPEnum(&pGB->pGizmos, FEnumHitTest, lParam);
+
+ if (NULL==pGizmo)
+ break; //Didn't hit one matching our needs.
+
+ /*
+ * Inform the associate that a command was hit like a menu item.
+ */
+ if (NULL!=pGB->hWndAssociate)
+ {
+ if (pGizmo->fNotify)
+ SendMenuSelect(pGB->hWndAssociate, pGizmo->uID, 0, 0);
+ }
+
+ /*
+ * We hit a button. If it's a command or attribute, then change
+ * the state and start tracking.
+ */
+ pGB->fTracking=TRUE;
+ pGB->pGizmoTrack=pGizmo;
+ pGB->fMouseOut=FALSE;
+ SetCapture(hWnd);
+
+ pGizmo->uStateOrg=pGizmo->uState;
+ GizmoPStateSet(hWnd, pGizmo, ATTRIBUTEBUTTON_MOUSEDOWN);
+
+ break;
+
+
+ case WM_MOUSEMOVE:
+ POINTFROMLPARAM(pt, lParam);
+
+ if (!pGB->fTracking)
+ break;
+
+ pGizmo=pGB->pGizmoTrack;
+ SetRect(&rc, pGizmo->x, pGizmo->y, pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy);
+
+ fTemp=pGB->fMouseOut;
+ pGB->fMouseOut=!PtInRect(&rc, pt);
+
+ //If the mouse went out, change state to the original.
+ if (!fTemp && pGB->fMouseOut)
+ {
+ GizmoPStateSet(hWnd, pGizmo, pGizmo->uStateOrg);
+
+ if (NULL!=pGB->hWndAssociate)
+ {
+ //Notify that we left the button
+ if (pGizmo->fNotify)
+ SendMenuSelect(pGB->hWndAssociate, 0x0000, 0xFFFF, 0);
+ }
+ }
+
+ if (fTemp && !pGB->fMouseOut)
+ {
+ GizmoPStateSet(hWnd, pGizmo, ATTRIBUTEBUTTON_MOUSEDOWN);
+
+ if (NULL!=pGB->hWndAssociate)
+ {
+ //Notify that we pressed down again
+ if (pGizmo->fNotify)
+ SendMenuSelect(pGB->hWndAssociate, pGizmo->uID, 0x0000, 0);
+ }
+ }
+
+ break;
+
+
+ case WM_LBUTTONUP:
+ if (!pGB->fTracking)
+ break;
+
+ pGB->fTracking=FALSE;
+ pGizmo=pGB->pGizmoTrack;
+ ReleaseCapture();
+
+
+ /*
+ * Repaint if we were actually below the mouse when this
+ * occurred. For command buttons, pop the button up. For
+ * attributes, either toggle the state (inclusive buttons)
+ * or check the selected one (exclusive buttons).
+ */
+
+ if (!pGB->fMouseOut)
+ {
+ //Command buttons always come up.
+ if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType)
+ GizmoPStateSet(hWnd, pGizmo, COMMANDBUTTON_UP);
+
+ //Attribute inclusive buttons toggle
+ if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType)
+ GizmoPCheck(hWnd, pGizmo, !(BUTTONGROUP_DOWN & pGizmo->uStateOrg));
+
+ //Attribure exclusive buttons are always checked.
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType)
+ GizmoPCheck(hWnd, pGizmo, TRUE);
+
+ //Only send messages if notify is ON.
+ if (NULL!=pGB->hWndAssociate && pGizmo->fNotify)
+ {
+ SendMenuSelect(pGB->hWndAssociate, 0, 0xFFFF, 0);
+ SendCommand(pGB->hWndAssociate, pGizmo->uID, BN_CLICKED, hWnd);
+ }
+ }
+
+ break;
+
+
+ case WM_COMMAND:
+ //Pass control messages on if the gizmo's notify is ON.
+ if (NULL!=pGB->hWndAssociate)
+ {
+ pGizmo=PGizmoFromHwndID(hWnd, wID);
+
+ if (NULL!=pGizmo)
+ {
+ if (pGizmo->fNotify)
+ SendMessage(pGB->hWndAssociate, iMsg, wParam, lParam);
+ }
+ }
+ break;
+
+ default:
+ return DefWindowProc(hWnd, iMsg, wParam, lParam);
+ }
+
+ return 0L;
+ }
+
+
+
+
+
+/*
+ * FEnumChangeFont
+ *
+ * Purpose:
+ * Enumeration callback for all the gizmos we know about in order to
+ * send a new font to them that's stored in LPGIZMOBAR in dw.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO to draw.
+ * iGizmo UINT index on the GizmoBar of this gizmo.
+ * dw DWORD extra data passed to GizmoPEnum, in our case
+ * the GizmoBar's pGB.
+ *
+ * Return Value:
+ * BOOL TRUE to continue the enumeration, FALSE otherwise.
+ */
+
+BOOL FAR PASCAL FEnumChangeFont(LPGIZMO pGizmo, UINT iGizmo, DWORD dw)
+ {
+ LPGIZMOBAR pGB=(LPGIZMOBAR)dw;
+
+ //We only need to change fonts in windowed controls using WM_SETFONT
+ if (NULL!=pGizmo->hWnd)
+ SendMessage(pGizmo->hWnd, WM_SETFONT, (WPARAM)pGB->hFont, 1L);
+
+ return TRUE;
+ }
+
+
+
+
+
+
+/*
+ * FEnumEnable
+ *
+ * Purpose:
+ * Enumeration callback for all the gizmos we know about in order to
+ * enable or disable them from the WM_ENABLE message.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO to draw.
+ * iGizmo UINT index on the GizmoBar of this gizmo.
+ * dw DWORD extra data passed to GizmoPEnum, in our case
+ * the GizmoBar's pGB.
+ *
+ * Return Value:
+ * BOOL TRUE to continue the enumeration, FALSE otherwise.
+ */
+
+BOOL FAR PASCAL FEnumEnable(LPGIZMO pGizmo, UINT iGizmo, DWORD dw)
+ {
+ LPGIZMOBAR pGB=(LPGIZMOBAR)dw;
+ BOOL fEnable=pGB->fEnabled;
+
+ //NOTE: This code is duplicated in GBGizmoEnable in API.C
+ if (NULL!=pGizmo->hWnd)
+ EnableWindow(pGizmo->hWnd, fEnable);
+ else
+ {
+ //If we're not down, command and attribute buttons act the same.
+ if (!(BUTTONGROUP_DOWN & pGizmo->uState))
+ {
+ GizmoPStateSet(pGB->hWnd, pGizmo
+ , fEnable ? COMMANDBUTTON_UP : COMMANDBUTTON_DISABLED);
+ }
+ else
+ {
+ //Attribute buttons are a little more sensitive with DOWNDISABLED
+ GizmoPStateSet(pGB->hWnd, pGizmo
+ , fEnable ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_DOWNDISABLED);
+ }
+ }
+
+ return TRUE;
+ }
+
+
+
+
+
+
+
+/*
+ * FEnumHitTest
+ *
+ * Purpose:
+ * Enumeration callback for all the gizmos we know about in order to
+ * hit-test them.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO to draw.
+ * iGizmo UINT index on the GizmoBar of this gizmo.
+ * dw DWORD extra data passed to GizmoPEnum, in our case
+ * the hDC on which to draw.
+ *
+ * Return Value:
+ * BOOL TRUE to continue the enumeration, FALSE otherwise.
+ */
+
+BOOL FAR PASCAL FEnumHitTest(LPGIZMO pGizmo, UINT iGizmo, DWORD dw)
+ {
+ RECT rc;
+ POINT pt;
+
+ POINTFROMLPARAM(pt, dw);
+
+ //Hit tests have to happen on visible, enabled, and drawn controls only.
+ if (GIZMOTYPE_DRAWN & pGizmo->iType
+ && !pGizmo->fHidden && !(BUTTONGROUP_DISABLED & pGizmo->uState))
+ {
+ SetRect(&rc, pGizmo->x, pGizmo->y
+ , pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy);
+
+ //Stop enumeration if we have a hit.
+ return !PtInRect(&rc, pt);
+ }
+
+ return TRUE;
+ }
diff --git a/private/oleutest/letest/gizmobar/gizmobar.h b/private/oleutest/letest/gizmobar/gizmobar.h
new file mode 100644
index 000000000..f4888f925
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmobar.h
@@ -0,0 +1,178 @@
+/*
+ * GIZMOBAR.H
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Public definitions for application that use the GizmoBar such as
+ * messages, prototypes for API functions, notification codes, and
+ * control styles.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#ifndef _GIZMOBAR_H_
+#define _GIZMOBAR_H_
+
+#ifdef __cplusplus
+extern "C"
+ {
+#endif
+
+
+//Classname
+#define CLASS_GIZMOBAR TEXT("gizmobar")
+
+
+//Message API Functions
+HWND WINAPI GBHwndAssociateSet(HWND, HWND);
+HWND WINAPI GBHwndAssociateGet(HWND);
+
+BOOL WINAPI GBGizmoAdd(HWND, UINT, UINT, UINT, UINT, UINT, LPTSTR, HBITMAP, UINT, UINT);
+BOOL WINAPI GBGizmoRemove(HWND, UINT);
+
+LRESULT WINAPI GBGizmoSendMessage(HWND, UINT, UINT, WPARAM, LPARAM);
+
+BOOL WINAPI GBGizmoShow(HWND, UINT, BOOL);
+BOOL WINAPI GBGizmoEnable(HWND, UINT, BOOL);
+BOOL WINAPI GBGizmoCheck(HWND, UINT, BOOL);
+UINT WINAPI GBGizmoFocusSet(HWND, UINT);
+BOOL WINAPI GBGizmoExist(HWND, UINT);
+
+int WINAPI GBGizmoTypeGet(HWND, UINT);
+
+DWORD WINAPI GBGizmoDataSet(HWND, UINT, DWORD);
+DWORD WINAPI GBGizmoDataGet(HWND, UINT);
+BOOL WINAPI GBGizmoNotifySet(HWND, UINT, BOOL);
+BOOL WINAPI GBGizmoNotifyGet(HWND, UINT);
+
+int WINAPI GBGizmoTextGet(HWND, UINT, LPTSTR, UINT);
+void WINAPI GBGizmoTextSet(HWND, UINT, LPTSTR);
+UINT WINAPI GBGizmoIntGet(HWND, UINT, BOOL FAR *, BOOL);
+void WINAPI GBGizmoIntSet(HWND, UINT, UINT, BOOL);
+
+
+
+//Notification codes sent via WM_COMMAND from GBHwndAssociateSet
+#define GBN_ASSOCIATEGAIN 1
+#define GBN_ASSOCIATELOSS 2
+#define GBN_GIZMOADDED 3
+#define GBN_GIZMOREMOVED 4
+
+//Message equivalents for functions.
+#define GBM_HWNDASSOCIATESET (WM_USER+0)
+#define GBM_HWNDASSOCIATEGET (WM_USER+1)
+#define GBM_GIZMOADD (WM_USER+2)
+#define GBM_GIZMOREMOVE (WM_USER+3)
+#define GBM_GIZMOSENDMESSAGE (WM_USER+4)
+#define GBM_GIZMOSHOW (WM_USER+5)
+#define GBM_GIZMOENABLE (WM_USER+6)
+#define GBM_GIZMOCHECK (WM_USER+7)
+#define GBM_GIZMOFOCUSSET (WM_USER+8)
+#define GBM_GIZMOEXIST (WM_USER+9)
+#define GBM_GIZMOTYPEGET (WM_USER+10)
+#define GBM_GIZMODATASET (WM_USER+11)
+#define GBM_GIZMODATAGET (WM_USER+12)
+#define GBM_GIZMONOTIFYSET (WM_USER+13)
+#define GBM_GIZMONOTIFYGET (WM_USER+14)
+#define GBM_GIZMOTEXTGET (WM_USER+15)
+#define GBM_GIZMOTEXTSET (WM_USER+16)
+#define GBM_GIZMOINTGET (WM_USER+17)
+#define GBM_GIZMOINTSET (WM_USER+18)
+
+
+
+
+/*
+ * Structure passed in lParam of GBM_GIZMOADD that mirrors the parameters
+ * to GBGizmoAdd.
+ */
+
+typedef struct
+ {
+ HWND hWndParent; //Parent window
+ UINT iType; //Type of gizmo
+ UINT iGizmo; //Position in which to create gizmo
+ UINT uID; //Identifier of gizmo (for WM_COMMAND messages)
+ UINT dx; //Dimensions of gizmo
+ UINT dy;
+ LPTSTR pszText; //Gizmo text
+ HBITMAP hBmp; //Source of gizmo button image.
+ UINT iImage; //Index of image from hBmp
+ UINT uState; //Initial state of the gizmo.
+ } CREATEGIZMO, FAR *LPCREATEGIZMO;
+
+#define CBCREATEGIZMO sizeof(CREATEGIZMO)
+
+
+//For GBM_GIZMOSENDMESSAGE
+typedef struct
+ {
+ UINT iMsg;
+ WPARAM wParam;
+ LPARAM lParam;
+ } GBMSG, FAR * LPGBMSG;
+
+#define CBGBMSG sizeof(GBMSG);
+
+//For GBM_GIZMOGETTEXT
+typedef struct
+ {
+ LPTSTR psz;
+ UINT cch;
+ } GBGETTEXT, FAR * LPGBGETTEXT;
+
+#define CBGBGETTEXT sizeof(GBGETTEXT);
+
+
+//For GBM_GIZMOGETINT
+typedef struct
+ {
+ BOOL fSigned;
+ BOOL fSuccess;
+ } GBGETINT, FAR * LPGBGETINT;
+
+#define CBGBGETINT sizeof(GBGETINT);
+
+
+//For GBM_GIZMOSETINT
+typedef struct
+ {
+ UINT uValue;
+ BOOL fSigned;
+ } GBSETINT, FAR * LPGBSETINT;
+
+#define CBGBSETINT sizeof(GBSETINT);
+
+
+
+//Gizmo control types. DO NOT CHANGE THESE!
+#define GIZMOTYPE_EDIT 0x0001
+#define GIZMOTYPE_LISTBOX 0x0002
+#define GIZMOTYPE_COMBOBOX 0x0004
+#define GIZMOTYPE_BUTTONNORMAL 0x0008 //Top of windowed gizmos.
+#define GIZMOTYPE_TEXT 0x0010
+#define GIZMOTYPE_SEPARATOR 0x0020
+#define GIZMOTYPE_BUTTONATTRIBUTEIN 0x0040
+#define GIZMOTYPE_BUTTONATTRIBUTEEX 0x0080
+#define GIZMOTYPE_BUTTONCOMMAND 0x0100
+
+
+//Generic state flags for non-buttons based on BTTNCUR.H's button groups.
+#define GIZMO_NORMAL (BUTTONGROUP_ACTIVE)
+#define GIZMO_DISABLED (BUTTONGROUP_DISABLED)
+
+
+
+#ifdef __cplusplus
+ } //Match with extern "C" above.
+#endif
+
+
+
+#endif //_GIZMOBAR_H_
diff --git a/private/oleutest/letest/gizmobar/gizmobar.rc b/private/oleutest/letest/gizmobar/gizmobar.rc
new file mode 100644
index 000000000..e1550028e
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmobar.rc
@@ -0,0 +1,20 @@
+/*
+ * GIZMOBAR.RC
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Strings and other resources for the GizmoBar.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+rcinclude gizmobar.rcv
diff --git a/private/oleutest/letest/gizmobar/gizmobar.rcv b/private/oleutest/letest/gizmobar/gizmobar.rcv
new file mode 100644
index 000000000..8958b7a2f
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmobar.rcv
@@ -0,0 +1,53 @@
+/*
+ * GIZMOBAR.RCV
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Version resource file for the GizmoBar Control DLL
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+//Default is nodebug
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VER_DEBUG
+ FILEOS VOS_DOS_WINDOWS16
+ FILETYPE VFT_DLL
+ FILESUBTYPE VFT_UNKNOWN
+
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0", "\0"
+ VALUE "FileDescription", "Kraig Brockschmidt's GizmoBar", "\0"
+ VALUE "FileVersion", "1.00\0", "\0"
+ VALUE "InternalName", "GIZMOBAR.DLL", "\0"
+ VALUE "LegalCopyright", "Copyright \251 1993 Microsoft Corp.", "\0"
+ VALUE "OriginalFilename","GIZMOBAR.DLL", "\0"
+ VALUE "ProductName", "Kraig Brockschmidt's GizmoBar", "\0"
+ VALUE "ProductVersion", "1.00\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x04E4
+ END
+ END
+
diff --git a/private/oleutest/letest/gizmobar/gizmoint.h b/private/oleutest/letest/gizmobar/gizmoint.h
new file mode 100644
index 000000000..842b62a3e
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmoint.h
@@ -0,0 +1,105 @@
+/*
+ * GIZMOINT.H
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Internal definitions for the GizmoBar DLL
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#ifndef _GIZMOINT_H_
+#define _GIZMOINT_H_
+
+#include <bttncur.h>
+#include <book1632.h>
+#include "gizmo.h"
+#include "gizmobar.h"
+
+#ifdef __cplusplus
+extern "C"
+ {
+#endif
+
+
+/*
+ * The main gizmobar structure itself. There's only one of these,
+ * but it references the first GIZMO in the list.
+ */
+
+typedef struct tagGIZMOBAR
+ {
+ LPGIZMO pGizmos; //List of gizmos we own.
+ HWND hWnd; //Window handle of ourselves.
+ HINSTANCE hInst;
+ HWND hWndAssociate; //Associate window handle who gets messages.
+ DWORD dwStyle; //Copy of GetWindowLong(hWnd, GWL_STYLE)
+ UINT uState; //State flags
+ UINT uID; //Control ID.
+
+ HBRUSH hBrFace; //Static control background color
+ COLORREF crFace; //Color of hBrFace
+ HFONT hFont; //Font in use, defaults to system, WM_SETFONT
+ BOOL fEnabled; //Are we enabled?
+
+ LPGIZMO pGizmoTrack; //Current pressed button.
+ BOOL fTracking;
+ BOOL fMouseOut;
+ } GIZMOBAR, FAR * LPGIZMOBAR;
+
+#define CBGIZMOBAR sizeof(GIZMOBAR)
+
+
+//Extra bytes for the window if the size of a local handle.
+#define CBWINDOWEXTRA sizeof(LPGIZMOBAR)
+
+#define GBWL_STRUCTURE 0
+
+
+//Structure for passing paint information to a gizmo enumeration callback.
+typedef struct
+ {
+ HDC hDC;
+ BOOL fPaint;
+ } PAINTGIZMO, FAR * LPPAINTGIZMO;
+
+
+
+//Private functions specific to the control.
+
+//INIT.C
+#ifdef WIN32
+ extern BOOL WINAPI _CRT_INIT(HINSTANCE, DWORD, LPVOID);
+ extern _cexit(void);
+#endif //WIN32
+
+void FAR PASCAL WEP(int);
+BOOL FRegisterControl(HINSTANCE);
+LPGIZMOBAR GizmoBarPAllocate(LPINT, HWND, HINSTANCE, HWND, DWORD, UINT, UINT);
+LPGIZMOBAR GizmoBarPFree(LPGIZMOBAR);
+
+
+//PAINT.C
+void GizmoBarPaint(HWND, LPGIZMOBAR);
+BOOL FAR PASCAL FEnumPaintGizmos(LPGIZMO, UINT, DWORD);
+
+
+//GIZMOBAR.C
+LRESULT FAR PASCAL GizmoBarWndProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FAR PASCAL FEnumChangeFont(LPGIZMO, UINT, DWORD);
+BOOL FAR PASCAL FEnumEnable(LPGIZMO, UINT, DWORD);
+BOOL FAR PASCAL FEnumHitTest(LPGIZMO, UINT, DWORD);
+
+
+//API.C Also see GIZMOBAR.H for others
+LRESULT GBMessageHandler(HWND, UINT, WPARAM, LPARAM, LPGIZMOBAR);
+LPGIZMO PGizmoFromHwndID(HWND, UINT);
+
+
+#endif //_GIZMOINT_H_
diff --git a/private/oleutest/letest/gizmobar/init.c b/private/oleutest/letest/gizmobar/init.c
new file mode 100644
index 000000000..736ef47b4
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/init.c
@@ -0,0 +1,233 @@
+/*
+ * INIT.C
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * LibMain entry point and initialization code for the GizmoBar
+ * DLL that is likely to be used once or very infrequently.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+
+/*
+ * LibMain
+ *
+ * Purpose:
+ * Entry point conditionally compiled for Windows NT and Windows
+ * 3.1. Provides the proper structure for each environment
+ * and calls InternalLibMain for real initialization.
+ */
+
+#ifdef WIN32
+BOOL _cdecl LibMain(
+ HINSTANCE hDll,
+ DWORD dwReason,
+ LPVOID lpvReserved)
+ {
+ if (DLL_PROCESS_ATTACH == dwReason)
+ {
+ return FRegisterControl(hDll);
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
+#else
+HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg
+ , WORD cbHeapSize, LPSTR lpCmdLine)
+ {
+ //Perform global initialization.
+ if (FRegisterControl(hInstance))
+ {
+ if (0!=cbHeapSize)
+ UnlockData(0);
+ }
+
+ return hInstance;
+ }
+#endif
+
+
+
+
+/*
+ * WEP
+ *
+ * Purpose:
+ * Required DLL Exit function. Does nothing.
+ *
+ * Parameters:
+ * bSystemExit BOOL indicating if the system is being shut
+ * down or the DLL has just been unloaded.
+ *
+ * Return Value:
+ * void
+ *
+ */
+
+void FAR PASCAL WEP(int bSystemExit)
+ {
+ return;
+ }
+
+
+
+
+/*
+ * FRegisterControl
+ *
+ * Purpose:
+ * Registers the GizmoBar control class, including CS_GLOBALCLASS
+ * to make the control available to all applications in the system.
+ *
+ * Parameters:
+ * hInst HINSTANCE of the DLL that will own this class.
+ *
+ * Return Value:
+ * BOOL TRUE if the class is registered, FALSE otherwise.
+ */
+
+BOOL FRegisterControl(HINSTANCE hInst)
+ {
+ static BOOL fRegistered=FALSE;
+ WNDCLASS wc;
+
+ if (!fRegistered)
+ {
+ wc.lpfnWndProc =GizmoBarWndProc;
+ wc.cbClsExtra =0;
+ wc.cbWndExtra =CBWINDOWEXTRA;
+ wc.hInstance =hInst;
+ wc.hIcon =NULL;
+ wc.hCursor =LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground =(HBRUSH)(COLOR_BTNFACE+1);
+ wc.lpszMenuName =NULL;
+ wc.lpszClassName =CLASS_GIZMOBAR;
+ wc.style =CS_DBLCLKS | CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
+
+ fRegistered=RegisterClass(&wc);
+ }
+
+ return fRegistered;
+ }
+
+
+
+
+
+
+/*
+ * GizmoBarPAllocate
+ *
+ * Purpose:
+ * Allocates and initializes the control's primary data structure for
+ * each window that gets created.
+ *
+ * Parameters:
+ * pfSuccess LPINT indicating success of the function.
+ * hWnd HWND that is tied to this structure.
+ * hInst HINSTANCE of the DLL.
+ * hWndAssociate HWND to which we send messages.
+ * dwStyle DWORD initial style.
+ * uState UINT initial state.
+ * uID UINT identifier for this window.
+ *
+ * Return Value:
+ * LPGIZMOBAR If NULL returned then GizmoBarPAllocate could not allocate
+ * memory. If a non-NULL pointer is returned with
+ * *pfSuccess, then call GizmoBarPFree immediately. If you
+ * get a non-NULL pointer and *pfSuccess==TRUE then the
+ * function succeeded.
+ */
+
+LPGIZMOBAR GizmoBarPAllocate(LPINT pfSuccess, HWND hWnd, HINSTANCE hInst
+ , HWND hWndAssociate, DWORD dwStyle, UINT uState, UINT uID)
+ {
+ LPGIZMOBAR pGB;
+
+ if (NULL==pfSuccess)
+ return NULL;
+
+ *pfSuccess=FALSE;
+
+ //Allocate the structure
+ pGB=(LPGIZMOBAR)(void *)LocalAlloc(LPTR, CBGIZMOBAR);
+
+ if (NULL==pGB)
+ return NULL;
+
+ //Initialize LibMain parameter holders.
+ pGB->hWnd =hWnd;
+ pGB->hInst =hInst;
+ pGB->hWndAssociate=hWndAssociate;
+ pGB->dwStyle =dwStyle;
+ pGB->uState =uState;
+ pGB->uID =uID;
+ pGB->fEnabled =TRUE;
+
+ pGB->crFace=GetSysColor(COLOR_BTNFACE);
+ pGB->hBrFace=CreateSolidBrush(pGB->crFace);
+
+ if (NULL==pGB->hBrFace)
+ return pGB;
+
+ pGB->hFont=GetStockObject(SYSTEM_FONT);
+
+ *pfSuccess=TRUE;
+ return pGB;
+ }
+
+
+
+
+/*
+ * GizmoBarPFree
+ *
+ * Purpose:
+ * Reverses all initialization done by GizmoBarPAllocate, cleaning up
+ * any allocations including the application structure itself.
+ *
+ * Parameters:
+ * pGB LPGIZMOBAR to the control's structure
+ *
+ * Return Value:
+ * LPGIZMOBAR NULL if successful, pGB if not, meaning we couldn't
+ * free some allocation.
+ */
+
+LPGIZMOBAR GizmoBarPFree(LPGIZMOBAR pGB)
+ {
+ if (NULL==pGB)
+ return NULL;
+
+ /*
+ * Free all the gizmos we own. When we call GizmoPFree we always
+ * free the first one in the list which updates pGB->pGizmos for
+ * us, so we just have to keep going until pGizmos is NULL, meaning
+ * we're at the end of the list.
+ */
+ while (NULL!=pGB->pGizmos)
+ GizmoPFree(&pGB->pGizmos, pGB->pGizmos);
+
+ if (NULL!=pGB->hBrFace)
+ DeleteObject(pGB->hBrFace);
+
+ /*
+ * Notice that since we never create a font, we aren't responsible
+ * for our hFont member.
+ */
+
+ return (LPGIZMOBAR)(void *)LocalFree((HLOCAL)(void *)(LONG)pGB);
+ }
diff --git a/private/oleutest/letest/gizmobar/paint.c b/private/oleutest/letest/gizmobar/paint.c
new file mode 100644
index 000000000..14f6c5930
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/paint.c
@@ -0,0 +1,132 @@
+/*
+ * PAINT.C
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Contains any code related to GizmoBar visuals, primarily
+ * the WM_PAINT handler.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+
+//In GIZMO.C
+extern TOOLDISPLAYDATA tdd;
+
+
+/*
+ * GizmoBarPaint
+ *
+ * Purpose:
+ * Handles all WM_PAINT messages for the control and paints either the
+ * entire thing or just one GizmoBar button if pGB->pGizmoPaint is non-NULL.
+ *
+ * Parameters:
+ * hWnd HWND Handle to the control.
+ * pGB LPGIZMOBAR control data pointer.
+ *
+ * Return Value:
+ * None
+ */
+
+void GizmoBarPaint(HWND hWnd, LPGIZMOBAR pGB)
+ {
+ PAINTSTRUCT ps;
+ RECT rc;
+ HDC hDC;
+ HBRUSH hBr=NULL;
+ HPEN hPen=NULL;
+
+
+ hDC=BeginPaint(hWnd, &ps);
+ GetClientRect(hWnd, &rc);
+
+ /*
+ * The only part of the frame we need to draw is the bottom line,
+ * so we inflate the rectangle such that all other parts are outside
+ * the visible region.
+ */
+ hBr =CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+
+ if (NULL!=hBr)
+ SelectObject(hDC, hBr);
+
+ hPen=CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
+
+ if (NULL!=hPen)
+ SelectObject(hDC, hPen);
+
+ Rectangle(hDC, rc.left-1, rc.top-1, rc.right+1, rc.bottom);
+
+
+ /*
+ * All that we have to do to draw the controls is start through the
+ * list, ignoring anything but buttons, and calling BTTNCUR's
+ * UIToolButtonDraw for buttons. Since we don't even have to track
+ * positions of things, we can just use an enum.
+ */
+ GizmoPEnum(&pGB->pGizmos, FEnumPaintGizmos, (DWORD)(LPSTR)&ps);
+
+ //Clean up
+ EndPaint(hWnd, &ps);
+
+ if (NULL!=hBr)
+ DeleteObject(hBr);
+
+ if (NULL!=hPen)
+ DeleteObject(hPen);
+
+ return;
+ }
+
+
+
+
+
+/*
+ * FEnumPaintGizmos
+ *
+ * Purpose:
+ * Enumeration callback for all the gizmos we know about in order to
+ * draw them.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO to draw.
+ * iGizmo UINT index on the GizmoBar of this gizmo.
+ * dw DWORD extra data passed to GizmoPEnum, in our case
+ * a pointer to the PAINTSTRUCT.
+ *
+ * Return Value:
+ * BOOL TRUE to continue the enumeration, FALSE otherwise.
+ */
+
+BOOL FAR PASCAL FEnumPaintGizmos(LPGIZMO pGizmo, UINT iGizmo, DWORD dw)
+ {
+ LPPAINTSTRUCT pps=(LPPAINTSTRUCT)dw;
+ RECT rc, rcI;
+
+ //Only draw those marked for repaint.
+ if ((GIZMOTYPE_DRAWN & pGizmo->iType))
+ {
+ SetRect(&rc, pGizmo->x, pGizmo->y, pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy);
+
+ //Only draw gizmos in the repaint area
+ if (IntersectRect(&rcI, &rc, &pps->rcPaint))
+ {
+ UIToolButtonDrawTDD(pps->hdc, pGizmo->x, pGizmo->y
+ , pGizmo->dx, pGizmo->dy, pGizmo->hBmp, pGizmo->cxImage
+ , pGizmo->cyImage, pGizmo->iBmp, (UINT)pGizmo->uState, &tdd);
+ }
+ }
+
+ return TRUE;
+ }
diff --git a/private/oleutest/letest/ole2ui/bang.ico b/private/oleutest/letest/ole2ui/bang.ico
new file mode 100644
index 000000000..90fe0f220
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/bang.ico
Binary files differ
diff --git a/private/oleutest/letest/ole2ui/busy.c b/private/oleutest/letest/ole2ui/busy.c
new file mode 100644
index 000000000..7be5c7414
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/busy.c
@@ -0,0 +1,551 @@
+/*
+ * BUSY.C
+ *
+ * Implements the OleUIBusy function which invokes the "Server Busy"
+ * dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "common.h"
+#include "utility.h"
+#include "busy.h"
+#include <ctype.h> // for tolower() and toupper()
+
+#ifndef WIN32
+#include <toolhelp.h>
+#endif
+
+
+/*
+ * OleUIBusy
+ *
+ * Purpose:
+ * Invokes the standard OLE "Server Busy" dialog box which
+ * notifies the user that the server application is not receiving
+ * messages. The dialog then asks the user to either cancel
+ * the operation, switch to the task which is blocked, or continue
+ * waiting.
+ *
+ * Parameters:
+ * lpBZ LPOLEUIBUSY pointing to the in-out structure
+ * for this dialog.
+ *
+ * Return Value:
+ * OLEUI_BZERR_HTASKINVALID : Error
+ * OLEUI_BZ_SWITCHTOSELECTED : Success, user selected "switch to"
+ * OLEUI_BZ_RETRYSELECTED : Success, user selected "retry"
+ * OLEUI_CANCEL : Success, user selected "cancel"
+ */
+
+STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY lpOBZ)
+ {
+ UINT uRet = 0;
+ HGLOBAL hMemDlg=NULL;
+
+#if !defined( WIN32 )
+// BUGBUG32: this is not yet ported to NT
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lpOBZ, sizeof(OLEUIBUSY)
+ , &hMemDlg);
+
+ // Error out if the standard validation failed
+ if (OLEUI_SUCCESS!=uRet)
+ return uRet;
+
+ // Validate HTASK
+ if (!IsTask(lpOBZ->hTask))
+ uRet = OLEUI_BZERR_HTASKINVALID;
+
+ // Error out if our secondary validation failed
+ if (OLEUI_ERR_STANDARDMIN <= uRet)
+ {
+ if (NULL!=hMemDlg)
+ FreeResource(hMemDlg);
+
+ return uRet;
+ }
+
+ // Invoke the dialog.
+ uRet=UStandardInvocation(BusyDialogProc, (LPOLEUISTANDARD)lpOBZ,
+ hMemDlg, MAKEINTRESOURCE(IDD_BUSY));
+#endif
+
+ return uRet;
+}
+
+
+/*
+ * BusyDialogProc
+ *
+ * Purpose:
+ * Implements the OLE Busy dialog as invoked through the OleUIBusy function.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ *
+ */
+
+BOOL CALLBACK EXPORT BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+ {
+ LPBUSY lpBZ;
+ UINT uRet = 0;
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ lpBZ=(LPBUSY)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
+
+ //If the hook processed the message, we're done.
+ if (0!=uRet)
+ return (BOOL)uRet;
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ BusyCleanup(hDlg);
+ StandardCleanup(lpBZ, hDlg);
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ // Process our special "close" message. If we get this message,
+ // this means that the call got unblocked, so we need to
+ // return OLEUI_BZ_CALLUNBLOCKED to our calling app.
+ if (iMsg == uMsgCloseBusyDlg)
+ {
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_CALLUNBLOCKED, 0L);
+ return TRUE;
+ }
+
+ switch (iMsg)
+ {
+ case WM_INITDIALOG:
+ FBusyInit(hDlg, wParam, lParam);
+ return TRUE;
+
+ case WM_ACTIVATEAPP:
+ {
+ /* try to bring down our Busy/NotResponding dialog as if
+ ** the user entered RETRY.
+ */
+ BOOL fActive = (BOOL)wParam;
+ if (fActive) {
+ // If this is the app BUSY case, then bring down our
+ // dialog when switching BACK to our app
+ if (lpBZ && !(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
+ SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);
+ } else {
+ // If this is the app NOT RESPONDING case, then bring down
+ // our dialog when switching AWAY to another app
+ if (lpBZ && (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
+ SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);
+ }
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (wID)
+ {
+ case IDBZ_SWITCHTO:
+ {
+ BOOL fNotRespondingDlg =
+ (BOOL)(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG);
+
+ // If user selects "Switch To...", switch activation
+ // directly to the window which is causing the problem.
+ if (IsWindow(lpBZ->hWndBlocked))
+ MakeWindowActive(lpBZ->hWndBlocked);
+ else
+ StartTaskManager(); // Fail safe: Start Task Manager
+
+ // If this is the app not responding case, then we want
+ // to bring down the dialog when "SwitchTo" is selected.
+ // If the app is busy (RetryRejectedCall situation) then
+ // we do NOT want to bring down the dialog. this is
+ // the OLE2.0 user model design.
+ if (fNotRespondingDlg)
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_SWITCHTOSELECTED, 0L);
+ break;
+ }
+ case IDBZ_RETRY:
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_RETRYSELECTED, 0L);
+ break;
+
+ case IDCANCEL:
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+ }
+
+
+/*
+ * FBusyInit
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the Busy dialog box.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
+ {
+ LPBUSY lpBZ;
+ LPOLEUIBUSY lpOBZ;
+ HFONT hFont;
+ LPTSTR lpTaskName;
+ LPTSTR lpWindowName;
+ HICON hIcon;
+
+ lpBZ=(LPBUSY)LpvStandardInit(hDlg, sizeof(OLEUIBUSY), TRUE, &hFont);
+
+ // PvStandardInit sent a termination to us already.
+ if (NULL==lpBZ)
+ return FALSE;
+
+ // Our original structure is in lParam
+ lpOBZ = (LPOLEUIBUSY)lParam;
+
+ // Copy it to our instance of the structure (in lpBZ)
+ lpBZ->lpOBZ=lpOBZ;
+
+ //Copy other information from lpOBZ that we might modify.
+ lpBZ->dwFlags = lpOBZ->dwFlags;
+
+ // Set default information
+ lpBZ->hWndBlocked = NULL;
+
+ // Insert HWND of our dialog into the address pointed to by
+ // lphWndDialog. This can be used by the app who called
+ // OleUIBusy to bring down the dialog with uMsgCloseBusyDialog
+ if (lpOBZ->lphWndDialog &&
+ !IsBadWritePtr((VOID FAR *)lpOBZ->lphWndDialog, sizeof(HWND)))
+ {
+ *lpOBZ->lphWndDialog = hDlg;
+ }
+
+ // Update text in text box --
+ // GetTaskInfo will return two pointers, one to the task name
+ // (file name) and one to the window name. We need to call
+ // OleStdFree on these when we're done with them. We also
+ // get the HWND which is blocked in this call
+ //
+ // In the case where this call fails, a default message should already
+ // be present in the dialog template, so no action is needed
+
+ if (GetTaskInfo(hDlg, lpOBZ->hTask, &lpTaskName, &lpWindowName, &lpBZ->hWndBlocked))
+ {
+ // Build string to present to user, place in IDBZ_MESSAGE1 control
+ BuildBusyDialogString(hDlg, lpBZ->dwFlags, IDBZ_MESSAGE1, lpTaskName, lpWindowName);
+ OleStdFree(lpTaskName);
+ OleStdFree(lpWindowName);
+ }
+
+ // Update icon with the system "exclamation" icon
+ hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
+ SendDlgItemMessage(hDlg, IDBZ_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
+
+ // Disable/Enable controls
+ if ((lpBZ->dwFlags & BZ_DISABLECANCELBUTTON) ||
+ (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG)) // Disable cancel for "not responding" dialog
+ EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
+
+ if (lpBZ->dwFlags & BZ_DISABLESWITCHTOBUTTON)
+ EnableWindow(GetDlgItem(hDlg, IDBZ_SWITCHTO), FALSE);
+
+ if (lpBZ->dwFlags & BZ_DISABLERETRYBUTTON)
+ EnableWindow(GetDlgItem(hDlg, IDBZ_RETRY), FALSE);
+
+ // Call the hook with lCustData in lParam
+ UStandardHook((LPVOID)lpBZ, hDlg, WM_INITDIALOG, wParam, lpOBZ->lCustData);
+
+ // Update caption if lpszCaption was specified
+ if (lpBZ->lpOBZ->lpszCaption && !IsBadReadPtr(lpBZ->lpOBZ->lpszCaption, 1)
+ && lpBZ->lpOBZ->lpszCaption[0] != '\0')
+ SetWindowText(hDlg, lpBZ->lpOBZ->lpszCaption);
+
+ return TRUE;
+ }
+
+
+/*
+ * BuildBusyDialogString
+ *
+ * Purpose:
+ * Builds the string that will be displayed in the dialog from the
+ * task name and window name parameters.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * dwFlags DWORD containing flags passed into dialog
+ * iControl Control ID to place the text string
+ * lpTaskName LPSTR pointing to name of task (e.g. C:\TEST\TEST.EXE)
+ * lpWindowName LPSTR for name of window
+ *
+ * Caveats:
+ * The caller of this function MUST de-allocate the lpTaskName and
+ * lpWindowName pointers itself with OleStdFree
+ *
+ * Return Value:
+ * void
+ */
+
+void BuildBusyDialogString(HWND hDlg, DWORD dwFlags, int iControl, LPTSTR lpTaskName, LPTSTR lpWindowName)
+{
+ LPTSTR pszT, psz1, psz2, psz3;
+ UINT cch;
+ LPTSTR pszDot, pszSlash;
+ UINT uiStringNum;
+
+ /*
+ * We need scratch memory for loading the stringtable string,
+ * the task name, and constructing the final string. We therefore
+ * allocate three buffers as large as the maximum message
+ * length (512) plus the object type, guaranteeing that we have enough
+ * in all cases.
+ */
+ cch=512;
+
+ // Use OLE-supplied allocation
+ if ((pszT = OleStdMalloc((ULONG)(3*cch))) == NULL)
+ return;
+
+ psz1=pszT;
+ psz2=psz1+cch;
+ psz3=psz2+cch;
+
+ // Parse base name out of path name, use psz2 for the task
+ // name to display
+ // In Win32, _fstrcpy is mapped to handle UNICODE stuff
+ _fstrcpy(psz2, lpTaskName);
+ pszDot = _fstrrchr(psz2, TEXT('.'));
+ pszSlash = _fstrrchr(psz2, TEXT('\\')); // Find last backslash in path
+
+ if (pszDot != NULL)
+#ifdef UNICODE
+ *pszDot = TEXT('\0'); // Null terminate at the DOT
+#else
+ *pszDot = '\0'; // Null terminate at the DOT
+#endif
+
+ if (pszSlash != NULL)
+ psz2 = pszSlash + 1; // Nuke everything up to this point
+
+#ifdef LOWERCASE_NAME
+ // Compile this with /DLOWERCASE_NAME if you want the lower-case
+ // module name to be displayed in the dialog rather than the
+ // all-caps name.
+ {
+ int i,l;
+
+ // Now, lowercase all letters except first one
+ l = _fstrlen(psz2);
+ for(i=0;i<l;i++)
+ psz2[i] = tolower(psz2[i]);
+
+ psz2[0] = toupper(psz2[0]);
+ }
+#endif
+
+ // Check size of lpWindowName. We can reasonably fit about 80
+ // characters into the text control, so truncate more than 80 chars
+ if (_fstrlen(lpWindowName)> 80)
+#ifdef UNICODE
+ lpWindowName[80] = TEXT('\0');
+#else
+ lpWindowName[80] = '\0';
+#endif
+
+ // Load the format string out of stringtable, choose a different
+ // string depending on what flags are passed in to the dialog
+ if (dwFlags & BZ_NOTRESPONDINGDIALOG)
+ uiStringNum = IDS_BZRESULTTEXTNOTRESPONDING;
+ else
+ uiStringNum = IDS_BZRESULTTEXTBUSY;
+
+ if (LoadString(ghInst, uiStringNum, psz1, cch) == 0)
+ return;
+
+ // Build the string. The format string looks like this:
+ // "This action cannot be completed because the '%s' application
+ // (%s) is [busy | not responding]. Choose \"Switch To\" to activate '%s' and
+ // correct the problem."
+
+ wsprintf(psz3, psz1, (LPSTR)psz2, (LPTSTR)lpWindowName, (LPTSTR)psz2);
+ SetDlgItemText(hDlg, iControl, (LPTSTR)psz3);
+ OleStdFree(pszT);
+
+ return;
+}
+
+
+
+/*
+ * BusyCleanup
+ *
+ * Purpose:
+ * Performs busy-specific cleanup before termination.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog box so we can access controls.
+ *
+ * Return Value:
+ * None
+ */
+void BusyCleanup(HWND hDlg)
+{
+ return;
+}
+
+
+
+/*
+ * GetTaskInfo()
+ *
+ * Purpose: Gets information about the specified task and places the
+ * module name, window name and top-level HWND for the task in the specified
+ * pointers
+ *
+ * NOTE: The two string pointers allocated in this routine are
+ * the responsibility of the CALLER to de-allocate.
+ *
+ * Parameters:
+ * hWnd HWND who called this function
+ * htask HTASK which we want to find out more info about
+ * lplpszTaskName Location that the module name is returned
+ * lplpszWindowName Location where the window name is returned
+ *
+ */
+
+BOOL GetTaskInfo(HWND hWnd, HTASK htask, LPTSTR FAR* lplpszTaskName, LPTSTR FAR*lplpszWindowName, HWND FAR*lphWnd)
+{
+ BOOL fRet = FALSE;
+#if !defined( WIN32 )
+ TASKENTRY te;
+#endif
+ HWND hwndNext;
+ LPTSTR lpszTN = NULL;
+ LPTSTR lpszWN = NULL;
+ HWND hwndFind = NULL;
+
+ // Clear out return values in case of error
+ *lplpszTaskName = NULL;
+ *lplpszWindowName = NULL;
+
+#if !defined( WIN32 )
+ te.dwSize = sizeof(TASKENTRY);
+ if (TaskFindHandle(&te, htask))
+#endif
+ {
+ // Now, enumerate top-level windows in system
+ hwndNext = GetWindow(hWnd, GW_HWNDFIRST);
+ while (hwndNext)
+ {
+ // See if we can find a non-owned top level window whose
+ // hInstance matches the one we just got passed. If we find one,
+ // we can be fairly certain that this is the top-level window for
+ // the task which is blocked.
+ //
+ // REVIEW: Will this filter hold true for InProcServer DLL-created
+ // windows?
+ //
+ if ((hwndNext != hWnd) &&
+#if !defined( WIN32 )
+ (GetWindowWord(hwndNext, GWW_HINSTANCE) == (WORD)te.hInst) &&
+#else
+ ((HTASK) GetWindowThreadProcessId(hwndNext,NULL) == htask) &&
+#endif
+ (IsWindowVisible(hwndNext)) &&
+ !GetWindow(hwndNext, GW_OWNER))
+ {
+ // We found our window! Alloc space for new strings
+ if ((lpszTN = OleStdMalloc(OLEUI_CCHPATHMAX_SIZE)) == NULL)
+ return TRUE; // continue task window enumeration
+
+ if ((lpszWN = OleStdMalloc(OLEUI_CCHPATHMAX_SIZE)) == NULL)
+ return TRUE; // continue task window enumeration
+
+ // We found the window we were looking for, copy info to
+ // local vars
+ GetWindowText(hwndNext, lpszWN, OLEUI_CCHPATHMAX);
+#if !defined( WIN32 )
+ LSTRCPYN(lpszTN, te.szModule, OLEUI_CCHPATHMAX);
+#else
+ /* WIN32 NOTE: we are not able to get a module name
+ ** given a thread process id on WIN32. the best we
+ ** can do is use the window title as the module/app
+ ** name.
+ */
+ LSTRCPYN(lpszTN, lpszWN, OLEUI_CCHPATHMAX);
+#endif
+ hwndFind = hwndNext;
+
+ fRet = TRUE;
+ goto OKDone;
+ }
+
+ hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
+ }
+ }
+
+OKDone:
+
+ // OK, everything was successful. Set string pointers to point to
+ // our data.
+
+ *lplpszTaskName = lpszTN;
+ *lplpszWindowName = lpszWN;
+ *lphWnd = hwndFind;
+
+ return fRet;
+}
+
+
+/*
+ * StartTaskManager()
+ *
+ * Purpose: Starts Task Manager. Used to bring up task manager to
+ * assist in switching to a given blocked task.
+ *
+ */
+
+StartTaskManager()
+{
+ WinExec("taskman.exe", SW_SHOW);
+ return TRUE;
+}
+
+
+
+/*
+ * MakeWindowActive()
+ *
+ * Purpose: Makes specified window the active window.
+ *
+ */
+
+void MakeWindowActive(HWND hWndSwitchTo)
+{
+ // Move the new window to the top of the Z-order
+ SetWindowPos(hWndSwitchTo, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE);
+
+ // If it's iconic, we need to restore it.
+ if (IsIconic(hWndSwitchTo))
+ ShowWindow(hWndSwitchTo, SW_RESTORE);
+}
diff --git a/private/oleutest/letest/ole2ui/busy.dlg b/private/oleutest/letest/ole2ui/busy.dlg
new file mode 100644
index 000000000..c2151956c
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/busy.dlg
@@ -0,0 +1,13 @@
+IDD_BUSY DIALOG DISCARDABLE 0, 0, 214, 76
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Server Busy"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "&Switch To...", IDBZ_SWITCHTO, 33, 55, 53, 15
+ PUSHBUTTON "&Cancel", IDCANCEL, 152, 55, 53, 15
+ PUSHBUTTON "&Retry", IDBZ_RETRY, 92, 55, 53, 15
+ LTEXT "This action cannot be completed because the other application is busy. Choose 'Switch To' to activate the busy application and correct the problem.", IDBZ_MESSAGE1, 35, 11, 167, 35
+ ICON "", IDBZ_ICON, 8, 18, 18, 20
+END
+
+
diff --git a/private/oleutest/letest/ole2ui/busy.h b/private/oleutest/letest/ole2ui/busy.h
new file mode 100644
index 000000000..3656aecf6
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/busy.h
@@ -0,0 +1,45 @@
+/*
+ * BUSY.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI Busy dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#ifndef _BUSY_H_
+#define _BUSY_H_
+
+//Internally used structure
+typedef struct tagBUSY
+ {
+ //Keep this item first as the Standard* functions depend on it here.
+ LPOLEUIBUSY lpOBZ; //Original structure passed.
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog or that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+
+ DWORD dwFlags; // Flags passed in
+ HWND hWndBlocked; // HWND of app which is blocking
+ } BUSY, *PBUSY, FAR *LPBUSY;
+
+// Internal function prototypes
+BOOL GetTaskInfo(HWND hWnd, HTASK htask, LPTSTR FAR* lplpszTaskName, LPTSTR FAR*lplpszWindowName, HWND FAR*lphWnd);
+void BuildBusyDialogString(HWND, DWORD, int, LPTSTR, LPTSTR);
+BOOL CALLBACK EXPORT BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
+void BusyCleanup(HWND hDlg);
+BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam);
+BOOL InitEnumeration(void);
+void UnInitEnumeration(void);
+ StartTaskManager(void);
+void MakeWindowActive(HWND hWndSwitchTo);
+
+#endif //_BUSY_H_
+
+
+
+
diff --git a/private/oleutest/letest/ole2ui/common.c b/private/oleutest/letest/ole2ui/common.c
new file mode 100644
index 000000000..40f450c72
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/common.c
@@ -0,0 +1,423 @@
+/*
+ * COMMON.C
+ *
+ * Standardized (and centralized) pieces of each OLE2UI dialog function:
+ * UStandardValidation Validates standard fields in each dialog structure
+ * UStandardInvocation Invokes a dialog through DialogBoxIndirectParam
+ * LpvStandardInit Common WM_INITDIALOG processing
+ * LpvStandardEntry Common code to execute on dialog proc entry.
+ * FStandardHook Centralized hook calling function.
+ * StandardCleanup Common exit/cleanup code.
+ * OleUIShowDlgItem Show-Enable/Hide-Disable dialog item
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "common.h"
+#include "utility.h"
+#include <malloc.h>
+
+
+/*
+ * UStandardValidation
+ *
+ * Purpose:
+ * Performs validation on the standard pieces of any dialog structure,
+ * that is, the fields defined in the OLEUISTANDARD structure.
+ *
+ * Parameters:
+ * lpUI const LPOLEUISTANDARD pointing to the shared data of
+ * all structs.
+ * cbExpect const UINT structure size desired by the caller.
+ * phDlgMem const HGLOBAL FAR * in which to store a loaded customized
+ * template, if one exists.
+ *
+ * Return Value:
+ * UINT OLEUI_SUCCESS if all validation succeeded. Otherwise
+ * it will be one of the standard error codes.
+ */
+
+UINT WINAPI UStandardValidation(const LPOLEUISTANDARD lpUI, const UINT cbExpect
+ , const HGLOBAL FAR *phMemDlg)
+ {
+ HRSRC hRes=NULL;
+ HGLOBAL hMem=NULL;
+
+
+ /*
+ * 1. Validate non-NULL pointer parameter. Note: We don't validate
+ * phDlg since it's not passed from an external source.
+ */
+ if (NULL==lpUI)
+ return OLEUI_ERR_STRUCTURENULL;
+
+ //2. Validate that the structure is readable and writable.
+ if (IsBadReadPtr(lpUI, cbExpect) || IsBadWritePtr(lpUI, cbExpect))
+ return OLEUI_ERR_STRUCTUREINVALID;
+
+ //3. Validate the structure size
+ if (cbExpect!=lpUI->cbStruct)
+ return OLEUI_ERR_CBSTRUCTINCORRECT;
+
+ //4. Validate owner-window handle. NULL is considered valid.
+ if (NULL!=lpUI->hWndOwner && !IsWindow(lpUI->hWndOwner))
+ return OLEUI_ERR_HWNDOWNERINVALID;
+
+ //5. Validate the dialog caption. NULL is considered valid.
+ if (NULL!=lpUI->lpszCaption && IsBadReadPtr(lpUI->lpszCaption, 1))
+ return OLEUI_ERR_LPSZCAPTIONINVALID;
+
+ //6. Validate the hook pointer. NULL is considered valid.
+ if ((LPFNOLEUIHOOK)NULL!=lpUI->lpfnHook
+ && IsBadCodePtr((FARPROC)lpUI->lpfnHook))
+ return OLEUI_ERR_LPFNHOOKINVALID;
+
+ /*
+ * 7. If hInstance is non-NULL, we have to also check lpszTemplate.
+ * Otherwise, lpszTemplate is not used and requires no validation.
+ * lpszTemplate cannot be NULL if used.
+ */
+ if (NULL!=lpUI->hInstance)
+ {
+ //Best we can try is one character
+ if (NULL==lpUI->lpszTemplate || IsBadReadPtr(lpUI->lpszTemplate, 1))
+ return OLEUI_ERR_LPSZTEMPLATEINVALID;
+
+ hRes=FindResource(lpUI->hInstance, lpUI->lpszTemplate, RT_DIALOG);
+
+ //This is the only thing that catches invalid non-NULL hInstance
+ if (NULL==hRes)
+ return OLEUI_ERR_FINDTEMPLATEFAILURE;
+
+ hMem=LoadResource(lpUI->hInstance, hRes);
+
+ if (NULL==hMem)
+ return OLEUI_ERR_LOADTEMPLATEFAILURE;
+ }
+
+
+ //8. If hResource is non-NULL, be sure we can lock it.
+ if (NULL!=lpUI->hResource)
+ {
+ if ((LPSTR)NULL==GlobalLock(lpUI->hResource))
+ return OLEUI_ERR_HRESOURCEINVALID;
+
+ GlobalUnlock(lpUI->hResource);
+ }
+
+ /*
+ * Here we have hMem==NULL if we should use the standard template
+ * or the one in lpUI->hResource. If hMem is non-NULL, then we
+ * loaded one from the calling application's resources which the
+ * caller of this function has to free if it sees any other error.
+ */
+ *(HGLOBAL FAR *)phMemDlg=hMem;
+ return OLEUI_SUCCESS;
+ }
+
+
+
+
+
+/*
+ * UStandardInvocation
+ *
+ * Purpose:
+ * Provides standard template loading and calling on DialogBoxIndirectParam
+ * for all the OLE UI dialogs.
+ *
+ * Parameters:
+ * lpDlgProc DLGPROC of the dialog function.
+ * lpUI LPOLEUISTANDARD containing the dialog structure.
+ * hMemDlg HGLOBAL containing the dialog template. If this
+ * is NULL and lpUI->hResource is NULL, then we load
+ * the standard template given the name in lpszStdTemplate
+ * lpszStdTemplate LPCSTR standard template to load if hMemDlg is NULL
+ * and lpUI->hResource is NULL.
+ *
+ * Return Value:
+ * UINT OLEUI_SUCCESS if all is well, otherwise and error
+ * code.
+ */
+
+UINT WINAPI UStandardInvocation
+#ifdef WIN32
+(DLGPROC lpDlgProc, LPOLEUISTANDARD lpUI, HGLOBAL hMemDlg, LPTSTR lpszStdTemplate)
+#else
+(DLGPROC lpDlgProc, LPOLEUISTANDARD lpUI, HGLOBAL hMemDlg, LPCTSTR lpszStdTemplate)
+#endif
+ {
+ HGLOBAL hTemplate=hMemDlg;
+ HRSRC hRes;
+ int iRet;
+
+ //Make sure we have a template, then lock it down
+ if (NULL==hTemplate)
+ hTemplate=lpUI->hResource;
+
+ if (NULL==hTemplate)
+ {
+ hRes=FindResource(ghInst, (LPCTSTR) lpszStdTemplate, RT_DIALOG);
+
+ if (NULL==hRes)
+ {
+ return OLEUI_ERR_FINDTEMPLATEFAILURE;
+ }
+
+ hTemplate=LoadResource(ghInst, hRes);
+
+ if (NULL==hTemplate)
+ {
+ return OLEUI_ERR_LOADTEMPLATEFAILURE;
+ }
+ }
+
+ /*
+ * hTemplate has the template to use, so now we can invoke the dialog.
+ * Since we have exported all of our dialog procedures using the
+ * _export keyword, we do not need to call MakeProcInstance,
+ * we can ue the dialog procedure address directly.
+ */
+
+ iRet=DialogBoxIndirectParam(ghInst, hTemplate, lpUI->hWndOwner
+ , lpDlgProc, (LPARAM)lpUI);
+
+ /*
+ * Cleanup the template if we explicitly loaded it. Caller is
+ * responsible for already loaded template resources.
+ */
+ if (hTemplate!=lpUI->hResource)
+ FreeResource(hTemplate);
+
+ if (-1==iRet)
+ return OLEUI_ERR_DIALOGFAILURE;
+
+ //Return the code from EndDialog, generally OLEUI_OK or OLEUI_CANCEL
+ return (UINT)iRet;
+ }
+
+
+
+
+
+
+/*
+ * LpvStandardInit
+ *
+ * Purpose:
+ * Default actions for WM_INITDIALOG handling in the dialog, allocating
+ * a dialog-specific structure, setting that memory as a dialog property,
+ * and creating a small font if necessary setting that font as a property.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * cbStruct UINT size of dialog-specific structure to allocate.
+ * fCreateFont BOOL indicating if we need to create a small Helv
+ * font for this dialog.
+ * phFont HFONT FAR * in which to place a created font. Can be
+ * NULL if fCreateFont is FALSE.
+ *
+ * Return Value:
+ * LPVOID Pointer to global memory allocated for the dialog.
+ * The memory will have been set as a dialog property
+ * using the STRUCTUREPROP label.
+ */
+
+LPVOID WINAPI LpvStandardInit(HWND hDlg, UINT cbStruct, BOOL fCreateFont, HFONT FAR * phFont)
+ {
+ LPVOID lpv;
+ HFONT hFont;
+ LOGFONT lf;
+ HGLOBAL gh;
+
+ //Must have at least sizeof(OLEUISTANDARD) bytes in cbStruct
+ if (sizeof(OLEUISTANDARD) > cbStruct || (fCreateFont && NULL==phFont))
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);
+ return NULL;
+ }
+
+ gh=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbStruct);
+
+ if (NULL==gh)
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);
+ return NULL;
+ }
+ lpv = GlobalLock(gh);
+ SetProp(hDlg, STRUCTUREPROP, gh);
+
+ if (fCreateFont) {
+ //Create the non-bold font for result and file texts. We call
+ hFont=(HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
+ GetObject(hFont, sizeof(LOGFONT), &lf);
+ lf.lfWeight=FW_NORMAL;
+
+ //Attempt to create the font. If this fails, then we return no font.
+ *phFont=CreateFontIndirect(&lf);
+
+ //If we couldn't create the font, we'll do with the default.
+ if (NULL!=*phFont)
+ SetProp(hDlg, FONTPROP, (HANDLE)*phFont);
+ }
+
+ return lpv;
+ }
+
+
+
+
+
+/*
+ * LpvStandardEntry
+ *
+ * Purpose:
+ * Retrieves the dialog's structure property and calls the hook
+ * as necessary. This should be called on entry into all dialog
+ * procedures.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * iMsg UINT message to the dialog
+ * wParam, lParam WPARAM, LPARAM message parameters
+ * puHookResult UINT FAR * in which this function stores the return value
+ * from the hook if it is called. If no hook is available,
+ * this will be FALSE.
+ *
+ * Return Value:
+ * LPVOID Pointer to the dialog's extra structure held in the
+ * STRUCTUREPROP property.
+ */
+
+LPVOID WINAPI LpvStandardEntry(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam
+ , UINT FAR * puHookResult)
+ {
+ LPVOID lpv = NULL;
+ HGLOBAL gh;
+
+ // This will fail under WM_INITDIALOG, where we allocate using StandardInit
+ gh = GetProp(hDlg, STRUCTUREPROP);
+
+ if (NULL!=puHookResult && NULL!=gh)
+ {
+ *puHookResult=0;
+
+ // gh was locked previously, lock and unlock to get lpv
+ lpv = GlobalLock(gh);
+ GlobalUnlock(gh);
+
+ //Call the hook for all messages except WM_INITDIALOG
+ if (NULL!=lpv && WM_INITDIALOG!=iMsg)
+ *puHookResult=UStandardHook(lpv, hDlg, iMsg, wParam, lParam);
+ }
+
+ return lpv;
+ }
+
+
+
+
+/*
+ * UStandardHook
+ *
+ * Purpose:
+ * Provides a generic hook calling function assuming that all private
+ * dialog structures have a far pointer to their assocated public
+ * structure as the first field, and that the first part of the public
+ * structure matches an OLEUISTANDARD.
+ *
+ * Parameters:
+ * pv PVOID to the dialog structure.
+ * hDlg HWND to send with the call to the hook.
+ * iMsg UINT message to send to the hook.
+ * wParam, lParam WPARAM, LPARAM message parameters
+ *
+ * Return Value:
+ * UINT Return value from the hook, zero to indicate that
+ * default action should occur, nonzero to specify
+ * that the hook did process the message. In some
+ * circumstances it will be important for the hook to
+ * return a non-trivial non-zero value here, such as
+ * a brush from WM_CTLCOLOR, in which case the caller
+ * should return that value from the dialog procedure.
+ */
+
+UINT WINAPI UStandardHook(LPVOID lpv, HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+ {
+ LPOLEUISTANDARD lpUI;
+ UINT uRet=0;
+
+ lpUI=*((LPOLEUISTANDARD FAR *)lpv);
+
+ if (NULL!=lpUI && NULL!=lpUI->lpfnHook)
+ {
+ /*
+ * In order for the hook to have the proper DS, they should be
+ * compiling with -GA -GEs so and usin __export to get everything
+ * set up properly.
+ */
+ uRet=(*lpUI->lpfnHook)(hDlg, iMsg, wParam, lParam);
+ }
+
+ return uRet;
+ }
+
+
+
+
+
+/*
+ * StandardCleanup
+ *
+ * Purpose:
+ * Removes properties and reverses any other standard initiazation
+ * done through StandardSetup.
+ *
+ * Parameters:
+ * lpv LPVOID containing the private dialog structure.
+ * hDlg HWND of the dialog closing.
+ *
+ * Return Value:
+ * None
+ */
+
+void WINAPI StandardCleanup(LPVOID lpv, HWND hDlg)
+ {
+ HFONT hFont;
+ HGLOBAL gh;
+
+ hFont=(HFONT)GetProp(hDlg, FONTPROP);
+
+ if (NULL!=hFont)
+ DeleteObject(hFont);
+
+ RemoveProp(hDlg, FONTPROP);
+
+ gh = RemoveProp(hDlg, STRUCTUREPROP);
+ if (gh)
+ {
+ GlobalUnlock(gh);
+ GlobalFree(gh);
+ }
+ return;
+ }
+
+
+/* StandardShowDlgItem
+** -------------------
+** Show & Enable or Hide & Disable a dialog item as appropriate.
+** it is NOT sufficient to simply hide the item; it must be disabled
+** too or the keyboard accelerator still functions.
+*/
+void WINAPI StandardShowDlgItem(HWND hDlg, int idControl, int nCmdShow)
+{
+ if (SW_HIDE == nCmdShow) {
+ ShowWindow(GetDlgItem(hDlg, idControl), SW_HIDE);
+ EnableWindow(GetDlgItem(hDlg, idControl), FALSE);
+ } else {
+ ShowWindow(GetDlgItem(hDlg, idControl), SW_SHOWNORMAL);
+ EnableWindow(GetDlgItem(hDlg, idControl), TRUE);
+ }
+}
diff --git a/private/oleutest/letest/ole2ui/common.h b/private/oleutest/letest/ole2ui/common.h
new file mode 100644
index 000000000..00466661f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/common.h
@@ -0,0 +1,166 @@
+/*
+ * COMMON.H
+ *
+ * Structures and definitions applicable to all OLE 2.0 UI dialogs.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+
+//Macros to handle control message packing between Win16 and Win32
+#ifdef WIN32
+
+#ifndef COMMANDPARAMS
+#define COMMANDPARAMS(wID, wCode, hWndMsg) \
+ WORD wID = LOWORD(wParam); \
+ WORD wCode = HIWORD(wParam); \
+ HWND hWndMsg = (HWND)(UINT)lParam;
+#endif //COMMANDPARAMS
+
+#ifndef SendCommand
+#define SendCommand(hWnd, wID, wCode, hControl) \
+ SendMessage(hWnd, WM_COMMAND, MAKELONG(wID, wCode) \
+ , (LPARAM)hControl)
+#endif //SendCommand
+
+#else //Start !WIN32
+
+#ifndef COMMANDPARAMS
+#define COMMANDPARAMS(wID, wCode, hWndMsg) \
+ WORD wID = LOWORD(wParam); \
+ WORD wCode = HIWORD(lParam); \
+ HWND hWndMsg = (HWND)(UINT)lParam;
+#endif //COMMANDPARAMS
+
+#ifndef SendCommand
+#define SendCommand(hWnd, wID, wCode, hControl) \
+ SendMessage(hWnd, WM_COMMAND, wID \
+ , MAKELONG(hControl, wCode))
+#endif //SendCommand
+
+#endif //!WIN32
+
+
+
+//Property labels used to store dialog structures and fonts
+#define STRUCTUREPROP TEXT("Structure")
+#define FONTPROP TEXT("Font")
+
+
+/*
+ * Standard structure for all dialogs. This commonality lets us make
+ * a single piece of code that will validate this entire structure and
+ * perform any necessary initialization.
+ */
+
+typedef struct tagOLEUISTANDARD
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+ } OLEUISTANDARD, *POLEUISTANDARD, FAR *LPOLEUISTANDARD;
+
+
+
+//Function prototypes
+//COMMON.C
+UINT WINAPI UStandardValidation(const LPOLEUISTANDARD, const UINT, const HGLOBAL FAR *);
+
+#ifdef WIN32
+UINT WINAPI UStandardInvocation(DLGPROC, LPOLEUISTANDARD, HGLOBAL, LPTSTR);
+#else
+UINT WINAPI UStandardInvocation(DLGPROC, LPOLEUISTANDARD, HGLOBAL, LPCTSTR);
+#endif
+
+LPVOID WINAPI LpvStandardInit(HWND, UINT, BOOL, HFONT FAR *);
+LPVOID WINAPI LpvStandardEntry(HWND, UINT, WPARAM, LPARAM, UINT FAR *);
+UINT WINAPI UStandardHook(LPVOID, HWND, UINT, WPARAM, LPARAM);
+void WINAPI StandardCleanup(LPVOID, HWND);
+void WINAPI StandardShowDlgItem(HWND hDlg, int idControl, int nCmdShow);
+
+
+//DRAWICON.C
+
+//Structure for label and source extraction from a metafile
+typedef struct tagLABELEXTRACT
+ {
+ LPTSTR lpsz;
+ UINT Index; // index in lpsz (so we can retrieve 2+ lines)
+ DWORD PrevIndex; // index of last line (so we can mimic word wrap)
+
+ union
+ {
+ UINT cch; //Length of label for label extraction
+ UINT iIcon; //Index of icon in source extraction.
+ } u;
+
+ //For internal use in enum procs
+ BOOL fFoundIconOnly;
+ BOOL fFoundSource;
+ BOOL fFoundIndex;
+ } LABELEXTRACT, FAR * LPLABELEXTRACT;
+
+
+//Structure for extracting icons from a metafile (CreateIcon parameters)
+typedef struct tagICONEXTRACT
+ {
+ HICON hIcon; //Icon created in the enumeration proc.
+
+ /*
+ * Since we want to handle multitasking well we have the caller
+ * of the enumeration proc instantiate these variables instead of
+ * using statics in the enum proc (which would be bad).
+ */
+ BOOL fAND;
+ HGLOBAL hMemAND; //Enumeration proc allocates and copies
+ } ICONEXTRACT, FAR * LPICONEXTRACT;
+
+
+//Structure to use to pass info to EnumMetafileDraw
+typedef struct tagDRAWINFO
+ {
+ RECT Rect;
+ BOOL fIconOnly;
+ } DRAWINFO, FAR * LPDRAWINFO;
+
+
+int CALLBACK EXPORT EnumMetafileIconDraw(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPARAM);
+int CALLBACK EXPORT EnumMetafileExtractLabel(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPLABELEXTRACT);
+int CALLBACK EXPORT EnumMetafileExtractIcon(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPICONEXTRACT);
+int CALLBACK EXPORT EnumMetafileExtractIconSource(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPLABELEXTRACT);
+
+
+//Shared globals: our instance, registered messages used from all dialogs and clipboard
+// formats used by the PasteSpecial dialog
+extern HINSTANCE ghInst;
+
+extern UINT uMsgHelp;
+extern UINT uMsgEndDialog;
+extern UINT uMsgBrowse;
+extern UINT uMsgChangeIcon;
+extern UINT uMsgFileOKString;
+extern UINT uMsgCloseBusyDlg;
+
+extern UINT cfObjectDescriptor;
+extern UINT cfLinkSrcDescriptor;
+extern UINT cfEmbedSource;
+extern UINT cfEmbeddedObject;
+extern UINT cfLinkSource;
+extern UINT cfOwnerLink;
+extern UINT cfFileName;
+
+//Standard control identifiers
+#define ID_NULL 98
+
+#endif //_COMMON_H_
diff --git a/private/oleutest/letest/ole2ui/convert.c b/private/oleutest/letest/ole2ui/convert.c
new file mode 100644
index 000000000..e5ca54131
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/convert.c
@@ -0,0 +1,1802 @@
+/*
+ * CONVERT.C
+ *
+ * Implements the OleUIConvert function which invokes the complete
+ * Convert dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include <stdlib.h>
+#include "common.h"
+#include "utility.h"
+#include "geticon.h"
+#include "regdb.h"
+#include "convert.h"
+
+#define CF_CLIPBOARDMIN 0xc000
+#define CF_CLIPBOARDMAX 0xffff
+
+#define AUXUSERTYPE_SHORTNAME USERCLASSTYPE_SHORT // short name
+
+static TCHAR szOLE2DLL[] = TEXT("ole2.dll"); // name of OLE 2.0 library
+
+static TCHAR szVanillaDocIcon[] = TEXT("DefIcon");
+
+/*
+ * OleUIConvert
+ *
+ * Purpose:
+ * Invokes the standard OLE Change Type dialog box allowing the user
+ * to change the type of the single specified object, or change the
+ * type of all OLE objects of a specified type.
+ *
+ * Parameters:
+ * lpCV LPOLEUICONVERT pointing to the in-out structure
+ * for this dialog.
+ *
+ * Return Value:
+ * UINT One of the following codes, indicating success or error:
+ * OLEUI_SUCCESS Success
+ * OLEUI_ERR_STRUCTSIZE The dwStructSize value is wrong
+ */
+
+STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT lpCV)
+ {
+ UINT uRet;
+ HGLOBAL hMemDlg=NULL;
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lpCV, sizeof(OLEUICONVERT)
+ , &hMemDlg);
+
+ if (OLEUI_SUCCESS!=uRet)
+ return uRet;
+
+ // Validate structure members passed in.
+#if defined( OBSOLETE )
+ if (!IsValidClassID(lpCV->clsid))
+ uRet = OLEUI_CTERR_CLASSIDINVALID;
+#endif
+
+ if ( (lpCV->dwFlags & CF_SETCONVERTDEFAULT)
+ && (!IsValidClassID(lpCV->clsidConvertDefault)) )
+ uRet = OLEUI_CTERR_CLASSIDINVALID;
+
+ if ( (lpCV->dwFlags & CF_SETACTIVATEDEFAULT)
+ && (!IsValidClassID(lpCV->clsidActivateDefault)) )
+ uRet = OLEUI_CTERR_CLASSIDINVALID;
+
+ if ( (lpCV->dvAspect != DVASPECT_ICON)
+ && (lpCV->dvAspect != DVASPECT_CONTENT) )
+ uRet = OLEUI_CTERR_DVASPECTINVALID;
+
+ if ( (lpCV->wFormat >= CF_CLIPBOARDMIN)
+ && (lpCV->wFormat <= CF_CLIPBOARDMAX) )
+ {
+ TCHAR szTemp[8];
+
+ if (0 == GetClipboardFormatName(lpCV->wFormat, (LPTSTR)szTemp, 8))
+ uRet = OLEUI_CTERR_CBFORMATINVALID;
+ }
+
+
+ if ( (NULL != lpCV->lpszUserType)
+ && (IsBadReadPtr(lpCV->lpszUserType, 1)) )
+ uRet = OLEUI_CTERR_STRINGINVALID;
+
+ if ( (NULL != lpCV->lpszDefLabel)
+ && (IsBadReadPtr(lpCV->lpszDefLabel, 1)) )
+ uRet = OLEUI_CTERR_STRINGINVALID;
+
+ if (0!=lpCV->cClsidExclude)
+ {
+ if (NULL!=lpCV->lpClsidExclude && IsBadReadPtr(lpCV->lpClsidExclude
+ , lpCV->cClsidExclude*sizeof(CLSID)))
+ uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;
+ }
+
+
+ if (OLEUI_ERR_STANDARDMIN <= uRet)
+ {
+ if (NULL!=hMemDlg)
+ FreeResource(hMemDlg);
+
+ return uRet;
+ }
+
+ //Now that we've validated everything, we can invoke the dialog.
+ uRet=UStandardInvocation(ConvertDialogProc, (LPOLEUISTANDARD)lpCV,
+ hMemDlg, MAKEINTRESOURCE(IDD_CONVERT));
+
+ return uRet;
+ }
+
+
+
+
+
+/*
+ * ConvertDialogProc
+ *
+ * Purpose:
+ * Implements the OLE Convert dialog as invoked through the
+ * OleUIConvert function.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ *
+ */
+
+BOOL CALLBACK EXPORT ConvertDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+ {
+ LPCONVERT lpCV;
+ UINT uRet = 0;
+ OLEUICHANGEICON ci;
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ lpCV=(LPCONVERT)LpvStandardEntry(hDlg, iMsg, wParam, lParam, (UINT FAR *)&uRet);
+
+ //If the hook processed the message, we're done.
+ if (0!=uRet)
+ return (BOOL)uRet;
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ ConvertCleanup(hDlg, lpCV);
+ StandardCleanup(lpCV, hDlg);
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ // Process help message from Change Icon
+ if (iMsg == uMsgHelp)
+ {
+
+ PostMessage(lpCV->lpOCV->hWndOwner, uMsgHelp, wParam, lParam);
+ return FALSE;
+
+ }
+
+ switch (iMsg)
+ {
+ case WM_INITDIALOG:
+ FConvertInit(hDlg, wParam, lParam);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wID)
+ {
+ case IDCV_ACTIVATELIST:
+ case IDCV_CONVERTLIST:
+ switch (wCode)
+ {
+ case LBN_SELCHANGE:
+
+ // Change "Results" window to reflect current selection
+ SetConvertResults(hDlg, lpCV);
+
+ // Update the icon we display, if we are indeed
+ // displaying an icon.
+ if ( (lpCV->dwFlags & CF_SELECTCONVERTTO)
+ && (lpCV->dvAspect == DVASPECT_ICON)
+ && (!lpCV->fCustomIcon) )
+ UpdateCVClassIcon(hDlg, lpCV, hWndMsg);
+
+ break;
+
+ case LBN_DBLCLK:
+ //Same as pressing OK.
+ SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
+ break;
+ }
+ break;
+
+ case IDCV_CONVERTTO:
+ case IDCV_ACTIVATEAS:
+ {
+ HWND hList, hListInvisible;
+ LRESULT lRetVal;
+ BOOL fState;
+
+ hList = lpCV->hListVisible;
+ hListInvisible = lpCV->hListInvisible;
+
+
+ if (IDCV_CONVERTTO == wParam)
+ {
+
+ // User just click on the button again - it was
+ // already selected.
+ if (lpCV->dwFlags & CF_SELECTCONVERTTO)
+ break;
+
+
+ // Turn painting updates off.
+ SendMessage(hDlg, WM_SETREDRAW, FALSE, 0L);
+
+
+ // If we're working with a linked object, don't
+ // add the activate list - just the object's
+ // class should appear in the listbox.
+
+ SwapWindows(hDlg,
+ hList,
+ hListInvisible);
+
+ lpCV->hListVisible = hListInvisible;
+ lpCV->hListInvisible = hList;
+
+ EnableWindow(lpCV->hListInvisible, FALSE);
+ EnableWindow(lpCV->hListVisible, TRUE);
+
+ // Update our flags.
+ lpCV->dwFlags &= ~CF_SELECTACTIVATEAS;
+ lpCV->dwFlags |= CF_SELECTCONVERTTO;
+
+ }
+ else
+ {
+ if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
+ break;
+
+ // Turn painting updates off.
+ SendMessage(hDlg, WM_SETREDRAW, FALSE, 0L);
+
+ SwapWindows(hDlg,
+ hList,
+ hListInvisible);
+
+ lpCV->hListVisible = hListInvisible;
+ lpCV->hListInvisible = hList;
+
+ EnableWindow(lpCV->hListInvisible, FALSE);
+ EnableWindow(lpCV->hListVisible, TRUE);
+
+
+ // Update our flags.
+ lpCV->dwFlags |= CF_SELECTACTIVATEAS;
+ lpCV->dwFlags &= ~CF_SELECTCONVERTTO;
+ }
+
+
+ if (lpCV->dwFlags & CF_SELECTCONVERTTO)
+ lRetVal = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)lpCV->lpszConvertDefault);
+ else
+ lRetVal = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)lpCV->lpszActivateDefault);
+
+ if (LB_ERR == lRetVal)
+ {
+ TCHAR szCurrentObject[40];
+
+ GetDlgItemText(hDlg, IDCV_OBJECTTYPE, (LPTSTR)szCurrentObject, 40);
+ SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPTSTR)szCurrentObject);
+ }
+
+ // Turn updates back on.
+ SendMessage(hDlg, WM_SETREDRAW, TRUE, 0L);
+
+ InvalidateRect(lpCV->hListVisible, NULL, TRUE);
+ UpdateWindow(lpCV->hListVisible);
+
+ if ((lpCV->dvAspect & DVASPECT_ICON) && (lpCV->dwFlags & CF_SELECTCONVERTTO))
+ UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);
+
+ // Hide the icon stuff when Activate is selected...show
+ // it again when Convert is selected.
+
+ fState = ((lpCV->dwFlags & CF_SELECTACTIVATEAS) ||
+ (lpCV->dwFlags & CF_DISABLEDISPLAYASICON)) ?
+ SW_HIDE : SW_SHOW;
+
+ StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, fState);
+
+ // Only display the icon if convert is selected AND
+ // display as icon is checked.
+ if ((SW_SHOW==fState) && (DVASPECT_ICON!=lpCV->dvAspect))
+ fState = SW_HIDE;
+
+ StandardShowDlgItem(hDlg, IDCV_CHANGEICON, fState);
+ StandardShowDlgItem(hDlg, IDCV_ICON, fState);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, fState);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, fState);
+
+ SetConvertResults(hDlg, lpCV);
+
+ }
+ break;
+
+
+ case IDOK:
+ {
+
+ LRESULT iCurSel;
+ LPTSTR lpszCLSID;
+ TCHAR szBuffer[256];
+
+ // Set OUT parameters
+
+ //
+ // Set output flags to current ones
+ //
+ lpCV->lpOCV->dwFlags = lpCV->dwFlags;
+
+
+ // Update the dvAspect and fObjectsIconChanged members
+ // as appropriate.
+ //
+ if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
+ {
+ // DON'T update aspect if activate as was selected.
+ lpCV->lpOCV->fObjectsIconChanged = FALSE;
+ }
+ else
+ lpCV->lpOCV->dvAspect = lpCV->dvAspect;
+
+
+ //
+ // Get the new clsid
+ //
+ iCurSel = SendMessage(lpCV->hListVisible, LB_GETCURSEL, 0, 0);
+ SendMessage(lpCV->hListVisible, LB_GETTEXT, iCurSel, (LPARAM)szBuffer);
+
+ lpszCLSID = PointerToNthField((LPTSTR)szBuffer, 2, TEXT('\t'));
+
+ CLSIDFromStringA(lpszCLSID, (&(lpCV->lpOCV->clsidNew)));
+
+ // Free the hMetaPict we got in.
+ OleUIMetafilePictIconFree(lpCV->lpOCV->hMetaPict);
+
+ //
+ // Get the hMetaPict (if display as icon is checked)
+ //
+ if (DVASPECT_ICON == lpCV->dvAspect)
+ {
+ HICON hIcon;
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ INT Index;
+
+
+ // Create the hMetaPict here from icon, label,
+ // index, and path
+
+ hIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_GETICON, 0, 0L);
+
+ // the combined length of the 2 label lines won't ever be more than
+ // OLEUI_CCHLABELMAX.
+ Index = (INT)SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,
+ WM_GETTEXT, OLEUI_CCHLABELMAX, (LPARAM)szLabel);
+
+ if (Index < OLEUI_CCHLABELMAX)
+ {
+ LPTSTR lpszSecondLine = szLabel + Index;
+
+
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_GETTEXT,
+ OLEUI_CCHLABELMAX-Index,
+ (LPARAM)lpszSecondLine);
+ }
+
+#ifdef OLE201
+ lpCV->lpOCV->hMetaPict =
+ OleUIMetafilePictFromIconAndLabel(hIcon,
+ (LPTSTR)szLabel,
+ lpCV->lpszIconSource,
+ lpCV->IconIndex);
+#endif
+
+ }
+ else
+ lpCV->lpOCV->hMetaPict = (HGLOBAL)NULL;
+
+
+ //
+ // End the dialog
+ //
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ }
+ break;
+
+ case IDCANCEL:
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ break;
+
+
+ case ID_OLEUIHELP:
+ PostMessage(lpCV->lpOCV->hWndOwner,
+ uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_CONVERT, 0));
+ break;
+
+ case IDCV_DISPLAYASICON:
+ {
+
+ int i;
+ BOOL fCheck;
+
+ fCheck=IsDlgButtonChecked(hDlg, wID);
+
+ if (fCheck)
+ lpCV->dvAspect = DVASPECT_ICON;
+ else
+ lpCV->dvAspect = DVASPECT_CONTENT;
+
+ if (fCheck && (!lpCV->fCustomIcon))
+ UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);
+
+ //Show or hide the icon depending on the check state.
+
+ i=(fCheck) ? SW_SHOWNORMAL : SW_HIDE;
+
+ StandardShowDlgItem(hDlg, IDCV_CHANGEICON, i);
+ StandardShowDlgItem(hDlg, IDCV_ICON, i);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, i);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, i);
+
+ SetConvertResults(hDlg, lpCV);
+
+ }
+ break;
+
+ case IDCV_CHANGEICON:
+ {
+ LPMALLOC pIMalloc;
+ LPTSTR pszString, pszCLSID;
+ INT iSel;
+ HICON hIcon;
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ INT Index;
+
+
+ //Initialize the structure for the hook.
+ _fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));
+
+ // Create the hMetaPict here from icon, label,
+ // index, and path
+
+ hIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_GETICON, 0, 0L);
+
+ // the combined length of the 2 label lines won't ever be more than
+ // OLEUI_CCHLABELMAX.
+
+ Index = (INT)SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_GETTEXT,
+ OLEUI_CCHLABELMAX, (LPARAM)szLabel);
+
+ if (Index < OLEUI_CCHLABELMAX)
+ {
+ LPTSTR lpszSecondLine;
+
+ lpszSecondLine = szLabel + Index;
+
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_GETTEXT,
+ OLEUI_CCHLABELMAX-Index,
+ (LPARAM)lpszSecondLine);
+ }
+
+#ifdef OLE201
+ ci.hMetaPict =
+ OleUIMetafilePictFromIconAndLabel(hIcon,
+ szLabel,
+ lpCV->lpszIconSource,
+ lpCV->IconIndex);
+#endif
+
+ ci.cbStruct =sizeof(ci);
+ ci.hWndOwner=hDlg;
+ ci.dwFlags = CIF_SELECTCURRENT;
+
+ // Only show help if we're showing it for this dialog.
+ if (lpCV->dwFlags & CF_SHOWHELPBUTTON)
+ ci.dwFlags |= CIF_SHOWHELP;
+
+ iSel = (INT)SendMessage(lpCV->hListVisible, LB_GETCURSEL, 0, 0L);
+
+ CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ pszString = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc,
+ OLEUI_CCHLABELMAX_SIZE +
+ OLEUI_CCHCLSIDSTRING_SIZE);
+
+ // Get whole string
+ SendMessage(lpCV->hListVisible, LB_GETTEXT, iSel, (LONG)pszString);
+
+ // Set pointer to CLSID (string)
+ pszCLSID = PointerToNthField(pszString, 2, TEXT('\t'));
+
+ // Get the clsid to pass to change icon.
+ CLSIDFromStringA(pszCLSID, &(ci.clsid));
+
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszString);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+
+ //Let the hook in to customize Change Icon if desired.
+ uRet=UStandardHook(lpCV, hDlg, uMsgChangeIcon
+ , 0, (LONG)(LPTSTR)&ci);
+
+ if (0==uRet)
+ uRet=(UINT)(OLEUI_OK==OleUIChangeIcon((LPOLEUICHANGEICON)&ci));
+
+ //Update the display if necessary.
+ if (0!=uRet)
+ {
+ HICON hIcon;
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ DWORD dwWrapIndex;
+
+
+ hIcon = OleUIMetafilePictExtractIcon(ci.hMetaPict);
+
+ SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
+
+ OleUIMetafilePictExtractIconSource(ci.hMetaPict, lpCV->lpszIconSource, &(lpCV->IconIndex));
+
+ OleUIMetafilePictExtractLabel(ci.hMetaPict, szLabel, OLEUI_CCHLABELMAX, &dwWrapIndex);
+
+ if (0 == dwWrapIndex) // no second line
+ {
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETTEXT, 0, (LPARAM)(LPTSTR)szLabel);
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)(LPTSTR)TEXT(""));
+ }
+ else
+ {
+
+ LPTSTR lpszSecondLine;
+
+ lpszSecondLine = szLabel + dwWrapIndex;
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2,
+ WM_SETTEXT, 0, (LPARAM)lpszSecondLine);
+
+ *lpszSecondLine = TEXT('\0');
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,
+ WM_SETTEXT, 0, (LPARAM)(LPTSTR)szLabel);
+ }
+
+
+ // Update our custom/default flag
+
+ if (ci.dwFlags & CIF_SELECTDEFAULT)
+ lpCV->fCustomIcon = FALSE; // we're in default mode (icon changes on each LB selchange)
+ else if (ci.dwFlags & CIF_SELECTFROMFILE)
+ lpCV->fCustomIcon = TRUE; // we're in custom mode (icon doesn't change)
+ // no change in fCustomIcon if user selected current
+
+
+ lpCV->lpOCV->fObjectsIconChanged = TRUE;
+ }
+ }
+ break;
+
+ }
+ break;
+ }
+ return FALSE;
+ }
+
+
+/*
+ * FConvertInit
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the Convert dialog box.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL FConvertInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
+ {
+ LPCONVERT lpCV;
+ LPOLEUICONVERT lpOCV;
+ LPMALLOC pIMalloc;
+ HFONT hFont; // non-bold version of dialog's font
+ RECT rc;
+ DWORD dw;
+ INT cItemsActivate;
+ HKEY hKey;
+ LONG lRet;
+ UINT nRet;
+
+
+ //Copy the structure at lParam into our instance memory.
+ lpCV=(LPCONVERT)LpvStandardInit(hDlg, sizeof(CONVERT), TRUE, (HFONT FAR *)&hFont);
+
+ //PvStandardInit send a termination to us already.
+ if (NULL==lpCV)
+ return FALSE;
+
+ lpOCV=(LPOLEUICONVERT)lParam;
+
+ lpCV->lpOCV=lpOCV;
+
+ lpCV->fCustomIcon = FALSE;
+
+ //Copy other information from lpOCV that we might modify.
+ lpCV->dwFlags = lpOCV->dwFlags;
+ lpCV->clsid = lpOCV->clsid;
+ lpCV->dvAspect = lpOCV->dvAspect;
+ lpCV->hListVisible = GetDlgItem(hDlg, IDCV_ACTIVATELIST);
+ lpCV->hListInvisible = GetDlgItem(hDlg, IDCV_CONVERTLIST);
+ lpCV->lpszCurrentObject = lpOCV->lpszUserType;
+
+ lpOCV->clsidNew = CLSID_NULL;
+
+ lpOCV->fObjectsIconChanged = FALSE;
+
+ //Allocate space for our strings
+ if (NOERROR != CoGetMalloc(MEMCTX_TASK, &pIMalloc))
+ return FALSE;
+
+ lpCV->lpszConvertDefault = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX_SIZE);
+ lpCV->lpszActivateDefault = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX_SIZE);
+ lpCV->lpszIconSource = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHPATHMAX_SIZE);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+
+ //If we got a font, send it to the necessary controls.
+ if (NULL!=hFont)
+ {
+ SendDlgItemMessage(hDlg, IDCV_OBJECTTYPE, WM_SETFONT, (WPARAM)hFont, 0L);
+ SendDlgItemMessage(hDlg, IDCV_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L);
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETFONT, (WPARAM)hFont, 0L);
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETFONT, (WPARAM)hFont, 0L);
+ }
+
+ //Hide the help button if necessary
+ if (!(lpCV->dwFlags & CF_SHOWHELPBUTTON))
+ StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
+
+ //Fill the Object Type listbox with entries from the reg DB.
+ nRet = FillClassList(lpOCV->clsid,
+ lpCV->hListVisible,
+ lpCV->hListInvisible,
+ &(lpCV->lpszCurrentObject),
+ lpOCV->fIsLinkedObject,
+ lpOCV->wFormat,
+ lpOCV->cClsidExclude,
+ lpOCV->lpClsidExclude);
+
+ if (nRet == -1) {
+ // bring down dialog if error when filling list box
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
+ }
+
+ // Set the name of the current object.
+ SetDlgItemText(hDlg, IDCV_OBJECTTYPE, (LPTSTR)lpCV->lpszCurrentObject);
+
+ // Disable the "Activate As" button if the Activate list doesn't
+ // have any objects in it.
+
+ cItemsActivate = (INT)SendMessage(lpCV->hListVisible, LB_GETCOUNT, 0, 0L);
+
+ if (1 >= cItemsActivate || (lpCV->dwFlags & CF_DISABLEACTIVATEAS))
+ EnableWindow(GetDlgItem(hDlg, IDCV_ACTIVATEAS), FALSE);
+
+ //Set the tab width in the list to push all the tabs off the side.
+ GetClientRect(lpCV->hListVisible, (LPRECT)&rc);
+ dw=GetDialogBaseUnits();
+ rc.right =(8*rc.right)/LOWORD(dw); //Convert pixels to 2x dlg units.
+ SendMessage(lpCV->hListVisible, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)(&rc.right));
+ SendMessage(lpCV->hListInvisible, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)(&rc.right));
+
+
+ // Make sure that either "Convert To" or "Activate As" is selected
+ // and initialize listbox contents and selection accordingly
+ if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
+ {
+ // Don't need to adjust listbox here because FillClassList
+ // initializes to the "Activate As" state.
+ CheckRadioButton(hDlg, IDCV_CONVERTTO, IDCV_ACTIVATEAS, IDCV_ACTIVATEAS);
+
+ // Hide the icon stuff when Activate is selected...it gets shown
+ // again when Convert is selected.
+
+ StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);
+ }
+ else
+ {
+ // Default case. If user hasn't selected either flag, we will
+ // come here anyway.
+ // swap listboxes.
+
+ HWND hWndTemp = lpCV->hListVisible;
+
+ if ( lpCV->dwFlags & CF_DISABLEDISPLAYASICON ) {
+ StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);
+ }
+
+ lpCV->dwFlags |= CF_SELECTCONVERTTO; // Make sure flag is set
+ CheckRadioButton(hDlg, IDCV_CONVERTTO, IDCV_ACTIVATEAS, IDCV_CONVERTTO);
+
+ SwapWindows(hDlg, lpCV->hListVisible, lpCV->hListInvisible);
+
+ lpCV->hListVisible = lpCV->hListInvisible;
+ lpCV->hListInvisible = hWndTemp;
+
+ EnableWindow(lpCV->hListInvisible, FALSE);
+ EnableWindow(lpCV->hListVisible, TRUE);
+ }
+
+
+
+ // Initialize Default strings.
+
+ // Default convert string is easy...just user the user type name from
+ // the clsid we got, or the current object
+ if ( (lpCV->dwFlags & CF_SETCONVERTDEFAULT)
+ && (IsValidClassID(lpCV->lpOCV->clsidConvertDefault)) )
+ {
+ dw = OleStdGetUserTypeOfClass((LPCLSID)(&lpCV->lpOCV->clsidConvertDefault),
+ lpCV->lpszConvertDefault,
+ OLEUI_CCHLABELMAX_SIZE,
+ NULL);
+
+ if (0 == dw)
+ lstrcpy((LPTSTR)lpCV->lpszConvertDefault, (LPTSTR)lpCV->lpszCurrentObject);
+ }
+ else
+ lstrcpy((LPTSTR)lpCV->lpszConvertDefault, (LPTSTR)lpCV->lpszCurrentObject);
+
+
+ // Default activate is a bit trickier. We want to use the user type
+ // name if from the clsid we got (assuming we got one), or the current
+ // object if it fails or we didn't get a clsid. But...if there's a
+ // Treat As entry in the reg db, then we use that instead. So... the
+ // logic boils down to this:
+ //
+ // if ("Treat As" in reg db)
+ // use it;
+ // else
+ // if (CF_SETACTIVATEDEFAULT)
+ // use it;
+ // else
+ // use current object;
+
+
+
+ lRet = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), (HKEY FAR *)&hKey);
+
+ if (lRet != ERROR_SUCCESS)
+ goto CheckInputFlag;
+
+ else
+ {
+ LPTSTR lpszCLSID;
+ TCHAR szKey[OLEUI_CCHKEYMAX];
+ CLSID clsid;
+ TCHAR szValue[OLEUI_CCHKEYMAX];
+
+ StringFromCLSIDA(&(lpCV->lpOCV->clsid), &lpszCLSID);
+ lstrcpy(szKey, lpszCLSID);
+ lstrcat(szKey, TEXT("\\TreatAs"));
+
+ dw = OLEUI_CCHKEYMAX_SIZE;
+ lRet = RegQueryValue(hKey, (LPTSTR)szKey, (LPTSTR)szValue, (LPDWORD)&dw);
+
+ if (lRet != ERROR_SUCCESS)
+ {
+
+ RegCloseKey(hKey);
+ OleStdFreeString(lpszCLSID, NULL);
+ goto CheckInputFlag;
+ }
+ else
+ {
+ CLSIDFromStringA(szValue, &clsid);
+
+ if (0 == OleStdGetUserTypeOfClass(&clsid,
+ lpCV->lpszActivateDefault,
+ OLEUI_CCHLABELMAX_SIZE,
+ NULL))
+ {
+ RegCloseKey(hKey);
+ OleStdFreeString(lpszCLSID, NULL);
+ goto CheckInputFlag;
+ }
+ }
+ RegCloseKey(hKey);
+ OleStdFreeString(lpszCLSID, NULL);
+ goto SelectStringInListbox;
+ }
+
+
+CheckInputFlag:
+ if ( (lpCV->dwFlags & CF_SETACTIVATEDEFAULT)
+ && (IsValidClassID(lpCV->lpOCV->clsidActivateDefault)) )
+ {
+ dw = OleStdGetUserTypeOfClass((LPCLSID)(&lpCV->lpOCV->clsidActivateDefault),
+ lpCV->lpszActivateDefault,
+ OLEUI_CCHLABELMAX_SIZE,
+ NULL);
+
+ if (0 == dw)
+ lstrcpy((LPTSTR)lpCV->lpszActivateDefault, (LPTSTR)lpCV->lpszCurrentObject);
+ }
+ else
+ lstrcpy((LPTSTR)(lpCV->lpszActivateDefault), (LPTSTR)lpCV->lpszCurrentObject);
+
+
+SelectStringInListbox:
+
+ if (lpCV->dwFlags & CF_SELECTCONVERTTO)
+ lRet = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPTSTR)(lpCV->lpszConvertDefault));
+
+ else
+ lRet = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPTSTR)(lpCV->lpszActivateDefault));
+
+ if (LB_ERR == lRet)
+ SendMessage(lpCV->hListVisible, LB_SETCURSEL, (WPARAM)0, 0L);
+
+
+ // Initialize icon stuff
+ if (DVASPECT_ICON == lpCV->dvAspect )
+ {
+ SendDlgItemMessage(hDlg, IDCV_DISPLAYASICON, BM_SETCHECK, TRUE, 0L);
+
+ if ((HGLOBAL)NULL != lpOCV->hMetaPict)
+ {
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ HICON hIcon;
+ DWORD dwWrapIndex;
+
+
+ // Set the icon to the icon from the hMetaPict,
+ // set the label to the label from the hMetaPict.
+
+ if (0 != OleUIMetafilePictExtractLabel(lpOCV->hMetaPict, (LPTSTR)szLabel, OLEUI_CCHLABELMAX_SIZE, &dwWrapIndex))
+ {
+ if (0 == dwWrapIndex) // no second line
+ {
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETTEXT, 0, (LPARAM)(LPTSTR)szLabel);
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)(LPTSTR)TEXT(""));
+ }
+ else
+ {
+
+ LPTSTR lpszSecondLine;
+
+ lpszSecondLine = szLabel + dwWrapIndex;
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2,
+ WM_SETTEXT, 0, (LPARAM)lpszSecondLine);
+
+ *lpszSecondLine = TEXT('\0');
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,
+ WM_SETTEXT, 0, (LPARAM)(LPTSTR)szLabel);
+ }
+
+
+ }
+
+ hIcon = OleUIMetafilePictExtractIcon(lpOCV->hMetaPict);
+
+ if (NULL != hIcon)
+ {
+ SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
+ lpCV->fCustomIcon = TRUE;
+ }
+
+ OleUIMetafilePictExtractIconSource(lpOCV->hMetaPict,
+ (LPTSTR)(lpCV->lpszIconSource),
+ &(lpCV->IconIndex));
+
+ }
+ else
+ UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);
+ }
+ else
+ {
+ // Hide & disable icon stuff
+ StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);
+ StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);
+ }
+
+ // Call the hook with lCustData in lParam
+ UStandardHook((LPVOID)lpCV, hDlg, WM_INITDIALOG, wParam, lpOCV->lCustData);
+ // Update results window
+ SetConvertResults(hDlg, lpCV);
+
+ // Update caption if lpszCaption was specified
+ if (lpCV->lpOCV->lpszCaption && !IsBadReadPtr(lpCV->lpOCV->lpszCaption, 1)
+ && lpCV->lpOCV->lpszCaption[0] != '\0')
+ SetWindowText(hDlg, (LPTSTR)lpCV->lpOCV->lpszCaption);
+
+ return TRUE;
+ }
+
+
+/*
+ * FillClassList
+ *
+ * Purpose:
+ * Enumerates available OLE object classes from the registration
+ * database that we can convert or activate the specified clsid from.
+ *
+ * Note that this function removes any prior contents of the listbox.
+ *
+ * Parameters:
+ * clsid Class ID for class to find convert classes for
+ * hList HWND to the listbox to fill.
+ * hListActivate HWND to invisible listbox that stores "activate as" list.
+ * lpszClassName LPSTR to put the (hr) class name of the clsid; we
+ * do it here since we've already got the reg db open.
+ * fIsLinkedObject BOOL is the original object a linked object
+ * wFormat WORD specifying the format of the original class.
+ * cClsidExclude UINT number of entries in exclude list
+ * lpClsidExclude LPCLSID array classes to exclude for list
+ *
+ * Return Value:
+ * UINT Number of strings added to the listbox, -1 on failure.
+ */
+
+UINT FillClassList(
+ CLSID clsid,
+ HWND hList,
+ HWND hListInvisible,
+ LPTSTR FAR *lplpszCurrentClass,
+ BOOL fIsLinkedObject,
+ WORD wFormat,
+ UINT cClsidExclude,
+ LPCLSID lpClsidExclude)
+{
+
+ DWORD dw;
+ UINT cStrings=0;
+ HKEY hKey;
+ LONG lRet;
+ TCHAR szFormatKey[OLEUI_CCHKEYMAX];
+ TCHAR szClass[OLEUI_CCHKEYMAX];
+ TCHAR szFormat[OLEUI_CCHKEYMAX];
+ TCHAR szHRClassName[OLEUI_CCHKEYMAX];
+ CLSID clsidForList;
+
+ LPTSTR lpszCLSID;
+
+
+ //Clean out the existing strings.
+ SendMessage(hList, LB_RESETCONTENT, 0, 0L);
+ SendMessage(hListInvisible, LB_RESETCONTENT, 0, 0L);
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, (LPCTSTR) TEXT("CLSID"), (HKEY FAR *)&hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return (UINT)-1;
+
+ if (NULL == *lplpszCurrentClass)
+ {
+ // alloc buffer here...
+
+ LPMALLOC pIMalloc = NULL;
+ HRESULT hrErr;
+
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ if (hrErr != NOERROR)
+ {
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ // Allocate space for lpszCurrentClass
+ *lplpszCurrentClass = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX_SIZE);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+
+ lRet = OleStdGetUserTypeOfClass((REFCLSID)&clsid,
+ *lplpszCurrentClass,
+ OLEUI_CCHLABELMAX_SIZE,
+ NULL);
+
+ if (0 ==lRet)
+ {
+ INT n = LoadString(ghInst, IDS_PSUNKNOWNTYPE, *lplpszCurrentClass,
+ OLEUI_CCHKEYMAX);
+ if (!n)
+ {
+ OutputDebugString(TEXT("Cannot LoadString\n"));
+ RegCloseKey(hKey);
+ return (UINT)-1;
+ }
+ }
+ }
+
+ // Get the class name of the original class.
+ StringFromCLSIDA(&clsid, &lpszCLSID);
+
+
+ // Here, we step through the entire registration db looking for
+ // class that can read or write the original class' format. We
+ // maintain two lists - an activate list and a convert list. The
+ // activate list is a subset of the convert list - activate == read/write
+ // and convert == read. We swap the listboxes as needed with
+ // SwapWindows, and keep track of which is which in the lpCV structure.
+
+ // Every item has the following format:
+ //
+ // Class Name\tclsid\0
+
+
+ cStrings=0;
+ lRet=RegEnumKey(hKey, cStrings++, szClass, OLEUI_CCHKEYMAX_SIZE);
+
+ while ((LONG)ERROR_SUCCESS==lRet)
+ {
+ INT j;
+ BOOL fExclude=FALSE;
+
+
+ //Check if this CLSID is in the exclusion list.
+ CLSIDFromStringA(szClass, &clsidForList);
+
+ for (j=0; j < (int)cClsidExclude; j++)
+ {
+ if (IsEqualCLSID(&clsidForList, (LPCLSID)(lpClsidExclude+j)))
+ {
+ fExclude=TRUE;
+ break;
+ }
+ }
+ if (fExclude)
+ goto Next; // don't add this class to list
+
+ // Check for a \Conversion\Readwritable\Main - if its
+ // readwriteable, then the class can be added to the ActivateAs
+ // list.
+ // NOTE: the presence of this key should NOT automatically be
+ // used to add the class to the CONVERT list.
+
+ lstrcpy((LPTSTR)szFormatKey, (LPTSTR)szClass);
+ lstrcat((LPTSTR)szFormatKey, (LPTSTR) TEXT("\\Conversion\\Readwritable\\Main"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+
+ lRet=RegQueryValue(hKey, (LPTSTR)szFormatKey, (LPTSTR)szFormat, (LONG FAR *)&dw);
+
+ if ( ((LONG)ERROR_SUCCESS==lRet)
+ && (FormatIncluded((LPTSTR)szFormat, wFormat)) )
+ {
+ // Here, we've got a list of formats that this class can read
+ // and write. We need to see if the original class' format is
+ // in this list. We do that by looking for wFormat in
+ // szFormat - if it in there, then we add this class to the
+ // ACTIVATEAS list only. we do NOT automatically add it to the
+ // CONVERT list. Readable and Readwritable format lists should
+ // be handled separately.
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, (LPTSTR)szClass, (LPTSTR)szHRClassName, (LPDWORD)&dw);
+
+ if ((LONG)ERROR_SUCCESS==lRet)
+ {
+ lstrcat((LPTSTR)szHRClassName, (LPTSTR) TEXT("\t"));
+
+ // only add if not already in list
+ if (LB_ERR==SendMessage(hList,LB_FINDSTRING, 0,
+ (LPARAM)(LPSTR)szHRClassName)) {
+ lstrcat((LPTSTR)szHRClassName, (LPTSTR)szClass);
+ SendMessage(hList, LB_ADDSTRING, 0,
+ (DWORD)(LPTSTR)szHRClassName);
+ }
+ }
+
+ }
+
+
+ // Here we'll check to see if the original class' format is in the
+ // readable list. if so, we will add the class to the CONVERTLIST
+
+
+ // We've got a special case for a linked object here.
+ // If an object is linked, then the only class that
+ // should appear in the convert list is the object's
+ // class. So, here we check to see if the object is
+ // linked. If it is, then we compare the classes. If
+ // they aren't the same, then we just go to the next key.
+
+ if ( (!fIsLinkedObject)||(lstrcmp((LPCTSTR)lpszCLSID, szClass) == 0))
+ {
+
+ //Check for a \Conversion\Readable\Main entry
+ lstrcpy((LPTSTR)szFormatKey, (LPTSTR)szClass);
+ lstrcat((LPTSTR)szFormatKey, (LPTSTR) TEXT("\\Conversion\\Readable\\Main"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+
+ // Check to see if this class can read the original class
+ // format. If it can, add the string to the listbox as
+ // CONVERT_LIST.
+
+ lRet=RegQueryValue(hKey, (LPCTSTR)szFormatKey, (LPTSTR)szFormat, (LPDWORD)&dw);
+
+ if ( ((LONG)ERROR_SUCCESS==lRet)
+ && (FormatIncluded((LPTSTR)szFormat, wFormat)) )
+ {
+
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, (LPCTSTR)szClass, (LPTSTR)szHRClassName, (LPDWORD)&dw);
+
+ if ((LONG)ERROR_SUCCESS==lRet)
+ {
+ lstrcat((LPTSTR)szHRClassName, (LPTSTR) TEXT("\t"));
+
+ // only add if not already in list
+ if (LB_ERR==SendMessage(hListInvisible,LB_FINDSTRING, 0,
+ (LPARAM)(LPSTR)szHRClassName)) {
+ lstrcat((LPTSTR)szHRClassName, szClass);
+ SendMessage(hListInvisible, LB_ADDSTRING, 0,
+ (DWORD)(LPTSTR)szHRClassName);
+ }
+ } // end if
+
+ } // end if
+ } // end else
+Next:
+ //Continue with the next key.
+ lRet=RegEnumKey(hKey, cStrings++, (LPTSTR)szClass, OLEUI_CCHKEYMAX_SIZE);
+
+ } // end while
+
+ // If the original class isn't already in the list, add it.
+
+ lstrcpy((LPTSTR)szHRClassName, *lplpszCurrentClass);
+ lstrcat((LPTSTR)szHRClassName, (LPTSTR) TEXT("\t"));
+
+ lRet = SendMessage(hList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPTSTR)szHRClassName);
+
+ // only add it if it's not there already.
+ if (LB_ERR == lRet) {
+ lstrcat((LPTSTR)szHRClassName, lpszCLSID);
+ SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)szHRClassName);
+ }
+
+ lRet = SendMessage(hListInvisible, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPTSTR)szHRClassName);
+
+ // only add it if it's not there already.
+ if (LB_ERR == lRet)
+ SendMessage(hListInvisible, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)szHRClassName);
+
+ // Free the string we got from StringFromCLSID.
+ // OLE2NOTE: StringFromCLSID uses your IMalloc to alloc a
+ // string, so you need to be sure to free the string you
+ // get back, otherwise you'll have leaky memory.
+
+ OleStdFreeString(lpszCLSID, NULL);
+
+ RegCloseKey(hKey);
+
+ return cStrings;
+}
+
+
+/*
+ * OleUICanConvertOrActivateAs
+ *
+ * Purpose:
+ * Determine if there is any OLE object class from the registration
+ * database that we can convert or activate the specified clsid from.
+ *
+ * Parameters:
+ * rClsid REFCLSID Class ID for class to find convert classes for
+ * fIsLinkedObject BOOL is the original object a linked object
+ * wFormat WORD specifying the format of the original class.
+ *
+ * Return Value:
+ * BOOL TRUE if Convert command should be enabled, else FALSE
+ */
+
+STDAPI_(BOOL) OleUICanConvertOrActivateAs(
+ REFCLSID rClsid,
+ BOOL fIsLinkedObject,
+ WORD wFormat
+)
+{
+
+ DWORD dw;
+ UINT cStrings=0;
+ HKEY hKey;
+ LONG lRet;
+ TCHAR szFormatKey[OLEUI_CCHKEYMAX];
+ TCHAR szClass[OLEUI_CCHKEYMAX];
+ TCHAR szFormat[OLEUI_CCHKEYMAX];
+ TCHAR szHRClassName[OLEUI_CCHKEYMAX];
+ BOOL fEnableConvert = FALSE;
+
+ LPTSTR lpszCLSID;
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", (HKEY FAR *)&hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return FALSE;
+
+ // Get the class name of the original class.
+ StringFromCLSIDA(rClsid, &lpszCLSID);
+
+ // Here, we step through the entire registration db looking for
+ // class that can read or write the original class' format.
+ // This loop stops if a single class is found.
+
+ cStrings=0;
+ lRet=RegEnumKey(hKey, cStrings++, szClass, OLEUI_CCHKEYMAX_SIZE);
+
+ while ((LONG)ERROR_SUCCESS==lRet)
+ {
+ if (lstrcmp(lpszCLSID, szClass)== 0)
+ goto next; // we don't want to consider the source class
+
+ // Check for a \Conversion\ReadWriteable\Main entry first - if its
+ // readwriteable, then we don't need to bother checking to see if
+ // its readable.
+
+ lstrcpy((LPTSTR)szFormatKey, (LPTSTR)szClass);
+ lstrcat((LPTSTR)szFormatKey, (LPTSTR) TEXT("\\Conversion\\Readwritable\\Main"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+
+ lRet=RegQueryValue(hKey, (LPCTSTR)szFormatKey, (LPTSTR)szFormat, (LONG FAR *)&dw);
+
+ if ( (LONG)ERROR_SUCCESS != lRet)
+ {
+ // Try \\DataFormats\DefaultFile too
+
+ lstrcpy((LPTSTR)szFormatKey, (LPTSTR)szClass);
+ lstrcat((LPTSTR)szFormatKey, (LPTSTR) TEXT("\\DataFormats\\DefaultFile"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+
+ lRet=RegQueryValue(hKey, (LPCTSTR)szFormatKey, (LPTSTR)szFormat, (LONG FAR *)&dw);
+ }
+
+
+ if ( ((LONG)ERROR_SUCCESS==lRet)
+ && (FormatIncluded((LPTSTR)szFormat, wFormat)) )
+ {
+
+ // Here, we've got a list of formats that this class can read
+ // and write. We need to see if the original class' format is
+ // in this list. We do that by looking for wFormat in
+ // szFormat - if it in there, then we add this class to the
+ // both lists and continue. If not, then we look at the
+ // class' readable formats.
+
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, (LPCTSTR)szClass, (LPTSTR)szHRClassName, (LPDWORD)&dw);
+
+ if ((LONG)ERROR_SUCCESS==lRet)
+ {
+ fEnableConvert = TRUE;
+ break; // STOP -- found one!
+ }
+
+ }
+
+
+ // We either didn't find the readwritable key, or the
+ // list of readwritable formats didn't include the
+ // original class format. So, here we'll check to
+ // see if its in the readable list.
+
+
+ // We've got a special case for a linked object here.
+ // If an object is linked, then the only class that
+ // should appear in the convert list is the object's
+ // class. So, here we check to see if the object is
+ // linked. If it is, then we compare the classes. If
+ // they aren't the same, then we just go to the next key.
+
+ else if ( (!fIsLinkedObject)||
+ (lstrcmp((LPTSTR)lpszCLSID, (LPTSTR)szClass)== 0))
+ {
+
+ //Check for a \Conversion\Readable\Main entry
+ lstrcpy((LPTSTR)szFormatKey, (LPTSTR)szClass);
+ lstrcat((LPTSTR)szFormatKey, (LPTSTR) TEXT("\\Conversion\\Readable\\Main"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+
+ // Check to see if this class can read the original class
+ // format. If it can, add the string to the listbox as
+ // CONVERT_LIST.
+
+ lRet=RegQueryValue(hKey, (LPTSTR)szFormatKey, (LPTSTR)szFormat, (LPDWORD)&dw);
+
+ if ( ((LONG)ERROR_SUCCESS==lRet)
+ && (FormatIncluded((LPTSTR)szFormat, wFormat)) )
+ {
+
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, (LPTSTR)szClass, (LPTSTR)szHRClassName, (LPDWORD)&dw);
+
+ if ((LONG)ERROR_SUCCESS==lRet)
+ {
+
+ fEnableConvert = TRUE;
+ break; // STOP -- found one!
+ } // end if
+
+ } // end if
+ } // end else
+next:
+ //Continue with the next key.
+ lRet=RegEnumKey(hKey, cStrings++, (LPTSTR)szClass, OLEUI_CCHKEYMAX_SIZE);
+
+ } // end while
+
+ // Free the string we got from StringFromCLSID.
+ // OLE2NOTE: StringFromCLSID uses your IMalloc to alloc a
+ // string, so you need to be sure to free the string you
+ // get back, otherwise you'll have leaky memory.
+
+ OleStdFreeString(lpszCLSID, NULL);
+
+ RegCloseKey(hKey);
+
+ return fEnableConvert;
+}
+
+
+/*
+ * FormatIncluded
+ *
+ * Purpose:
+ * Parses the string for format from the word.
+ *
+ * Parameters:
+ * szStringToSearch String to parse
+ * wFormat format to find
+ *
+ * Return Value:
+ * BOOL TRUE if format is found in string,
+ * FALSE otherwise.
+ */
+BOOL FormatIncluded(LPTSTR szStringToSearch, WORD wFormat)
+{
+
+ LPTSTR lpToken;
+ TCHAR seps[] = TEXT(",");
+ static TCHAR szFormat[255]; // max size of atom (what GetClipboardName returns)
+
+
+ if (wFormat < 0xC000) // RegisterClipboardFormat returns values
+ {
+ char szTemp[11];
+
+ _itoa(wFormat, szTemp, 10); // between 0xC000 and 0xFFFF.
+
+#ifdef UNICODE
+ mbstowcs(szFormat, szTemp, 11);
+#else
+ strncpy(szFormat, szTemp, 11);
+#endif
+
+ }
+
+ else
+ GetClipboardFormatName(wFormat, szFormat, 255);
+
+ lpToken = (LPTSTR)_fstrtok(szStringToSearch, seps);
+
+ while (lpToken != NULL)
+ {
+
+ if (0 ==lstrcmpi(lpToken, szFormat))
+ return TRUE;
+
+ else
+ lpToken = (LPTSTR)_fstrtok(NULL, seps);
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * UpdateCVClassIcon
+ *
+ * Purpose:
+ * Handles LBN_SELCHANGE for the Object Type listbox. On a selection
+ * change, we extract an icon from the server handling the currently
+ * selected object type using the utility function HIconFromClass.
+ * Note that we depend on the behavior of FillClassList to stuff the
+ * object class after a tab in the listbox string that we hide from
+ * view (see WM_INITDIALOG).
+ *
+ * Parameters
+ * hDlg HWND of the dialog box.
+ * lpCV LPCONVERT pointing to the dialog structure
+ * hList HWND of the Object Type listbox.
+ *
+ * Return Value:
+ * None
+ */
+
+void UpdateCVClassIcon(HWND hDlg, LPCONVERT lpCV, HWND hList)
+ {
+ UINT iSel;
+ DWORD cb;
+ HGLOBAL hMem;
+ LPTSTR pszName, pszCLSID;
+ CLSID clsid;
+ HICON hIcon, hOldIcon;
+ UINT cch, uWrapIndex;
+ RECT LabelRect;
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ LPTSTR lpszLabel = szLabel;
+ HFONT hFont;
+ HWND hLabel1;
+
+ /*
+ * When we change object type selection, get the new icon for that
+ * type into our structure and update it in the display.
+ */
+
+ iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+
+ if (LB_ERR==(INT)iSel)
+ return;
+
+ //Allocate a string to hold the entire listbox string
+ cb=SendMessage(hList, LB_GETTEXTLEN, iSel, 0L);
+
+ hMem=GlobalAlloc(GHND, cb+1);
+
+ if (NULL==hMem)
+ return;
+
+ pszName=GlobalLock(hMem);
+
+ // Get whole string
+ SendMessage(hList, LB_GETTEXT, iSel, (LONG)pszName);
+
+ // Set pointer to CLSID (string)
+ pszCLSID = PointerToNthField(pszName, 2, TEXT('\t'));
+
+ //Create the class ID with this string.
+ CLSIDFromStringA(pszCLSID, &clsid);
+
+ hIcon = HIconAndSourceFromClass(&clsid, (LPTSTR)(lpCV->lpszIconSource), &(lpCV->IconIndex));
+
+ if (NULL == hIcon) // Use Vanilla Document
+ {
+ lstrcpy((LPTSTR)(lpCV->lpszIconSource), (LPTSTR)szOLE2DLL);
+ lpCV->IconIndex = 0; // 1st icon in OLE2.DLL
+ hIcon = ExtractIcon(ghInst,
+ (LPTSTR)(lpCV->lpszIconSource),
+ lpCV->IconIndex);
+ }
+
+ //Replace the current display with this new one.
+ hOldIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
+
+ hLabel1 = GetDlgItem(hDlg, IDCV_ICONLABEL1);
+
+ GetWindowRect(hLabel1, &LabelRect);
+
+ // Get the label
+ if (lpCV->lpOCV->lpszDefLabel) {
+ // width is used as 1.5 times width of icon window
+ lpszLabel = ChopText(hLabel1, ((LabelRect.right-LabelRect.left)*3)/2, (LPTSTR)lpCV->lpOCV->lpszDefLabel);
+ LSTRCPYN(szLabel, lpCV->lpOCV->lpszDefLabel, sizeof(szLabel)/sizeof(TCHAR));
+ } else {
+ if ((cch = OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,
+ (LPTSTR)szLabel, OLEUI_CCHLABELMAX_SIZE, NULL)) == 0) {
+ // If we can't get the AuxUserType2, then try the long name
+ if ((cch = OleStdGetUserTypeOfClass(&clsid, (LPTSTR)szLabel,
+ OLEUI_CCHKEYMAX_SIZE, NULL)) == 0) {
+ // last resort; use "Document" as label
+ LoadString(ghInst,IDS_DEFICONLABEL,(LPTSTR)szLabel,OLEUI_CCHLABELMAX);
+ cch = lstrlen((LPCTSTR)szLabel);
+ }
+ }
+ }
+
+ hFont = (HFONT)SendMessage(hLabel1, WM_GETFONT, 0, 0L);
+
+ // Figure out where to split the label
+ uWrapIndex = OleStdIconLabelTextOut(NULL, hFont, 0, 0, 0, &LabelRect, (LPTSTR)lpszLabel, cch, NULL);
+
+ if (0 == uWrapIndex)
+ {
+ SendMessage(hLabel1, WM_SETTEXT, 0, (LPARAM)(LPTSTR)lpszLabel);
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)(LPTSTR)"");
+ }
+ else
+ {
+ TCHAR chKeep;
+ LPTSTR lpszSecondLine;
+
+ chKeep = szLabel[uWrapIndex];
+ lpszLabel[uWrapIndex] = TEXT('\0');
+
+ SendMessage(hLabel1, WM_SETTEXT, 0, (LPARAM)(LPTSTR)lpszLabel);
+
+ lpszLabel[uWrapIndex] = chKeep;
+ lpszSecondLine = lpszLabel + uWrapIndex;
+
+ SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)lpszSecondLine);
+ }
+
+ // get rid of the old icon
+ if ((HICON)NULL != hOldIcon)
+ DestroyIcon(hOldIcon);
+
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ return;
+ }
+
+
+
+
+
+
+BOOL IsValidClassID(CLSID cID)
+{
+ if (0 == _fmemcmp(&cID, &CLSID_NULL, sizeof(CLSID))) // if (CLSID_NULL == cID)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+
+/*
+ * SetConvertResults
+ *
+ * Purpose:
+ * Centralizes setting of the Result display in the Convert
+ * dialog. Handles loading the appropriate string from the module's
+ * resources and setting the text, displaying the proper result picture,
+ * and showing the proper icon.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog box so we can access controls.
+ * lpCV LPCONVERT in which we assume that the dwFlags is
+ * set to the appropriate radio button selection, and
+ * the list box has the appropriate class selected.
+ *
+ * Return Value:
+ * None
+ */
+
+void SetConvertResults(HWND hDlg, LPCONVERT lpCV)
+ {
+ LPTSTR pszT, // temp
+ lpszOutput, // text sent in SetDlgItemText
+ lpszDefObj, // string containing default object class
+ lpszSelObj, // string containing selected object class
+ lpszString; // stirng we get from loadstring
+
+ UINT i, cch;
+ HGLOBAL hMem;
+
+ HWND hList; // handle to listbox (so we can just use SendMsg i
+ // instead of SendDlgItemMsg).
+
+
+ hList = lpCV->hListVisible;
+ /*
+ * We need scratch memory for loading the stringtable string, loading
+ * the object type from the listbox, loading the source object
+ * type, and constructing the final string. We therefore allocate
+ * four buffers as large as the maximum message length (512) plus
+ * the object type, guaranteeing that we have enough
+ * in all cases.
+ */
+ i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+
+ cch=512+(UINT)SendMessage(hList, LB_GETTEXTLEN, i, 0L);
+
+ hMem=GlobalAlloc(GHND, (DWORD)(4*cch));
+
+ if (NULL==hMem)
+ return;
+
+ lpszOutput = (LPTSTR)GlobalLock(hMem);
+ lpszSelObj = lpszOutput + cch;
+ lpszDefObj = lpszSelObj + cch;
+ lpszString = lpszDefObj + cch;
+
+ // Get selected object and null terminate human-readable name (1st field).
+ SendMessage(hList, LB_GETTEXT, i, (LONG)lpszSelObj);
+
+ pszT = PointerToNthField(lpszSelObj, 2, TEXT('\t'));
+
+#ifdef WIN32
+ // AnsiPrev is obsolete in Win32
+ pszT = CharPrev((LPCTSTR) lpszSelObj, (LPCTSTR) pszT);
+#else
+ pszT = AnsiPrev((LPCTSTR) lpszSelObj, (LPCTSTR) pszT);
+#endif
+
+ *pszT = TEXT('\0');
+
+ // Get default object
+
+ GetDlgItemText(hDlg, IDCV_OBJECTTYPE, lpszDefObj, 512);
+
+
+ //Default is an empty string.
+ *lpszOutput=0;
+
+
+ if (lpCV->dwFlags & CF_SELECTCONVERTTO)
+ {
+
+ if (lpCV->lpOCV->fIsLinkedObject) // working with linked object
+ LoadString(ghInst, IDS_CVRESULTCONVERTLINK, lpszOutput, cch);
+
+ else
+ {
+ // converting to a new class
+ if (0 !=lstrcmp(lpszDefObj, lpszSelObj))
+ {
+ if (0 != LoadString(ghInst, IDS_CVRESULTCONVERTTO, lpszString, cch))
+ wsprintf(lpszOutput, lpszString, lpszDefObj, lpszSelObj);
+
+ }
+ else // converting to the same class (no conversion)
+ {
+
+ if (0 != LoadString(ghInst, IDS_CVRESULTNOCHANGE, lpszString, cch))
+ wsprintf(lpszOutput, lpszString, lpszDefObj);
+ }
+
+ }
+
+ if (lpCV->dvAspect == DVASPECT_ICON) // Display as icon is checked
+ {
+ if (0 != LoadString(ghInst, IDS_CVRESULTDISPLAYASICON, lpszString, cch))
+ lstrcat(lpszOutput, lpszString);
+ }
+ }
+
+ if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
+ {
+
+ if (0!=LoadString(ghInst, IDS_CVRESULTACTIVATEAS, lpszString, cch))
+ wsprintf(lpszOutput, lpszString, lpszDefObj, lpszSelObj);
+
+ // activating as a new class
+ if (0 !=lstrcmp(lpszDefObj, lpszSelObj))
+ {
+ if (0!=LoadString(ghInst, IDS_CVRESULTACTIVATEDIFF, lpszString, cch))
+ lstrcat(lpszOutput, lpszString);
+ }
+ else // activating as itself.
+ {
+ lstrcat(lpszOutput, TEXT("."));
+ }
+ }
+
+
+ //If LoadString failed, we simply clear out the results (*lpszOutput=0 above)
+ SetDlgItemText(hDlg, IDCV_RESULTTEXT, lpszOutput);
+
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ return;
+ }
+
+
+
+
+
+
+/*
+ * ConvertCleanup
+ *
+ * Purpose:
+ * Performs convert-specific cleanup before Convert termination.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog box so we can access controls.
+ *
+ * Return Value:
+ * None
+ */
+void ConvertCleanup(HWND hDlg, LPCONVERT lpCV)
+{
+
+ LPMALLOC pIMalloc;
+
+
+ // Free our strings. Zero out the user type name string
+ // the the calling app doesn't free to it.
+
+ if (NOERROR == CoGetMalloc(MEMCTX_TASK, &pIMalloc))
+ {
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszConvertDefault);
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszActivateDefault);
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszIconSource);
+ if (lpCV->lpOCV->lpszUserType) {
+ pIMalloc->lpVtbl->Free(pIMalloc,(LPVOID)lpCV->lpOCV->lpszUserType);
+ lpCV->lpOCV->lpszUserType = NULL;
+ }
+ if (lpCV->lpOCV->lpszDefLabel) {
+ pIMalloc->lpVtbl->Free(pIMalloc,(LPVOID)lpCV->lpOCV->lpszDefLabel);
+ lpCV->lpOCV->lpszDefLabel = NULL;
+ }
+
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ }
+
+ return;
+}
+
+
+
+
+
+/*
+ * SwapWindows
+ *
+ * Purpose:
+ * Moves hWnd1 to hWnd2's position and hWnd2 to hWnd1's position.
+ * Does NOT change sizes.
+ *
+ *
+ * Parameters:
+ * hDlg HWND of the dialog box so we can turn redraw off
+ *
+ * Return Value:
+ * None
+ */
+void SwapWindows(HWND hDlg, HWND hWnd1, HWND hWnd2)
+{
+
+ RECT Rect1, Rect2;
+
+
+ GetWindowRect(hWnd1, &Rect1);
+ GetWindowRect(hWnd2, &Rect2);
+
+ ScreenToClient(hDlg, (LPPOINT)&Rect1.left);
+ ScreenToClient(hDlg, (LPPOINT)&Rect1.right);
+
+ ScreenToClient(hDlg, (LPPOINT)&Rect2.left);
+ ScreenToClient(hDlg, (LPPOINT)&Rect2.right);
+
+ SetWindowPos(hWnd1,
+ NULL,
+ Rect2.left,
+ Rect2.top,
+ 0,
+ 0,
+ SWP_NOZORDER | SWP_NOSIZE);
+
+ SetWindowPos(hWnd2,
+ NULL,
+ Rect1.left,
+ Rect1.top,
+ 0,
+ 0,
+ SWP_NOZORDER | SWP_NOSIZE);
+
+ return;
+
+}
+
diff --git a/private/oleutest/letest/ole2ui/convert.dlg b/private/oleutest/letest/ole2ui/convert.dlg
new file mode 100644
index 000000000..4f6f4dfc0
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/convert.dlg
@@ -0,0 +1,32 @@
+
+IDD_CONVERT DIALOG 60, 26, 270, 146
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Convert"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ RTEXT "Current Type:", IDCV_STXCURTYPE, 5, 7, 47, 8
+ LTEXT "Current Object Type", IDCV_OBJECTTYPE, 55, 7, 129, 8
+ LTEXT "Object T&ype:", IDCV_STXCONVERTTO, 71, 21, 89, 8
+ LISTBOX IDCV_ACTIVATELIST, 71, 32, 118, 53,
+ LBS_USETABSTOPS | LBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ LISTBOX IDCV_CONVERTLIST, 350, 180, 118, 53,
+ LBS_USETABSTOPS | LBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 197, 6, 67, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 197, 24, 66, 14
+ PUSHBUTTON "&Help", ID_OLEUIHELP, 197, 42, 66, 14
+ CONTROL "&Display As Icon", IDCV_DISPLAYASICON, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 200, 61, 64, 10
+ GROUPBOX "Result", IDCV_GRPRESULT, 6, 87, 183, 50
+ CONTROL "&Convert to:", IDCV_CONVERTTO, "Button",
+ BS_AUTORADIOBUTTON, 6, 34, 59, 10
+ CONTROL "&Activate as:", IDCV_ACTIVATEAS, "Button",
+ BS_AUTORADIOBUTTON, 7, 58, 59, 10
+ LTEXT "Result Text...", IDCV_RESULTTEXT, 11, 98, 174, 27
+ ICON "", IDCV_ICON, 221, 75, 18, 20
+ CTEXT "", IDCV_ICONLABEL1, 197, 100, 66, 8
+ CTEXT "", IDCV_ICONLABEL2, 197, 108, 66, 12
+ PUSHBUTTON "Change &Icon...", IDCV_CHANGEICON, 197, 121, 67, 14
+END
+
+
+
diff --git a/private/oleutest/letest/ole2ui/convert.h b/private/oleutest/letest/ole2ui/convert.h
new file mode 100644
index 000000000..c6df6aa4f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/convert.h
@@ -0,0 +1,63 @@
+/*
+ * CONVERT.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI Convert dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _CONVERT_H_
+#define _CONVERT_H_
+
+
+//Internally used structure
+typedef struct tagCONVERT
+ {
+ //Keep this item first as the Standard* functions depend on it here.
+ LPOLEUICONVERT lpOCV; //Original structure passed.
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog but that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+
+ DWORD dwFlags; // Flags passed in
+ HWND hListVisible; // listbox that is currently visible
+ HWND hListInvisible; // listbox that is currently hidden
+ CLSID clsid; // Class ID sent in to dialog: IN only
+ DWORD dvAspect;
+ BOOL fCustomIcon;
+ UINT IconIndex; // index (in exe) of current icon
+ LPTSTR lpszIconSource; // path to current icon source
+ LPTSTR lpszCurrentObject;
+ LPTSTR lpszConvertDefault;
+ LPTSTR lpszActivateDefault;
+ } CONVERT, *PCONVERT, FAR *LPCONVERT;
+
+
+
+//Internal function prototypes in CONVERT.C
+BOOL CALLBACK EXPORT ConvertDialogProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FConvertInit(HWND hDlg, WPARAM, LPARAM);
+UINT FPopulateListbox(HWND hListbox, CLSID cID);
+BOOL IsValidClassID(CLSID cID);
+void SetConvertResults(HWND, LPCONVERT);
+UINT FillClassList(
+ CLSID clsid,
+ HWND hList,
+ HWND hListInvisible,
+ LPTSTR FAR *lplpszCurrentClass,
+ BOOL fIsLinkedObject,
+ WORD wFormat,
+ UINT cClsidExclude,
+ LPCLSID lpClsidExclude);
+BOOL FormatIncluded(LPTSTR szStringToSearch, WORD wFormat);
+void UpdateCVClassIcon(HWND hDlg, LPCONVERT lpCV, HWND hList);
+void SwapWindows(HWND, HWND, HWND);
+void ConvertCleanup(HWND hDlg, LPCONVERT lpCV);
+
+#endif // _CONVERT_H_
diff --git a/private/oleutest/letest/ole2ui/daytona/makefile b/private/oleutest/letest/ole2ui/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/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/ole2ui/daytona/ole2u32a.src b/private/oleutest/letest/ole2ui/daytona/ole2u32a.src
new file mode 100644
index 000000000..fe30edf8e
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/daytona/ole2u32a.src
@@ -0,0 +1,200 @@
+#if 0
+
+ Microsoft Windows
+ Copyright (C) Microsoft Corporation, 1992 - 1992.
+ All rights reserved.
+
+ This .def file is preprocessed by the compiler to create the version for
+ the current build in the appropriate subdir. Basically, whatever you
+ would have used in your code to control what is compiled when can be
+ used in this file for the same purpose. The following defines are in
+ use at the time this file was written:
+
+ FLAT - Used to indicate a NT/DOS7 build
+ i386 - Intel i386/i486 build
+ MIPS - MIPS R3000/R4000 build
+ ALPHA - DEC Alpha build
+ DBG - Used to control Debug/Retail. Set to 1 if Debug,
+ 0 if Retail.
+ WIN31 - Win16 build
+ __OS2__ - OS/2 build (used by CT mostly)
+
+ If none of these are used, it is assumed the entire file can be used
+ for all builds.
+
+#endif
+
+LIBRARY ole2u32a
+
+DESCRIPTION 'ole2u32a'
+
+EXPORTS
+
+ SetDCToAnisotropic
+ SetDCToDrawInHimetricRect
+ ResetOrigDC
+ XformRectInPixelsToHimetric
+ XformRectInHimetricToPixels
+ XformSizeInPixelsToHimetric
+ XformSizeInHimetricToPixels
+ XformWidthInHimetricToPixels
+ XformWidthInPixelsToHimetric
+ XformHeightInHimetricToPixels
+ XformHeightInPixelsToHimetric
+ ParseCmdLine
+ OleStdIsOleLink
+ OleStdQueryInterface
+ OleStdCreateRootStorage
+ OleStdOpenRootStorage
+ OleStdOpenOrCreateRootStorage
+ OleStdCreateChildStorage
+ OleStdOpenChildStorage
+ OleStdCommitStorage
+ OleStdCreateStorageOnHGlobal
+ OleStdCreateTempStorage
+ OleStdDoConvert
+ OleStdGetTreatAsFmtUserType
+ OleStdDoTreatAsClass
+ OleStdSetupAdvises
+ OleStdSwitchDisplayAspect
+ OleStdSetIconInCache
+ OleStdGetData
+ OleStdMarkPasteEntryList
+ OleStdGetPriorityClipboardFormat
+ OleStdIsDuplicateFormat
+ OleStdRegisterAsRunning
+ OleStdRevokeAsRunning
+ OleStdNoteFileChangeTime
+ OleStdNoteObjectChangeTime
+ OleStdGetOleObjectData
+ OleStdGetLinkSourceData
+ OleStdGetObjectDescriptorData
+ OleStdGetObjectDescriptorDataFromOleObject
+ OleStdFillObjectDescriptorFromData
+ OleStdGetMetafilePictFromOleObject
+ OleStdCreateTempFileMoniker
+ OleStdGetFirstMoniker
+ OleStdGetLenFilePrefixOfMoniker
+ OleStdMalloc
+ OleStdRealloc
+ OleStdFree
+ OleStdGetSize
+ OleStdFreeString
+ OleStdCopyString
+ OleStdGetItemToken
+ OleStdInitVtbl
+ OleStdCheckVtbl
+ OleStdVerifyRelease
+ OleStdRelease
+ OleStdCreateDC
+ OleStdCreateIC
+ OleStdDeleteTargetDevice
+ OleStdCopyTargetDevice
+ OleStdCopyFormatEtc
+ FnAssert
+ OleDbgPrint
+ OleDbgPrintAlways
+ OleDbgSetDbgLevel
+ OleDbgGetDbgLevel
+ OleDbgIndent
+ OleDbgPrintRefCnt
+ OleDbgPrintRefCntAlways
+ OleDbgPrintRect
+ OleDbgPrintRectAlways
+ OleDbgPrintScodeAlways
+ OleUIInitialize
+ OleUIUnInitialize
+ OleUIAddVerbMenu
+ OleUIMetafilePictIconFree
+ OleUIMetafilePictIconDraw
+ OleUIMetafilePictExtractLabel
+ OleUIMetafilePictExtractIcon
+ OleUIMetafilePictExtractIconSource
+ OleUIInsertObject
+ OleUIPasteSpecial
+ OleUIEditLinks
+ OleUIChangeIcon
+ OleUIConvert
+ OleUIBusy
+ OleUIUpdateLinks
+ OleUIDrawHandles
+ OleUICanConvertOrActivateAs
+ OleUIDrawShading
+ OleUIShowObject
+ OleUIPromptUser
+ RegisterHatchWindowClass
+ CreateHatchWindow
+ GetHatchWidth
+ GetHatchRect
+ SetHatchRect
+ SetHatchWindowSize
+ OleStdEnumFmtEtc_Create
+ OleStdGetAuxUserType
+ OleStdGetUserTypeOfClass
+ OleStdIconLabelTextOut
+ OleStdMsgFilter_Create
+ OleStdMsgFilter_SetInComingCallStatus
+ OleStdMsgFilter_GetInComingCallStatus
+ OleStdMsgFilter_EnableBusyDialog
+ OleStdMsgFilter_EnableNotRespondingDialog
+ OleStdMsgFilter_SetParentWindow
+ OleStdGetMiscStatusOfClass
+ OleStdGetDefaultFileFormatOfClass
+ OleStdDestroyAllElements
+ OleStdCreateDbAlloc
+ OleStdInitSummaryInfo
+ OleStdFreeSummaryInfo
+ OleStdClearSummaryInfo
+ OleStdReadSummaryInfo
+ OleStdWriteSummaryInfo
+ OleStdGetSecurityProperty
+ OleStdSetSecurityProperty
+ OleStdGetStringProperty
+ OleStdSetStringProperty
+ OleStdGetStringZProperty
+ OleStdGetDocProperty
+ OleStdSetDocProperty
+ OleStdGetThumbNailProperty
+ OleStdSetThumbNailProperty
+ OleStdGetDateProperty
+ OleStdSetDateProperty
+ OleStdMsgFilter_SetHandleInComingCallbackProc
+ OleStdEnumStatData_Create
+ OleStdCopyStatData
+ OleStdCreateStandardPalette
+ OleStdMkParseDisplayName
+ CopyAndFreeOLESTR
+ CopyAndFreeSTR
+ CreateOLESTR
+ CreateSTR
+ CLSIDFromStringA
+ CLSIDFromProgIDA
+ CreateFileMonikerA
+ CreateItemMonikerA
+ GetClassFileA
+ MkParseDisplayNameA
+ OleCreateFromFileA
+ OleCreateLinkToFileA
+ OleGetIconOfClassA
+ OleGetIconOfFileA
+ OleMetafilePictFromIconAndLabelA
+ OleRegGetUserTypeA
+ ProgIDFromCLSIDA
+ ReadFmtUserTypeStgA
+ StgCreateDocfileA
+ StgOpenStorageA
+ StgSetTimesA
+ StringFromCLSIDA
+ WriteFmtUserTypeStgA
+ CallIMonikerGetDisplayNameA
+ CallIOleLinkGetSourceDisplayNameA
+ CallIOleLinkSetSourceDisplayNameA
+ CallIOleInPlaceFrameSetStatusTextA
+ CallIOleInPlaceUIWindowSetActiveObjectA
+ CallIOleObjectGetUserTypeA
+ CallIOleObjectSetHostNamesA
+ CallIStorageCreateStorageA
+ CallIStorageDestroyElementA
+ CallIStorageOpenStorageA
+ CallIStorageCreateStreamA
+ CallIStorageOpenStreamA
diff --git a/private/oleutest/letest/ole2ui/daytona/ole2ui.src b/private/oleutest/letest/ole2ui/daytona/ole2ui.src
new file mode 100644
index 000000000..24b82dcf6
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/daytona/ole2ui.src
@@ -0,0 +1,199 @@
+#if 0
+
+ Microsoft Windows
+ Copyright (C) Microsoft Corporation, 1992 - 1992.
+ All rights reserved.
+
+ This .def file is preprocessed by the compiler to create the version for
+ the current build in the appropriate subdir. Basically, whatever you
+ would have used in your code to control what is compiled when can be
+ used in this file for the same purpose. The following defines are in
+ use at the time this file was written:
+
+ FLAT - Used to indicate a NT/DOS7 build
+ i386 - Intel i386/i486 build
+ MIPS - MIPS R3000/R4000 build
+ ALPHA - DEC Alpha build
+ DBG - Used to control Debug/Retail. Set to 1 if Debug,
+ 0 if Retail.
+ WIN31 - Win16 build
+ __OS2__ - OS/2 build (used by CT mostly)
+
+ If none of these are used, it is assumed the entire file can be used
+ for all builds.
+
+#endif
+
+LIBRARY ole2ui
+
+DESCRIPTION 'ole2ui'
+
+EXPORTS
+
+ SetDCToAnisotropic
+ SetDCToDrawInHimetricRect
+ ResetOrigDC
+ XformRectInPixelsToHimetric
+ XformRectInHimetricToPixels
+ XformSizeInPixelsToHimetric
+ XformSizeInHimetricToPixels
+ XformWidthInHimetricToPixels
+ XformWidthInPixelsToHimetric
+ XformHeightInHimetricToPixels
+ XformHeightInPixelsToHimetric
+ ParseCmdLine
+ OleStdIsOleLink
+ OleStdQueryInterface
+ OleStdCreateRootStorage
+ OleStdOpenRootStorage
+ OleStdOpenOrCreateRootStorage
+ OleStdCreateChildStorage
+ OleStdOpenChildStorage
+ OleStdCommitStorage
+ OleStdCreateStorageOnHGlobal
+ OleStdCreateTempStorage
+ OleStdDoConvert
+ OleStdGetTreatAsFmtUserType
+ OleStdDoTreatAsClass
+ OleStdSetupAdvises
+ OleStdSwitchDisplayAspect
+ OleStdSetIconInCache
+ OleStdGetData
+ OleStdMarkPasteEntryList
+ OleStdGetPriorityClipboardFormat
+ OleStdIsDuplicateFormat
+ OleStdRegisterAsRunning
+ OleStdRevokeAsRunning
+ OleStdNoteFileChangeTime
+ OleStdNoteObjectChangeTime
+ OleStdGetOleObjectData
+ OleStdGetLinkSourceData
+ OleStdGetObjectDescriptorData
+ OleStdGetObjectDescriptorDataFromOleObject
+ OleStdFillObjectDescriptorFromData
+ OleStdGetMetafilePictFromOleObject
+ OleStdCreateTempFileMoniker
+ OleStdGetFirstMoniker
+ OleStdGetLenFilePrefixOfMoniker
+ OleStdMalloc
+ OleStdRealloc
+ OleStdFree
+ OleStdGetSize
+ OleStdFreeString
+ OleStdCopyString
+ OleStdGetItemToken
+ OleStdInitVtbl
+ OleStdCheckVtbl
+ OleStdVerifyRelease
+ OleStdRelease
+ OleStdCreateDC
+ OleStdCreateIC
+ OleStdDeleteTargetDevice
+ OleStdCopyTargetDevice
+ OleStdCopyFormatEtc
+ OleDbgPrint
+ OleDbgPrintAlways
+ OleDbgSetDbgLevel
+ OleDbgGetDbgLevel
+ OleDbgIndent
+ OleDbgPrintRefCnt
+ OleDbgPrintRefCntAlways
+ OleDbgPrintRect
+ OleDbgPrintRectAlways
+ OleDbgPrintScodeAlways
+ OleUIInitialize
+ OleUIUnInitialize
+ OleUIAddVerbMenu
+ OleUIMetafilePictIconFree
+ OleUIMetafilePictIconDraw
+ OleUIMetafilePictExtractLabel
+ OleUIMetafilePictExtractIcon
+ OleUIMetafilePictExtractIconSource
+ OleUIInsertObject
+ OleUIPasteSpecial
+ OleUIEditLinks
+ OleUIChangeIcon
+ OleUIConvert
+ OleUIBusy
+ OleUIUpdateLinks
+ OleUIDrawHandles
+ OleUICanConvertOrActivateAs
+ OleUIDrawShading
+ OleUIShowObject
+ OleUIPromptUser
+ RegisterHatchWindowClass
+ CreateHatchWindow
+ GetHatchWidth
+ GetHatchRect
+ SetHatchRect
+ SetHatchWindowSize
+ OleStdEnumFmtEtc_Create
+ OleStdGetAuxUserType
+ OleStdGetUserTypeOfClass
+ OleStdIconLabelTextOut
+ OleStdMsgFilter_Create
+ OleStdMsgFilter_SetInComingCallStatus
+ OleStdMsgFilter_GetInComingCallStatus
+ OleStdMsgFilter_EnableBusyDialog
+ OleStdMsgFilter_EnableNotRespondingDialog
+ OleStdMsgFilter_SetParentWindow
+ OleStdGetMiscStatusOfClass
+ OleStdGetDefaultFileFormatOfClass
+ OleStdDestroyAllElements
+ OleStdCreateDbAlloc
+ OleStdInitSummaryInfo
+ OleStdFreeSummaryInfo
+ OleStdClearSummaryInfo
+ OleStdReadSummaryInfo
+ OleStdWriteSummaryInfo
+ OleStdGetSecurityProperty
+ OleStdSetSecurityProperty
+ OleStdGetStringProperty
+ OleStdSetStringProperty
+ OleStdGetStringZProperty
+ OleStdGetDocProperty
+ OleStdSetDocProperty
+ OleStdGetThumbNailProperty
+ OleStdSetThumbNailProperty
+ OleStdGetDateProperty
+ OleStdSetDateProperty
+ OleStdMsgFilter_SetHandleInComingCallbackProc
+ OleStdEnumStatData_Create
+ OleStdCopyStatData
+ OleStdCreateStandardPalette
+ OleStdMkParseDisplayName
+ CopyAndFreeOLESTR
+ CopyAndFreeSTR
+ CreateOLESTR
+ CreateSTR
+ CLSIDFromStringA
+ CLSIDFromProgIDA
+ CreateFileMonikerA
+ CreateItemMonikerA
+ GetClassFileA
+ MkParseDisplayNameA
+ OleCreateFromFileA
+ OleCreateLinkToFileA
+ OleGetIconOfClassA
+ OleGetIconOfFileA
+ OleMetafilePictFromIconAndLabelA
+ OleRegGetUserTypeA
+ ProgIDFromCLSIDA
+ ReadFmtUserTypeStgA
+ StgCreateDocfileA
+ StgOpenStorageA
+ StgSetTimesA
+ StringFromCLSIDA
+ WriteFmtUserTypeStgA
+ CallIMonikerGetDisplayNameA
+ CallIOleLinkGetSourceDisplayNameA
+ CallIOleLinkSetSourceDisplayNameA
+ CallIOleInPlaceFrameSetStatusTextA
+ CallIOleInPlaceUIWindowSetActiveObjectA
+ CallIOleObjectGetUserTypeA
+ CallIOleObjectSetHostNamesA
+ CallIStorageCreateStorageA
+ CallIStorageDestroyElementA
+ CallIStorageOpenStorageA
+ CallIStorageCreateStreamA
+ CallIStorageOpenStreamA
diff --git a/private/oleutest/letest/ole2ui/daytona/sources b/private/oleutest/letest/ole2ui/daytona/sources
new file mode 100644
index 000000000..91c6ca237
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/daytona/sources
@@ -0,0 +1,64 @@
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+TARGETNAME= ole2u32a
+TARGETPATH= obj
+TARGETTYPE= DYNLINK
+
+DLLDEF= obj\*\ole2u32a.def
+DLLENTRY= DllEntryPoint
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+INCLUDES=..
+
+C_DEFINES=-DWIN32 -DDEBUG -DINC_OLE2 -DCLIENT -DWINDOWS -DOLE201
+
+SOURCES= \
+ ..\BUSY.C \
+ ..\COMMON.C \
+ ..\CONVERT.C \
+ ..\DBALLOC.CPP \
+ ..\DBGUTIL.C \
+ ..\DLLENTRY.C \
+ ..\DLLFUNCS.C \
+ ..\DRAWICON.C \
+ ..\ENUMFETC.C \
+ ..\ENUMSTAT.C \
+ ..\GETICON.C \
+ ..\HATCH.C \
+ ..\ICON.C \
+ ..\ICONBOX.C \
+ ..\INSOBJ.C \
+ ..\LINKS.C \
+ ..\MSGFILTR.C \
+ ..\OBJFDBK.C \
+ ..\OLE2UI.C \
+ ..\OLESTD.C \
+ ..\OLETHUNK.C \
+ ..\OLEUTL.C \
+ ..\PASTESPL.C \
+ ..\PRECOMP.C \
+ ..\REGDB.C \
+ ..\RESIMAGE.C \
+ ..\STDPAL.C \
+ ..\SUMINFO.CPP \
+ ..\TARGTDEV.C \
+ ..\UTILITY.C \
+ ..\OLE2UI.RC
+
+UMTYPE=windows
+
+TARGETLIBS= \
+ $(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
+
+USE_CRTDLL= 1
+
+MISCFILES=..\..\data\letest12.olc
diff --git a/private/oleutest/letest/ole2ui/dballoc.cpp b/private/oleutest/letest/ole2ui/dballoc.cpp
new file mode 100644
index 000000000..b62259c64
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/dballoc.cpp
@@ -0,0 +1,900 @@
+
+/***
+*dballoc.cpp
+*
+* Copyright (C) 1992-93, Microsoft Corporation. All Rights Reserved.
+*
+*Purpose:
+* This file contains a debug implementation of the IMalloc interface.
+*
+* This implementation is basically a simple wrapping of the C runtime,
+* with additional work to detect memory leakage, and memory overwrite.
+*
+* Leakage is detected by tracking each allocation in an address
+* instance table, and then checking to see if the table is empty
+* when the last reference to the allocator is released.
+*
+* Memory overwrite is detected by placing a signature at the end
+* of every allocated block, and checking to make sure the signature
+* is unchanged when the block is freed.
+*
+* This implementation also has additional param validation code, as
+* well as additional check make sure that instances that are passed
+* to Free() were actually allocated by the corresponding instance
+* of the allocator.
+*
+*
+* Creating an instance of this debug allocator that uses the default
+* output interface would look like the following,
+*
+*
+* BOOL init_application_instance()
+* {
+* HRESULT hresult;
+* IMalloc FAR* pmalloc;
+*
+* pmalloc = NULL;
+*
+* if((hresult = OleStdCreateDbAlloc(0,&pmalloc))!=NOERROR)
+* goto LReturn;
+*
+* hresult = OleInitialize(pmalloc);
+*
+* // release pmalloc to let OLE hold the only ref to the it. later
+* // when OleUnitialize is called, memory leaks will be reported.
+* if(pmalloc != NULL)
+* pmalloc->Release();
+*
+* LReturn:
+*
+* return (hresult == NOERROR) ? TRUE : FALSE;
+* }
+*
+*
+* CONSIDER: could add an option to force error generation, something
+* like DBALLOC_ERRORGEN
+*
+* CONSIDER: add support for heap-checking. say for example,
+* DBALLOC_HEAPCHECK would do a heapcheck every free? every 'n'
+* calls to free? ...
+*
+*
+*Implementation Notes:
+*
+* The method IMalloc::DidAlloc() is allowed to always return
+* "Dont Know" (-1). This method is called by Ole, and they take
+* some appropriate action when they get this answer.
+
+The debugging allocator has the option to catch bugs where code is writing off
+the end of allocated memory. This is implemented by using NT's virtual memory
+services. To switch on this option, use
+
+#define DBALLOC_POWERDEBUG
+
+Note it will ONLY WORK ON NT. This option consumes a very large amount of
+memory. Basically, for every allocation, it cooks the allocation so that the
+end of the allocation will fall on a page boundary. An extra page of memory
+is allocated after the requested memory. The protection bits for this page
+are altered so that it is an error to read or write to it. Any incident of
+writing past the end of allocated memory is trapped at the point of the error.
+
+This consumes a great deal of memory because at least two pages must be
+allocated for each allocation.
+*
+*****************************************************************************/
+
+
+// Note: this file is designed to be stand-alone; it includes a
+// carefully chosen, minimal set of headers.
+//
+// For conditional compilation we use the ole2 conventions,
+// _MAC = mac
+// WIN32 = Win32 (NT really)
+// <nothing> = defaults to Win16
+
+
+// REVIEW: the following needs to modified to handle _MAC
+#define STRICT
+#ifndef INC_OLE2
+ #define INC_OLE2
+#endif
+
+#include <windows.h>
+
+#include "ole2.h"
+
+#if defined( __TURBOC__)
+#define __STDC__ (1)
+#endif
+
+#define WINDLL 1 // make far pointer version of stdargs.h
+#include <stdarg.h>
+
+#if defined( __TURBOC__)
+#undef __STDC__
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <limits.h>
+
+#include "dballoc.h"
+
+
+#define DIM(X) (sizeof(X)/sizeof((X)[0]))
+
+#define UNREACHED 0
+
+#if defined(WIN32)
+# define MEMCMP(PV1, PV2, CB) memcmp((PV1), (PV2), (CB))
+# define MEMCPY(PV1, PV2, CB) memcpy((PV1), (PV2), (CB))
+# define MEMSET(PV, VAL, CB) memset((PV), (VAL), (CB))
+# define MALLOC(CB) malloc(CB)
+# define REALLOC(PV, CB) realloc((PV), (CB))
+# define FREE(PV) free(PV)
+
+#ifndef WIN32
+# define HEAPMIN() _heapmin()
+#else
+# define HEAPMIN()
+#endif
+
+#elif defined(_MAC)
+# define MEMCMP(PV1, PV2) ERROR -- NYI
+# define MEMCPY(PV1, PV2, CB) ERROR -- NYI
+# define MEMSET(PV, VAL, CB) ERROR -- NYI
+# define MALLOC(CB) ERROR -- NYI
+# define REALLOC(PV, CB) ERROR -- NYI
+# define FREE(PV) ERROR -- NYI
+# define HEAPMIN() ERROR -- NYI
+#else
+# define MEMCMP(PV1, PV2, CB) _fmemcmp((PV1), (PV2), (CB))
+# define MEMCPY(PV1, PV2, CB) _fmemcpy((PV1), (PV2), (CB))
+# define MEMSET(PV, VAL, CB) _fmemset((PV), (VAL), (CB))
+# define MALLOC(CB) _fmalloc(CB)
+# define REALLOC(PV, CB) _frealloc(PV, CB)
+# define FREE(PV) _ffree(PV)
+# define HEAPMIN() _fheapmin()
+#endif
+
+#if defined( __TURBOC__ )
+#define classmodel _huge
+#else
+#define classmodel FAR
+#endif
+
+class classmodel CStdDbOutput : public IDbOutput {
+public:
+ static IDbOutput FAR* Create();
+
+ // IUnknown methods
+
+ STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+
+ // IDbOutput methods
+
+ STDMETHOD_(void, Printf)(TCHAR FAR* szFmt, ...);
+
+ STDMETHOD_(void, Assertion)(
+ BOOL cond,
+ TCHAR FAR* szExpr,
+ TCHAR FAR* szFile,
+ UINT uLine,
+ TCHAR FAR* szMsg);
+
+
+ void FAR* operator new(size_t cb){
+ return MALLOC(cb);
+ }
+ void operator delete(void FAR* pv){
+ FREE(pv);
+ }
+
+ CStdDbOutput(){
+ m_refs = 0;
+ }
+
+private:
+ ULONG m_refs;
+
+ TCHAR m_rgch[128]; // buffer for output formatting
+};
+
+
+//---------------------------------------------------------------------
+// implementation of the debug allocator
+//---------------------------------------------------------------------
+
+class FAR CAddrNode
+{
+public:
+ void FAR* m_pv; // instance
+ ULONG m_cb; // size of allocation in BYTES
+ ULONG m_nAlloc; // the allocation pass count
+ CAddrNode FAR* m_next;
+
+ void FAR* operator new(size_t cb){
+ return MALLOC(cb);
+ }
+ void operator delete(void FAR* pv){
+ FREE(pv);
+ }
+};
+
+
+class classmodel CDbAlloc : public IMalloc
+{
+public:
+ static HRESULT Create(
+ ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc);
+
+ // IUnknown methods
+
+ STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // IMalloc methods
+
+ STDMETHOD_(void FAR*, Alloc)(ULONG cb);
+ STDMETHOD_(void FAR*, Realloc)(void FAR* pv, ULONG cb);
+ STDMETHOD_(void, Free)(void FAR* pv);
+ STDMETHOD_(ULONG, GetSize)(void FAR* pv);
+ STDMETHOD_(int, DidAlloc)(void FAR* pv);
+ STDMETHOD_(void, HeapMinimize)(void);
+
+
+ void FAR* operator new(size_t cb){
+ return MALLOC(cb);
+ }
+ void operator delete(void FAR* pv){
+ FREE(pv);
+ }
+
+ CDbAlloc(){
+ m_refs = 1;
+ m_pdbout = NULL;
+ m_cAllocCalls = 0;
+ m_nBreakAtNthAlloc = 0;
+ m_nBreakAtAllocSize = 0;
+ MEMSET(m_rganode, 0, sizeof(m_rganode));
+#ifdef DBALLOC_POWERDEBUG
+ {
+ SYSTEM_INFO si;
+
+ GetSystemInfo(&si);
+ m_virtPgSz = si.dwPageSize;
+ }
+#endif // DBALLOC_POWERDEBUG
+ }
+
+private:
+
+ ULONG m_refs;
+ ULONG m_cAllocCalls; // total count of allocation calls
+ ULONG m_nBreakAtNthAlloc; // allocation number to break to debugger
+ // this value should be set typically in the
+ // debugger.
+ ULONG m_nBreakAtAllocSize; // allocation size to break to debugger
+ // this value should be set typically in the
+ // debugger.
+ IDbOutput FAR* m_pdbout; // output interface
+ CAddrNode FAR* m_rganode[64]; // address instance table
+
+
+ // instance table methods
+
+ BOOL IsEmpty(void);
+
+ void AddInst(void FAR* pv, ULONG nAlloc, ULONG cb);
+ void DelInst(void FAR* pv);
+ CAddrNode FAR* GetInst(void FAR* pv);
+
+ void DumpInst(CAddrNode FAR* pn);
+ void DumpInstTable(void);
+
+ inline UINT HashInst(void FAR* pv) const {
+ return ((UINT)((ULONG)pv >> 4)) % DIM(m_rganode);
+
+ }
+
+ // output method(s)
+
+ inline void Assertion(
+ BOOL cond,
+ TCHAR FAR* szExpr,
+ TCHAR FAR* szFile,
+ UINT uLine,
+ TCHAR FAR* szMsg)
+ {
+ m_pdbout->Assertion(cond, szExpr, szFile, uLine, szMsg);
+ }
+
+ #define ASSERT(X) Assertion(X, TEXT(#X), TEXT(__FILE__), __LINE__, NULL)
+
+ #define ASSERTSZ(X, SZ) Assertion(X, TEXT(#X), TEXT(__FILE__), __LINE__, SZ)
+
+ static const BYTE m_rgchSig[];
+
+#ifdef DBALLOC_POWERDEBUG
+ size_t m_virtPgSz;
+#endif // DBALLOC_POWERDEBUG
+};
+
+const BYTE CDbAlloc::m_rgchSig[] = { 0xDE, 0xAD, 0xBE, 0xEF };
+
+
+/***
+*HRESULT OleStdCreateDbAlloc(ULONG reserved, IMalloc** ppmalloc)
+* Purpose:
+* Create an instance of CDbAlloc -- a debug implementation
+* of IMalloc.
+*
+* Parameters:
+* ULONG reserved - reserved for future use. must be 0.
+* IMalloc FAR* FAR* ppmalloc - (OUT) pointer to an IMalloc interface
+* of new debug allocator object
+* Returns:
+* HRESULT
+* NOERROR - if no error.
+* E_OUTOFMEMORY - allocation failed.
+*
+***********************************************************************/
+STDAPI OleStdCreateDbAlloc(ULONG reserved,IMalloc FAR* FAR* ppmalloc)
+{
+ return CDbAlloc::Create(reserved, NULL, ppmalloc);
+}
+
+
+HRESULT
+CDbAlloc::Create(
+ ULONG options,
+ IDbOutput FAR* pdbout,
+ IMalloc FAR* FAR* ppmalloc)
+{
+ HRESULT hresult;
+ CDbAlloc FAR* pmalloc;
+
+
+ // default the instance of IDbOutput if the user didn't supply one
+ if(pdbout == NULL && ((pdbout = CStdDbOutput::Create()) == NULL)){
+ hresult = ResultFromScode(E_OUTOFMEMORY);
+ goto LError0;
+ }
+
+ pdbout->AddRef();
+
+ if((pmalloc = new FAR CDbAlloc()) == NULL){
+ hresult = ResultFromScode(E_OUTOFMEMORY);
+ goto LError1;
+ }
+
+ pmalloc->m_pdbout = pdbout;
+
+ *ppmalloc = pmalloc;
+
+ return NOERROR;
+
+LError1:;
+ pdbout->Release();
+ pmalloc->Release();
+
+LError0:;
+ return hresult;
+}
+
+STDMETHODIMP
+CDbAlloc::QueryInterface(REFIID riid, void FAR* FAR* ppv)
+{
+ if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IMalloc)){
+ *ppv = this;
+ AddRef();
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+CDbAlloc::AddRef()
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+CDbAlloc::Release()
+{
+ if(--m_refs == 0){
+
+ // check for memory leakage
+ if(IsEmpty()){
+ m_pdbout->Printf(TEXT("No Memory Leaks.\n"));
+ }else{
+ m_pdbout->Printf(TEXT("Memory Leak Detected,\n"));
+ DumpInstTable();
+ }
+
+ m_pdbout->Release();
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+STDMETHODIMP_(void FAR*)
+CDbAlloc::Alloc(ULONG cb)
+{
+ size_t size;
+ void FAR* pv;
+
+ ++m_cAllocCalls;
+
+ if (m_nBreakAtNthAlloc && m_cAllocCalls == m_nBreakAtNthAlloc) {
+ ASSERTSZ(FALSE, TEXT("DBALLOC: NthAlloc Break target reached\r\n"));
+ } else if (m_nBreakAtAllocSize && cb == m_nBreakAtAllocSize) {
+ ASSERTSZ(FALSE, TEXT("DBALLOC: AllocSize Break target reached\r\n"));
+ }
+
+#ifndef DBALLOC_POWERDEBUG
+ // REVIEW: need to add support for huge allocations (on win16)
+ if((cb + sizeof(m_rgchSig)) > UINT_MAX)
+ return NULL;
+
+ size = (size_t)cb;
+
+ if((pv = MALLOC(size + sizeof(m_rgchSig))) == NULL)
+ return NULL;
+
+ // set allocated block to some non-zero value
+ MEMSET(pv, -1, size);
+
+ // put signature at end of allocated block
+ MEMCPY(((char FAR*)pv) + size, m_rgchSig, sizeof(m_rgchSig));
+
+ AddInst(pv, m_cAllocCalls, size);
+#else
+ // for each allocate, allocate the amount of memory required, and
+ // one more page beyond that. We will change the protection bits of
+ // the trailing page so that we get an access violation if someone
+ // writes beyond the end of their allocated memory
+ {
+ size_t allocpgs; // number of pages to allocate
+ DWORD dwOldProt; // previous protection of the last page
+ void *plastpg; // points to the beginning of the last page
+
+ // allocate at least one page for the allocation, and
+ // one to go after it
+ allocpgs = (cb + 2*m_virtPgSz) / m_virtPgSz;
+ pv = VirtualAlloc(NULL, allocpgs*m_virtPgSz,
+ MEM_COMMIT, PAGE_READWRITE);
+
+ // change the protection of the last page
+ plastpg = (void *)(((BYTE *)pv)+m_virtPgSz*(allocpgs-1));
+ VirtualProtect(plastpg, m_virtPgSz, PAGE_NOACCESS, &dwOldProt);
+
+ // figure out what pointer to return to the user
+ pv = (void *)(((BYTE *)plastpg)-cb);
+
+ // record the allocation
+ AddInst(pv, m_cAllocCalls, cb);
+ }
+#endif // DBALLOC_POWERDEBUG
+
+ return pv;
+}
+
+STDMETHODIMP_(void FAR*)
+CDbAlloc::Realloc(void FAR* pv, ULONG cb)
+{
+ size_t size;
+ CAddrNode *pcan;
+
+#ifndef DBALLOC_POWERDEBUG
+ // REVIEW: need to add support for huge realloc
+ if((cb + sizeof(m_rgchSig)) > UINT_MAX)
+ return NULL;
+#endif // DBALLOC_POWERDEBUG
+
+ if(pv == NULL){
+ return Alloc(cb);
+ }
+
+ ++m_cAllocCalls;
+
+ ASSERT((pcan = GetInst(pv)) != NULL);
+#ifndef DBALLOC_POWERDEBUG
+
+ DelInst(pv);
+
+ if(cb == 0){
+ Free(pv);
+ return NULL;
+ }
+
+ size = (size_t)cb;
+
+ if((pv = REALLOC(pv, size + sizeof(m_rgchSig))) == NULL)
+ return NULL;
+
+ // put signature at end of allocated block
+ MEMCPY(((char FAR*)pv) + size, m_rgchSig, sizeof(m_rgchSig));
+
+ AddInst(pv, m_cAllocCalls, size);
+#else
+ {
+ void *pnew;
+ DWORD dwOldProt;
+
+ // allocate new memory
+ pnew = Alloc(cb);
+
+ // copy in the previous material
+ memcpy(pnew, pcan->m_pv, pcan->m_cb);
+
+ // protect the old memory
+ VirtualProtect(pcan->m_pv, pcan->m_cb, PAGE_NOACCESS,
+ &dwOldProt);
+
+ DelInst(pv);
+ AddInst(pv, m_cAllocCalls, cb);
+ pv = pnew;
+ }
+#endif // DBALLOC_POWERDEBUG
+
+ return pv;
+}
+
+STDMETHODIMP_(void)
+CDbAlloc::Free(void FAR* pv)
+{
+ if (pv == NULL)
+ {
+ // Free of NULL is a NO-OP
+ return;
+ }
+
+ CAddrNode FAR* pn;
+ static TCHAR szSigMsg[] = TEXT("Signature Check Failed");
+
+ pn = GetInst(pv);
+
+ // check for attempt to free an instance we didnt allocate
+ if(pn == NULL){
+ ASSERTSZ(FALSE, TEXT("pointer freed by wrong allocator"));
+ return;
+ }
+
+#ifndef DBALLOC_POWERDEBUG
+ // verify the signature
+ if(MEMCMP(((char FAR*)pv) + pn->m_cb, m_rgchSig, sizeof(m_rgchSig)) != 0){
+ m_pdbout->Printf(szSigMsg); m_pdbout->Printf(TEXT("\n"));
+ DumpInst(GetInst(pv));
+ ASSERTSZ(FALSE, szSigMsg);
+ }
+
+ // stomp on the contents of the block
+ MEMSET(pv, 0xCC, ((size_t)pn->m_cb + sizeof(m_rgchSig)));
+
+ DelInst(pv);
+ FREE(pv);
+#else
+ {
+ DWORD dwOldProt;
+
+ // make the block inaccessible
+ VirtualProtect(pv, pn->m_cb, PAGE_NOACCESS, &dwOldProt);
+ DelInst(pv);
+ }
+#endif // DBALLOC_POWERDEBUG
+}
+
+
+STDMETHODIMP_(ULONG)
+CDbAlloc::GetSize(void FAR* pv)
+{
+ CAddrNode FAR* pn;
+
+ if (pv == NULL)
+ {
+ // GetSize is supposed to return a -1 when NULL is passed in.
+ return (ULONG) -1;
+ }
+
+ pn = GetInst(pv);
+
+ if (pn == NULL) {
+ ASSERT(pn != NULL);
+ return 0;
+ }
+
+ return pn->m_cb;
+}
+
+
+/***
+*PUBLIC HRESULT CDbAlloc::DidAlloc
+*Purpose:
+* Answer if the given address belongs to a block allocated by
+* this allocator.
+*
+*Entry:
+* pv = the instance to lookup
+*
+*Exit:
+* return value = int
+* 1 - did alloc
+* 0 - did *not* alloc
+* -1 - dont know (according to the ole2 spec it is always legal
+* for the allocator to answer "dont know")
+*
+***********************************************************************/
+STDMETHODIMP_(int)
+CDbAlloc::DidAlloc(void FAR* pv)
+{
+ return -1; // answer "I dont know"
+}
+
+
+STDMETHODIMP_(void)
+CDbAlloc::HeapMinimize()
+{
+ HEAPMIN();
+}
+
+
+//---------------------------------------------------------------------
+// instance table methods
+//---------------------------------------------------------------------
+
+/***
+*PRIVATE CDbAlloc::AddInst
+*Purpose:
+* Add the given instance to the address instance table.
+*
+*Entry:
+* pv = the instance to add
+* nAlloc = the allocation passcount of this instance
+*
+*Exit:
+* None
+*
+***********************************************************************/
+void
+CDbAlloc::AddInst(void FAR* pv, ULONG nAlloc, ULONG cb)
+{
+ UINT hash;
+ CAddrNode FAR* pn;
+
+
+ ASSERT(pv != NULL);
+
+ pn = (CAddrNode FAR*)new FAR CAddrNode();
+
+ if (pn == NULL) {
+ ASSERT(pn != NULL);
+ return;
+ }
+
+ pn->m_pv = pv;
+ pn->m_cb = cb;
+ pn->m_nAlloc = nAlloc;
+
+ hash = HashInst(pv);
+ pn->m_next = m_rganode[hash];
+ m_rganode[hash] = pn;
+}
+
+
+/***
+*UNDONE
+*Purpose:
+* Remove the given instance from the address instance table.
+*
+*Entry:
+* pv = the instance to remove
+*
+*Exit:
+* None
+*
+***********************************************************************/
+void
+CDbAlloc::DelInst(void FAR* pv)
+{
+ CAddrNode FAR* FAR* ppn, FAR* pnDead;
+
+ for(ppn = &m_rganode[HashInst(pv)]; *ppn != NULL; ppn = &(*ppn)->m_next){
+ if((*ppn)->m_pv == pv){
+ pnDead = *ppn;
+ *ppn = (*ppn)->m_next;
+ delete pnDead;
+ // make sure it doesnt somehow appear twice
+ ASSERT(GetInst(pv) == NULL);
+ return;
+ }
+ }
+
+ // didnt find the instance
+ ASSERT(UNREACHED);
+}
+
+
+CAddrNode FAR*
+CDbAlloc::GetInst(void FAR* pv)
+{
+ CAddrNode FAR* pn;
+
+ for(pn = m_rganode[HashInst(pv)]; pn != NULL; pn = pn->m_next){
+ if(pn->m_pv == pv)
+ return pn;
+ }
+ return NULL;
+}
+
+
+void
+CDbAlloc::DumpInst(CAddrNode FAR* pn)
+{
+ if (pn == NULL)
+ return;
+
+ m_pdbout->Printf(TEXT("[0x%lx] nAlloc=%ld size=%ld\n"),
+ pn->m_pv, pn->m_nAlloc, GetSize(pn->m_pv));
+}
+
+
+/***
+*PRIVATE BOOL IsEmpty
+*Purpose:
+* Answer if the address instance table is empty.
+*
+*Entry:
+* None
+*
+*Exit:
+* return value = BOOL, TRUE if empty, FALSE otherwise
+*
+***********************************************************************/
+BOOL
+CDbAlloc::IsEmpty()
+{
+ UINT u;
+
+ for(u = 0; u < DIM(m_rganode); ++u){
+ if(m_rganode[u] != NULL)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/***
+*PRIVATE CDbAlloc::Dump
+*Purpose:
+* Print the current contents of the address instance table,
+*
+*Entry:
+* None
+*
+*Exit:
+* None
+*
+***********************************************************************/
+void
+CDbAlloc::DumpInstTable()
+{
+ UINT u;
+ CAddrNode FAR* pn;
+
+ for(u = 0; u < DIM(m_rganode); ++u){
+ for(pn = m_rganode[u]; pn != NULL; pn = pn->m_next){
+ DumpInst(pn);
+ }
+ }
+}
+
+
+//---------------------------------------------------------------------
+// implementation of CStdDbOutput
+//---------------------------------------------------------------------
+
+IDbOutput FAR*
+CStdDbOutput::Create()
+{
+ return (IDbOutput FAR*)new FAR CStdDbOutput();
+}
+
+STDMETHODIMP
+CStdDbOutput::QueryInterface(REFIID riid, void FAR* FAR* ppv)
+{
+ if(IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = this;
+ AddRef();
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+CStdDbOutput::AddRef()
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+CStdDbOutput::Release()
+{
+ if(--m_refs == 0){
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+STDMETHODIMP_(void)
+CStdDbOutput::Printf(TCHAR FAR* lpszFmt, ...)
+{
+ va_list args;
+ TCHAR szBuf[256];
+#if defined( OBSOLETE )
+ TCHAR *pn, FAR* pf;
+static TCHAR rgchFmtBuf[128];
+static TCHAR rgchOutputBuf[128];
+
+ // copy the 'far' format string to a near buffer so we can use
+ // a medium model vsprintf, which only supports near data pointers.
+ //
+ pn = rgchFmtBuf, pf=szFmt;
+ while(*pf != TEXT('\0'))
+ *pn++ = *pf++;
+ *pn = TEXT('\0');
+#endif
+
+ va_start(args, lpszFmt);
+
+// wvsprintf(rgchOutputBuf, rgchFmtBuf, args);
+ wvsprintf(szBuf, lpszFmt, args);
+
+ OutputDebugString(szBuf);
+}
+
+STDMETHODIMP_(void)
+CStdDbOutput::Assertion(
+ BOOL cond,
+ TCHAR FAR* szExpr,
+ TCHAR FAR* szFile,
+ UINT uLine,
+ TCHAR FAR* szMsg)
+{
+ if(cond)
+ return;
+
+#ifdef _DEBUG
+ // following is from compobj.dll (ole2)
+ #ifdef UNICODE
+ #ifndef NOASSERT
+ FnAssert(szExpr, szMsg, szFile, uLine);
+ #endif
+ #else
+ // we need to talk to comobj in UNICODE even though we are not defined
+ // as UNICODE
+ {
+ WCHAR wszExpr[255], wszMsg[255], wszFile[255];
+ mbstowcs(wszExpr, szExpr, 255);
+ mbstowcs(wszMsg, szMsg, 255);
+ mbstowcs(wszFile, szFile, 255);
+ #ifndef NOASSERT
+ FnAssert(wszExpr, wszMsg, wszFile, uLine);
+ #endif
+ }
+ #endif
+#else
+ // REVIEW: should be able to do something better that this...
+ DebugBreak();
+#endif
+}
diff --git a/private/oleutest/letest/ole2ui/dballoc.h b/private/oleutest/letest/ole2ui/dballoc.h
new file mode 100644
index 000000000..42ccbaff2
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/dballoc.h
@@ -0,0 +1,36 @@
+/***
+*dballoc.h
+*
+* Copyright (C) 1992-93, Microsoft Corporation. All Rights Reserved.
+*
+*Purpose:
+* This file contains the definition of CDbAlloc - A debug implementation
+* of the IMalloc interface.
+*
+*Implementation Notes:
+*
+*****************************************************************************/
+
+#ifndef DBALLOC_H_INCLUDED /* { */
+#define DBALLOC_H_INCLUDED
+
+
+interface IDbOutput : public IUnknown
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppv) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+ STDMETHOD_(void, Printf)(THIS_
+ TCHAR FAR* szFmt, ...) PURE;
+
+ STDMETHOD_(void, Assertion)(THIS_
+ BOOL cond,
+ TCHAR FAR* szExpr,
+ TCHAR FAR* szFile,
+ UINT uLine,
+ TCHAR FAR* szMsg) PURE;
+};
+
+
+#endif /* } DBALLOC_H_INCLUDED */
diff --git a/private/oleutest/letest/ole2ui/dbgutil.c b/private/oleutest/letest/ole2ui/dbgutil.c
new file mode 100644
index 000000000..15c17a248
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/dbgutil.c
@@ -0,0 +1,419 @@
+/*************************************************************************
+**
+** OLE 2.0 Common Utilities
+**
+** dbgutil.h
+**
+** This file contains file contains functions to support debug output.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#define STRICT 1
+#include "ole2ui.h"
+
+static int s_nDbgIndent = 0; // indent level for debug message
+#if defined( _DEBUG )
+static int s_nDbgLevel = 0; // default dbg level printed
+#else
+static int s_nDbgLevel = 0; // default dbg level printed
+#endif
+
+STDAPI_(void) OleDbgPrint(
+ int nDbgLvl,
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ int nIndent
+)
+{
+ if (nDbgLvl <= s_nDbgLevel)
+ OleDbgPrintAlways(lpszPrefix, lpszMsg, nIndent);
+}
+
+
+STDAPI_(void) OleDbgPrintAlways(LPTSTR lpszPrefix, LPTSTR lpszMsg, int nIndent)
+{
+ int i;
+
+ if (nIndent < 0)
+ OleDbgIndent(nIndent);
+
+ if (lpszPrefix && *lpszPrefix != TEXT('\0')) {
+ OutputDebugString(TEXT("| "));
+ for (i = 0; i < s_nDbgIndent; i++)
+ OutputDebugString(TEXT("----"));
+
+ OutputDebugString(lpszPrefix);
+ OutputDebugString(TEXT(": "));
+ }
+
+ OutputDebugString(lpszMsg);
+ if (nIndent > 0)
+ OleDbgIndent(nIndent);
+}
+
+STDAPI_(void) OleDbgSetDbgLevel(int nDbgLvl)
+{
+ s_nDbgLevel = nDbgLvl;
+}
+
+STDAPI_(int) OleDbgGetDbgLevel( void )
+{
+ return s_nDbgLevel;
+}
+
+STDAPI_(void) OleDbgIndent(int n)
+{
+ switch (n) {
+ case -1:
+ s_nDbgIndent--;
+ break;
+ case 1:
+ s_nDbgIndent++;
+ break;
+ case -2:
+ s_nDbgIndent = 0;
+ break;
+ }
+}
+
+
+STDAPI_(void) OleDbgPrintRefCnt(
+ int nDbgLvl,
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPVOID lpObj,
+ ULONG refcnt
+)
+{
+ if (nDbgLvl <= s_nDbgLevel)
+ OleDbgPrintRefCntAlways(lpszPrefix, lpszMsg, lpObj, refcnt);
+}
+
+
+STDAPI_(void) OleDbgPrintRefCntAlways(
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPVOID lpObj,
+ ULONG refcnt
+)
+{
+#if defined( _DEBUG )
+ TCHAR szBuf[256];
+
+ wsprintf(szBuf, TEXT("[obj=(0x%lx) cnt=%ld] %s"), lpObj, refcnt, lpszMsg);
+ OleDbgPrintAlways(lpszPrefix, szBuf, 0);
+#endif
+}
+
+
+STDAPI_(void) OleDbgPrintRect(
+ int nDbgLvl,
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPRECT lpRect
+)
+{
+ if (nDbgLvl <= s_nDbgLevel)
+ OleDbgPrintRectAlways(lpszPrefix, lpszMsg, lpRect);
+}
+
+
+STDAPI_(void) OleDbgPrintRectAlways(
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPRECT lpRect
+)
+{
+#if defined( _DEBUG )
+ TCHAR szBuf[256];
+
+ wsprintf(
+ szBuf,
+ TEXT("%s: (%d,%d)-(%d,%d) %dx%d\r\n"),
+ lpszMsg,
+ lpRect->left,
+ lpRect->top,
+ lpRect->right,
+ lpRect->bottom,
+ (lpRect->right-lpRect->left),
+ (lpRect->bottom-lpRect->top)
+ );
+ OleDbgPrintAlways(lpszPrefix, szBuf, 0);
+#endif
+}
+
+
+#define CASE_SCODE(sc) \
+ case sc: \
+ lstrcpy((LPTSTR)szErrName, (LPTSTR)#sc); \
+ break;
+
+STDAPI_(void) OleDbgPrintScodeAlways(LPTSTR lpszPrefix, LPTSTR lpszMsg, SCODE sc)
+{
+#if defined( _DEBUG )
+ TCHAR szBuf[256];
+ TCHAR szErrName[40];
+
+ switch (sc) {
+
+ /* SCODE's defined in SCODE.H */
+
+ CASE_SCODE(S_OK)
+ CASE_SCODE(S_FALSE)
+ CASE_SCODE(E_UNEXPECTED)
+ CASE_SCODE(E_OUTOFMEMORY)
+ CASE_SCODE(E_INVALIDARG)
+ CASE_SCODE(E_NOINTERFACE)
+ CASE_SCODE(E_POINTER)
+ CASE_SCODE(E_HANDLE)
+ CASE_SCODE(E_ABORT)
+ CASE_SCODE(E_FAIL)
+ CASE_SCODE(E_ACCESSDENIED)
+
+ /* SCODE's defined in OLE2.H */
+
+ CASE_SCODE(OLE_E_OLEVERB)
+ CASE_SCODE(OLE_E_ADVF)
+ CASE_SCODE(OLE_E_ENUM_NOMORE)
+ CASE_SCODE(OLE_E_ADVISENOTSUPPORTED)
+ CASE_SCODE(OLE_E_NOCONNECTION)
+ CASE_SCODE(OLE_E_NOTRUNNING)
+ CASE_SCODE(OLE_E_NOCACHE)
+ CASE_SCODE(OLE_E_BLANK)
+ CASE_SCODE(OLE_E_CLASSDIFF)
+ CASE_SCODE(OLE_E_CANT_GETMONIKER)
+ CASE_SCODE(OLE_E_CANT_BINDTOSOURCE)
+ CASE_SCODE(OLE_E_STATIC)
+ CASE_SCODE(OLE_E_PROMPTSAVECANCELLED)
+ CASE_SCODE(OLE_E_INVALIDRECT)
+ CASE_SCODE(OLE_E_WRONGCOMPOBJ)
+ CASE_SCODE(OLE_E_INVALIDHWND)
+ CASE_SCODE(OLE_E_NOT_INPLACEACTIVE)
+ CASE_SCODE(OLE_E_CANTCONVERT)
+ CASE_SCODE(OLE_E_NOSTORAGE)
+
+ CASE_SCODE(DV_E_FORMATETC)
+ CASE_SCODE(DV_E_DVTARGETDEVICE)
+ CASE_SCODE(DV_E_STGMEDIUM)
+ CASE_SCODE(DV_E_STATDATA)
+ CASE_SCODE(DV_E_LINDEX)
+ CASE_SCODE(DV_E_TYMED)
+ CASE_SCODE(DV_E_CLIPFORMAT)
+ CASE_SCODE(DV_E_DVASPECT)
+ CASE_SCODE(DV_E_DVTARGETDEVICE_SIZE)
+ CASE_SCODE(DV_E_NOIVIEWOBJECT)
+
+ CASE_SCODE(OLE_S_USEREG)
+ CASE_SCODE(OLE_S_STATIC)
+ CASE_SCODE(OLE_S_MAC_CLIPFORMAT)
+
+ CASE_SCODE(CONVERT10_E_OLESTREAM_GET)
+ CASE_SCODE(CONVERT10_E_OLESTREAM_PUT)
+ CASE_SCODE(CONVERT10_E_OLESTREAM_FMT)
+ CASE_SCODE(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)
+ CASE_SCODE(CONVERT10_E_STG_FMT)
+ CASE_SCODE(CONVERT10_E_STG_NO_STD_STREAM)
+ CASE_SCODE(CONVERT10_E_STG_DIB_TO_BITMAP)
+ CASE_SCODE(CONVERT10_S_NO_PRESENTATION)
+
+ CASE_SCODE(CLIPBRD_E_CANT_OPEN)
+ CASE_SCODE(CLIPBRD_E_CANT_EMPTY)
+ CASE_SCODE(CLIPBRD_E_CANT_SET)
+ CASE_SCODE(CLIPBRD_E_BAD_DATA)
+ CASE_SCODE(CLIPBRD_E_CANT_CLOSE)
+
+ CASE_SCODE(DRAGDROP_E_NOTREGISTERED)
+ CASE_SCODE(DRAGDROP_E_ALREADYREGISTERED)
+ CASE_SCODE(DRAGDROP_E_INVALIDHWND)
+ CASE_SCODE(DRAGDROP_S_DROP)
+ CASE_SCODE(DRAGDROP_S_CANCEL)
+ CASE_SCODE(DRAGDROP_S_USEDEFAULTCURSORS)
+
+ CASE_SCODE(OLEOBJ_E_NOVERBS)
+ CASE_SCODE(OLEOBJ_E_INVALIDVERB)
+ CASE_SCODE(OLEOBJ_S_INVALIDVERB)
+ CASE_SCODE(OLEOBJ_S_CANNOT_DOVERB_NOW)
+ CASE_SCODE(OLEOBJ_S_INVALIDHWND)
+ CASE_SCODE(INPLACE_E_NOTUNDOABLE)
+ CASE_SCODE(INPLACE_E_NOTOOLSPACE)
+ CASE_SCODE(INPLACE_S_TRUNCATED)
+
+ /* SCODE's defined in COMPOBJ.H */
+
+ CASE_SCODE(CO_E_NOTINITIALIZED)
+ CASE_SCODE(CO_E_ALREADYINITIALIZED)
+ CASE_SCODE(CO_E_CANTDETERMINECLASS)
+ CASE_SCODE(CO_E_CLASSSTRING)
+ CASE_SCODE(CO_E_IIDSTRING)
+ CASE_SCODE(CO_E_APPNOTFOUND)
+ CASE_SCODE(CO_E_APPSINGLEUSE)
+ CASE_SCODE(CO_E_ERRORINAPP)
+ CASE_SCODE(CO_E_DLLNOTFOUND)
+ CASE_SCODE(CO_E_ERRORINDLL)
+ CASE_SCODE(CO_E_WRONGOSFORAPP)
+ CASE_SCODE(CO_E_OBJNOTREG)
+ CASE_SCODE(CO_E_OBJISREG)
+ CASE_SCODE(CO_E_OBJNOTCONNECTED)
+ CASE_SCODE(CO_E_APPDIDNTREG)
+ CASE_SCODE(CLASS_E_NOAGGREGATION)
+// CASE_SCODE(CLASS_E_CLASSNOTAVAILABLE)
+ CASE_SCODE(REGDB_E_READREGDB)
+ CASE_SCODE(REGDB_E_WRITEREGDB)
+ CASE_SCODE(REGDB_E_KEYMISSING)
+ CASE_SCODE(REGDB_E_INVALIDVALUE)
+ CASE_SCODE(REGDB_E_CLASSNOTREG)
+ CASE_SCODE(REGDB_E_IIDNOTREG)
+ CASE_SCODE(RPC_E_CALL_REJECTED)
+ CASE_SCODE(RPC_E_CALL_CANCELED)
+ CASE_SCODE(RPC_E_CANTPOST_INSENDCALL)
+ CASE_SCODE(RPC_E_CANTCALLOUT_INASYNCCALL)
+ CASE_SCODE(RPC_E_CANTCALLOUT_INEXTERNALCALL)
+ CASE_SCODE(RPC_E_CONNECTION_TERMINATED)
+ CASE_SCODE(RPC_E_SERVER_DIED)
+ CASE_SCODE(RPC_E_CLIENT_DIED)
+ CASE_SCODE(RPC_E_INVALID_DATAPACKET)
+ CASE_SCODE(RPC_E_CANTTRANSMIT_CALL)
+ CASE_SCODE(RPC_E_CLIENT_CANTMARSHAL_DATA)
+ CASE_SCODE(RPC_E_CLIENT_CANTUNMARSHAL_DATA)
+ CASE_SCODE(RPC_E_SERVER_CANTMARSHAL_DATA)
+ CASE_SCODE(RPC_E_SERVER_CANTUNMARSHAL_DATA)
+ CASE_SCODE(RPC_E_INVALID_DATA)
+ CASE_SCODE(RPC_E_INVALID_PARAMETER)
+// CASE_SCODE(RPC_E_CANTCALLOUT_AGAIN)
+ CASE_SCODE(RPC_E_UNEXPECTED)
+
+ /* SCODE's defined in DVOBJ.H */
+
+ CASE_SCODE(DATA_S_SAMEFORMATETC)
+ CASE_SCODE(VIEW_E_DRAW)
+ CASE_SCODE(VIEW_S_ALREADY_FROZEN)
+ CASE_SCODE(CACHE_E_NOCACHE_UPDATED)
+ CASE_SCODE(CACHE_S_FORMATETC_NOTSUPPORTED)
+ CASE_SCODE(CACHE_S_SAMECACHE)
+ CASE_SCODE(CACHE_S_SOMECACHES_NOTUPDATED)
+
+ /* SCODE's defined in STORAGE.H */
+
+ CASE_SCODE(STG_E_INVALIDFUNCTION)
+ CASE_SCODE(STG_E_FILENOTFOUND)
+ CASE_SCODE(STG_E_PATHNOTFOUND)
+ CASE_SCODE(STG_E_TOOMANYOPENFILES)
+ CASE_SCODE(STG_E_ACCESSDENIED)
+ CASE_SCODE(STG_E_INVALIDHANDLE)
+ CASE_SCODE(STG_E_INSUFFICIENTMEMORY)
+ CASE_SCODE(STG_E_INVALIDPOINTER)
+ CASE_SCODE(STG_E_NOMOREFILES)
+ CASE_SCODE(STG_E_DISKISWRITEPROTECTED)
+ CASE_SCODE(STG_E_SEEKERROR)
+ CASE_SCODE(STG_E_WRITEFAULT)
+ CASE_SCODE(STG_E_READFAULT)
+ CASE_SCODE(STG_E_SHAREVIOLATION)
+ CASE_SCODE(STG_E_LOCKVIOLATION)
+ CASE_SCODE(STG_E_FILEALREADYEXISTS)
+ CASE_SCODE(STG_E_INVALIDPARAMETER)
+ CASE_SCODE(STG_E_MEDIUMFULL)
+ CASE_SCODE(STG_E_ABNORMALAPIEXIT)
+ CASE_SCODE(STG_E_INVALIDHEADER)
+ CASE_SCODE(STG_E_INVALIDNAME)
+ CASE_SCODE(STG_E_UNKNOWN)
+ CASE_SCODE(STG_E_UNIMPLEMENTEDFUNCTION)
+ CASE_SCODE(STG_E_INVALIDFLAG)
+ CASE_SCODE(STG_E_INUSE)
+ CASE_SCODE(STG_E_NOTCURRENT)
+ CASE_SCODE(STG_E_REVERTED)
+ CASE_SCODE(STG_E_CANTSAVE)
+ CASE_SCODE(STG_E_OLDFORMAT)
+ CASE_SCODE(STG_E_OLDDLL)
+ CASE_SCODE(STG_E_SHAREREQUIRED)
+ CASE_SCODE(STG_E_NOTFILEBASEDSTORAGE)
+ CASE_SCODE(STG_E_EXTANTMARSHALLINGS)
+ CASE_SCODE(STG_S_CONVERTED)
+
+ /* SCODE's defined in STORAGE.H */
+
+ CASE_SCODE(MK_E_CONNECTMANUALLY)
+ CASE_SCODE(MK_E_EXCEEDEDDEADLINE)
+ CASE_SCODE(MK_E_NEEDGENERIC)
+ CASE_SCODE(MK_E_UNAVAILABLE)
+ CASE_SCODE(MK_E_SYNTAX)
+ CASE_SCODE(MK_E_NOOBJECT)
+ CASE_SCODE(MK_E_INVALIDEXTENSION)
+ CASE_SCODE(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)
+ CASE_SCODE(MK_E_NOTBINDABLE)
+ CASE_SCODE(MK_E_NOTBOUND)
+ CASE_SCODE(MK_E_CANTOPENFILE)
+ CASE_SCODE(MK_E_MUSTBOTHERUSER)
+ CASE_SCODE(MK_E_NOINVERSE)
+ CASE_SCODE(MK_E_NOSTORAGE)
+ CASE_SCODE(MK_E_NOPREFIX)
+ CASE_SCODE(MK_S_REDUCED_TO_SELF)
+ CASE_SCODE(MK_S_ME)
+ CASE_SCODE(MK_S_HIM)
+ CASE_SCODE(MK_S_US)
+ CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)
+
+ default:
+ lstrcpy(szErrName, TEXT("UNKNOWN SCODE"));
+ }
+
+ wsprintf(szBuf, TEXT("%s %s (0x%lx)\n"), lpszMsg, (LPTSTR)szErrName, sc);
+ OleDbgPrintAlways(lpszPrefix, szBuf, 0);
+#endif // _DEBUG
+}
+
+STDAPI FnAssert(LPSTR lpstrExpr, LPSTR lpstrMsg, LPSTR lpstrFileName, UINT iLine)
+{
+#ifdef _DEBUG
+ char szOutput[1024];
+ char szTitle[256];
+ char szModuleName[128];
+ char *pszModuleName;
+ int id;
+
+ DWORD tid = GetCurrentThreadId();
+ DWORD pid = GetCurrentProcessId();
+
+ wsprintfA(szOutput, "%s %s File: %s Line: %d PID: %d TID: %d\n",
+ lpstrExpr, lpstrMsg ? lpstrMsg : "", lpstrFileName, pid, tid);
+ OutputDebugString(szOutput);
+
+ if (GetModuleFileNameA(NULL, szModuleName, 128))
+ {
+ pszModuleName = strrchr(szModuleName, '\\');
+ if (!pszModuleName)
+ {
+ pszModuleName = szModuleName;
+ }
+ else
+ {
+ pszModuleName++;
+ }
+ }
+ else
+ {
+ pszModuleName = "Unknown";
+ }
+
+ wsprintfA(szTitle, "Process: %s File: %s, line %u",
+ pszModuleName, lpstrFileName, iLine);
+
+ wsprintfA(szOutput, "%s %s PID.TID %d.%d",
+ lpstrExpr, lpstrMsg ? lpstrMsg : "", pid, tid);
+
+ id = MessageBoxA(NULL,
+ szOutput,
+ szTitle,
+ MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY |
+ MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL);
+
+
+ if (id == IDCANCEL)
+ {
+ DebugBreak();
+ }
+
+#endif // _DEBUG
+ return NOERROR;
+}
diff --git a/private/oleutest/letest/ole2ui/debug.h b/private/oleutest/letest/ole2ui/debug.h
new file mode 100644
index 000000000..fa5bfc7ef
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/debug.h
@@ -0,0 +1,69 @@
+/*
+ * DEBUG.H
+ *
+ * Definitions, structures, types, and function prototypes for debugging
+ * purposes.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved,
+ * as applied to redistribution of this source code in source form
+ * License is granted to use of compiled code in shipped binaries.
+ */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#ifdef DEBUG
+
+//Basic debug macros
+#define D(x) {x;}
+#define ODS(x) D(OutputDebugString(x);OutputDebugString("\r\n"))
+
+#define ODSsz(f, s) {\
+ char szDebug[128];\
+ wsprintf(szDebug, f, (LPSTR)s);\
+ ODS(szDebug);\
+ }
+
+
+#define ODSu(f, u) {\
+ char szDebug[128];\
+ wsprintf(szDebug, f, (UINT)u);\
+ ODS(szDebug);\
+ }
+
+
+#define ODSlu(f, lu) {\
+ char szDebug[128];\
+ wsprintf(szDebug, f, (DWORD)lu);\
+ ODS(szDebug);\
+ }
+
+#define ODSszu(f, s, u) {\
+ char szDebug[128];\
+ wsprintf(szDebug, f, (LPSTR)s, (UINT)u);\
+ ODS(szDebug);\
+ }
+
+
+#define ODSszlu(f, s, lu) {\
+ char szDebug[128];\
+ wsprintf(szDebug, f, (LPSTR)s, (DWORD)lu);\
+ ODS(szDebug);\
+ }
+
+
+#else //NO DEBUG
+
+#define D(x)
+#define ODS(x)
+
+#define ODSsz(f, s)
+#define ODSu(f, u)
+#define ODSlu(f, lu)
+#define ODSszu(f, s, u)
+#define ODSszlu(f, s, lu)
+
+
+#endif //DEBUG
+
+#endif //_DEBUG_H_
diff --git a/private/oleutest/letest/ole2ui/default.ico b/private/oleutest/letest/ole2ui/default.ico
new file mode 100644
index 000000000..4542c57d3
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/default.ico
Binary files differ
diff --git a/private/oleutest/letest/ole2ui/defuimak.ini b/private/oleutest/letest/ole2ui/defuimak.ini
new file mode 100644
index 000000000..39517d711
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/defuimak.ini
@@ -0,0 +1,20 @@
+# This is the DEBUG UILibrary INI file
+MSG=DEBUG Version ($(LANG))
+DEBUG=1
+LIBNAME=outlui
+REL_DIR=c:\ole2samp\release
+OLEREL_DIR=c:\ole2samp\release
+OBJ=DEBUG
+RESOURCE=RESOURCE
+CFLAGS=-c -Od -Gw2cs -W3 -Zpei -AMw -D_DEBUG -D_WINDLL -Gi
+AFLAGS=-mx -Zi -DDEBUG
+RFLAGS=-D DEBUG
+LFLAGS=/MAP /CO /L /NOD /NOE /SE:300
+UILIBS=mdllcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+LANG=USA
+DLLOBJS = $(UI_DLLOBJS:D^\=DEBUG^\)
+LIBOBJS = $(UI_COBJS:D^\=DEBUG^\) $(UI_NOPCOBJS:D^\=DEBUG\NOPC^\)
diff --git a/private/oleutest/letest/ole2ui/depend b/private/oleutest/letest/ole2ui/depend
new file mode 100644
index 000000000..4007c4980
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/depend
@@ -0,0 +1,87 @@
+$(O)busy.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h utility.h busy.h
+
+$(O)common.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h utility.h
+
+$(O)convert.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h utility.h geticon.h regdb.h \
+ convert.h
+
+$(O)dbgutil.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h
+
+$(O)regdb.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h
+
+$(O)drawicon.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h utility.h geticon.h
+
+$(O)hatch.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h
+
+$(O)icon.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h utility.h icon.h geticon.h
+
+$(O)iconbox.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h iconbox.h
+
+$(O)insobj.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h utility.h icon.h insobj.h \
+ resimage.h iconbox.h geticon.h
+
+$(O)links.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h common.h edlinks.h utility.h
+
+$(O)msgfiltr.obj : $(PRECOMP) \
+ ole2ui.h olestd.h uiclass.h msgfiltr.h
+
+$(O)enumfetc.obj : $(PRECOMP) \
+ ole2ui.h olestd.h
+
+$(O)enumstat.obj : $(PRECOMP) \
+ ole2ui.h olestd.h
+
+$(O)objfdbk.obj : $(PRECOMP) \
+ ole2ui.h olestd.h
+
+$(O)ole2ui.obj : $(PRECOMP) \
+ ole2ui.h olestd.h common.h utility.h resimage.h iconbox.h
+
+$(O)olestd.obj : $(PRECOMP) \
+ ole2ui.h olestd.h regdb.h geticon.h common.h
+
+$(O)targtdev.obj : $(PRECOMP) \
+ ole2ui.h olestd.h
+
+$(O)oleutl.obj : $(PRECOMP) \
+ ole2ui.h olestd.h
+
+$(O)pastespl.obj : $(PRECOMP) \
+ ole2ui.h olestd.h pastespl.h common.h utility.h resimage.h iconbox.h \
+ geticon.h regdb.h
+
+$(O)resimage.obj : $(PRECOMP) \
+ ole2ui.h olestd.h resimage.h
+
+$(O)utility.obj : $(PRECOMP) \
+ ole2ui.h olestd.h common.h utility.h geticon.h
+
+$(O)dllfuncs.obj : $(PRECOMP) \
+ ole2ui.h olestd.h common.h uiclass.h
+
+$(O)NOPC\geticon.obj : \
+ ole2ui.h olestd.h uiclass.h geticon.h
+
+$(O)NOPC\dballoc.obj : \
+ dballoc.h
+
+$(O)NOPC\suminfo.obj : \
+ suminfo.h wn_dos.h
+
+$(O)NOPC\stdpal.obj : \
+ stdpal.h
+
+$(O)precomp.pch : \
+ ole2ui.h olestd.h uiclass.h
+
diff --git a/private/oleutest/letest/ole2ui/depend.mk b/private/oleutest/letest/ole2ui/depend.mk
new file mode 100644
index 000000000..2b6c05155
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/depend.mk
@@ -0,0 +1,569 @@
+#
+# Built automatically
+#
+
+#
+# Source files
+#
+
+$(OBJDIR)\busy.obj $(OBJDIR)\busy.lst: .\busy.c $(CAIROLE)\h\export\coguid.h \
+ $(CAIROLE)\h\export\compobj.h $(CAIROLE)\h\export\dvobj.h \
+ $(CAIROLE)\h\export\initguid.h $(CAIROLE)\h\export\moniker.h \
+ $(CAIROLE)\h\export\ole2.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(CRTINC)\ctype.h $(CRTINC)\dos.h $(CRTINC)\excpt.h \
+ $(CRTINC)\stdarg.h $(CRTINC)\string.h $(OSINC)\cderr.h \
+ $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \
+ $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \
+ $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \
+ $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \
+ $(OSINC)\shellapi.h $(OSINC)\winbase.h $(OSINC)\wincon.h \
+ $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \
+ $(OSINC)\wingdi.h $(OSINC)\winnetwk.h $(OSINC)\winnls.h \
+ $(OSINC)\winnt.h $(OSINC)\winperf.h $(OSINC)\winreg.h \
+ $(OSINC)\winsock.h $(OSINC)\winspool.h $(OSINC)\winsvc.h \
+ $(OSINC)\winuser.h $(OSINC)\winver.h .\busy.h .\common.h .\ole2ui.h \
+ .\olestd.h .\utility.h
+
+$(OBJDIR)\common.obj $(OBJDIR)\common.lst: .\common.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\malloc.h $(CRTINC)\ctype.h \
+ $(CRTINC)\dos.h $(CRTINC)\excpt.h $(CRTINC)\stdarg.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\common.h .\ole2ui.h .\olestd.h .\utility.h
+
+$(OBJDIR)\convert.obj $(OBJDIR)\convert.lst: .\convert.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\stdlib.h $(CRTINC)\ctype.h \
+ $(CRTINC)\dos.h $(CRTINC)\excpt.h $(CRTINC)\stdarg.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\convert.h .\geticon.h .\regdb.h .\common.h \
+ .\ole2ui.h .\olestd.h .\utility.h
+
+$(OBJDIR)\dballoc.obj $(OBJDIR)\dballoc.lst: .\dballoc.cpp \
+ $(CAIROLE)\h\export\ole2.h $(CAIROLE)\h\export\coguid.h \
+ $(CAIROLE)\h\export\compobj.h $(CAIROLE)\h\export\dvobj.h \
+ $(CAIROLE)\h\export\initguid.h $(CAIROLE)\h\export\moniker.h \
+ $(CAIROLE)\h\export\ole2.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(CRTINC)\limits.h $(CRTINC)\stdio.h $(CRTINC)\ctype.h \
+ $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \
+ $(CRTINC)\stdlib.h $(CRTINC)\string.h $(OSINC)\cderr.h \
+ $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \
+ $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \
+ $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \
+ $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \
+ $(OSINC)\shellapi.h $(OSINC)\winbase.h $(OSINC)\wincon.h \
+ $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \
+ $(OSINC)\wingdi.h $(OSINC)\winnetwk.h $(OSINC)\winnls.h \
+ $(OSINC)\winnt.h $(OSINC)\winperf.h $(OSINC)\winreg.h \
+ $(OSINC)\winsock.h $(OSINC)\winspool.h $(OSINC)\winsvc.h \
+ $(OSINC)\winuser.h $(OSINC)\winver.h .\dballoc.h
+
+$(OBJDIR)\dbgutil.obj $(OBJDIR)\dbgutil.lst: .\dbgutil.c \
+ $(CAIROLE)\h\export\ole2.h $(CAIROLE)\h\export\coguid.h \
+ $(CAIROLE)\h\export\compobj.h $(CAIROLE)\h\export\dvobj.h \
+ $(CAIROLE)\h\export\initguid.h $(CAIROLE)\h\export\moniker.h \
+ $(CAIROLE)\h\export\ole2.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(CRTINC)\ctype.h $(CRTINC)\dos.h $(CRTINC)\excpt.h \
+ $(CRTINC)\stdarg.h $(CRTINC)\string.h $(OSINC)\shellapi.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h
+
+$(OBJDIR)\dllfuncs.obj $(OBJDIR)\dllfuncs.lst: .\dllfuncs.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\uiclass.h \
+ .\common.h .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\drawicon.obj $(OBJDIR)\drawicon.lst: .\drawicon.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\common.h \
+ .\geticon.h .\ole2ui.h .\olestd.h .\utility.h
+
+$(OBJDIR)\enumfetc.obj $(OBJDIR)\enumfetc.lst: .\enumfetc.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\enumfetc.h \
+ .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\enumstat.obj $(OBJDIR)\enumstat.lst: .\enumstat.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h
+
+$(OBJDIR)\geticon.obj $(OBJDIR)\geticon.lst: .\geticon.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\memory.h $(CRTINC)\ctype.h \
+ $(CRTINC)\dos.h $(CRTINC)\excpt.h $(CRTINC)\stdarg.h \
+ $(CRTINC)\stdlib.h $(CRTINC)\string.h $(OSINC)\cderr.h \
+ $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \
+ $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \
+ $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \
+ $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \
+ $(OSINC)\shellapi.h $(OSINC)\winbase.h $(OSINC)\wincon.h \
+ $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \
+ $(OSINC)\wingdi.h $(OSINC)\winnetwk.h $(OSINC)\winnls.h \
+ $(OSINC)\winnt.h $(OSINC)\winperf.h $(OSINC)\winreg.h \
+ $(OSINC)\winsock.h $(OSINC)\winspool.h $(OSINC)\winsvc.h \
+ $(OSINC)\winuser.h $(OSINC)\winver.h .\common.h .\ole2ui.h \
+ .\olestd.h .\utility.h
+
+$(OBJDIR)\hatch.obj $(OBJDIR)\hatch.lst: .\hatch.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h
+
+$(OBJDIR)\icon.obj $(OBJDIR)\icon.lst: .\icon.c $(CAIROLE)\h\export\coguid.h \
+ $(CAIROLE)\h\export\compobj.h $(CAIROLE)\h\export\dvobj.h \
+ $(CAIROLE)\h\export\initguid.h $(CAIROLE)\h\export\moniker.h \
+ $(CAIROLE)\h\export\ole2.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(CRTINC)\ctype.h $(CRTINC)\dos.h $(CRTINC)\excpt.h \
+ $(CRTINC)\stdarg.h $(CRTINC)\string.h $(OSINC)\cderr.h \
+ $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \
+ $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \
+ $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \
+ $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \
+ $(OSINC)\shellapi.h $(OSINC)\winbase.h $(OSINC)\wincon.h \
+ $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \
+ $(OSINC)\wingdi.h $(OSINC)\winnetwk.h $(OSINC)\winnls.h \
+ $(OSINC)\winnt.h $(OSINC)\winperf.h $(OSINC)\winreg.h \
+ $(OSINC)\winsock.h $(OSINC)\winspool.h $(OSINC)\winsvc.h \
+ $(OSINC)\winuser.h $(OSINC)\winver.h .\icon.h .\common.h .\geticon.h \
+ .\ole2ui.h .\olestd.h .\utility.h
+
+$(OBJDIR)\iconbox.obj $(OBJDIR)\iconbox.lst: .\iconbox.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\iconbox.h \
+ .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\insobj.obj $(OBJDIR)\insobj.lst: .\insobj.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\direct.h $(CRTINC)\ctype.h \
+ $(CRTINC)\dos.h $(CRTINC)\excpt.h $(CRTINC)\malloc.h \
+ $(CRTINC)\memory.h $(CRTINC)\stdarg.h $(CRTINC)\stdlib.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\insobj.h .\resimage.h .\common.h .\geticon.h \
+ .\icon.h .\iconbox.h .\ole2ui.h .\olestd.h .\utility.h
+
+$(OBJDIR)\links.obj $(OBJDIR)\links.lst: .\links.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\stdlib.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\edlinks.h .\common.h .\ole2ui.h .\olestd.h \
+ .\utility.h
+
+$(OBJDIR)\msgfiltr.obj $(OBJDIR)\msgfiltr.lst: .\msgfiltr.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\msgfiltr.h \
+ .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\objfdbk.obj $(OBJDIR)\objfdbk.lst: .\objfdbk.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h
+
+$(OBJDIR)\ole2ui.obj $(OBJDIR)\ole2ui.lst: .\ole2ui.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\common.h \
+ .\iconbox.h .\ole2ui.h .\olestd.h .\resimage.h .\utility.h
+
+$(OBJDIR)\olestd.obj $(OBJDIR)\olestd.lst: .\olestd.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\stdlib.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\common.h .\geticon.h .\ole2ui.h .\olestd.h \
+ .\regdb.h
+
+$(OBJDIR)\oleutl.obj $(OBJDIR)\oleutl.lst: .\oleutl.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\stdlib.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\pastespl.obj $(OBJDIR)\pastespl.lst: .\pastespl.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\stdlib.h \
+ $(CRTINC)\string.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \
+ $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \
+ $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \
+ $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \
+ $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \
+ $(OSINC)\winbase.h $(OSINC)\wincon.h $(OSINC)\windef.h \
+ $(OSINC)\windows.h $(OSINC)\winerror.h $(OSINC)\wingdi.h \
+ $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \
+ $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \
+ $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \
+ $(OSINC)\winver.h .\pastespl.h .\common.h .\geticon.h .\icon.h \
+ .\iconbox.h .\ole2ui.h .\olestd.h .\regdb.h .\resimage.h \
+ .\utility.h
+
+$(OBJDIR)\precomp.obj $(OBJDIR)\precomp.lst: .\precomp.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h
+
+$(OBJDIR)\regdb.obj $(OBJDIR)\regdb.lst: .\regdb.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\common.h \
+ .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\resimage.obj $(OBJDIR)\resimage.lst: .\resimage.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h .\resimage.h
+
+$(OBJDIR)\stdpal.obj $(OBJDIR)\stdpal.lst: .\stdpal.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\excpt.h \
+ $(CRTINC)\stdarg.h $(CRTINC)\string.h $(OSINC)\cderr.h \
+ $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \
+ $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \
+ $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \
+ $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \
+ $(OSINC)\shellapi.h $(OSINC)\winbase.h $(OSINC)\wincon.h \
+ $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \
+ $(OSINC)\wingdi.h $(OSINC)\winnetwk.h $(OSINC)\winnls.h \
+ $(OSINC)\winnt.h $(OSINC)\winperf.h $(OSINC)\winreg.h \
+ $(OSINC)\winsock.h $(OSINC)\winspool.h $(OSINC)\winsvc.h \
+ $(OSINC)\winuser.h $(OSINC)\winver.h .\stdpal.h
+
+$(OBJDIR)\suminfo.obj $(OBJDIR)\suminfo.lst: .\suminfo.cpp \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h \
+ .\..\release\variant.h .\suminfo.h .\wn_dos.h .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\targtdev.obj $(OBJDIR)\targtdev.lst: .\targtdev.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\ole2ui.h \
+ .\olestd.h
+
+$(OBJDIR)\template.obj $(OBJDIR)\template.lst: .\template.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\stdarg.h $(CRTINC)\string.h \
+ $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h \
+ $(OSINC)\dlgs.h $(OSINC)\drivinit.h $(OSINC)\lzexpand.h \
+ $(OSINC)\mmsystem.h $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h \
+ $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h \
+ $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h $(OSINC)\winbase.h \
+ $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \
+ $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winnetwk.h \
+ $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \
+ $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \
+ $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h .\common.h \
+ .\ole2ui.h .\olestd.h
+
+$(OBJDIR)\utility.obj $(OBJDIR)\utility.lst: .\utility.c \
+ $(CAIROLE)\h\export\coguid.h $(CAIROLE)\h\export\compobj.h \
+ $(CAIROLE)\h\export\dvobj.h $(CAIROLE)\h\export\initguid.h \
+ $(CAIROLE)\h\export\moniker.h $(CAIROLE)\h\export\ole2.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(CRTINC)\ctype.h $(CRTINC)\dos.h \
+ $(CRTINC)\excpt.h $(CRTINC)\memory.h $(CRTINC)\stdarg.h \
+ $(CRTINC)\stdlib.h $(CRTINC)\string.h $(OSINC)\cderr.h \
+ $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \
+ $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \
+ $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \
+ $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \
+ $(OSINC)\shellapi.h $(OSINC)\winbase.h $(OSINC)\wincon.h \
+ $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \
+ $(OSINC)\wingdi.h $(OSINC)\winnetwk.h $(OSINC)\winnls.h \
+ $(OSINC)\winnt.h $(OSINC)\winperf.h $(OSINC)\winreg.h \
+ $(OSINC)\winsock.h $(OSINC)\winspool.h $(OSINC)\winsvc.h \
+ $(OSINC)\winuser.h $(OSINC)\winver.h .\common.h .\geticon.h \
+ .\ole2ui.h .\olestd.h .\utility.h
+
diff --git a/private/oleutest/letest/ole2ui/dirs b/private/oleutest/letest/ole2ui/dirs
new file mode 100644
index 000000000..90a66698e
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/dirs
@@ -0,0 +1,3 @@
+DIRS=
+OPTIONAL_DIRS= daytona \
+
diff --git a/private/oleutest/letest/ole2ui/dllentry.c b/private/oleutest/letest/ole2ui/dllentry.c
new file mode 100644
index 000000000..1cd1159e4
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/dllentry.c
@@ -0,0 +1,55 @@
+//+-------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: dllentry.c
+//
+// Contents: Dll Entry point code. Calls the appropriate run-time
+// init/term code and then defers to LibMain for further
+// processing.
+//
+// Classes: <none>
+//
+// Functions: DllEntryPoint - Called by loader
+//
+// History: 10-May-92 BryanT Created
+// 22-Jul-92 BryanT Switch to calling _cexit/_mtdeletelocks
+// on cleanup.
+// 06-Oct-92 BryanT Call RegisterWithCommnot on entry
+// and DeRegisterWithCommnot on exit.
+// This should fix the heap dump code.
+// 27-Dec-93 AlexT Post 543 builds don't need special code.
+//
+//--------------------------------------------------------------------
+
+#define USE_CRTDLL
+#include <windows.h>
+
+BOOL WINAPI _CRT_INIT (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL _CRTAPI1 LibMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+ BOOL fRc = FALSE;
+
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ _CRT_INIT(hDll, dwReason, lpReserved);
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ _CRT_INIT(hDll, dwReason, lpReserved);
+ }
+
+ return(fRc);
+}
diff --git a/private/oleutest/letest/ole2ui/dllfuncs.c b/private/oleutest/letest/ole2ui/dllfuncs.c
new file mode 100644
index 000000000..283ca9d67
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/dllfuncs.c
@@ -0,0 +1,110 @@
+/*
+ * DLLFUNCS.C
+ *
+ * Contains entry and exit points for the DLL implementation
+ * of the OLE 2.0 User Interface Support Library.
+ *
+ * This file is not needed if we are linking the static library
+ * version of this library.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "uiclass.h"
+#include "common.h"
+
+OLEDBGDATA_MAIN("ole2u32a")
+
+
+/*
+ * LibMain
+ *
+ * Purpose:
+ * DLL-specific entry point called from LibEntry. Initializes
+ * the DLL's heap and registers the GizmoBar GizmoBar.
+ *
+ * Parameters:
+ * hInst HINSTANCE instance of the DLL.
+ * wDataSeg WORD segment selector of the DLL's data segment.
+ * wHeapSize WORD byte count of the heap.
+ * lpCmdLine LPSTR to command line used to start the module.
+ *
+ * Return Value:
+ * HANDLE Instance handle of the DLL.
+ *
+ */
+
+#ifdef WIN32
+
+BOOL _cdecl LibMain(
+ HINSTANCE hDll,
+ DWORD dwReason,
+ LPVOID lpvReserved)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ // Initialize OLE UI libraries. If you're linking with the static
+ // LIB version of this library, you need to make the below call in
+ // your application (because this LibMain won't be executed).
+ OleUIInitialize(hDll, (HINSTANCE)0, SZCLASSICONBOX, SZCLASSRESULTIMAGE);
+ }
+ else if (dwReason == DLL_PROCESS_DETACH)
+ {
+ OleUIUnInitialize();
+ }
+
+ return TRUE;
+}
+
+#else
+
+int FAR PASCAL LibMain(HINSTANCE hInst, WORD wDataSeg
+ , WORD cbHeapSize, LPTSTR lpCmdLine)
+ {
+ OleDbgOut2(TEXT("LibMain: OLE2UI.DLL loaded\r\n"));
+
+ // Initialize OLE UI libraries. If you're linking with the static LIB version
+ // of this library, you need to make the below call in your application (because
+ // this LibMain won't be executed).
+
+ // The symbols SZCLASSICONBOX and SZCLASSRESULTIMAGE are both defined
+ // in uiclass.h
+
+ OleUIInitialize(hInst, (HINSTANCE)0, TEXT(SZCLASSICONBOX), TEXT(SZCLASSRESULTIMAGE));
+
+ //All done...
+ if (0!=cbHeapSize)
+ UnlockData(0);
+
+ return (int)hInst;
+ }
+
+#endif
+
+/*
+ * WEP
+ *
+ * Purpose:
+ * Required DLL Exit function.
+ *
+ * Parameters:
+ * bSystemExit BOOL indicating if the system is being shut
+ * down or the DLL has just been unloaded.
+ *
+ * Return Value:
+ * void
+ *
+ */
+int CALLBACK EXPORT WEP(int bSystemExit)
+{
+ OleUIUnInitialize();
+ return 0;
+}
+
+
+
+
+
+
diff --git a/private/oleutest/letest/ole2ui/drawicon.c b/private/oleutest/letest/ole2ui/drawicon.c
new file mode 100644
index 000000000..06cdd3ab7
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/drawicon.c
@@ -0,0 +1,729 @@
+/*
+ * DRAWICON.C
+ *
+ * Functions to handle creation of metafiles with icons and labels
+ * as well as functions to draw such metafiles with or without the label.
+ *
+ * The metafile is created with a comment that marks the records containing
+ * the label code. Drawing the metafile enumerates the records, draws
+ * all records up to that point, then decides to either skip the label
+ * or draw it.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "common.h"
+#include "utility.h"
+#include "geticon.h"
+
+/*
+ * Strings for metafile comments. KEEP THESE IN SYNC WITH THE
+ * STRINGS IN GETICON.C.
+ */
+
+static TCHAR szIconOnly[]=TEXT("IconOnly"); //Where to stop to exclude label.
+
+
+
+
+/*
+ * OleUIMetafilePictIconFree
+ *
+ * Purpose:
+ * Deletes the metafile contained in a METAFILEPICT structure and
+ * frees the memory for the structure itself.
+ *
+ * Parameters:
+ * hMetaPict HGLOBAL metafilepict structure created in
+ * OleUIMetafilePictFromIconAndLabel
+ *
+ * Return Value:
+ * None
+ */
+
+STDAPI_(void) OleUIMetafilePictIconFree(HGLOBAL hMetaPict)
+ {
+ LPMETAFILEPICT pMF;
+
+ if (NULL==hMetaPict)
+ return;
+
+ pMF=(LPMETAFILEPICT)GlobalLock(hMetaPict);
+
+ if (NULL!=pMF)
+ {
+ if (NULL!=pMF->hMF)
+ DeleteMetaFile(pMF->hMF);
+ }
+
+ GlobalUnlock(hMetaPict);
+ GlobalFree(hMetaPict);
+ return;
+ }
+
+
+
+
+
+
+
+
+/*
+ * OleUIMetafilePictIconDraw
+ *
+ * Purpose:
+ * Draws the metafile from OleUIMetafilePictFromIconAndLabel, either with
+ * the label or without.
+ *
+ * Parameters:
+ * hDC HDC on which to draw.
+ * pRect LPRECT in which to draw the metafile.
+ * hMetaPict HGLOBAL to the METAFILEPICT from
+ * OleUIMetafilePictFromIconAndLabel
+ * fIconOnly BOOL specifying to draw the label or not.
+ *
+ * Return Value:
+ * BOOL TRUE if the function is successful, FALSE if the
+ * given metafilepict is invalid.
+ */
+
+STDAPI_(BOOL) OleUIMetafilePictIconDraw(HDC hDC, LPRECT pRect, HGLOBAL hMetaPict
+ , BOOL fIconOnly)
+ {
+ LPMETAFILEPICT pMF;
+ DRAWINFO di;
+ int cx, cy;
+ SIZE size;
+ POINT point;
+
+ if (NULL==hMetaPict)
+ return FALSE;
+
+ pMF=GlobalLock(hMetaPict);
+
+ if (NULL==pMF)
+ return FALSE;
+
+ di.Rect = *pRect;
+ di.fIconOnly = fIconOnly;
+
+ //Transform to back to pixels
+ cx=XformWidthInHimetricToPixels(hDC, pMF->xExt);
+ cy=XformHeightInHimetricToPixels(hDC, pMF->yExt);
+
+ SaveDC(hDC);
+
+ SetMapMode(hDC, pMF->mm);
+ SetViewportOrgEx(hDC, (pRect->right - cx) / 2, 0, &point);
+
+ SetViewportExtEx(hDC, min ((pRect->right - cx) / 2 + cx, cx), cy, &size);
+
+ if (fIconOnly)
+ {
+ // Since we've used the __export keyword on the
+ // EnumMetafileIconDraw proc, we do not need to use
+ // MakeProcInstance
+ EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileIconDraw
+ , (LPARAM)(LPDRAWINFO)&di);
+ }
+ else
+ PlayMetaFile(hDC, pMF->hMF);
+
+ RestoreDC(hDC, -1);
+
+ GlobalUnlock(hMetaPict);
+ return TRUE;
+ }
+
+
+
+
+/*
+ * EnumMetafileIconDraw
+ *
+ * Purpose:
+ * EnumMetaFile callback function that draws either the icon only or
+ * the icon and label depending on given flags.
+ *
+ * Parameters:
+ * hDC HDC into which the metafile should be played.
+ * phTable HANDLETABLE FAR * providing handles selected into the DC.
+ * pMFR METARECORD FAR * giving the enumerated record.
+ * lParam LPARAM flags passed in EnumMetaFile.
+ *
+ * Return Value:
+ * int 0 to stop enumeration, 1 to continue.
+ */
+
+int CALLBACK EXPORT EnumMetafileIconDraw(HDC hDC, HANDLETABLE FAR *phTable
+ , METARECORD FAR *pMFR, int cObj, LPARAM lParam)
+ {
+ LPDRAWINFO lpdi = (LPDRAWINFO)lParam;
+
+ /*
+ * We play everything blindly except for DIBBITBLT (or DIBSTRETCHBLT)
+ * and ESCAPE with MFCOMMENT. For the BitBlts we change the x,y to
+ * draw at (0,0) instead of wherever it was written to draw. The
+ * comment tells us there to stop if we don't want to draw the label.
+ */
+
+ //If we're playing icon only, stop enumeration at the comment.
+ if (lpdi->fIconOnly)
+ {
+ if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])
+ {
+ if (0==lstrcmpi(szIconOnly, (LPTSTR)&pMFR->rdParm[2]))
+ return 0;
+ }
+
+ /*
+ * Check for the records in which we want to munge the coordinates.
+ * destX is offset 6 for BitBlt, offset 9 for StretchBlt, either of
+ * which may appear in the metafile.
+ */
+ if (META_DIBBITBLT==pMFR->rdFunction)
+ pMFR->rdParm[6]=0;
+
+ if (META_DIBSTRETCHBLT==pMFR->rdFunction)
+ pMFR->rdParm[9] = 0;
+
+ }
+
+
+ PlayMetaFileRecord(hDC, phTable, pMFR, cObj);
+ return 1;
+ }
+
+
+
+
+
+/*
+ * OleUIMetafilePictExtractLabel
+ *
+ * Purpose:
+ * Retrieves the label string from metafile representation of an icon.
+ *
+ * Parameters:
+ * hMetaPict HGLOBAL to the METAFILEPICT containing the metafile.
+ * lpszLabel LPSTR in which to store the label.
+ * cchLabel UINT length of lpszLabel.
+ * lpWrapIndex DWORD index of first character in last line. Can be NULL
+ * if calling function doesn't care about word wrap.
+ *
+ * Return Value:
+ * UINT Number of characters copied.
+ */
+STDAPI_(UINT) OleUIMetafilePictExtractLabel(HGLOBAL hMetaPict, LPTSTR lpszLabel
+ , UINT cchLabel, LPDWORD lpWrapIndex)
+ {
+ LPMETAFILEPICT pMF;
+ LABELEXTRACT le;
+ HDC hDC;
+
+ /*
+ * We extract the label by getting a screen DC and walking the metafile
+ * records until we see the ExtTextOut record we put there. That
+ * record will have the string embedded in it which we then copy out.
+ */
+
+ if (NULL==hMetaPict || NULL==lpszLabel || 0==cchLabel)
+ return FALSE;
+
+ pMF=GlobalLock(hMetaPict);
+
+ if (NULL==pMF)
+ return FALSE;
+
+ le.lpsz=lpszLabel;
+ le.u.cch=cchLabel;
+ le.Index=0;
+ le.fFoundIconOnly=FALSE;
+ le.fFoundSource=FALSE; //Unused for this function.
+ le.fFoundIndex=FALSE; //Unused for this function.
+ le.PrevIndex = 0;
+
+ //Use a screen DC so we have something valid to pass in.
+ hDC=GetDC(NULL);
+
+ // Since we've used the EXPORT keyword on the
+ // EnumMetafileExtractLabel proc, we do not need to use
+ // MakeProcInstance
+
+ EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractLabel, (LONG)(LPLABELEXTRACT)&le);
+
+ ReleaseDC(NULL, hDC);
+
+ GlobalUnlock(hMetaPict);
+
+ //Tell where we wrapped (if calling function cares)
+ if (NULL != lpWrapIndex)
+ *lpWrapIndex = le.PrevIndex;
+
+ //Return amount of text copied
+ return le.u.cch;
+ }
+
+
+
+
+
+/*
+ * EnumMetafileExtractLabel
+ *
+ * Purpose:
+ * EnumMetaFile callback function that walks a metafile looking for
+ * ExtTextOut, then concatenates the text from each one into a buffer
+ * in lParam.
+ *
+ * Parameters:
+ * hDC HDC into which the metafile should be played.
+ * phTable HANDLETABLE FAR * providing handles selected into the DC.
+ * pMFR METARECORD FAR * giving the enumerated record.
+ * pLE LPLABELEXTRACT providing the destination buffer and length.
+ *
+ * Return Value:
+ * int 0 to stop enumeration, 1 to continue.
+ */
+
+int CALLBACK EXPORT EnumMetafileExtractLabel(HDC hDC, HANDLETABLE FAR *phTable
+ , METARECORD FAR *pMFR, int cObj, LPLABELEXTRACT pLE)
+ {
+
+ /*
+ * We don't allow anything to happen until we see "IconOnly"
+ * in an MFCOMMENT that is used to enable everything else.
+ */
+ if (!pLE->fFoundIconOnly)
+ {
+ if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])
+ {
+ if (0==lstrcmpi(szIconOnly, (LPTSTR)&pMFR->rdParm[2]))
+ pLE->fFoundIconOnly=TRUE;
+ }
+
+ return 1;
+ }
+
+ //Enumerate all records looking for META_EXTTEXTOUT - there can be more
+ //than one.
+ if (META_EXTTEXTOUT==pMFR->rdFunction)
+ {
+ UINT cchMax;
+ LPTSTR lpszTemp;
+
+ /*
+ * If ExtTextOut has NULL fuOptions, then the rectangle is omitted
+ * from the record, and the string starts at rdParm[4]. If
+ * fuOptions is non-NULL, then the string starts at rdParm[8]
+ * (since the rectange takes up four WORDs in the array). In
+ * both cases, the string continues for (rdParm[2]+1) >> 1
+ * words. We just cast a pointer to rdParm[8] to an LPSTR and
+ * lstrcpyn into the buffer we were given.
+ *
+ * Note that we use element 8 in rdParm instead of 4 because we
+ * passed ETO_CLIPPED in for the options on ExtTextOut--docs say
+ * [4] which is rect doesn't exist if we passed zero there.
+ *
+ */
+
+ cchMax=min(pLE->u.cch - pLE->Index, (UINT)pMFR->rdParm[2]);
+ lpszTemp = pLE->lpsz + pLE->Index;
+
+ lstrcpyn(lpszTemp, (LPTSTR)&(pMFR->rdParm[8]), cchMax + 1);
+// lstrcpyn(lpszTemp, (LPTSTR)&(pMFR->rdParm[4]), cchMax + 1);
+
+ pLE->PrevIndex = pLE->Index;
+
+ pLE->Index += cchMax;
+ }
+
+ return 1;
+ }
+
+
+
+
+
+/*
+ * OleUIMetafilePictExtractIcon
+ *
+ * Purpose:
+ * Retrieves the icon from metafile into which DrawIcon was done before.
+ *
+ * Parameters:
+ * hMetaPict HGLOBAL to the METAFILEPICT containing the metafile.
+ *
+ * Return Value:
+ * HICON Icon recreated from the data in the metafile.
+ */
+STDAPI_(HICON) OleUIMetafilePictExtractIcon(HGLOBAL hMetaPict)
+ {
+ LPMETAFILEPICT pMF;
+ HDC hDC;
+ ICONEXTRACT ie;
+
+ /*
+ * We extract the label by getting a screen DC and walking the metafile
+ * records until we see the ExtTextOut record we put there. That
+ * record will have the string embedded in it which we then copy out.
+ */
+
+ if (NULL==hMetaPict)
+ return NULL;
+
+ pMF=GlobalLock(hMetaPict);
+
+ if (NULL==pMF)
+ return FALSE;
+
+ //Use a screen DC so we have something valid to pass in.
+ hDC=GetDC(NULL);
+ ie.fAND=TRUE;
+
+ // We get information back in the ICONEXTRACT structure.
+ // (Since we've used the EXPORT keyword on the
+ // EnumMetafileExtractLabel proc, we do not need to use
+ // MakeProcInstance)
+ EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractIcon, (LONG)(LPICONEXTRACT)&ie);
+
+ ReleaseDC(NULL, hDC);
+ GlobalUnlock(hMetaPict);
+
+ return ie.hIcon;
+ }
+
+
+
+
+
+/*
+ * EnumMetafileExtractIcon
+ *
+ * Purpose:
+ * EnumMetaFile callback function that walks a metafile looking for
+ * StretchBlt (3.1) and BitBlt (3.0) records. We expect to see two
+ * of them, the first being the AND mask and the second being the XOR
+ * data. We
+ * ExtTextOut, then copies the text into a buffer in lParam.
+ *
+ * Parameters:
+ * hDC HDC into which the metafile should be played.
+ * phTable HANDLETABLE FAR * providing handles selected into the DC.
+ * pMFR METARECORD FAR * giving the enumerated record.
+ * pIE LPICONEXTRACT providing the destination buffer and length.
+ *
+ * Return Value:
+ * int 0 to stop enumeration, 1 to continue.
+ */
+
+int CALLBACK EXPORT EnumMetafileExtractIcon(HDC hDC, HANDLETABLE FAR *phTable
+ , METARECORD FAR *pMFR, int cObj, LPICONEXTRACT pIE)
+ {
+ LPBITMAPINFO lpBI;
+ LPBITMAPINFOHEADER lpBH;
+ LPBYTE lpbSrc;
+ LPBYTE lpbDst;
+ UINT uWidth, uHeight;
+ DWORD cb;
+ HGLOBAL hMem;
+ BITMAP bm;
+ HBITMAP hBmp;
+ int cxIcon, cyIcon;
+
+
+ //Continue enumeration if we don't see the records we want.
+ if (META_DIBBITBLT!=pMFR->rdFunction && META_DIBSTRETCHBLT!=pMFR->rdFunction)
+ return 1;
+
+ /*
+ * Windows 3.0 DrawIcon uses META_DIBBITBLT in whereas 3.1 uses
+ * META_DIBSTRETCHBLT so we have to handle each case separately.
+ */
+
+ if (META_DIBBITBLT==pMFR->rdFunction) //Win3.0
+ {
+ //Get dimensions and the BITMAPINFO struct.
+ uHeight=pMFR->rdParm[1];
+ uWidth =pMFR->rdParm[2];
+ lpBI=(LPBITMAPINFO)&(pMFR->rdParm[8]);
+ }
+
+ if (META_DIBSTRETCHBLT==pMFR->rdFunction) //Win3.1
+ {
+ //Get dimensions and the BITMAPINFO struct.
+ uHeight=pMFR->rdParm[2];
+ uWidth =pMFR->rdParm[3];
+ lpBI=(LPBITMAPINFO)&(pMFR->rdParm[10]);
+ }
+
+ lpBH=(LPBITMAPINFOHEADER)&(lpBI->bmiHeader);
+
+ //Pointer to the bits which follows the BITMAPINFO structure.
+ lpbSrc=(LPBYTE)lpBI+sizeof(BITMAPINFOHEADER);
+
+ //Add the length of the color table (if one exists)
+
+ if (0!=lpBH->biClrUsed)
+ {
+ // If we have an explicit count of colors used, we
+ // can find the offset to the data directly
+
+ lpbSrc += (lpBH->biClrUsed*sizeof(RGBQUAD));
+ }
+ else if (lpBH->biCompression == BI_BITFIELDS)
+ {
+ // 16 or 32 bpp, indicated by BI_BITFIELDS in the compression
+ // field, have 3 DWORD masks for adjusting subsequent
+ // direct-color values, and no palette
+
+ lpbSrc += 3 * sizeof(DWORD);
+ }
+ else
+ {
+ // In other cases, there is an array of RGBQUAD entries
+ // equal to 2^(biBitCount) where biBitCount is the number
+ // of bits per pixel. The exception is 24 bpp bitmaps,
+ // which have no color table and just use direct RGB values.
+
+ lpbSrc+=
+ (lpBH->biBitCount == 24) ? 0 :
+ (1 << (lpBH->biBitCount)) * sizeof(RGBQUAD);
+ }
+
+
+ /*
+ * All the bits we have in lpbSrc are device-independent, so we
+ * need to change them over to be device-dependent using SetDIBits.
+ * Once we have a bitmap with the device-dependent bits, we can
+ * GetBitmapBits to have buffers with the real data.
+ *
+ * For each pass we have to allocate memory for the bits. We save
+ * the memory for the mask between passes.
+ */
+
+ //Use CreateBitmap for ANY monochrome bitmaps
+ if (pIE->fAND || 1==lpBH->biBitCount || lpBH->biBitCount > 8)
+ hBmp=CreateBitmap((UINT)lpBH->biWidth, (UINT)lpBH->biHeight, 1, 1, NULL);
+ else if (lpBH->biBitCount <= 8)
+ hBmp=CreateCompatibleBitmap(hDC, (UINT)lpBH->biWidth, (UINT)lpBH->biHeight);
+
+ if (!hBmp || !SetDIBits(hDC, hBmp, 0, (UINT)lpBH->biHeight, (LPVOID)lpbSrc, lpBI, DIB_RGB_COLORS))
+ {
+ if (!pIE->fAND)
+ GlobalFree(pIE->hMemAND);
+
+ DeleteObject(hBmp);
+ return 0;
+ }
+
+ //Allocate memory and get the DDBits into it.
+ GetObject(hBmp, sizeof(bm), &bm);
+
+ cb=bm.bmHeight*bm.bmWidthBytes * bm.bmPlanes;
+
+// if (cb % 4 != 0) // dword align
+// cb += 4 - (cb % 4);
+
+ hMem=GlobalAlloc(GHND, cb);
+
+ if (NULL==hMem)
+ {
+ if (NULL!=pIE->hMemAND)
+ GlobalFree(pIE->hMemAND);
+
+ DeleteObject(hBmp);
+ return 0;
+ }
+
+ lpbDst=(LPBYTE)GlobalLock(hMem);
+ GetBitmapBits(hBmp, cb, (LPVOID)lpbDst);
+
+ DeleteObject(hBmp);
+ GlobalUnlock(hMem);
+
+
+ /*
+ * If this is the first pass (pIE->fAND==TRUE) then save the memory
+ * of the AND bits for the next pass.
+ */
+ if (pIE->fAND)
+ {
+ pIE->fAND=FALSE;
+ pIE->hMemAND=hMem;
+
+ //Continue enumeration looking for the next blt record.
+ return 1;
+ }
+ else
+ {
+ //Get the AND pointer again.
+ lpbSrc=(LPBYTE)GlobalLock(pIE->hMemAND);
+
+ /*
+ * Create the icon now that we have all the data. lpbDst already
+ * points to the XOR bits.
+ */
+ cxIcon = GetSystemMetrics(SM_CXICON);
+ cyIcon = GetSystemMetrics(SM_CYICON);
+
+ pIE->hIcon=CreateIcon(ghInst,
+ uWidth,
+ uHeight,
+ (BYTE)bm.bmPlanes,
+ (BYTE)bm.bmBitsPixel,
+ (LPVOID)lpbSrc,
+ (LPVOID)lpbDst);
+
+ GlobalUnlock(pIE->hMemAND);
+ GlobalFree(pIE->hMemAND);
+ GlobalFree(hMem);
+
+ //We're done so we can stop.
+ return 0;
+ }
+ }
+
+
+
+
+
+/*
+ * OleUIMetafilePictExtractIconSource
+ *
+ * Purpose:
+ * Retrieves the filename and index of the icon source from a metafile
+ * created with OleUIMetafilePictFromIconAndLabel.
+ *
+ * Parameters:
+ * hMetaPict HGLOBAL to the METAFILEPICT containing the metafile.
+ * lpszSource LPTSTR in which to store the source filename. This
+ * buffer should be OLEUI_CCHPATHMAX characters.
+ * piIcon UINT FAR * in which to store the icon's index
+ * within lpszSource
+ *
+ * Return Value:
+ * BOOL TRUE if the records were found, FALSE otherwise.
+ */
+STDAPI_(BOOL) OleUIMetafilePictExtractIconSource(HGLOBAL hMetaPict
+ , LPTSTR lpszSource, UINT FAR *piIcon)
+ {
+ LPMETAFILEPICT pMF;
+ LABELEXTRACT le;
+ HDC hDC;
+
+ /*
+ * We will walk the metafile looking for the two comment records
+ * following the IconOnly comment. The flags fFoundIconOnly and
+ * fFoundSource indicate if we have found IconOnly and if we have
+ * found the source comment already.
+ */
+
+ if (NULL==hMetaPict || NULL==lpszSource || NULL==piIcon)
+ return FALSE;
+
+ pMF=GlobalLock(hMetaPict);
+
+ if (NULL==pMF)
+ return FALSE;
+
+ le.lpsz=lpszSource;
+ le.fFoundIconOnly=FALSE;
+ le.fFoundSource=FALSE;
+ le.fFoundIndex=FALSE;
+
+ //Use a screen DC so we have something valid to pass in.
+ hDC=GetDC(NULL);
+
+ EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractIconSource, (LONG)(LPLABELEXTRACT)&le);
+
+ ReleaseDC(NULL, hDC);
+ GlobalUnlock(hMetaPict);
+
+ //Copy the icon index to the caller's variable.
+ *piIcon=le.u.iIcon;
+
+ //Check that we found everything.
+ return (le.fFoundIconOnly && le.fFoundSource && le.fFoundIndex);
+ }
+
+
+
+
+
+/*
+ * EnumMetafileExtractIconSource
+ *
+ * Purpose:
+ * EnumMetaFile callback function that walks a metafile skipping the first
+ * comment record, extracting the source filename from the second, and
+ * the index of the icon in the third.
+ *
+ * Parameters:
+ * hDC HDC into which the metafile should be played.
+ * phTable HANDLETABLE FAR * providing handles selected into the DC.
+ * pMFR METARECORD FAR * giving the enumerated record.
+ * pLE LPLABELEXTRACT providing the destination buffer and
+ * area to store the icon index.
+ *
+ * Return Value:
+ * int 0 to stop enumeration, 1 to continue.
+ */
+
+int CALLBACK EXPORT EnumMetafileExtractIconSource(HDC hDC, HANDLETABLE FAR *phTable
+ , METARECORD FAR *pMFR, int cObj, LPLABELEXTRACT pLE)
+ {
+ LPTSTR psz;
+
+ /*
+ * We don't allow anything to happen until we see "IconOnly"
+ * in an MFCOMMENT that is used to enable everything else.
+ */
+ if (!pLE->fFoundIconOnly)
+ {
+ if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])
+ {
+ if (0==lstrcmpi(szIconOnly, (LPTSTR)&pMFR->rdParm[2]))
+ pLE->fFoundIconOnly=TRUE;
+ }
+
+ return 1;
+ }
+
+ //Now see if we find the source string.
+ if (!pLE->fFoundSource)
+ {
+ if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])
+ {
+ LSTRCPYN(pLE->lpsz, (LPTSTR)&pMFR->rdParm[2], OLEUI_CCHPATHMAX);
+ pLE->lpsz[OLEUI_CCHPATHMAX-1] = TEXT('\0');
+ pLE->fFoundSource=TRUE;
+ }
+
+ return 1;
+ }
+
+ //Next comment will be the icon index.
+ if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])
+ {
+ /*
+ * This string contains the icon index in string form,
+ * so we need to convert back to a UINT. After we see this
+ * we can stop the enumeration. The comment will have
+ * a null terminator because we made sure to save it.
+ */
+ psz=(LPTSTR)&pMFR->rdParm[2];
+ pLE->u.iIcon=0;
+
+ //Do Ye Olde atoi
+ while (*psz)
+ pLE->u.iIcon=(10*pLE->u.iIcon)+((*psz++)-'0');
+
+ pLE->fFoundIndex=TRUE;
+ return 0;
+ }
+
+ return 1;
+ }
diff --git a/private/oleutest/letest/ole2ui/edlinks.h b/private/oleutest/letest/ole2ui/edlinks.h
new file mode 100644
index 000000000..db721f47f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/edlinks.h
@@ -0,0 +1,135 @@
+/*
+ * EDLINKS.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI Edit Links dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _LINKS_H_
+#define _LINKS_H_
+
+//INTERNAL INFORMATION STARTS HERE
+#define OLEUI_SZMAX 255
+#define LINKTYPELEN 9
+#define szNULL TEXT("\0")
+
+typedef UINT (CALLBACK* COMMDLGHOOKPROC)(HWND, UINT, WPARAM, LPARAM);
+
+//Internally used structure
+
+typedef struct tagLINKINFO
+ {
+ DWORD dwLink; // app specific identifier of a link
+ LPTSTR lpszDisplayName; // file based part of name
+ LPTSTR lpszItemName; // object part of name
+ LPTSTR lpszShortFileName; // filename without path
+ LPTSTR lpszShortLinkType; // Short link type - progID
+ LPTSTR lpszFullLinkType; // Full link type - user friendly name
+ LPTSTR lpszAMX; // Is the link auto (A) man (M) or dead (X)
+ ULONG clenFileName; // count of file part of mon.
+ BOOL fSourceAvailable; // bound or not - on boot assume yes??
+ BOOL fIsAuto; // 1 =automatic, 0=manual update
+ BOOL fIsMarked; // 1 = marked, 0 = not
+ BOOL fDontFree; // Don't free this data since it's being reused
+ BOOL fIsSelected; // item selected or to be selected
+ } LINKINFO, FAR* LPLINKINFO;
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog but that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+
+typedef struct tagEDITLINKS
+ {
+ //Keep this item first as the Standard* functions depend on it here.
+
+ LPOLEUIEDITLINKS lpOEL; //Original structure passed.
+
+ BOOL fClose; // Does the button read cancel (0) or
+ // close (1)?
+ int *rgIndex; // Array to hold indexes of selected items
+ int cSelItems; // Number of selected items
+ BOOL fItemsExist; // TRUE, items in lbox, FALSE, none
+ UINT nChgSrcHelpID; // ID for Help callback from ChangeSrc dlg
+ TCHAR szClose[50]; // Text for Close button
+ // (when Cancel button gets renamed)
+} EDITLINKS, *PEDITLINKS, FAR *LPEDITLINKS;
+
+// Data to and from the ChangeSource dialog hook
+typedef struct tagOLEUICHANGESOURCEHOOKDATA
+{
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUIINSERTOBJECT. All are IN-OUT unless otherwise spec.
+ LPLINKINFO lpLI; // IN: ptr to LinkInfo entry
+ LPEDITLINKS lpEL; // IN: ptr to EditLinks dialog struct
+ BOOL fValidLink; // OUT: was link source validated
+ LPTSTR lpszFrom; // OUT: string containing prefix of
+ // source changed from
+ LPTSTR lpszTo; // OUT: string containing prefix of
+ // source changed to
+} OLEUICHANGESOURCEHOOKDATA, *POLEUICHANGESOURCEHOOKDATA,
+ FAR *LPOLEUICHANGESOURCEHOOKDATA;
+
+
+// Data to and from the ChangeSource dialog hook
+typedef struct tagCHANGESOURCEHOOKDATA
+{
+ LPOLEUICHANGESOURCEHOOKDATA lpOCshData; //Original structure passed.
+ LPOPENFILENAME lpOfn;
+ BOOL fValidLink;
+ int nFileLength;
+ int nEditLength;
+ TCHAR szFileName[OLEUI_CCHPATHMAX];
+ TCHAR szItemName[OLEUI_CCHPATHMAX];
+ BOOL bFileNameStored;
+ BOOL bItemNameStored;
+ TCHAR szEdit[OLEUI_CCHPATHMAX];
+ LPTSTR lpszFrom; // string containing prefix of source
+ // changed from
+ LPTSTR lpszTo; // string containing prefix of source
+ // source changed to
+} CHANGESOURCEHOOKDATA, *PCHANGESOURCEHOOKDATA, FAR *LPCHANGESOURCEHOOKDATA;
+
+
+//Internal function prototypes
+//LINKS.C
+BOOL CALLBACK EXPORT EditLinksDialogProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FEditLinksInit(HWND, WPARAM, LPARAM);
+BOOL Container_ChangeSource(HWND, LPEDITLINKS);
+HRESULT Container_AutomaticManual(HWND, BOOL, LPEDITLINKS);
+HRESULT CancelLink(HWND, LPEDITLINKS);
+HRESULT Container_UpdateNow(HWND, LPEDITLINKS);
+HRESULT Container_OpenSource(HWND, LPEDITLINKS);
+int AddLinkLBItem(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPLINKINFO lpLI, BOOL fGetSelected);
+VOID BreakString(LPLINKINFO);
+int GetSelectedItems(HWND, int FAR* FAR*);
+BOOL WINAPI ChangeSource(HWND hWndOwner,
+ LPTSTR lpszFile,
+ UINT cchFile,
+ UINT iFilterString,
+ COMMDLGHOOKPROC lpfnBrowseHook,
+ LPOLEUICHANGESOURCEHOOKDATA lpLbhData);
+UINT CALLBACK EXPORT ChangeSourceHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+VOID InitControls(HWND hDlg, LPEDITLINKS lpEL);
+VOID UpdateLinkLBItem(HWND hListBox, int nIndex, LPEDITLINKS lpEL, BOOL bSelect);
+VOID DiffPrefix(LPCTSTR lpsz1, LPCTSTR lpsz2, TCHAR FAR* FAR* lplpszPrefix1, TCHAR FAR* FAR* lplpszPrefix2);
+int PopupMessage(HWND hwndParent, UINT idTitle, UINT idMessage, UINT fuStyle);
+VOID ChangeAllLinks(HWND hLIstBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPTSTR lpszFrom, LPTSTR lpszTo);
+int LoadLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr);
+VOID RefreshLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr);
+#endif // __LINKS_H__
diff --git a/private/oleutest/letest/ole2ui/egares.bmp b/private/oleutest/letest/ole2ui/egares.bmp
new file mode 100644
index 000000000..e9dbb065a
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/egares.bmp
Binary files differ
diff --git a/private/oleutest/letest/ole2ui/enumfetc.c b/private/oleutest/letest/ole2ui/enumfetc.c
new file mode 100644
index 000000000..15a6b3a90
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/enumfetc.c
@@ -0,0 +1,308 @@
+/*************************************************************************
+**
+** OLE 2 Utility Code
+**
+** enumfetc.c
+**
+** This file contains a standard implementation of IEnumFormatEtc
+** interface.
+** This file is part of the OLE 2.0 User Interface support library.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "enumfetc.h"
+
+
+typedef struct tagOleStdEnumFmtEtc {
+ IEnumFORMATETCVtbl FAR* lpVtbl;
+ ULONG m_dwRefs; /* referance count */
+ ULONG m_nIndex; /* current index in list */
+ ULONG m_nCount; /* how many items in list */
+ LPFORMATETC m_lpEtc; /* list of formatetc */
+} OLESTDENUMFMTETC, FAR* LPOLESTDENUMFMTETC;
+
+VOID OleStdEnumFmtEtc_Destroy(LPOLESTDENUMFMTETC pEtc);
+
+STDMETHODIMP OleStdEnumFmtEtc_QueryInterface(
+ LPENUMFORMATETC lpThis, REFIID riid, LPVOID FAR* ppobj);
+STDMETHODIMP_(ULONG) OleStdEnumFmtEtc_AddRef(LPENUMFORMATETC lpThis);
+STDMETHODIMP_(ULONG) OleStdEnumFmtEtc_Release(LPENUMFORMATETC lpThis);
+STDMETHODIMP OleStdEnumFmtEtc_Next(LPENUMFORMATETC lpThis, ULONG celt,
+ LPFORMATETC rgelt, ULONG FAR* pceltFetched);
+STDMETHODIMP OleStdEnumFmtEtc_Skip(LPENUMFORMATETC lpThis, ULONG celt);
+STDMETHODIMP OleStdEnumFmtEtc_Reset(LPENUMFORMATETC lpThis);
+STDMETHODIMP OleStdEnumFmtEtc_Clone(LPENUMFORMATETC lpThis,
+ LPENUMFORMATETC FAR* ppenum);
+
+static IEnumFORMATETCVtbl g_EnumFORMATETCVtbl = {
+ OleStdEnumFmtEtc_QueryInterface,
+ OleStdEnumFmtEtc_AddRef,
+ OleStdEnumFmtEtc_Release,
+ OleStdEnumFmtEtc_Next,
+ OleStdEnumFmtEtc_Skip,
+ OleStdEnumFmtEtc_Reset,
+ OleStdEnumFmtEtc_Clone,
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+STDAPI_(LPENUMFORMATETC)
+ OleStdEnumFmtEtc_Create(ULONG nCount, LPFORMATETC lpEtc)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPMALLOC lpMalloc=NULL;
+ LPOLESTDENUMFMTETC lpEF=NULL;
+ DWORD dwSize;
+ WORD i;
+ HRESULT hRes;
+
+ hRes = CoGetMalloc(MEMCTX_TASK, &lpMalloc);
+ if (hRes != NOERROR) {
+ return NULL;
+ }
+
+ lpEF = (LPOLESTDENUMFMTETC)lpMalloc->lpVtbl->Alloc(lpMalloc,
+ sizeof(OLESTDENUMFMTETC));
+ if (lpEF == NULL) {
+ goto errReturn;
+ }
+
+ lpEF->lpVtbl = &g_EnumFORMATETCVtbl;
+ lpEF->m_dwRefs = 1;
+ lpEF->m_nCount = nCount;
+ lpEF->m_nIndex = 0;
+
+ dwSize = sizeof(FORMATETC) * lpEF->m_nCount;
+
+ lpEF->m_lpEtc = (LPFORMATETC)lpMalloc->lpVtbl->Alloc(lpMalloc, dwSize);
+ if (lpEF->m_lpEtc == NULL)
+ goto errReturn;
+
+ lpMalloc->lpVtbl->Release(lpMalloc);
+
+ for (i=0; i<nCount; i++) {
+ OleStdCopyFormatEtc(
+ (LPFORMATETC)&(lpEF->m_lpEtc[i]), (LPFORMATETC)&(lpEtc[i]));
+ }
+
+ return (LPENUMFORMATETC)lpEF;
+
+errReturn:
+ if (lpEF != NULL)
+ lpMalloc->lpVtbl->Free(lpMalloc, lpEF);
+
+ if (lpMalloc != NULL)
+ lpMalloc->lpVtbl->Release(lpMalloc);
+
+ return NULL;
+
+} /* OleStdEnumFmtEtc_Create()
+ */
+
+
+VOID
+ OleStdEnumFmtEtc_Destroy(LPOLESTDENUMFMTETC lpEF)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPMALLOC lpMalloc=NULL;
+ WORD i;
+
+ if (lpEF != NULL) {
+
+ if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) == NOERROR) {
+
+ /* OLE2NOTE: we MUST free any memory that was allocated for
+ ** TARGETDEVICES contained within the FORMATETC elements.
+ */
+ for (i=0; i<lpEF->m_nCount; i++) {
+ OleStdFree(lpEF->m_lpEtc[i].ptd);
+ }
+
+ if (lpEF->m_lpEtc != NULL) {
+ lpMalloc->lpVtbl->Free(lpMalloc, lpEF->m_lpEtc);
+ }
+
+ lpMalloc->lpVtbl->Free(lpMalloc, lpEF);
+ lpMalloc->lpVtbl->Release(lpMalloc);
+ }
+ }
+} /* OleStdEnumFmtEtc_Destroy()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumFmtEtc_QueryInterface(
+ LPENUMFORMATETC lpThis, REFIID riid, LPVOID FAR* ppobj)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+ *ppobj = NULL;
+
+ if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IEnumFORMATETC)){
+ *ppobj = (LPVOID)lpEF;
+ }
+
+ if (*ppobj == NULL) return ResultFromScode(E_NOINTERFACE);
+ else{
+ OleStdEnumFmtEtc_AddRef(lpThis);
+ return NOERROR;
+ }
+
+} /* OleStdEnumFmtEtc_QueryInterface()
+ */
+
+
+STDMETHODIMP_(ULONG)
+ OleStdEnumFmtEtc_AddRef(LPENUMFORMATETC lpThis)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+ return lpEF->m_dwRefs++;
+
+} /* OleStdEnumFmtEtc_AddRef()
+ */
+
+
+STDMETHODIMP_(ULONG)
+ OleStdEnumFmtEtc_Release(LPENUMFORMATETC lpThis)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+ DWORD dwRefs = --lpEF->m_dwRefs;
+
+ if (dwRefs == 0)
+ OleStdEnumFmtEtc_Destroy(lpEF);
+
+ return dwRefs;
+
+} /* OleStdEnumFmtEtc_Release()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumFmtEtc_Next(LPENUMFORMATETC lpThis, ULONG celt, LPFORMATETC rgelt,
+ ULONG FAR* pceltFetched)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+ ULONG i=0;
+ ULONG nOffset;
+
+ if (rgelt == NULL) {
+ return ResultFromScode(E_INVALIDARG);
+ }
+
+ while (i < celt) {
+ nOffset = lpEF->m_nIndex + i;
+
+ if (nOffset < lpEF->m_nCount) {
+ OleStdCopyFormatEtc(
+ (LPFORMATETC)&(rgelt[i]), (LPFORMATETC)&(lpEF->m_lpEtc[nOffset]));
+ i++;
+ }else{
+ break;
+ }
+ }
+
+ lpEF->m_nIndex += (WORD)i;
+
+ if (pceltFetched != NULL) {
+ *pceltFetched = i;
+ }
+
+ if (i != celt) {
+ return ResultFromScode(S_FALSE);
+ }
+
+ return NOERROR;
+} /* OleStdEnumFmtEtc_Next()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumFmtEtc_Skip(LPENUMFORMATETC lpThis, ULONG celt)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+ ULONG i=0;
+ ULONG nOffset;
+
+ while (i < celt) {
+ nOffset = lpEF->m_nIndex + i;
+
+ if (nOffset < lpEF->m_nCount) {
+ i++;
+ }else{
+ break;
+ }
+ }
+
+ lpEF->m_nIndex += (WORD)i;
+
+ if (i != celt) {
+ return ResultFromScode(S_FALSE);
+ }
+
+ return NOERROR;
+} /* OleStdEnumFmtEtc_Skip()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumFmtEtc_Reset(LPENUMFORMATETC lpThis)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+ lpEF->m_nIndex = 0;
+
+ return NOERROR;
+} /* OleStdEnumFmtEtc_Reset()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumFmtEtc_Clone(LPENUMFORMATETC lpThis, LPENUMFORMATETC FAR* ppenum)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;
+
+ if (ppenum == NULL) {
+ return ResultFromScode(E_INVALIDARG);
+ }
+
+ *ppenum = OleStdEnumFmtEtc_Create(lpEF->m_nCount, lpEF->m_lpEtc);
+
+ // make sure cloned enumerator has same index state as the original
+ if (*ppenum) {
+ LPOLESTDENUMFMTETC lpEFClone = (LPOLESTDENUMFMTETC)*ppenum;
+ lpEFClone->m_nIndex = lpEF->m_nIndex;
+ return NOERROR;
+ } else
+ return ResultFromScode(E_OUTOFMEMORY);
+
+} /* OleStdEnumFmtEtc_Clone()
+ */
+
diff --git a/private/oleutest/letest/ole2ui/enumfetc.h b/private/oleutest/letest/ole2ui/enumfetc.h
new file mode 100644
index 000000000..60b82d151
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/enumfetc.h
@@ -0,0 +1,13 @@
+// This file is now OBSOLETE (include olestd.h instead)
+
+/*************************************************************************
+**
+** OLE 2 Utility Code
+**
+** enumfetc.c
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+// Function prototypes moved to olestd.h
diff --git a/private/oleutest/letest/ole2ui/enumstat.c b/private/oleutest/letest/ole2ui/enumstat.c
new file mode 100644
index 000000000..17a42048f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/enumstat.c
@@ -0,0 +1,336 @@
+/*************************************************************************
+**
+** OLE 2 Utility Code
+**
+** enumstat.c
+**
+** This file contains a standard implementation of IEnumStatData
+** interface.
+** This file is part of the OLE 2.0 User Interface support library.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#define STRICT 1
+#include "ole2ui.h"
+
+
+typedef struct tagOleStdEnumStatData {
+ IEnumSTATDATAVtbl FAR* lpVtbl;
+ ULONG m_dwRefs; /* referance count */
+ ULONG m_nIndex; /* current index in list */
+ ULONG m_nCount; /* how many items in list */
+ LPSTATDATA m_lpStat; /* list of STATDATA */
+} OLESTDENUMSTATDATA, FAR* LPOLESTDENUMSTATDATA;
+
+VOID OleStdEnumStatData_Destroy(LPOLESTDENUMSTATDATA pStat);
+
+STDMETHODIMP OleStdEnumStatData_QueryInterface(
+ LPENUMSTATDATA lpThis, REFIID riid, LPVOID FAR* ppobj);
+STDMETHODIMP_(ULONG) OleStdEnumStatData_AddRef(LPENUMSTATDATA lpThis);
+STDMETHODIMP_(ULONG) OleStdEnumStatData_Release(LPENUMSTATDATA lpThis);
+STDMETHODIMP OleStdEnumStatData_Next(LPENUMSTATDATA lpThis, ULONG celt,
+ LPSTATDATA rgelt, ULONG FAR* pceltFetched);
+STDMETHODIMP OleStdEnumStatData_Skip(LPENUMSTATDATA lpThis, ULONG celt);
+STDMETHODIMP OleStdEnumStatData_Reset(LPENUMSTATDATA lpThis);
+STDMETHODIMP OleStdEnumStatData_Clone(LPENUMSTATDATA lpThis,
+ LPENUMSTATDATA FAR* ppenum);
+
+static IEnumSTATDATAVtbl g_EnumSTATDATAVtbl = {
+ OleStdEnumStatData_QueryInterface,
+ OleStdEnumStatData_AddRef,
+ OleStdEnumStatData_Release,
+ OleStdEnumStatData_Next,
+ OleStdEnumStatData_Skip,
+ OleStdEnumStatData_Reset,
+ OleStdEnumStatData_Clone,
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+STDAPI_(BOOL)
+ OleStdCopyStatData(LPSTATDATA pDest, LPSTATDATA pSrc)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ if ((pDest == NULL) || (pSrc == NULL)) {
+ return FALSE;
+ }
+
+ if (OleStdCopyFormatEtc(&pDest->formatetc, &pSrc->formatetc) == FALSE) {
+ return FALSE;
+ }
+
+ pDest->advf = pSrc->advf;
+ pDest->pAdvSink = pSrc->pAdvSink;
+ pDest->dwConnection = pSrc->dwConnection;
+
+ if (pDest->pAdvSink != NULL) {
+ pDest->pAdvSink->lpVtbl->AddRef(pDest->pAdvSink);
+ }
+
+ return TRUE;
+
+} /* OleStdCopyStatData()
+ */
+
+STDAPI_(LPENUMSTATDATA)
+ OleStdEnumStatData_Create(ULONG nCount, LPSTATDATA lpStatOrg)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPMALLOC lpMalloc=NULL;
+ LPOLESTDENUMSTATDATA lpSD=NULL;
+ DWORD dwSize;
+ WORD i;
+ HRESULT hRes;
+
+ hRes = CoGetMalloc(MEMCTX_TASK, &lpMalloc);
+ if (hRes != NOERROR) {
+ return NULL;
+ }
+
+ lpSD = (LPOLESTDENUMSTATDATA)lpMalloc->lpVtbl->Alloc(lpMalloc,
+ sizeof(OLESTDENUMSTATDATA));
+ if (lpSD == NULL) {
+ goto errReturn;
+ }
+
+ lpSD->lpVtbl = &g_EnumSTATDATAVtbl;
+ lpSD->m_dwRefs = 1;
+ lpSD->m_nCount = nCount;
+ lpSD->m_nIndex = 0;
+
+ dwSize = sizeof(STATDATA) * lpSD->m_nCount;
+
+ lpSD->m_lpStat = (LPSTATDATA)lpMalloc->lpVtbl->Alloc(lpMalloc, dwSize);
+ if (lpSD->m_lpStat == NULL)
+ goto errReturn;
+
+ lpMalloc->lpVtbl->Release(lpMalloc);
+
+ for (i=0; i<nCount; i++) {
+ OleStdCopyStatData(
+ (LPSTATDATA)&(lpSD->m_lpStat[i]), (LPSTATDATA)&(lpStatOrg[i]));
+ }
+
+ return (LPENUMSTATDATA)lpSD;
+
+errReturn:
+ if (lpSD != NULL)
+ lpMalloc->lpVtbl->Free(lpMalloc, lpSD);
+
+ if (lpMalloc != NULL)
+ lpMalloc->lpVtbl->Release(lpMalloc);
+
+ return NULL;
+
+} /* OleStdEnumStatData_Create()
+ */
+
+
+VOID
+ OleStdEnumStatData_Destroy(LPOLESTDENUMSTATDATA lpSD)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPMALLOC lpMalloc=NULL;
+ WORD i;
+
+ if (lpSD != NULL) {
+
+ if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) == NOERROR) {
+
+ /* OLE2NOTE: we MUST free any memory that was allocated for
+ ** TARGETDEVICES contained within the STATDATA elements.
+ */
+ for (i=0; i<lpSD->m_nCount; i++) {
+ if( lpSD->m_lpStat[i].pAdvSink )
+ lpSD->m_lpStat[i].pAdvSink->lpVtbl->Release(lpSD->m_lpStat[i].pAdvSink);
+
+ OleStdFree(lpSD->m_lpStat[i].formatetc.ptd);
+ }
+
+ if (lpSD->m_lpStat != NULL) {
+ lpMalloc->lpVtbl->Free(lpMalloc, lpSD->m_lpStat);
+ }
+
+ lpMalloc->lpVtbl->Free(lpMalloc, lpSD);
+ lpMalloc->lpVtbl->Release(lpMalloc);
+ }
+ }
+} /* OleStdEnumStatData_Destroy()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumStatData_QueryInterface(
+ LPENUMSTATDATA lpThis, REFIID riid, LPVOID FAR* ppobj)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+ *ppobj = NULL;
+
+ if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IEnumSTATDATA)){
+ *ppobj = (LPVOID)lpSD;
+ }
+
+ if (*ppobj == NULL) return ResultFromScode(E_NOINTERFACE);
+ else{
+ OleStdEnumStatData_AddRef(lpThis);
+ return NOERROR;
+ }
+
+} /* OleStdEnumStatData_QueryInterface()
+ */
+
+
+STDMETHODIMP_(ULONG)
+ OleStdEnumStatData_AddRef(LPENUMSTATDATA lpThis)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+ return lpSD->m_dwRefs++;
+
+} /* OleStdEnumStatData_AddRef()
+ */
+
+
+STDMETHODIMP_(ULONG)
+ OleStdEnumStatData_Release(LPENUMSTATDATA lpThis)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+ DWORD dwRefs = --lpSD->m_dwRefs;
+
+ if (dwRefs == 0)
+ OleStdEnumStatData_Destroy(lpSD);
+
+ return dwRefs;
+
+} /* OleStdEnumStatData_Release()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumStatData_Next(LPENUMSTATDATA lpThis, ULONG celt, LPSTATDATA rgelt,
+ ULONG FAR* pceltFetched)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+ ULONG i=0;
+ ULONG nOffset;
+
+ if (rgelt == NULL) {
+ return ResultFromScode(E_INVALIDARG);
+ }
+
+ while (i < celt) {
+ nOffset = lpSD->m_nIndex + i;
+
+ if (nOffset < lpSD->m_nCount) {
+ OleStdCopyStatData(
+ (LPSTATDATA)&(rgelt[i]), (LPSTATDATA)&(lpSD->m_lpStat[nOffset]));
+ i++;
+ }else{
+ break;
+ }
+ }
+
+ lpSD->m_nIndex += (WORD)i;
+
+ if (pceltFetched != NULL) {
+ *pceltFetched = i;
+ }
+
+ if (i != celt) {
+ return ResultFromScode(S_FALSE);
+ }
+
+ return NOERROR;
+} /* OleStdEnumStatData_Next()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumStatData_Skip(LPENUMSTATDATA lpThis, ULONG celt)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+ ULONG i=0;
+ ULONG nOffset;
+
+ while (i < celt) {
+ nOffset = lpSD->m_nIndex + i;
+
+ if (nOffset < lpSD->m_nCount) {
+ i++;
+ }else{
+ break;
+ }
+ }
+
+ lpSD->m_nIndex += (WORD)i;
+
+ if (i != celt) {
+ return ResultFromScode(S_FALSE);
+ }
+
+ return NOERROR;
+} /* OleStdEnumStatData_Skip()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumStatData_Reset(LPENUMSTATDATA lpThis)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+ lpSD->m_nIndex = 0;
+
+ return NOERROR;
+} /* OleStdEnumStatData_Reset()
+ */
+
+
+STDMETHODIMP
+ OleStdEnumStatData_Clone(LPENUMSTATDATA lpThis, LPENUMSTATDATA FAR* ppenum)
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+{
+ LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;
+
+ if (ppenum == NULL) {
+ return ResultFromScode(E_INVALIDARG);
+ }
+
+ *ppenum = OleStdEnumStatData_Create(lpSD->m_nCount, lpSD->m_lpStat);
+
+ // make sure cloned enumerator has same index state as the original
+ if (*ppenum) {
+ LPOLESTDENUMSTATDATA lpSDClone = (LPOLESTDENUMSTATDATA)*ppenum;
+ lpSDClone->m_nIndex = lpSD->m_nIndex;
+ return NOERROR;
+ } else
+ return ResultFromScode(E_OUTOFMEMORY);
+
+} /* OleStdEnumStatData_Clone()
+ */
+
diff --git a/private/oleutest/letest/ole2ui/filelist.mk b/private/oleutest/letest/ole2ui/filelist.mk
new file mode 100644
index 000000000..1a15317c7
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/filelist.mk
@@ -0,0 +1,75 @@
+############################################################################
+#
+# Microsoft Windows
+# Copyright (C) Microsoft Corporation, 1992 - 1992.
+# All rights reserved.
+#
+############################################################################
+
+
+#
+# Name of target. Include an extension (.dll, .lib, .exe)
+# If the target is part of the release, set RELEASE to 1.
+#
+
+TARGET = ole2uixd.lib
+RELEASE = 0
+TARGET_DESCRIPTION = "$(PLATFORM) $(BUILDTYPE) OLE 2 UI Library"
+
+
+#
+# Source files. Remember to prefix each name with .\
+#
+
+CFILES = .\busy.c \
+ .\common.c \
+ .\convert.c \
+ .\dbgutil.c \
+ .\dllfuncs.c \
+ .\drawicon.c \
+ .\enumfetc.c \
+ .\enumstat.c \
+ .\geticon.c \
+ .\hatch.c \
+ .\icon.c \
+ .\iconbox.c \
+ .\insobj.c \
+ .\links.c \
+ .\msgfiltr.c \
+ .\objfdbk.c \
+ .\ole2ui.c \
+ .\olestd.c \
+ .\oleutl.c \
+ .\pastespl.c \
+ .\precomp.c \
+ .\regdb.c \
+ .\resimage.c \
+ .\stdpal.c \
+ .\targtdev.c \
+ .\utility.c
+
+CPPFILES = .\suminfo.cpp \
+ .\dballoc.cpp
+
+RCFILES = .\ole2ui.rc
+
+#
+# Libraries and other object files to link.
+#
+OBJFILES =
+LIBS =
+
+DEFFILE =
+
+
+#
+# Precompiled headers.
+#
+
+PXXFILE =
+PFILE =
+CINC = -I$(CAIROLE)\h -I$(CAIROLE)\common \
+ -I.\resource\usa -I.\resource\static
+
+CFLAGS=/DWIN32 /D_DEBUG /DOLE201 /D_INC_OLE
+
diff --git a/private/oleutest/letest/ole2ui/fileopen.dlg b/private/oleutest/letest/ole2ui/fileopen.dlg
new file mode 100644
index 000000000..65f6e91dc
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/fileopen.dlg
@@ -0,0 +1,33 @@
+DLGINCLUDE RCDATA DISCARDABLE
+BEGIN
+ "OLE2UI.H\0"
+END
+
+IDD_FILEOPEN DIALOG 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Open"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Source:", stc3, 6, 3, 76, 9
+ EDITTEXT edt1, 7, 13, 195, 12, ES_AUTOHSCROLL | ES_OEMCONVERT
+ LISTBOX lst1, 6, 34, 90, 68, LBS_SORT | LBS_OWNERDRAWFIXED |
+ LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "&Directories:", ID_DUMMY, 110, 28, 92, 9
+ LTEXT "", stc1, 110, 36, 92, 9, SS_NOPREFIX
+ LISTBOX lst2, 110, 49, 92, 53, LBS_SORT | LBS_OWNERDRAWFIXED |
+ LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "List Files of &Type:", stc2, 6, 104, 90, 9
+ COMBOBOX cmb1, 6, 114, 90, 36, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
+ WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Dri&ves:", stc4, 110, 104, 92, 9
+ COMBOBOX cmb2, 110, 114, 92, 68, CBS_DROPDOWNLIST |
+ CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT |
+ CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 208, 6, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 50, 14, WS_GROUP
+ PUSHBUTTON "&Help", IDHELP, 208, 46, 50, 14, WS_GROUP
+ CONTROL "&Read Only", chx1, "Button", BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP, 208, 68, 50, 12
+END
diff --git a/private/oleutest/letest/ole2ui/geticon.c b/private/oleutest/letest/ole2ui/geticon.c
new file mode 100644
index 000000000..0bf1e13b3
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/geticon.c
@@ -0,0 +1,1177 @@
+/*************************************************************************
+**
+** The following API's are now OBSOLETE because equivalent API's have been
+** added to the OLE2.DLL library
+** GetIconOfFile superceeded by OleGetIconOfFile
+** GetIconOfClass superceeded by OleGetIconOfClass
+** OleUIMetafilePictFromIconAndLabel
+** superceeded by OleMetafilePictFromIconAndLabel
+*************************************************************************/
+
+/*
+ * GETICON.C
+ *
+ * Functions to create DVASPECT_ICON metafile from filename or classname.
+ *
+ * GetIconOfFile
+ * GetIconOfClass
+ * OleUIMetafilePictFromIconAndLabel
+ * HIconAndSourceFromClass Extracts the first icon in a class's server path
+ * and returns the path and icon index to caller.
+ * FIconFileFromClass Retrieves the path to the exe/dll containing the
+ * default icon, and the index of the icon.
+ * OleStdIconLabelTextOut Draw icon label text (line break if necessary)
+ *
+ * (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved
+ */
+
+
+/*******
+ *
+ * ICON (DVASPECT_ICON) METAFILE FORMAT:
+ *
+ * The metafile generated with OleUIMetafilePictFromIconAndLabel contains
+ * the following records which are used by the functions in DRAWICON.C
+ * to draw the icon with and without the label and to extract the icon,
+ * label, and icon source/index.
+ *
+ * SetWindowOrg
+ * SetWindowExt
+ * DrawIcon:
+ * Inserts records of DIBBITBLT or DIBSTRETCHBLT, once for the
+ * AND mask, one for the image bits.
+ * Escape with the comment "IconOnly"
+ * This indicates where to stop record enumeration to draw only
+ * the icon.
+ * SetTextColor
+ * SetTextAlign
+ * SetBkColor
+ * CreateFont
+ * SelectObject on the font.
+ * ExtTextOut
+ * One or more ExtTextOuts occur if the label is wrapped. The
+ * text in these records is used to extract the label.
+ * SelectObject on the old font.
+ * DeleteObject on the font.
+ * Escape with a comment that contains the path to the icon source.
+ * Escape with a comment that is the ASCII of the icon index.
+ *
+ *******/
+
+#define STRICT 1
+#include "ole2ui.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <commdlg.h>
+#include <memory.h>
+#include <cderr.h>
+#include "common.h"
+#include "utility.h"
+
+static TCHAR szSeparators[] = TEXT(" \t\\/!:");
+
+#define IS_SEPARATOR(c) ( (c) == TEXT(' ') || (c) == TEXT('\\') \
+ || (c) == TEXT('/') || (c) == TEXT('\t') \
+ || (c) == TEXT('!') || (c) == TEXT(':') )
+#define IS_FILENAME_DELIM(c) ( (c) == TEXT('\\') || (c) == TEXT('/') \
+ || (c) == TEXT(':') )
+
+
+#if defined( OBSOLETE )
+static HINSTANCE s_hInst;
+
+static TCHAR szMaxWidth[] =TEXT("WWWWWWWWWW");
+
+//Strings for metafile comments.
+static TCHAR szIconOnly[]=TEXT("IconOnly"); //Where to stop to exclude label.
+
+#ifdef WIN32
+static TCHAR szOLE2DLL[] = TEXT("ole2w32.dll"); // name of OLE 2.0 library
+#else
+static TCHAR szOLE2DLL[] = TEXT("ole2.dll"); // name of OLE 2.0 library
+#endif
+
+#define ICONINDEX 0
+
+#define AUXUSERTYPE_SHORTNAME USERCLASSTYPE_SHORT // short name
+#define HIMETRIC_PER_INCH 2540 // number HIMETRIC units per inch
+#define PTS_PER_INCH 72 // number points (font size) per inch
+
+#define MAP_PIX_TO_LOGHIM(x,ppli) MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
+#define MAP_LOGHIM_TO_PIX(x,ppli) MulDiv((ppli), (x), HIMETRIC_PER_INCH)
+
+static TCHAR szVanillaDocIcon[] = TEXT("DefIcon");
+
+static TCHAR szDocument[40] = TEXT("");
+
+
+/*
+ * GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)
+ *
+ * Purpose:
+ * Returns a hMetaPict containing an icon and label (filename) for the
+ * specified filename.
+ *
+ * Parameters:
+ * hinst
+ * lpszPath LPTSTR path including filename to use
+ * fUseFileAsLabel BOOL TRUE if the icon's label is the filename, FALSE if
+ * there should be no label.
+ *
+ * Return Value:
+ * HGLOBAL hMetaPict containing the icon and label - if there's no
+ * class in reg db for the file in lpszPath, then we use
+ * Document. If lpszPath is NULL, then we return NULL.
+ */
+
+STDAPI_(HGLOBAL) GetIconOfFile(HINSTANCE hInst, LPTSTR lpszPath, BOOL fUseFileAsLabel)
+{
+ TCHAR szIconFile[OLEUI_CCHPATHMAX];
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ LPTSTR lpszClsid = NULL;
+ CLSID clsid;
+ HICON hDefIcon = NULL;
+ UINT IconIndex = 0;
+ HGLOBAL hMetaPict;
+ HRESULT hResult;
+
+ if (NULL == lpszPath) // even if fUseFileAsLabel is FALSE, we still
+ return NULL; // need a valid filename to get the class.
+
+ s_hInst = hInst;
+
+ hResult = GetClassFileA(lpszPath, &clsid);
+
+ if (NOERROR == hResult) // use the clsid we got to get to the icon
+ {
+ hDefIcon = HIconAndSourceFromClass(&clsid,
+ (LPTSTR)szIconFile,
+ &IconIndex);
+ }
+
+ if ( (NOERROR != hResult) || (NULL == hDefIcon) )
+ {
+ // Here, either GetClassFile failed or HIconAndSourceFromClass failed.
+
+ LPTSTR lpszTemp;
+
+ lpszTemp = lpszPath;
+
+ while ((*lpszTemp != TEXT('.')) && (*lpszTemp != TEXT('\0')))
+ lpszTemp++;
+
+
+ if (TEXT('.') != *lpszTemp)
+ goto UseVanillaDocument;
+
+
+ if (FALSE == GetAssociatedExecutable(lpszTemp, (LPTSTR)szIconFile))
+ goto UseVanillaDocument;
+
+ hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
+ }
+
+ if (hDefIcon <= (HICON)1) // ExtractIcon returns 1 if szExecutable is not exe,
+ { // 0 if there are no icons.
+UseVanillaDocument:
+
+ lstrcpy((LPTSTR)szIconFile, (LPTSTR)szOLE2DLL);
+ IconIndex = ICONINDEX;
+ hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
+
+ }
+
+ // Now let's get the label we want to use.
+
+ if (fUseFileAsLabel) // strip off path, so we just have the filename.
+ {
+ int istrlen;
+ LPTSTR lpszBeginFile;
+
+ istrlen = lstrlen(lpszPath);
+
+ // set pointer to END of path, so we can walk backwards through it.
+ lpszBeginFile = lpszPath + istrlen -1;
+
+ while ( (lpszBeginFile >= lpszPath)
+ && (!IS_FILENAME_DELIM(*lpszBeginFile)) )
+ lpszBeginFile--;
+
+
+ lpszBeginFile++; // step back over the delimiter
+
+
+ LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel)/sizeof(TCHAR));
+ }
+
+ else // use the short user type (AuxUserType2) for the label
+ {
+
+ if (0 == OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,
+ (LPTSTR)szLabel, OLEUI_CCHLABELMAX_SIZE, NULL)) {
+
+ if ('\0'==szDocument[0]) {
+ LoadString(
+ s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument)/sizeof(TCHAR));
+ }
+ lstrcpy(szLabel, szDocument);
+ }
+ }
+
+
+ hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon,
+ szLabel,
+ (LPTSTR)szIconFile,
+ IconIndex);
+
+ DestroyIcon(hDefIcon);
+
+ return hMetaPict;
+
+}
+
+
+
+/*
+ * GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)
+ *
+ * Purpose:
+ * Returns a hMetaPict containing an icon and label (human-readable form
+ * of class) for the specified clsid.
+ *
+ * Parameters:
+ * hinst
+ * rclsid REFCLSID pointing to clsid to use.
+ * lpszLabel label to use for icon.
+ * fUseTypeAsLabel Use the clsid's user type name as the icon's label.
+ *
+ * Return Value:
+ * HGLOBAL hMetaPict containing the icon and label - if we
+ * don't find the clsid in the reg db then we
+ * return NULL.
+ */
+
+STDAPI_(HGLOBAL) GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPTSTR lpszLabel, BOOL fUseTypeAsLabel)
+{
+
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ TCHAR szIconFile[OLEUI_CCHPATHMAX];
+ HICON hDefIcon;
+ UINT IconIndex;
+ HGLOBAL hMetaPict;
+
+
+ s_hInst = hInst;
+
+ if (!fUseTypeAsLabel) // Use string passed in as label
+ {
+ if (NULL != lpszLabel)
+ LSTRCPYN(szLabel, lpszLabel, OLEUI_CCHLABELMAX_SIZE);
+ else
+ *szLabel = TEXT('\0');
+ }
+ else // Use AuxUserType2 (short name) as label
+ {
+
+ if (0 == OleStdGetAuxUserType(rclsid,
+ AUXUSERTYPE_SHORTNAME,
+ (LPTSTR)szLabel,
+ OLEUI_CCHLABELMAX_SIZE,
+ NULL))
+
+ // If we can't get the AuxUserType2, then try the long name
+ if (0 == OleStdGetUserTypeOfClass(rclsid, szLabel, OLEUI_CCHKEYMAX_SIZE, NULL)) {
+ if (TEXT('\0')==szDocument[0]) {
+ LoadString(
+ s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument)/sizeof(TCHAR));
+ }
+ lstrcpy(szLabel, szDocument); // last resort
+ }
+ }
+
+ // Get the icon, icon index, and path to icon file
+ hDefIcon = HIconAndSourceFromClass(rclsid,
+ (LPTSTR)szIconFile,
+ &IconIndex);
+
+ if (NULL == hDefIcon) // Use Vanilla Document
+ {
+ lstrcpy((LPTSTR)szIconFile, (LPTSTR)szOLE2DLL);
+ IconIndex = ICONINDEX;
+ hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
+ }
+
+ // Create the metafile
+ hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon, szLabel,
+ (LPTSTR)szIconFile, IconIndex);
+
+ DestroyIcon(hDefIcon);
+
+ return hMetaPict;
+
+}
+
+
+/*
+ * OleUIMetafilePictFromIconAndLabel
+ *
+ * Purpose:
+ * Creates a METAFILEPICT structure that container a metafile in which
+ * the icon and label are drawn. A comment record is inserted between
+ * the icon and the label code so our special draw function can stop
+ * playing before the label.
+ *
+ * Parameters:
+ * hIcon HICON to draw into the metafile
+ * pszLabel LPTSTR to the label string.
+ * pszSourceFile LPTSTR containing the local pathname of the icon
+ * as we either get from the user or from the reg DB.
+ * iIcon UINT providing the index into pszSourceFile where
+ * the icon came from.
+ *
+ * Return Value:
+ * HGLOBAL Global memory handle containing a METAFILEPICT where
+ * the metafile uses the MM_ANISOTROPIC mapping mode. The
+ * extents reflect both icon and label.
+ */
+
+STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON hIcon, LPTSTR pszLabel
+ , LPTSTR pszSourceFile, UINT iIcon)
+ {
+ HDC hDC, hDCScreen;
+ HMETAFILE hMF;
+ HGLOBAL hMem;
+ LPMETAFILEPICT pMF;
+ UINT cxIcon, cyIcon;
+ UINT cxText, cyText;
+ UINT cx, cy;
+ UINT cchLabel = 0;
+ HFONT hFont, hFontT;
+ int cyFont;
+ TCHAR szIndex[10];
+ RECT TextRect;
+ SIZE size;
+ POINT point;
+ UINT fuAlign;
+
+ if (NULL==hIcon) // null label is valid but NOT a null icon
+ return NULL;
+
+ //Create a memory metafile
+ hDC=(HDC)CreateMetaFile(NULL);
+
+ if (NULL==hDC)
+ return NULL;
+
+ //Allocate the metafilepict
+ hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));
+
+ if (NULL==hMem)
+ {
+ hMF=CloseMetaFile(hDC);
+ DeleteMetaFile(hMF);
+ return NULL;
+ }
+
+
+ if (NULL!=pszLabel)
+ {
+ cchLabel=lstrlen(pszLabel);
+
+ if (cchLabel >= OLEUI_CCHLABELMAX)
+ pszLabel[cchLabel] = TEXT('\0'); // truncate string
+ }
+
+ //Need to use the screen DC for these operations
+ hDCScreen=GetDC(NULL);
+ cyFont=-(8*GetDeviceCaps(hDCScreen, LOGPIXELSY))/72;
+
+ //cyFont was calculated to give us 8 point.
+ hFont=CreateFont(cyFont, 5, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET
+ , OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY
+ , FF_SWISS, TEXT("MS Sans Serif"));
+
+ hFontT=SelectObject(hDCScreen, hFont);
+
+ GetTextExtentPoint(hDCScreen,szMaxWidth,lstrlen(szMaxWidth),&size);
+ SelectObject(hDCScreen, hFontT);
+
+ cxText = size.cx;
+ cyText = size.cy * 2;
+
+ cxIcon = GetSystemMetrics(SM_CXICON);
+ cyIcon = GetSystemMetrics(SM_CYICON);
+
+
+ // If we have no label, then we want the metafile to be the width of
+ // the icon (plus margin), not the width of the fattest string.
+ if ( (NULL == pszLabel) || (TEXT('\0') == *pszLabel) )
+ cx = cxIcon + cxIcon / 4;
+ else
+ cx = max(cxText, cxIcon);
+
+ cy=cyIcon+cyText+4;
+
+ //Set the metafile size to fit the icon and label
+ SetWindowOrgEx(hDC, 0, 0, &point);
+ SetWindowExtEx(hDC, cx, cy, &size);
+
+ //Set up rectangle to pass to OleStdIconLabelTextOut
+ SetRectEmpty(&TextRect);
+
+ TextRect.right = cx;
+ TextRect.bottom = cy;
+
+ //Draw the icon and the text, centered with respect to each other.
+ DrawIcon(hDC, (cx-cxIcon)/2, 0, hIcon);
+
+ //String that indicates where to stop if we're only doing icons
+ Escape(hDC, MFCOMMENT, lstrlen(szIconOnly)+1, szIconOnly, NULL);
+
+ SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+ SetBkMode(hDC, TRANSPARENT);
+ fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);
+
+ OleStdIconLabelTextOut(hDC,
+ hFont,
+ 0,
+ cy - cyText,
+ ETO_CLIPPED,
+ &TextRect,
+ pszLabel,
+ cchLabel,
+ NULL);
+
+ //Write comments containing the icon source file and index.
+ if (NULL!=pszSourceFile)
+ {
+ //+1 on string lengths insures the null terminator is embedded.
+ Escape(hDC, MFCOMMENT, lstrlen(pszSourceFile)+1, pszSourceFile, NULL);
+
+ cchLabel=wsprintf(szIndex, TEXT("%u"), iIcon);
+ Escape(hDC, MFCOMMENT, cchLabel+1, szIndex, NULL);
+ }
+
+ SetTextAlign(hDC, fuAlign);
+
+ //All done with the metafile, now stuff it all into a METAFILEPICT.
+ hMF=CloseMetaFile(hDC);
+
+ if (NULL==hMF)
+ {
+ GlobalFree(hMem);
+ ReleaseDC(NULL, hDCScreen);
+ return NULL;
+ }
+
+ //Fill out the structure
+ pMF=(LPMETAFILEPICT)GlobalLock(hMem);
+
+ //Transform to HIMETRICS
+ cx=XformWidthInPixelsToHimetric(hDCScreen, cx);
+ cy=XformHeightInPixelsToHimetric(hDCScreen, cy);
+ ReleaseDC(NULL, hDCScreen);
+
+ pMF->mm=MM_ANISOTROPIC;
+ pMF->xExt=cx;
+ pMF->yExt=cy;
+ pMF->hMF=hMF;
+
+ GlobalUnlock(hMem);
+
+ DeleteObject(hFont);
+
+ return hMem;
+ }
+
+#endif // OBSOLETE
+
+
+/*
+ * GetAssociatedExecutable
+ *
+ * Purpose: Finds the executable associated with the provided extension
+ *
+ * Parameters:
+ * lpszExtension LPSTR points to the extension we're trying to find
+ * an exe for. Does **NO** validation.
+ *
+ * lpszExecutable LPSTR points to where the exe name will be returned.
+ * No validation here either - pass in 128 char buffer.
+ *
+ * Return:
+ * BOOL TRUE if we found an exe, FALSE if we didn't.
+ *
+ */
+
+BOOL FAR PASCAL GetAssociatedExecutable(LPTSTR lpszExtension, LPTSTR lpszExecutable)
+
+{
+ HKEY hKey;
+ LONG dw;
+ LRESULT lRet;
+ TCHAR szValue[OLEUI_CCHKEYMAX];
+ TCHAR szKey[OLEUI_CCHKEYMAX];
+ LPTSTR lpszTemp, lpszExe;
+
+
+ lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+
+ if (ERROR_SUCCESS != lRet)
+ return FALSE;
+
+ dw = OLEUI_CCHPATHMAX_SIZE;
+ lRet = RegQueryValue(hKey, lpszExtension, (LPTSTR)szValue, &dw); //ProgId
+
+ if (ERROR_SUCCESS != lRet)
+ {
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+
+ // szValue now has ProgID
+ lstrcpy(szKey, szValue);
+ lstrcat(szKey, TEXT("\\Shell\\Open\\Command"));
+
+
+ dw = OLEUI_CCHPATHMAX_SIZE;
+ lRet = RegQueryValue(hKey, (LPTSTR)szKey, (LPTSTR)szValue, &dw);
+
+ if (ERROR_SUCCESS != lRet)
+ {
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ // szValue now has an executable name in it. Let's null-terminate
+ // at the first post-executable space (so we don't have cmd line
+ // args.
+
+ lpszTemp = (LPTSTR)szValue;
+
+ while ((TEXT('\0') != *lpszTemp) && (iswspace(*lpszTemp)))
+ lpszTemp++; // Strip off leading spaces
+
+ lpszExe = lpszTemp;
+
+ while ((TEXT('\0') != *lpszTemp) && (!iswspace(*lpszTemp)))
+ lpszTemp++; // Step through exe name
+
+ *lpszTemp = TEXT('\0'); // null terminate at first space (or at end).
+
+
+ lstrcpy(lpszExecutable, lpszExe);
+
+ return TRUE;
+
+}
+
+
+/*
+ * HIconAndSourceFromClass
+ *
+ * Purpose:
+ * Given an object class name, finds an associated executable in the
+ * registration database and extracts the first icon from that
+ * executable. If none is available or the class has no associated
+ * executable, this function returns NULL.
+ *
+ * Parameters:
+ * rclsid pointer to clsid to look up.
+ * pszSource LPSTR in which to place the source of the icon.
+ * This is assumed to be OLEUI_CCHPATHMAX
+ * puIcon UINT FAR * in which to store the index of the
+ * icon in pszSource.
+ *
+ * Return Value:
+ * HICON Handle to the extracted icon if there is a module
+ * associated to pszClass. NULL on failure to either
+ * find the executable or extract and icon.
+ */
+
+HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPTSTR pszSource, UINT FAR *puIcon)
+ {
+ HICON hIcon;
+ UINT IconIndex;
+
+ if (NULL==rclsid || NULL==pszSource || IsEqualCLSID(rclsid,&CLSID_NULL))
+ return NULL;
+
+ if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX_SIZE, &IconIndex))
+ return NULL;
+
+ hIcon=ExtractIcon(ghInst, pszSource, IconIndex);
+
+ if ((HICON)32 > hIcon)
+ hIcon=NULL;
+ else
+ *puIcon= IconIndex;
+
+ return hIcon;
+ }
+
+
+/*
+ * PointerToNthField
+ *
+ * Purpose:
+ * Returns a pointer to the beginning of the nth field.
+ * Assumes null-terminated string.
+ *
+ * Parameters:
+ * lpszString string to parse
+ * nField field to return starting index of.
+ * chDelimiter char that delimits fields
+ *
+ * Return Value:
+ * LPSTR pointer to beginning of nField field.
+ * NOTE: If the null terminator is found
+ * Before we find the Nth field, then
+ * we return a pointer to the null terminator -
+ * calling app should be sure to check for
+ * this case.
+ *
+ */
+LPTSTR FAR PASCAL PointerToNthField(LPTSTR lpszString, int nField, TCHAR chDelimiter)
+{
+ LPTSTR lpField = lpszString;
+ int cFieldFound = 1;
+
+ if (1 ==nField)
+ return lpszString;
+
+ while (*lpField != TEXT('\0'))
+ {
+
+ if (*lpField++ == chDelimiter)
+ {
+
+ cFieldFound++;
+
+ if (nField == cFieldFound)
+ return lpField;
+ }
+ }
+
+ return lpField;
+
+}
+
+
+/*
+ * FIconFileFromClass
+ *
+ * Purpose:
+ * Looks up the path to executable that contains the class default icon.
+ *
+ * Parameters:
+ * rclsid pointer to CLSID to look up.
+ * pszEXE LPSTR at which to store the server name
+ * cch UINT size of pszEXE
+ * lpIndex LPUINT to index of icon within executable
+ *
+ * Return Value:
+ * BOOL TRUE if one or more characters were loaded into pszEXE.
+ * FALSE otherwise.
+ */
+
+BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPTSTR pszEXE, UINT cchBytes, UINT FAR *lpIndex)
+{
+
+ LONG dw;
+ LONG lRet;
+ HKEY hKey;
+ LPMALLOC lpIMalloc;
+ HRESULT hrErr;
+ LPTSTR lpBuffer;
+ LPTSTR lpIndexString;
+ UINT cBufferSize = 136;// room for 128 char path and icon's index
+ TCHAR szKey[64];
+ LPSTR pszClass;
+ UINT cch=cchBytes / sizeof(TCHAR); // number of characters
+
+
+ if (NULL==rclsid || NULL==pszEXE || 0==cch || IsEqualCLSID(rclsid,&CLSID_NULL))
+ return FALSE;
+
+ //Here, we use CoGetMalloc and alloc a buffer (maxpathlen + 8) to
+ //pass to RegQueryValue. Then, we copy the exe to pszEXE and the
+ //index to *lpIndex.
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &lpIMalloc);
+
+ if (NOERROR != hrErr)
+ return FALSE;
+
+ lpBuffer = (LPTSTR)lpIMalloc->lpVtbl->Alloc(lpIMalloc, cBufferSize);
+
+ if (NULL == lpBuffer)
+ {
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return FALSE;
+ }
+
+
+ if (CoIsOle1Class(rclsid))
+ {
+
+ LPOLESTR lpszProgID;
+
+ // we've got an ole 1.0 class on our hands, so we look at
+ // progID\protocol\stdfileedting\server to get the
+ // name of the executable.
+
+ ProgIDFromCLSID(rclsid, &lpszProgID);
+
+ //Open up the class key
+#ifdef UNICODE
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);
+#else
+ {
+ char szTemp[255];
+
+ wcstombs(szTemp, lpszProgID, 255);
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, szTemp, &hKey);
+ }
+#endif
+
+ if (ERROR_SUCCESS != lRet)
+ {
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return FALSE;
+ }
+
+ dw=(LONG)cBufferSize;
+ lRet = RegQueryValue(hKey, TEXT("Protocol\\StdFileEditing\\Server"), lpBuffer, &dw);
+
+ if (ERROR_SUCCESS != lRet)
+ {
+
+ RegCloseKey(hKey);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return FALSE;
+ }
+
+
+ // Use server and 0 as the icon index
+ LSTRCPYN(pszEXE, lpBuffer, cch);
+
+ *lpIndex = 0;
+
+ RegCloseKey(hKey);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return TRUE;
+
+ }
+
+
+
+ /*
+ * We have to go walking in the registration database under the
+ * classname, so we first open the classname key and then check
+ * under "\\DefaultIcon" to get the file that contains the icon.
+ */
+
+ StringFromCLSIDA(rclsid, &pszClass);
+
+ lstrcpy(szKey, TEXT("CLSID\\"));
+
+ lstrcat(szKey, pszClass);
+
+ //Open up the class key
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey);
+
+ if (ERROR_SUCCESS != lRet)
+ {
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return FALSE;
+ }
+
+ //Get the executable path and icon index.
+
+ dw=(LONG)cBufferSize;
+ lRet=RegQueryValue(hKey, TEXT("DefaultIcon"), lpBuffer, &dw);
+
+ if (ERROR_SUCCESS != lRet)
+ {
+ // no DefaultIcon key...try LocalServer
+
+ dw=(LONG)cBufferSize;
+ lRet=RegQueryValue(hKey, TEXT("LocalServer"), lpBuffer, &dw);
+
+ if (ERROR_SUCCESS != lRet)
+ {
+ // no LocalServer entry either...they're outta luck.
+
+ RegCloseKey(hKey);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return FALSE;
+ }
+
+
+ // Use server from LocalServer or Server and 0 as the icon index
+ LSTRCPYN(pszEXE, lpBuffer, cch);
+
+ *lpIndex = 0;
+
+ RegCloseKey(hKey);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return TRUE;
+ }
+
+ RegCloseKey(hKey);
+
+ // lpBuffer contains a string that looks like "<pathtoexe>,<iconindex>",
+ // so we need to separate the path and the icon index.
+
+ lpIndexString = PointerToNthField(lpBuffer, 2, TEXT(','));
+
+ if (TEXT('\0') == *lpIndexString) // no icon index specified - use 0 as default.
+ {
+ *lpIndex = 0;
+
+ }
+ else
+ {
+ LPTSTR lpTemp;
+ static TCHAR szTemp[16];
+
+ lstrcpy((LPTSTR)szTemp, lpIndexString);
+
+ // Put the icon index part into *pIconIndex
+#ifdef UNICODE
+ {
+ char szTEMP1[16];
+
+ wcstombs(szTEMP1, szTemp, 16);
+ *lpIndex = atoi((const char *)szTEMP1);
+ }
+#else
+ *lpIndex = atoi((const char *)szTemp);
+#endif
+
+ // Null-terminate the exe part.
+#ifdef WIN32
+ lpTemp = CharPrev(lpBuffer, lpIndexString);
+#else
+ lpTemp = AnsiPrev(lpBuffer, lpIndexString);
+#endif
+ *lpTemp = TEXT('\0');
+ }
+
+ if (!LSTRCPYN(pszEXE, lpBuffer, cch))
+ {
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return FALSE;
+ }
+
+ // Free the memory we alloc'd and leave.
+ lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
+ lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ return TRUE;
+}
+
+
+
+/*
+ * OleStdIconLabelTextOut
+ *
+ * Purpose:
+ * Replacement for DrawText to be used in the "Display as Icon" metafile.
+ * Uses ExtTextOut to output a string center on (at most) two lines.
+ * Uses a very simple word wrap algorithm to split the lines.
+ *
+ * Parameters: (same as for ExtTextOut, except for hFont)
+ * hDC device context to draw into; if this is NULL, then we don't
+ * ETO the text, we just return the index of the beginning
+ * of the second line
+ * hFont font to use
+ * nXStart x-coordinate of starting position
+ * nYStart y-coordinate of starting position
+ * fuOptions rectangle type
+ * lpRect rect far * containing rectangle to draw text in.
+ * lpszString string to draw
+ * cchString length of string (truncated if over OLEUI_CCHLABELMAX)
+ * lpDX spacing between character cells
+ *
+ * Return Value:
+ * UINT Index of beginning of last line (0 if there's only one
+ * line of text).
+ *
+ */
+
+STDAPI_(UINT) OleStdIconLabelTextOut(HDC hDC,
+ HFONT hFont,
+ int nXStart,
+ int nYStart,
+ UINT fuOptions,
+ RECT FAR * lpRect,
+ LPTSTR lpszString,
+ UINT cchString,
+ int FAR * lpDX)
+{
+
+ HDC hDCScreen;
+ static TCHAR szTempBuff[OLEUI_CCHLABELMAX];
+ int cxString, cyString, cxMaxString;
+ int cxFirstLine, cyFirstLine, cxSecondLine;
+ int index;
+ int cch = cchString;
+ TCHAR chKeep;
+ LPTSTR lpszSecondLine;
+ HFONT hFontT;
+ BOOL fPrintText = TRUE;
+ UINT iLastLineStart = 0;
+ SIZE size;
+
+ // Initialization stuff...
+
+ if (NULL == hDC) // If we got NULL as the hDC, then we don't actually call ETO
+ fPrintText = FALSE;
+
+
+ // Make a copy of the string (NULL or non-NULL) that we're using
+ if (NULL == lpszString)
+ *szTempBuff = TEXT('\0');
+
+ else
+ LSTRCPYN(szTempBuff, lpszString, sizeof(szTempBuff)/sizeof(TCHAR));
+
+ // set maximum width
+ cxMaxString = lpRect->right - lpRect->left;
+
+ // get screen DC to do text size calculations
+ hDCScreen = GetDC(NULL);
+
+ hFontT=SelectObject(hDCScreen, hFont);
+
+ // get the extent of our label
+#ifdef WIN32
+ // GetTextExtentPoint32 has fixed the off-by-one bug.
+ GetTextExtentPoint32(hDCScreen, szTempBuff, cch, &size);
+#else
+ GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size);
+#endif
+
+ cxString = size.cx;
+ cyString = size.cy;
+
+ // Select in the font we want to use
+ if (fPrintText)
+ SelectObject(hDC, hFont);
+
+ // String is smaller than max string - just center, ETO, and return.
+ if (cxString <= cxMaxString)
+ {
+
+ if (fPrintText)
+ ExtTextOut(hDC,
+ nXStart + (lpRect->right - cxString) / 2,
+ nYStart,
+ fuOptions,
+ lpRect,
+ szTempBuff,
+ cch,
+ NULL);
+
+ iLastLineStart = 0; // only 1 line of text
+ goto CleanupAndLeave;
+ }
+
+ // String is too long...we've got to word-wrap it.
+
+
+ // Are there any spaces, slashes, tabs, or bangs in string?
+
+ if (lstrlen(szTempBuff) != (int)
+#ifdef UNICODE
+ wcscspn(szTempBuff, szSeparators)
+#else
+ strcspn(szTempBuff, szSeparators)
+#endif
+ )
+ {
+ // Yep, we've got spaces, so we'll try to find the largest
+ // space-terminated string that will fit on the first line.
+
+ index = cch;
+
+
+ while (index >= 0)
+ {
+
+ TCHAR cchKeep;
+
+ // scan the string backwards for spaces, slashes, tabs, or bangs
+
+ while (!IS_SEPARATOR(szTempBuff[index]) )
+ index--;
+
+
+ if (index <= 0)
+ break;
+
+ cchKeep = szTempBuff[index]; // remember what char was there
+
+ szTempBuff[index] = TEXT('\0'); // just for now
+
+#ifdef WIN32
+ GetTextExtentPoint32(
+ hDCScreen, (LPTSTR)szTempBuff,lstrlen((LPTSTR)szTempBuff),&size);
+#else
+ GetTextExtentPoint(
+ hDCScreen, (LPTSTR)szTempBuff,lstrlen((LPTSTR)szTempBuff),&size);
+#endif
+
+ cxFirstLine = size.cx;
+ cyFirstLine = size.cy;
+
+ szTempBuff[index] = cchKeep; // put the right char back
+
+ if (cxFirstLine <= cxMaxString)
+ {
+
+ iLastLineStart = index + 1;
+
+ if (!fPrintText)
+ goto CleanupAndLeave;
+
+ ExtTextOut(hDC,
+ nXStart + (lpRect->right - cxFirstLine) / 2,
+ nYStart,
+ fuOptions,
+ lpRect,
+ (LPTSTR)szTempBuff,
+ index + 1,
+ lpDX);
+
+ lpszSecondLine = (LPTSTR)szTempBuff;
+
+ lpszSecondLine += (index + 1) ;
+
+ GetTextExtentPoint(hDCScreen,
+ lpszSecondLine,
+ lstrlen(lpszSecondLine),
+ &size);
+
+ // If the second line is wider than the rectangle, we
+ // just want to clip the text.
+ cxSecondLine = min(size.cx, cxMaxString);
+
+ ExtTextOut(hDC,
+ nXStart + (lpRect->right - cxSecondLine) / 2,
+ nYStart + cyFirstLine,
+ fuOptions,
+ lpRect,
+ lpszSecondLine,
+ lstrlen(lpszSecondLine),
+ lpDX);
+
+ goto CleanupAndLeave;
+
+ } // end if
+
+ index--;
+
+ } // end while
+
+ } // end if
+
+ // Here, there are either no spaces in the string (strchr(szTempBuff, ' ')
+ // returned NULL), or there spaces in the string, but they are
+ // positioned so that the first space terminated string is still
+ // longer than one line. So, we walk backwards from the end of the
+ // string until we find the largest string that will fit on the first
+ // line , and then we just clip the second line.
+
+ cch = lstrlen((LPTSTR)szTempBuff);
+
+ chKeep = szTempBuff[cch];
+ szTempBuff[cch] = TEXT('\0');
+
+ GetTextExtentPoint(hDCScreen, szTempBuff, lstrlen(szTempBuff),&size);
+
+ cxFirstLine = size.cx;
+ cyFirstLine = size.cy;
+
+ while (cxFirstLine > cxMaxString)
+ {
+ // We allow 40 characters in the label, but the metafile is
+ // only as wide as 10 W's (for aesthetics - 20 W's wide looked
+ // dumb. This means that if we split a long string in half (in
+ // terms of characters), then we could still be wider than the
+ // metafile. So, if this is the case, we just step backwards
+ // from the halfway point until we get something that will fit.
+ // Since we just let ETO clip the second line
+
+ szTempBuff[cch--] = chKeep;
+ if (0 == cch)
+ goto CleanupAndLeave;
+
+ chKeep = szTempBuff[cch];
+ szTempBuff[cch] = TEXT('\0');
+
+ GetTextExtentPoint(
+ hDCScreen, szTempBuff, lstrlen(szTempBuff), &size);
+ cxFirstLine = size.cx;
+ }
+
+ iLastLineStart = cch;
+
+ if (!fPrintText)
+ goto CleanupAndLeave;
+
+ ExtTextOut(hDC,
+ nXStart + (lpRect->right - cxFirstLine) / 2,
+ nYStart,
+ fuOptions,
+ lpRect,
+ (LPTSTR)szTempBuff,
+ lstrlen((LPTSTR)szTempBuff),
+ lpDX);
+
+ szTempBuff[cch] = chKeep;
+ lpszSecondLine = szTempBuff;
+ lpszSecondLine += cch ;
+
+ GetTextExtentPoint(
+ hDCScreen, (LPTSTR)lpszSecondLine, lstrlen(lpszSecondLine), &size);
+
+ // If the second line is wider than the rectangle, we
+ // just want to clip the text.
+ cxSecondLine = min(size.cx, cxMaxString);
+
+ ExtTextOut(hDC,
+ nXStart + (lpRect->right - cxSecondLine) / 2,
+ nYStart + cyFirstLine,
+ fuOptions,
+ lpRect,
+ lpszSecondLine,
+ lstrlen(lpszSecondLine),
+ lpDX);
+
+CleanupAndLeave:
+ SelectObject(hDCScreen, hFontT);
+ ReleaseDC(NULL, hDCScreen);
+ return iLastLineStart;
+
+}
+
diff --git a/private/oleutest/letest/ole2ui/geticon.h b/private/oleutest/letest/ole2ui/geticon.h
new file mode 100644
index 000000000..223411385
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/geticon.h
@@ -0,0 +1,18 @@
+// This file is now OBSOLETE (include olestd.h instead)
+/*
+ * GETICON.H
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+/*************************************************************************
+**
+** The following API's are now OBSOLETE because equivalent API's have been
+** added to the OLE2.DLL library
+** GetIconOfFile superceeded by OleGetIconOfFile
+** GetIconOfClass superceeded by OleGetIconOfClass
+** OleUIMetafilePictFromIconAndLabel
+** superceeded by OleMetafilePictFromIconAndLabel
+*************************************************************************/
+
+// Other function prototypes moved to olestd.h
diff --git a/private/oleutest/letest/ole2ui/hatch.c b/private/oleutest/letest/ole2ui/hatch.c
new file mode 100644
index 000000000..1e156a1e0
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/hatch.c
@@ -0,0 +1,325 @@
+/*
+ * HATCH.C
+ *
+ * Miscellaneous API's to generate hatch window for in-place active
+ * objects. This is part of the OLE 2.0 User Interface Support Library.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+
+// offsets in the extra bytes stored with the hatch window
+#define EB_HATCHWIDTH 0
+#define EB_HATCHRECT_LEFT 2
+#define EB_HATCHRECT_TOP 4
+#define EB_HATCHRECT_RIGHT 6
+#define EB_HATCHRECT_BOTTOM 8
+
+// class name of hatch window
+#define CLASS_HATCH TEXT("Hatch Window")
+
+// local function prototypes
+LRESULT FAR PASCAL EXPORT HatchWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
+
+
+/*
+ * HatchRegisterClass
+ *
+ * Purpose:
+ * Register the hatch window
+ *
+ * Parameters:
+ * hInst Process instance
+ *
+ * Return Value:
+ * TRUE if successful
+ * FALSE if failed
+ *
+ */
+STDAPI_(BOOL) RegisterHatchWindowClass(HINSTANCE hInst)
+{
+ WNDCLASS wc;
+
+ // Register Hatch Window Class
+ wc.style = CS_BYTEALIGNWINDOW;
+ wc.lpfnWndProc = HatchWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 5 * sizeof(int); // extra bytes stores
+ // uHatchWidth
+ // rcHatchRect
+ wc.hInstance = hInst;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = CLASS_HATCH;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/*
+ * CreateHatchWindow
+ *
+ * Purpose:
+ * Create the hatch window
+ *
+ * Parameters:
+ * hWndParent parent of hatch window
+ * hInst instance handle
+ *
+ * Return Value:
+ * pointer to hatch window if successful
+ * NULL if failed
+ *
+ */
+STDAPI_(HWND) CreateHatchWindow(HWND hWndParent, HINSTANCE hInst)
+{
+ HWND hWnd;
+
+ if (!hWndParent || !hInst)
+ return NULL;
+
+ hWnd = CreateWindow(
+ CLASS_HATCH,
+ TEXT("Hatch Window"),
+ WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, 0, 0,
+ hWndParent,
+ (HMENU)NULL,
+ hInst,
+ 0L
+ );
+
+ if (!hWnd)
+ return NULL;
+
+ return hWnd;
+}
+
+/*
+ * GetHatchWidth
+ *
+ * Purpose:
+ * Get width of hatch border
+ *
+ * Parameters:
+ * hWndHatch hatch window handle
+ *
+ * Return Value:
+ * width of the hatch border
+ */
+STDAPI_(UINT) GetHatchWidth(HWND hWndHatch)
+{
+ if (!IsWindow(hWndHatch))
+ return 0;
+
+ return (UINT)GetWindowWord(hWndHatch, EB_HATCHWIDTH);
+}
+
+/*
+ * GetHatchRect
+ *
+ * Purpose:
+ * Get hatch rect. this is the size of the hatch window if it were
+ * not clipped by the ClipRect.
+ *
+ * Parameters:
+ * hWndHatch hatch window handle
+ * lprcHatchRect hatch rect
+ *
+ * Return Value:
+ * none
+ */
+STDAPI_(void) GetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect)
+{
+ if (!IsWindow(hWndHatch)) {
+ SetRect(lprcHatchRect, 0, 0, 0, 0);
+ return;
+ }
+
+ lprcHatchRect->left = GetWindowWord(hWndHatch, EB_HATCHRECT_LEFT);
+ lprcHatchRect->top = GetWindowWord(hWndHatch, EB_HATCHRECT_TOP);
+ lprcHatchRect->right = GetWindowWord(hWndHatch, EB_HATCHRECT_RIGHT);
+ lprcHatchRect->bottom = GetWindowWord(hWndHatch, EB_HATCHRECT_BOTTOM);
+}
+
+
+/* SetHatchRect
+ *
+ *
+ * Purpose:
+ * Store hatch rect with HatchRect window.
+ * this rect is the size of the hatch window if it were
+ * not clipped by the ClipRect.
+ *
+ * Parameters:
+ * hWndHatch hatch window handle
+ * lprcHatchRect hatch rect
+ *
+ * Return Value:
+ * none
+ */
+STDAPI_(void) SetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect)
+{
+ if (!IsWindow(hWndHatch))
+ return;
+
+ SetWindowWord(hWndHatch, EB_HATCHRECT_LEFT, (WORD)lprcHatchRect->left);
+ SetWindowWord(hWndHatch, EB_HATCHRECT_TOP, (WORD)lprcHatchRect->top);
+ SetWindowWord(hWndHatch, EB_HATCHRECT_RIGHT, (WORD)lprcHatchRect->right);
+ SetWindowWord(hWndHatch, EB_HATCHRECT_BOTTOM,(WORD)lprcHatchRect->bottom);
+}
+
+
+/* SetHatchWindowSize
+ *
+ *
+ * Purpose:
+ * Move/size the HatchWindow correctly given the rect required by the
+ * in-place server object window and the lprcClipRect imposed by the
+ * in-place container. both rect's are expressed in the client coord.
+ * of the in-place container's window (which is the parent of the
+ * HatchWindow).
+ *
+ * OLE2NOTE: the in-place server must honor the lprcClipRect specified
+ * by its in-place container. it must NOT draw outside of the ClipRect.
+ * in order to achieve this, the hatch window is sized to be
+ * exactly the size that should be visible (rcVisRect). the
+ * rcVisRect is defined as the intersection of the full size of
+ * the HatchRect 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
+ * in-place server document window (child of HatchWindow) must be moved
+ * by the delta that was clipped. the window origin of the
+ * in-place server window will then have negative coordinates relative
+ * to its parent HatchWindow.
+ *
+ * Parameters:
+ * hWndHatch hatch window handle
+ * lprcIPObjRect full size of in-place server object window
+ * lprcClipRect clipping rect imposed by in-place container
+ * lpptOffset offset required to position in-place server object
+ * window properly. caller should call:
+ * OffsetRect(&rcObjRect,lpptOffset->x,lpptOffset->y)
+ *
+ * Return Value:
+ * none
+ */
+STDAPI_(void) SetHatchWindowSize(
+ HWND hWndHatch,
+ LPRECT lprcIPObjRect,
+ LPRECT lprcClipRect,
+ LPPOINT lpptOffset
+)
+{
+ RECT rcHatchRect;
+ RECT rcVisRect;
+ UINT uHatchWidth;
+ POINT ptOffset;
+
+ if (!IsWindow(hWndHatch))
+ return;
+
+ rcHatchRect = *lprcIPObjRect;
+ uHatchWidth = GetHatchWidth(hWndHatch);
+ InflateRect((LPRECT)&rcHatchRect, uHatchWidth + 1, uHatchWidth + 1);
+
+ IntersectRect((LPRECT)&rcVisRect, (LPRECT)&rcHatchRect, lprcClipRect);
+ MoveWindow(
+ hWndHatch,
+ rcVisRect.left,
+ rcVisRect.top,
+ rcVisRect.right-rcVisRect.left,
+ rcVisRect.bottom-rcVisRect.top,
+ TRUE /* fRepaint */
+ );
+ InvalidateRect(hWndHatch, NULL, TRUE);
+
+ ptOffset.x = -rcHatchRect.left + (rcHatchRect.left - rcVisRect.left);
+ ptOffset.y = -rcHatchRect.top + (rcHatchRect.top - rcVisRect.top);
+
+ /* convert the rcHatchRect into the client coordinate system of the
+ ** HatchWindow itself
+ */
+ OffsetRect((LPRECT)&rcHatchRect, ptOffset.x, ptOffset.y);
+
+ SetHatchRect(hWndHatch, (LPRECT)&rcHatchRect);
+
+ // calculate offset required to position in-place server doc window
+ lpptOffset->x = ptOffset.x;
+ lpptOffset->y = ptOffset.y;
+}
+
+
+/*
+ * HatchWndProc
+ *
+ * Purpose:
+ * WndProc for hatch window
+ *
+ * Parameters:
+ * hWnd
+ * Message
+ * wParam
+ * lParam
+ *
+ * Return Value:
+ * message dependent
+ */
+LRESULT FAR PASCAL EXPORT HatchWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+ int nBorderWidth;
+
+ switch (Message) {
+
+ case WM_CREATE:
+ nBorderWidth = GetProfileInt(
+ TEXT("windows"),
+ TEXT("oleinplaceborderwidth"),
+ DEFAULT_HATCHBORDER_WIDTH
+ );
+ SetWindowWord(hWnd, EB_HATCHWIDTH, (WORD)nBorderWidth);
+ break;
+
+ case WM_PAINT:
+ {
+ HDC hDC;
+ PAINTSTRUCT ps;
+ RECT rcHatchRect;
+
+ nBorderWidth = GetHatchWidth(hWnd);
+ hDC = BeginPaint(hWnd, &ps);
+ GetHatchRect(hWnd, (LPRECT)&rcHatchRect);
+ OleUIDrawShading(&rcHatchRect, hDC, OLEUI_SHADE_BORDERIN,
+ nBorderWidth);
+ InflateRect((LPRECT)&rcHatchRect, -nBorderWidth, -nBorderWidth);
+ OleUIDrawHandles(&rcHatchRect, hDC, OLEUI_HANDLES_OUTSIDE,
+ nBorderWidth+1, TRUE);
+ EndPaint(hWnd, &ps);
+ break;
+ }
+
+ /* 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.
+ */
+ case WM_SETCURSOR:
+ SetCursor(LoadCursor( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );
+ return (LRESULT)TRUE;
+
+ default:
+ return DefWindowProc(hWnd, Message, wParam, lParam);
+ }
+
+ return 0L;
+}
diff --git a/private/oleutest/letest/ole2ui/hivgares.bmp b/private/oleutest/letest/ole2ui/hivgares.bmp
new file mode 100644
index 000000000..0011166da
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/hivgares.bmp
Binary files differ
diff --git a/private/oleutest/letest/ole2ui/icon.c b/private/oleutest/letest/ole2ui/icon.c
new file mode 100644
index 000000000..048a991fe
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/icon.c
@@ -0,0 +1,857 @@
+/*
+ * ICON.C
+ *
+ * Implements the OleUIChangeIcon function which invokes the complete
+ * Change Icon dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "common.h"
+#include "utility.h"
+#include "icon.h"
+#include "geticon.h"
+
+/*
+ * OleUIChangeIcon
+ *
+ * Purpose:
+ * Invokes the standard OLE Change Icon dialog box allowing the user
+ * to select an icon from an icon file, executable, or DLL.
+ *
+ * Parameters:
+ * lpCI LPOLEUIChangeIcon pointing to the in-out structure
+ * for this dialog.
+ *
+ * Return Value:
+ * UINT OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise
+ * an error value.
+ */
+
+STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON lpCI)
+ {
+ UINT uRet;
+ HGLOBAL hMemDlg=NULL;
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lpCI, sizeof(OLEUICHANGEICON)
+ , &hMemDlg);
+
+ if (OLEUI_SUCCESS!=uRet)
+ return uRet;
+
+#if defined( OBSOLETE )
+ if (NULL==lpCI->hMetaPict)
+ uRet=OLEUI_CIERR_MUSTHAVECURRENTMETAFILE;
+#endif
+
+ if (lpCI->dwFlags & CIF_USEICONEXE)
+ {
+ if ( (NULL == lpCI->szIconExe)
+ || (IsBadReadPtr(lpCI->szIconExe, lpCI->cchIconExe))
+ || (IsBadWritePtr(lpCI->szIconExe, lpCI->cchIconExe)) )
+ uRet = OLEUI_CIERR_SZICONEXEINVALID;
+
+ }
+
+ // REVIEW: how do we validate the CLSID?
+/*
+ if ('\0'==*((LPSTR)&lpCI->clsid))
+ uRet=OLEUI_CIERR_MUSTHAVECLSID;
+*/
+ if (OLEUI_ERR_STANDARDMIN <= uRet)
+ {
+ if (NULL!=hMemDlg)
+ FreeResource(hMemDlg);
+
+ return uRet;
+ }
+
+ //Now that we've validated everything, we can invoke the dialog.
+ return UStandardInvocation(ChangeIconDialogProc, (LPOLEUISTANDARD)lpCI
+ , hMemDlg, MAKEINTRESOURCE(IDD_CHANGEICON));
+ }
+
+
+
+
+
+/*
+ * ChangeIconDialogProc
+ *
+ * Purpose:
+ * Implements the OLE Change Icon dialog as invoked through the
+ * OleUIChangeIcon function.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+BOOL CALLBACK EXPORT ChangeIconDialogProc(HWND hDlg, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ LPCHANGEICON lpCI;
+ HICON hIcon;
+ HGLOBAL hMetaPict;
+ BOOL fOK=FALSE;
+ UINT uRet=0;
+ LPTSTR psz;
+ TCHAR szTemp[OLEUI_CCHPATHMAX];
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ lpCI=(LPCHANGEICON)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
+
+ //If the hook processed the message, we're done.
+ if (0!=uRet)
+ return uRet;
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ //Insure that icons are properly destroyed.
+ SendDlgItemMessage(hDlg, ID_ICONLIST, LB_RESETCONTENT, 0, 0L);
+
+ StandardCleanup(lpCI, hDlg);
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ switch (iMsg)
+ {
+ case WM_INITDIALOG:
+ FChangeIconInit(hDlg, wParam, lParam);
+ return TRUE;
+
+
+ case WM_MEASUREITEM:
+ {
+ LPMEASUREITEMSTRUCT lpMI=(LPMEASUREITEMSTRUCT)lParam;
+
+ //All icons are system metric+padding in width and height
+ lpMI->itemWidth =GetSystemMetrics(SM_CXICON)+CXICONPAD;
+ lpMI->itemHeight=GetSystemMetrics(SM_CYICON)+CYICONPAD;
+ }
+ break;
+
+
+ case WM_DRAWITEM:
+ return FDrawListIcon((LPDRAWITEMSTRUCT)lParam);
+
+
+ case WM_DELETEITEM:
+ //Free the GDI object for the item
+ DestroyIcon((HICON)LOWORD(((LPDELETEITEMSTRUCT)lParam)->itemData));
+ break;
+
+
+ case WM_COMMAND:
+ switch (wID)
+ {
+ case ID_CURRENT:
+ case ID_DEFAULT:
+ case ID_FROMFILE:
+ UpdateResultIcon(lpCI, hDlg, wID);
+ break;
+
+ case ID_LABELEDIT:
+ //When the edit loses focus, update the result display
+ if (EN_KILLFOCUS==wCode)
+ {
+ GetDlgItemText(hDlg, ID_LABELEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, ID_RESULTLABEL, szTemp);
+ }
+ break;
+
+ case ID_FROMFILEEDIT:
+ //If the text changed, remove any selection in the list.
+ GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
+
+ if (lpCI && lstrcmpi(szTemp, lpCI->szFile))
+ {
+ SendDlgItemMessage(hDlg, ID_ICONLIST, LB_SETCURSEL
+ , (WPARAM)-1, 0);
+
+ //Also force selection of ID_FROMFILE
+ CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_FROMFILE);
+ }
+ break;
+
+
+ case ID_ICONLIST:
+ switch (wCode)
+ {
+ case LBN_SETFOCUS:
+ //If we got the focus, see about updating.
+ GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp
+ , sizeof(szTemp)/sizeof(TCHAR));
+
+ //Check if file changed and update the list if so
+ if (lpCI && 0!=lstrcmpi(szTemp, lpCI->szFile))
+ {
+ lstrcpy(lpCI->szFile, szTemp);
+ UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);
+ UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
+ }
+ break;
+
+ case LBN_SELCHANGE:
+ UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
+ break;
+
+ case LBN_DBLCLK:
+ //Same as pressing OK.
+ SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
+ break;
+ }
+ break;
+
+
+ case ID_BROWSE:
+ {
+ DWORD dwOfnFlags;
+
+ /*
+ * To allow the hook to customize the browse dialog, we
+ * send OLEUI_MSG_BROWSE. If the hook returns FALSE
+ * we use the default, otherwise we trust that it retrieved
+ * a filename for us. This mechanism prevents hooks from
+ * trapping ID_BROWSE to customize the dialog and from
+ * trying to figure out what we do after we have the name.
+ */
+
+ //Copy for reference
+ LSTRCPYN(szTemp, lpCI->szFile, sizeof(szTemp)/sizeof(TCHAR));
+
+ uRet=UStandardHook(lpCI, hDlg, uMsgBrowse, OLEUI_CCHPATHMAX_SIZE
+ , (LONG)(LPSTR)lpCI->szFile);
+
+ dwOfnFlags = OFN_FILEMUSTEXIST;
+ if (lpCI->lpOCI->dwFlags & CIF_SHOWHELP)
+ dwOfnFlags |= OFN_SHOWHELP;
+
+ if (0==uRet)
+ uRet=(BOOL)Browse(hDlg, lpCI->szFile, NULL, OLEUI_CCHPATHMAX_SIZE, IDS_ICONFILTERS, dwOfnFlags);
+
+ /*
+ * Only reinitialize if the file changed, so if we got
+ * TRUE from the hook but the user hit Cancel, we don't
+ * spend time unecessarily refilling the list.
+ */
+ if (0!=uRet && 0!=lstrcmpi(szTemp, lpCI->szFile))
+ {
+ CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_FROMFILE);
+ SetDlgItemText(hDlg, ID_FROMFILEEDIT, lpCI->szFile);
+ UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);
+ UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
+ }
+ }
+ break;
+
+
+ case IDOK:
+ /*
+ * If the user pressed enter, compare the current file
+ * and the one we have stored. If they match, then
+ * refill the listbox instead of closing down. This is
+ * so the user can press Enter in the edit control as
+ * they would expect to be able to do.
+ */
+ GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
+
+ //Check if the file changed at all.
+ if (0!=lstrcmpi(szTemp, lpCI->szFile))
+ {
+ lstrcpy(lpCI->szFile, szTemp);
+ UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);
+ UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
+
+ //Eat this message to prevent focus change.
+ return TRUE;
+ }
+
+ // Check if the file name is valid
+ // (if FromFile is enabled)
+ if (ID_FROMFILE & lpCI->dwFlags)
+ {
+ OFSTRUCT of;
+ HWND hWnd;
+ if (HFILE_ERROR==DoesFileExist(lpCI->szFile, &of))
+ {
+ OpenFileError(hDlg, of.nErrCode, lpCI->szFile);
+ hWnd = GetDlgItem(hDlg, ID_FROMFILEEDIT);
+ SetFocus(hWnd);
+ SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
+ return TRUE; // eat this message
+ }
+ }
+
+ if ((HWND)LOWORD(lParam) != GetFocus())
+ SetFocus((HWND)LOWORD(lParam));
+
+ /*
+ * On closing, create a new metafilepict with the
+ * current icon and label, destroying the old structure.
+ *
+ * Since we make a copy of the icon by placing it into
+ * the metafile, we have to make sure we delete the
+ * icon in the current field. When the listbox is
+ * destroyed WM_DELETEITEMs will clean it up appropriately.
+ */
+
+ hIcon=(HICON)SendDlgItemMessage(hDlg, ID_RESULTICON
+ , STM_GETICON, 0, 0L);
+
+ /*
+ * If default is selected then we get the source
+ * information from registrion database for the
+ * current class to put in the metafile. If current
+ * is selected the we just retrieve the original file
+ * again and recreate the metafile. If from file is
+ * selected we use the current filename from the
+ * control and the current listbox selection.
+ */
+
+ psz=lpCI->szFile;
+
+ if (lpCI->dwFlags & CIF_SELECTDEFAULT)
+ {
+ psz=lpCI->szDefIconFile;
+ lpCI->iIcon=lpCI->iDefIcon;
+ hIcon=lpCI->hDefIcon;
+ }
+
+ if (lpCI->dwFlags & CIF_SELECTCURRENT)
+ {
+ //Go get the current icon source back.
+ OleUIMetafilePictExtractIconSource(lpCI->lpOCI->hMetaPict
+ , psz, &lpCI->iIcon);
+ }
+
+ if (lpCI->dwFlags & CIF_SELECTFROMFILE)
+ {
+ GetDlgItemText(hDlg, ID_FROMFILEEDIT, psz, OLEUI_CCHPATHMAX);
+
+ lpCI->iIcon=(UINT)SendDlgItemMessage(hDlg
+ , ID_ICONLIST, LB_GETCURSEL, 0, 0L);
+ }
+
+
+ //Get the label and go create the metafile
+ GetDlgItemText(hDlg, ID_LABELEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
+
+ //If psz is NULL (default) we get no source comments.
+
+#ifdef OLE201
+ hMetaPict=OleUIMetafilePictFromIconAndLabel(hIcon,
+ szTemp, psz, lpCI->iIcon);
+#endif
+
+ //Clean up the current icon that we extracted.
+ hIcon=(HICON)SendDlgItemMessage(hDlg, ID_CURRENTICON
+ , STM_GETICON, 0, 0L);
+ DestroyIcon(hIcon);
+
+ //Clean up the default icon
+ DestroyIcon(lpCI->hDefIcon);
+
+ // Remove the prop set on our parent
+ RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);
+
+ if (NULL==hMetaPict)
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_FALSE, 0L);
+
+ OleUIMetafilePictIconFree(lpCI->lpOCI->hMetaPict);
+ lpCI->lpOCI->hMetaPict=hMetaPict;
+
+ lpCI->lpOCI->dwFlags = lpCI->dwFlags;
+
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ break;
+
+
+ case IDCANCEL:
+ //Clean up the current icon that we extracted.
+ hIcon=(HICON)SendDlgItemMessage(hDlg, ID_CURRENTICON
+ , STM_GETICON, 0, 0L);
+ DestroyIcon(hIcon);
+
+ //Clean up the default icon
+ DestroyIcon(lpCI->hDefIcon);
+
+ // Remove the prop set on our parent
+ RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);
+
+ //We leave hMetaPict intact on Cancel; caller's responsibility
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ break;
+
+
+ case ID_OLEUIHELP:
+ PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,
+ (WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICON, 0));
+ break;
+ }
+ break;
+
+ default:
+ {
+ if (lpCI && iMsg == lpCI->nBrowseHelpID) {
+ PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,
+ (WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICONBROWSE, 0));
+ }
+ }
+ break;
+ }
+ return FALSE;
+ }
+
+
+
+
+/*
+ * FChangeIconInit
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the Change Icon dialog box.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL FChangeIconInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
+ {
+ LPCHANGEICON lpCI;
+ LPOLEUICHANGEICON lpOCI;
+ HFONT hFont;
+ HWND hList;
+ UINT cyList;
+ RECT rc, rcG;
+ UINT uID;
+
+ //1. Copy the structure at lParam into our instance memory.
+ lpCI=(LPCHANGEICON)LpvStandardInit(hDlg, sizeof(CHANGEICON), TRUE, &hFont);
+
+ //PvStandardInit send a termination to us already.
+ if (NULL==lpCI)
+ return FALSE;
+
+ //Save the original pointer and copy necessary information.
+ lpOCI=(LPOLEUICHANGEICON)lParam;
+
+ lpCI->lpOCI =lpOCI;
+ lpCI->dwFlags=lpOCI->dwFlags;
+
+ //Go extract the icon source from the metafile.
+ OleUIMetafilePictExtractIconSource(lpOCI->hMetaPict, lpCI->szFile, &lpCI->iIcon);
+
+ //Go extract the icon and the label from the metafile
+ OleUIMetafilePictExtractLabel(lpOCI->hMetaPict, lpCI->szLabel, OLEUI_CCHLABELMAX_SIZE, NULL);
+ lpCI->hCurIcon=OleUIMetafilePictExtractIcon(lpOCI->hMetaPict);
+
+ //2. If we got a font, send it to the necessary controls.
+ if (NULL!=hFont)
+ {
+ SendDlgItemMessage(hDlg, ID_RESULTLABEL, WM_SETFONT
+ , (WPARAM)hFont, 0L);
+ }
+
+
+ //3. Show or hide the help button
+ if (!(lpCI->dwFlags & CIF_SHOWHELP))
+ StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
+
+
+ /*
+ * 4. Set text limits and initial control values. If we're given
+ * an intial label we set it in the edit and static controls.
+ * If we don't, then we copy the default contents of the static
+ * control into the edit control, meaning that only the default
+ * static control string need be localized.
+ */
+
+ SendDlgItemMessage(hDlg, ID_LABELEDIT, EM_LIMITTEXT, OLEUI_CCHLABELMAX, 0L);
+ SendDlgItemMessage(hDlg, ID_FROMFILEEDIT, EM_LIMITTEXT, OLEUI_CCHPATHMAX, 0L);
+ SetDlgItemText(hDlg, ID_FROMFILEEDIT, lpCI->szFile);
+
+ //Copy the label text into the edit and static controls.
+ SetDlgItemText(hDlg, ID_LABELEDIT, lpCI->szLabel);
+ SetDlgItemText(hDlg, ID_RESULTLABEL, lpCI->szLabel);
+
+
+ lpCI->hDefIcon = NULL;
+
+ if (lpCI->dwFlags & CIF_USEICONEXE)
+ {
+ lpCI->hDefIcon = ExtractIcon(ghInst, lpCI->lpOCI->szIconExe, 0);
+
+ if (NULL != lpCI->hDefIcon)
+ {
+ lstrcpy(lpCI->szDefIconFile, lpCI->lpOCI->szIconExe);
+ lpCI->iDefIcon = 0;
+ }
+ }
+
+
+ if (NULL == lpCI->hDefIcon)
+ {
+ HGLOBAL hMetaPict;
+
+#ifdef OLE201
+ hMetaPict = GetIconOfClass(ghInst,
+ &lpCI->lpOCI->clsid,
+ NULL,
+ TRUE);
+#endif
+
+ lpCI->hDefIcon = OleUIMetafilePictExtractIcon(hMetaPict);
+
+ OleUIMetafilePictExtractIconSource(hMetaPict,
+ lpCI->szDefIconFile,
+ &lpCI->iDefIcon);
+
+ OleUIMetafilePictIconFree(hMetaPict);
+ }
+
+
+ //Initialize all the icon displays.
+ SendDlgItemMessage(hDlg, ID_CURRENTICON, STM_SETICON
+ , (WPARAM)lpCI->hCurIcon, 0L);
+ SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_SETICON
+ , (WPARAM)lpCI->hDefIcon, 0L);
+ SendDlgItemMessage(hDlg, ID_RESULTICON, STM_SETICON
+ , (WPARAM)lpCI->hCurIcon, 0L);
+
+
+ /*
+ * 5. Since we cannot predict the size of icons on any display,
+ * we have to resize the icon listbox to the size of an icon
+ * (plus padding), a scrollbar, and two borders (top & bottom).
+ */
+ cyList=GetSystemMetrics(SM_CYICON)+GetSystemMetrics(SM_CYHSCROLL)
+ +GetSystemMetrics(SM_CYBORDER)*2+CYICONPAD;
+
+ hList=GetDlgItem(hDlg, ID_ICONLIST);
+ GetClientRect(hList, &rc);
+ SetWindowPos(hList, NULL, 0, 0, rc.right, cyList
+ , SWP_NOMOVE | SWP_NOZORDER);
+
+ //Set the columns in this multi-column listbox to hold one icon
+ SendMessage(hList, LB_SETCOLUMNWIDTH
+ , GetSystemMetrics(SM_CXICON)+CXICONPAD,0L);
+
+ /*
+ * 5a. If the listbox expanded below the group box, then size
+ * the groupbox down, move the label static and exit controls
+ * down, and expand the entire dialog appropriately.
+ */
+
+ GetWindowRect(hList, &rc);
+ GetWindowRect(GetDlgItem(hDlg, ID_GROUP), &rcG);
+
+ if (rc.bottom > rcG.bottom)
+ {
+ //Calculate amount to move things down.
+ cyList=(rcG.bottom-rcG.top)-(rc.bottom-rc.top-cyList);
+
+ //Expand the group box.
+ rcG.right -=rcG.left;
+ rcG.bottom-=rcG.top;
+ SetWindowPos(GetDlgItem(hDlg, ID_GROUP), NULL, 0, 0
+ , rcG.right, rcG.bottom+cyList
+ , SWP_NOMOVE | SWP_NOZORDER);
+
+ //Expand the dialog box.
+ GetClientRect(hDlg, &rc);
+ SetWindowPos(hDlg, NULL, 0, 0, rc.right, rc.bottom+cyList
+ , SWP_NOMOVE | SWP_NOZORDER);
+
+ //Move the label and edit controls down.
+ GetClientRect(GetDlgItem(hDlg, ID_LABEL), &rc);
+ SetWindowPos(GetDlgItem(hDlg, ID_LABEL), NULL, 0, cyList
+ , rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);
+
+ GetClientRect(GetDlgItem(hDlg, ID_LABELEDIT), &rc);
+ SetWindowPos(GetDlgItem(hDlg, ID_LABELEDIT), NULL, 0, cyList
+ , rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);
+ }
+
+
+ /*
+ * 6. Select Current, Default, or From File radiobuttons appropriately.
+ * The CheckRadioButton call sends WM_COMMANDs which handle
+ * other actions. Note that if we check From File, which
+ * takes an icon from the list, we better fill the list.
+ * This will also fill the list even if default is selected.
+ */
+
+ if (0!=UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile))
+ {
+ //If szFile worked, then select the source icon in the listbox.
+ SendDlgItemMessage(hDlg, ID_ICONLIST, LB_SETCURSEL, lpCI->iIcon, 0L);
+ }
+
+
+ if (lpCI->dwFlags & CIF_SELECTCURRENT)
+ CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_CURRENT);
+ else
+ {
+ uID=(lpCI->dwFlags & CIF_SELECTFROMFILE) ? ID_FROMFILE : ID_DEFAULT;
+ CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, uID);
+ }
+
+ //7. Give our parent window access to our hDlg (via a special SetProp).
+ // The PasteSpecial dialog may need to force our dialog down if the
+ // clipboard contents change underneath it. if so it will send
+ // us a IDCANCEL command.
+ SetProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG, hDlg);
+
+ lpCI->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);
+
+ //8. Call the hook with lCustData in lParam
+ UStandardHook(lpCI, hDlg, WM_INITDIALOG, wParam, lpOCI->lCustData);
+ return TRUE;
+ }
+
+
+
+
+
+/*
+ * UFillIconList
+ *
+ * Purpose:
+ * Given a listbox and a filename, attempts to open that file and
+ * read all the icons that exist therein, adding them to the listbox
+ * hList as owner-draw items. If the file does not exist or has no
+ * icons, then you get no icons and an appropriate warning message.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog containing the listbox.
+ * idList UINT identifier of the listbox to fill.
+ * pszFile LPSTR of the file from which to extract icons.
+ *
+ * Return Value:
+ * UINT Number of items added to the listbox. 0 on failure.
+ */
+
+UINT UFillIconList(HWND hDlg, UINT idList, LPTSTR pszFile)
+ {
+ HWND hList;
+ UINT i;
+ UINT cIcons=0;
+ HCURSOR hCur;
+ HICON hIcon;
+ OFSTRUCT of;
+
+ if (NULL==hDlg || !IsWindow(hDlg) || NULL==pszFile)
+ return 0;
+
+ hList=GetDlgItem(hDlg, idList);
+
+ if (NULL==hList)
+ return 0;
+
+ //Clean out the listbox.
+ SendMessage(hList, LB_RESETCONTENT, 0, 0L);
+
+ //If we have an empty string, just exit leaving the listbox empty as well
+ if (0==lstrlen(pszFile))
+ return 0;
+
+ //Turn on the hourglass
+ hCur=HourGlassOn();
+
+ //Check if the file is valid.
+ if (HFILE_ERROR!=DoesFileExist(pszFile, &of))
+ {
+ #ifdef EXTRACTICONWORKS
+ //Get the icon count for this file.
+ cIcons=(UINT)ExtractIcon(ghInst, pszFile, (UINT)-1);
+ #else
+ /*
+ * ExtractIcon in Windows 3.1 with -1 eats a selector, leaving an
+ * extra global memory object around for this applciation. Since
+ * changing icons may happen very often with all OLE apps in
+ * the system, we have to work around it. So we'll say we
+ * have lots of icons and just call ExtractIcon until it
+ * fails. We check if there's any around by trying to get
+ * the first one.
+ */
+ cIcons=0xFFFF;
+
+ hIcon=ExtractIcon(ghInst, pszFile, 0);
+
+ //Fake a failure with cIcons=0, or cleanup hIcon from this test.
+ if (32 > (UINT)hIcon)
+ cIcons=0;
+ else
+ DestroyIcon(hIcon);
+ #endif
+
+ if (0!=cIcons)
+ {
+ SendMessage(hList, WM_SETREDRAW, FALSE, 0L);
+
+ for (i=0; i<cIcons; i++)
+ {
+ hIcon=ExtractIcon(ghInst, pszFile, i);
+
+ if (32 < (UINT)hIcon)
+ SendMessage(hList, LB_ADDSTRING, 0, (LONG)(UINT)hIcon);
+ #ifndef EXTRACTICONWORKS
+ else
+ {
+ //ExtractIcon failed, so let's leave now.
+ break;
+ }
+ #endif
+ }
+
+ //Force complete repaint
+ SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
+ InvalidateRect(hList, NULL, TRUE);
+
+ //Select an icon
+ SendMessage(hList, LB_SETCURSEL, 0, 0L);
+ }
+ else
+ ErrorWithFile(hDlg, ghInst, IDS_CINOICONSINFILE, pszFile, MB_OK);
+ }
+ else
+ OpenFileError(hDlg, of.nErrCode, pszFile);
+
+ HourGlassOff(hCur);
+ return cIcons;
+ }
+
+
+
+
+/*
+ * FDrawListIcon
+ *
+ * Purpose:
+ * Handles WM_DRAWITEM for the icon listbox.
+ *
+ * Parameters:
+ * lpDI LPDRAWITEMSTRUCT from WM_DRAWITEM
+ *
+ * Return Value:
+ * BOOL TRUE if we did anything, FALSE if there are no items
+ * in the list.
+ */
+
+BOOL FDrawListIcon(LPDRAWITEMSTRUCT lpDI)
+ {
+ COLORREF cr;
+
+ /*
+ * If there are no items in the list, then itemID is negative according
+ * to the Win3.1 SDK. Unfortunately DRAWITEMSTRUCT has an unsigned int
+ * for this field, so we need the typecast to do a signed comparison.
+ */
+ if ((int)lpDI->itemID < 0)
+ return FALSE;
+
+ /*
+ * For selection or draw entire case we just draw the entire item all
+ * over again. For focus cases, we only call DrawFocusRect.
+ */
+
+ if (lpDI->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))
+ {
+ //Clear background and draw the icon.
+ if (lpDI->itemState & ODS_SELECTED)
+ cr=SetBkColor(lpDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
+ else
+ cr=SetBkColor(lpDI->hDC, GetSysColor(COLOR_WINDOW));
+
+ //Draw a cheap rectangle.
+ ExtTextOut(lpDI->hDC, 0, 0, ETO_OPAQUE, &lpDI->rcItem
+ , NULL, 0, NULL);
+
+ DrawIcon(lpDI->hDC, lpDI->rcItem.left+(CXICONPAD/2)
+ , lpDI->rcItem.top+(CYICONPAD/2)
+ , (HICON)LOWORD(lpDI->itemData));
+
+ //Restore original background for DrawFocusRect
+ SetBkColor(lpDI->hDC, cr);
+ }
+
+ //Always change focus on the focus action.
+ if (lpDI->itemAction & ODA_FOCUS || lpDI->itemState & ODS_FOCUS)
+ DrawFocusRect(lpDI->hDC, &lpDI->rcItem);
+
+ return TRUE;
+ }
+
+
+
+
+
+/*
+ * UpdateResultIcon
+ *
+ * Purpose:
+ * Updates the result icon using the current icon in the default display
+ * or the icon listbox depending on fFromDefault.
+ *
+ * Parameters:
+ * lpCI LPCHANGEICON containing dialog flags.
+ * hDlg HWND of the dialog
+ * uID UINT identifying the radiobutton selected.
+ *
+ * Return Value:
+ * None
+ */
+
+void UpdateResultIcon(LPCHANGEICON lpCI, HWND hDlg, UINT uID)
+ {
+ UINT iSel;
+ LONG lTemp=LB_ERR;
+
+ lpCI->dwFlags &= ~(CIF_SELECTCURRENT | CIF_SELECTDEFAULT | CIF_SELECTFROMFILE);
+
+ switch (uID)
+ {
+ case ID_CURRENT:
+ lTemp=SendDlgItemMessage(hDlg, ID_CURRENTICON, STM_GETICON, 0, 0L);
+ lpCI->dwFlags |= CIF_SELECTCURRENT;
+ break;
+
+ case ID_DEFAULT:
+ lTemp=SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_GETICON, 0, 0L);
+ lpCI->dwFlags |= CIF_SELECTDEFAULT;
+ break;
+
+ case ID_FROMFILE:
+ //Get the selected icon from the list and place it in the result
+ lpCI->dwFlags |= CIF_SELECTFROMFILE;
+
+ iSel=(UINT)SendDlgItemMessage(hDlg, ID_ICONLIST, LB_GETCURSEL, 0, 0L);
+ if ((UINT)LB_ERR==iSel)
+ lTemp=SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_GETICON, 0, 0L);
+ else
+ SendDlgItemMessage(hDlg, ID_ICONLIST, LB_GETTEXT, iSel
+ , (LPARAM)(LPLONG)&lTemp);
+
+ break;
+ }
+
+ if ((LONG)LB_ERR!=lTemp)
+ SendDlgItemMessage(hDlg, ID_RESULTICON, STM_SETICON, LOWORD(lTemp), 0L);
+ return;
+ }
+
+
diff --git a/private/oleutest/letest/ole2ui/icon.dlg b/private/oleutest/letest/ole2ui/icon.dlg
new file mode 100644
index 000000000..43a2f274c
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/icon.dlg
@@ -0,0 +1,48 @@
+// DLGINCLUDE RCDATA DISCARDABLE
+// BEGIN
+// "OLE2UI.H\0"
+// END
+
+
+IDD_CHANGEICON DIALOG 18, 18, 261, 152
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Change Icon"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Icon", ID_GROUP, 4, 6, 180, 124
+ CONTROL "&Current", ID_CURRENT, "Button", BS_AUTORADIOBUTTON |
+ WS_GROUP , 10, 19, 46, 10
+
+ CONTROL "&Default", ID_DEFAULT, "Button", BS_AUTORADIOBUTTON,
+ 10, 44, 46, 10
+
+ CONTROL "&From File:", ID_FROMFILE, "Button", BS_AUTORADIOBUTTON,
+ 10, 68, 46, 10
+
+ ICON "", ID_CURRENTICON, 58, 15, 18, 20
+
+ ICON "", ID_DEFAULTICON, 58, 40, 18, 20
+
+ EDITTEXT ID_FROMFILEEDIT, 58, 68, 119, 12, ES_LOWERCASE |
+ ES_AUTOHSCROLL | WS_GROUP | ES_OEMCONVERT
+
+ LISTBOX ID_ICONLIST, 58, 84, 119, 40, LBS_OWNERDRAWFIXED |
+ LBS_NOINTEGRALHEIGHT | LBS_MULTICOLUMN | WS_HSCROLL |
+ WS_TABSTOP
+
+ LTEXT "&Label:", ID_LABEL, 6, 138, 32, 8
+
+ EDITTEXT ID_LABELEDIT, 38, 136, 146, 12, ES_AUTOHSCROLL
+
+ DEFPUSHBUTTON "OK", IDOK, 189, 6, 66, 14
+
+ PUSHBUTTON "Cancel", IDCANCEL, 189, 23, 66, 14
+
+ PUSHBUTTON "&Browse...", ID_BROWSE, 189, 41, 66, 14
+
+ PUSHBUTTON "&Help", ID_OLEUIHELP, 189, 59, 66, 14
+
+ CTEXT "", ID_RESULTLABEL, 193, 114, 63, 24
+ ICON "", ID_RESULTICON, 214, 90, 18, 20
+END
+
diff --git a/private/oleutest/letest/ole2ui/icon.h b/private/oleutest/letest/ole2ui/icon.h
new file mode 100644
index 000000000..512155949
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/icon.h
@@ -0,0 +1,59 @@
+/*
+ * ICON.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI Change Icon dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _ICON_H_
+#define _ICON_H_
+
+#ifndef RC_INVOKED
+#pragma message ("INCLUDING ICON.H from " __FILE__)
+#endif /* RC_INVOKED */
+
+#define CXICONPAD 12
+#define CYICONPAD 4
+
+// Property used by ChangeIcon dialog to give its parent window access to
+// its hDlg. The PasteSpecial dialog may need to force the ChgIcon dialog
+// down if the clipboard contents change underneath it. if so it will send
+// a IDCANCEL command to the ChangeIcon dialog.
+#define PROP_HWND_CHGICONDLG TEXT("HWND_CIDLG")
+
+//Internally used structure
+typedef struct tagCHANGEICON
+ {
+ LPOLEUICHANGEICON lpOCI; //Original structure passed.
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog but that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+ DWORD dwFlags;
+ HICON hCurIcon;
+ TCHAR szLabel[OLEUI_CCHLABELMAX+1];
+ TCHAR szFile[OLEUI_CCHPATHMAX];
+ UINT iIcon;
+ HICON hDefIcon;
+ TCHAR szDefIconFile[OLEUI_CCHPATHMAX];
+ UINT iDefIcon;
+ UINT nBrowseHelpID; // Help ID callback for Browse dlg
+ } CHANGEICON, *PCHANGEICON, FAR *LPCHANGEICON;
+
+
+//Internal function prototypes
+//ICON.C
+BOOL CALLBACK EXPORT ChangeIconDialogProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FChangeIconInit(HWND, WPARAM, LPARAM);
+UINT UFillIconList(HWND, UINT, LPTSTR);
+BOOL FDrawListIcon(LPDRAWITEMSTRUCT);
+void UpdateResultIcon(LPCHANGEICON, HWND, UINT);
+
+
+#endif //_ICON_H_
diff --git a/private/oleutest/letest/ole2ui/iconbox.c b/private/oleutest/letest/ole2ui/iconbox.c
new file mode 100644
index 000000000..8422f5dcc
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/iconbox.c
@@ -0,0 +1,253 @@
+/*
+ * ICONBOX.C
+ *
+ * Implemenatation of an IconBox control for OLE 2.0 UI dialogs that we'll
+ * use wherever a dialog needs an icon/label display. Through the control's
+ * interface we can change the image or control label visibility.
+ *
+ * The IconBox discusses images in CF_METAFILEPICT format. When drawing
+ * such a metafile, the entire aspect is centered in the IconBox, so long
+ * labels are chopped at either end.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "iconbox.h"
+
+
+//Flag indicating if we've registered the class
+static BOOL fRegistered=FALSE;
+
+
+/*
+ * FIconBoxInitialize
+ *
+ * Purpose:
+ * Registers the IconBox control class.
+ *
+ * Parameters:
+ * hInst HINSTANCE instance of the DLL.
+ *
+ * hPrevInst HINSTANCE of the previous instance. Used to
+ * determine whether to register window classes or not.
+ *
+ * lpszClassName LPSTR containing the class name to register the
+ * IconBox control class with.
+ *
+ * Return Value:
+ * BOOL TRUE if all initialization succeeded, FALSE otherwise.
+ */
+
+BOOL FIconBoxInitialize(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpszClassName)
+ {
+ WNDCLASS wc;
+
+ // Only register class if we're the first instance
+ if (hPrevInst)
+ fRegistered = TRUE;
+ else
+ {
+
+ // Static flag fRegistered guards against calling this function more
+ // than once
+ if (!fRegistered)
+ {
+ wc.lpfnWndProc =IconBoxWndProc;
+ wc.cbClsExtra =0;
+ wc.cbWndExtra =CBICONBOXWNDEXTRA;
+ wc.hInstance =hInst;
+ wc.hIcon =NULL;
+ wc.hCursor =LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground =(HBRUSH)NULL;
+ wc.lpszMenuName =NULL;
+ wc.lpszClassName =lpszClassName;
+ wc.style =CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
+
+ fRegistered=RegisterClass(&wc);
+ }
+ }
+
+ return fRegistered;
+}
+
+
+/*
+ * IconBoxUninitialize
+ *
+ * Purpose:
+ * Cleans up anything done in FIconBoxInitialize. Currently there is
+ * nothing, but we do this for symmetry.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * None
+ */
+
+void IconBoxUninitialize(void)
+ {
+ //Nothing to do.
+ return;
+ }
+
+
+
+
+
+
+/*
+ * IconBoxWndProc
+ *
+ * Purpose:
+ * Window Procedure for the IconBox custom control. Only handles
+ * WM_CREATE, WM_PAINT, and private messages to manipulate the image.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+LONG CALLBACK EXPORT IconBoxWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+ {
+ HGLOBAL hMF=NULL;
+ PAINTSTRUCT ps;
+ HDC hDC;
+ RECT rc;
+
+
+ //Handle standard Windows messages.
+ switch (iMsg)
+ {
+ case WM_CREATE:
+ SetWindowLong(hWnd, IBWW_HIMAGE, 0);
+ SetWindowWord(hWnd, IBWW_FLABEL, TRUE);
+ return 0L;
+
+
+ case WM_ERASEBKGND:
+ {
+
+ HBRUSH hBrush;
+ RECT Rect;
+#if defined( WIN32 )
+ POINT point;
+#endif
+
+ GetClientRect(hWnd, &Rect);
+#if defined( WIN32 )
+ hBrush = (HBRUSH)SendMessage(GetParent(hWnd),
+ WM_CTLCOLORDLG,
+ wParam,
+ (LPARAM)GetParent(hWnd));
+#else
+ hBrush = (HBRUSH)SendMessage(GetParent(hWnd),
+ WM_CTLCOLOR,
+ wParam,
+ MAKELPARAM(GetParent(hWnd), CTLCOLOR_DLG));
+#endif
+
+
+ if (!hBrush)
+ return FALSE;
+
+ UnrealizeObject(hBrush);
+
+#if defined( WIN32 )
+ SetBrushOrgEx((HDC)wParam, 0, 0, &point);
+#else
+ SetBrushOrg((HDC)wParam, 0, 0);
+#endif
+
+ FillRect((HDC)wParam, &Rect, hBrush);
+
+ return TRUE;
+ }
+
+
+ case WM_PAINT:
+ hMF=(HGLOBAL)GetWindowLong(hWnd, IBWW_HIMAGE);
+
+ //BeginPaint and EndPaint clear us even if hMF is NULL.
+ hDC=BeginPaint(hWnd, &ps);
+
+ if (NULL!=hMF)
+ {
+ BOOL fLabel;
+
+ //Now we get to paint the metafile, centered in our rect.
+ GetClientRect(hWnd, &rc);
+
+ /*
+ * If we're doing icon only, then place the metafile
+ * at the center of our box minus half the icon width.
+ * Top is top.
+ */
+
+ fLabel=GetWindowWord(hWnd, IBWW_FLABEL);
+
+
+ //Go draw where we decided to place it.
+ OleUIMetafilePictIconDraw(hDC, &rc, hMF, !fLabel);
+ }
+
+ EndPaint(hWnd, &ps);
+ break;
+
+
+ case IBXM_IMAGESET:
+ /*
+ * wParam contains the new handle.
+ * lParam is a flag to delete the old or not.
+ */
+ hMF=(HGLOBAL)SetWindowLong(hWnd, IBWW_HIMAGE, wParam);
+ InvalidateRect(hWnd, NULL, TRUE);
+ UpdateWindow(hWnd);
+
+ //Delete the old handle if requested
+ if (0L!=lParam)
+ {
+ OleUIMetafilePictIconFree(hMF);
+ hMF=NULL;
+ }
+
+ return (LONG)(UINT)hMF;
+
+
+ case IBXM_IMAGEGET:
+ //Return the current index.
+ hMF=(HGLOBAL)GetWindowLong(hWnd, IBWW_HIMAGE);
+ return (LONG)(UINT)hMF;
+
+
+ case IBXM_IMAGEFREE:
+ //Free up whatever we're holding.
+ hMF=(HGLOBAL)GetWindowLong(hWnd, IBWW_HIMAGE);
+ OleUIMetafilePictIconFree(hMF);
+ return 1L;
+
+
+ case IBXM_LABELENABLE:
+ //wParam has the new flag, returns the previous flag.
+ return (LONG)SetWindowWord(hWnd, IBWW_FLABEL, (WORD)wParam);
+
+
+ default:
+ return DefWindowProc(hWnd, iMsg, wParam, lParam);
+ }
+
+ return 0L;
+ }
+
+
+
+
+
+
+
+
diff --git a/private/oleutest/letest/ole2ui/iconbox.h b/private/oleutest/letest/ole2ui/iconbox.h
new file mode 100644
index 000000000..057b59e75
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/iconbox.h
@@ -0,0 +1,31 @@
+/*
+ * ICONBOX.H
+ *
+ * Structures and definitions for the IconBox control.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _ICONBOX_H_
+#define _ICONBOX_H_
+
+//Function prototypes
+BOOL FIconBoxInitialize(HINSTANCE, HINSTANCE, LPTSTR);
+void IconBoxUninitialize(void);
+LONG CALLBACK EXPORT IconBoxWndProc(HWND, UINT, WPARAM, LPARAM);
+
+
+//Window extra bytes contain the bitmap index we deal with currently.
+#define CBICONBOXWNDEXTRA (sizeof(HGLOBAL)+sizeof(BOOL))
+#define IBWW_HIMAGE 0
+#define IBWW_FLABEL (sizeof(HGLOBAL))
+
+//Control messages
+#define IBXM_IMAGESET (WM_USER+0)
+#define IBXM_IMAGEGET (WM_USER+1)
+#define IBXM_IMAGEFREE (WM_USER+2)
+#define IBXM_LABELENABLE (WM_USER+3)
+
+
+#endif //_ICONBOX_H_
diff --git a/private/oleutest/letest/ole2ui/insobj.c b/private/oleutest/letest/ole2ui/insobj.c
new file mode 100644
index 000000000..53fa094c9
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/insobj.c
@@ -0,0 +1,1724 @@
+/*
+ * INSOBJ.C
+ *
+ * Implements the OleUIInsertObject function which invokes the complete
+ * Insert Object dialog. Makes use of the OleChangeIcon function in
+ * ICON.C.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include <commdlg.h>
+#include <memory.h>
+#include <direct.h>
+#include <malloc.h>
+#include <dos.h>
+#include <stdlib.h>
+#include "common.h"
+#include "utility.h"
+#include "icon.h"
+#include "insobj.h"
+#include "resimage.h"
+#include "iconbox.h"
+#include "geticon.h"
+
+#define IS_FILENAME_DELIM(c) ( (c) == TEXT('\\') || (c) == TEXT('/') || (c) == TEXT(':') )
+
+/*
+ * OleUIInsertObject
+ *
+ * Purpose:
+ * Invokes the standard OLE Insert Object dialog box allowing the
+ * user to select an object source and classname as well as the option
+ * to display the object as itself or as an icon.
+ *
+ * Parameters:
+ * lpIO LPOLEUIINSERTOBJECT pointing to the in-out structure
+ * for this dialog.
+ *
+ * Return Value:
+ * UINT OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise
+ * an error value.
+ */
+
+STDAPI_(UINT) OleUIInsertObject(LPOLEUIINSERTOBJECT lpIO)
+ {
+ UINT uRet;
+ HGLOBAL hMemDlg=NULL;
+ HRESULT hrErr;
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lpIO, sizeof(OLEUIINSERTOBJECT)
+ , &hMemDlg);
+
+ if (OLEUI_SUCCESS!=uRet)
+ return uRet;
+
+ //Now we can do Insert Object specific validation.
+
+
+ // NULL is NOT valid for lpszFile
+ if ( (NULL == lpIO->lpszFile)
+ || (IsBadReadPtr(lpIO->lpszFile, lpIO->cchFile))
+ || (IsBadWritePtr(lpIO->lpszFile, lpIO->cchFile)) )
+ uRet=OLEUI_IOERR_LPSZFILEINVALID;
+
+ if (NULL != lpIO->lpszFile
+ && (lpIO->cchFile <= 0 || lpIO->cchFile > OLEUI_CCHPATHMAX_SIZE))
+ uRet=OLEUI_IOERR_CCHFILEINVALID;
+
+ if (0!=lpIO->cClsidExclude)
+ {
+ if (NULL!=lpIO->lpClsidExclude && IsBadReadPtr(lpIO->lpClsidExclude
+ , lpIO->cClsidExclude*sizeof(CLSID)))
+ uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;
+ }
+
+ //If we have flags to create any object, validate necessary data.
+ if (lpIO->dwFlags & (IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT | IOF_CREATELINKOBJECT))
+ {
+ if (NULL!=lpIO->lpFormatEtc
+ && IsBadReadPtr(lpIO->lpFormatEtc, sizeof(FORMATETC)))
+ uRet=OLEUI_IOERR_LPFORMATETCINVALID;
+
+ if (NULL!=lpIO->ppvObj && IsBadWritePtr(lpIO->ppvObj, sizeof(LPVOID)))
+ uRet=OLEUI_IOERR_PPVOBJINVALID;
+
+ if (NULL!=lpIO->lpIOleClientSite
+ && IsBadReadPtr(lpIO->lpIOleClientSite->lpVtbl, sizeof(IOleClientSiteVtbl)))
+ uRet=OLEUI_IOERR_LPIOLECLIENTSITEINVALID;
+
+ if (NULL!=lpIO->lpIStorage
+ && IsBadReadPtr(lpIO->lpIStorage->lpVtbl, sizeof(IStorageVtbl)))
+ uRet=OLEUI_IOERR_LPISTORAGEINVALID;
+ }
+
+ if (OLEUI_ERR_STANDARDMIN <= uRet)
+ {
+ if (NULL!=hMemDlg)
+ FreeResource(hMemDlg);
+
+ return uRet;
+ }
+
+ //Now that we've validated everything, we can invoke the dialog.
+ uRet=UStandardInvocation(InsertObjectDialogProc, (LPOLEUISTANDARD)lpIO
+ , hMemDlg, MAKEINTRESOURCE(IDD_INSERTOBJECT));
+
+
+ //Stop here if we cancelled or had an error.
+ if (OLEUI_SUCCESS !=uRet && OLEUI_OK!=uRet)
+ return uRet;
+
+
+ /*
+ * If any of the flags specify that we're to create objects on return
+ * from this dialog, then do so. If we encounter an error in this
+ * processing, we return OLEUI_IOERR_SCODEHASERROR. Since the
+ * three select flags are mutually exclusive, we don't have to
+ * if...else here, just if each case (keeps things cleaner that way).
+ */
+
+ lpIO->sc=S_OK;
+
+ //Check if Create New was selected and we have IOF_CREATENEWOBJECT
+ if ((lpIO->dwFlags & IOF_SELECTCREATENEW) && (lpIO->dwFlags & IOF_CREATENEWOBJECT))
+ {
+ hrErr=OleCreate(&lpIO->clsid, &lpIO->iid, lpIO->oleRender
+ , lpIO->lpFormatEtc, lpIO->lpIOleClientSite, lpIO->lpIStorage
+ , lpIO->ppvObj);
+ lpIO->sc = GetScode(hrErr);
+ }
+
+ //Try Create From File
+ if ((lpIO->dwFlags & IOF_SELECTCREATEFROMFILE))
+ {
+ if (!(lpIO->dwFlags & IOF_CHECKLINK) && (lpIO->dwFlags & IOF_CREATEFILEOBJECT))
+ {
+ hrErr=OleCreateFromFileA(&CLSID_NULL, lpIO->lpszFile, &lpIO->iid
+ , lpIO->oleRender, lpIO->lpFormatEtc, lpIO->lpIOleClientSite
+ , lpIO->lpIStorage, lpIO->ppvObj);
+ lpIO->sc = GetScode(hrErr);
+ }
+
+ if ((lpIO->dwFlags & IOF_CHECKLINK) && (lpIO->dwFlags & IOF_CREATELINKOBJECT))
+ {
+ hrErr=OleCreateLinkToFileA(lpIO->lpszFile, &lpIO->iid
+ , lpIO->oleRender, lpIO->lpFormatEtc, lpIO->lpIOleClientSite
+ , lpIO->lpIStorage, lpIO->ppvObj);
+ lpIO->sc = GetScode(hrErr);
+ }
+ }
+
+ //If we tried but failed a create option, then return the appropriate error
+ if (S_OK!=lpIO->sc)
+ uRet=OLEUI_IOERR_SCODEHASERROR;
+
+ return uRet;
+ }
+
+
+
+
+
+/*
+ * InsertObjectDialogProc
+ *
+ * Purpose:
+ * Implements the OLE Insert Object dialog as invoked through the
+ * OleUIInsertObject function.
+ */
+
+BOOL CALLBACK EXPORT InsertObjectDialogProc(HWND hDlg, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ LPOLEUIINSERTOBJECT lpOIO;
+ LPINSERTOBJECT lpIO;
+ OLEUICHANGEICON ci;
+ UINT i;
+ BOOL fCheck=FALSE;
+ UINT uRet=0;
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ lpIO=(LPINSERTOBJECT)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
+
+ //If the hook processed the message, we're done.
+ if (0!=uRet)
+ return (BOOL)uRet;
+
+ //Process help message from Change Icon
+ if (iMsg==uMsgHelp)
+ {
+ PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp, wParam, lParam);
+ return FALSE;
+ }
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ InsertObjectCleanup(hDlg);
+ StandardCleanup(lpIO, hDlg);
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ switch (iMsg)
+ {
+ case WM_INITDIALOG:
+ return FInsertObjectInit(hDlg, wParam, lParam);
+
+ case WM_COMMAND:
+ switch (wID)
+ {
+ case ID_IO_CREATENEW:
+ FToggleObjectSource(hDlg, lpIO, IOF_SELECTCREATENEW);
+ break;
+
+ case ID_IO_CREATEFROMFILE:
+ FToggleObjectSource(hDlg, lpIO, IOF_SELECTCREATEFROMFILE);
+ break;
+
+ case ID_IO_LINKFILE:
+ fCheck=IsDlgButtonChecked(hDlg, wID);
+
+ if (fCheck)
+ lpIO->dwFlags |=IOF_CHECKLINK;
+ else
+ lpIO->dwFlags &=~IOF_CHECKLINK;
+
+ //Results change here, so be sure to update it.
+ SetInsertObjectResults(hDlg, lpIO);
+ UpdateClassIcon(hDlg, lpIO, NULL);
+ break;
+
+ case ID_IO_OBJECTTYPELIST:
+ switch (wCode)
+ {
+ case LBN_SELCHANGE:
+ UpdateClassIcon(hDlg, lpIO, hWndMsg);
+ SetInsertObjectResults(hDlg, lpIO);
+ break;
+
+ case LBN_DBLCLK:
+ //Same as pressing OK.
+ SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
+ break;
+ }
+ break;
+
+
+ case ID_IO_FILEDISPLAY:
+ //If there are characters, enable OK and Display As Icon
+ if (EN_CHANGE==wCode)
+ {
+ lpIO->fFileDirty = TRUE;
+ lpIO->fFileValid = FALSE;
+
+ lpIO->fFileSelected=
+ (0L!=SendMessage(hWndMsg, EM_LINELENGTH, 0, 0L));
+ EnableWindow(GetDlgItem(hDlg, ID_IO_LINKFILE), lpIO->fFileSelected);
+ EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), lpIO->fFileSelected);
+ EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), lpIO->fFileSelected);
+ EnableWindow(GetDlgItem(hDlg, IDOK), lpIO->fFileSelected);
+ }
+
+ if (EN_KILLFOCUS==wCode && NULL!=lpIO)
+ {
+ if (FValidateInsertFile(hDlg,FALSE,&lpIO->nErrCode)) {
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = TRUE;
+ UpdateClassIcon(hDlg, lpIO, NULL);
+ UpdateClassType(hDlg, lpIO, TRUE);
+ } else {
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = FALSE;
+ UpdateClassType(hDlg, lpIO, FALSE);
+ }
+ }
+ break;
+
+
+ case ID_IO_DISPLAYASICON:
+ fCheck=IsDlgButtonChecked(hDlg, wID);
+ EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), fCheck);
+
+ if (fCheck)
+ lpIO->dwFlags |=IOF_CHECKDISPLAYASICON;
+ else
+ lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;
+
+ //Update the internal flag based on this checking
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ lpIO->fAsIconNew=fCheck;
+ else
+ lpIO->fAsIconFile=fCheck;
+
+ //Re-read the class icon on Display checked
+ if (fCheck)
+ {
+ if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
+ {
+ if (FValidateInsertFile(hDlg, TRUE,&lpIO->nErrCode))
+ {
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = TRUE;
+ UpdateClassIcon(hDlg, lpIO,
+ GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
+
+ UpdateClassType(hDlg, lpIO, TRUE);
+ }
+
+ else
+ {
+ HWND hWndEC;
+
+ lpIO->fAsIconFile= FALSE;
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = FALSE;
+ SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, 0, 0L);
+ UpdateClassType(hDlg, lpIO, FALSE);
+
+ lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;
+ CheckDlgButton(hDlg, ID_IO_DISPLAYASICON, 0);
+
+ hWndEC = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
+ SetFocus(hWndEC);
+ SendMessage(hWndEC, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
+ return TRUE;
+ }
+ }
+ else
+ UpdateClassIcon(hDlg, lpIO,
+ GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
+ }
+
+
+ //Results change here, so be sure to update it.
+ SetInsertObjectResults(hDlg, lpIO);
+
+
+ /*
+ * Show or hide controls as appropriate. Do the icon
+ * display last because it will take some time to repaint.
+ * If we do it first then the dialog looks too sluggish.
+ */
+ i=(fCheck) ? SW_SHOWNORMAL : SW_HIDE;
+ StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, i);
+ StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, i);
+
+ break;
+
+
+ case ID_IO_CHANGEICON:
+ {
+
+ LPMALLOC pIMalloc;
+ HWND hList;
+ LPTSTR pszString, pszCLSID;
+
+ int iCurSel;
+
+ // if we're in SELECTCREATEFROMFILE mode, then we need to Validate
+ // the contents of the edit control first.
+
+ if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
+ {
+ if ( lpIO->fFileDirty
+ && !FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode) )
+ {
+ HWND hWndEC;
+
+ lpIO->fFileDirty = TRUE;
+ hWndEC = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
+ SetFocus(hWndEC);
+ SendMessage(hWndEC, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
+ return TRUE;
+ }
+ else
+ lpIO->fFileDirty = FALSE;
+ }
+
+
+
+ //Initialize the structure for the hook.
+ _fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));
+
+ ci.hMetaPict=(HGLOBAL)SendDlgItemMessage(hDlg
+ , ID_IO_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);
+
+ ci.cbStruct =sizeof(ci);
+ ci.hWndOwner=hDlg;
+ ci.dwFlags =CIF_SELECTCURRENT;
+
+ if (lpIO->dwFlags & IOF_SHOWHELP)
+ ci.dwFlags |= CIF_SHOWHELP;
+
+
+
+
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ // Initialize clsid...
+ if (NOERROR != CoGetMalloc(MEMCTX_TASK, &pIMalloc))
+ return FALSE;
+
+ pszString = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc,
+ OLEUI_CCHKEYMAX_SIZE +
+ OLEUI_CCHCLSIDSTRING_SIZE);
+
+
+ hList = GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
+ iCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+ SendMessage(hList, LB_GETTEXT, iCurSel, (LONG)pszString);
+
+ pszCLSID = PointerToNthField(pszString, 2, TEXT('\t'));
+
+ CLSIDFromStringA((LPTSTR)pszCLSID, (LPCLSID)&(ci.clsid));
+
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszString);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ }
+ else // IOF_SELECTCREATEFROMFILE
+ {
+
+ TCHAR szFileName[OLEUI_CCHPATHMAX];
+
+ GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPTSTR)szFileName, OLEUI_CCHPATHMAX);
+
+ if (NOERROR != GetClassFileA(szFileName, (LPCLSID)&(ci.clsid)))
+ {
+ LPTSTR lpszExtension;
+ int istrlen;
+
+ istrlen = lstrlen(szFileName);
+
+ lpszExtension = (LPTSTR)szFileName + istrlen -1;
+
+ while ( (lpszExtension > szFileName) &&
+ (*lpszExtension != TEXT('.')) )
+ lpszExtension--;
+
+ GetAssociatedExecutable(lpszExtension, (LPTSTR)ci.szIconExe);
+ ci.cchIconExe = lstrlen(ci.szIconExe);
+ ci.dwFlags |= CIF_USEICONEXE;
+
+ }
+ }
+
+
+ //Let the hook in to customize Change Icon if desired.
+ uRet=UStandardHook(lpIO, hDlg, uMsgChangeIcon
+ , 0, (LONG)(LPTSTR)&ci);
+
+ if (0==uRet)
+ uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci));
+
+ //Update the display and itemdata if necessary.
+ if (0!=uRet)
+ {
+
+ /*
+ * OleUIChangeIcon will have already freed our
+ * current hMetaPict that we passed in when OK is
+ * pressed in that dialog. So we use 0L as lParam
+ * here so the IconBox doesn't try to free the
+ * metafilepict again.
+ */
+ SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET
+ , (WPARAM)ci.hMetaPict, 0L);
+
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ SendMessage(hList, LB_SETITEMDATA, iCurSel, ci.hMetaPict);
+ }
+ }
+ break;
+
+
+ case ID_IO_FILE:
+ {
+ /*
+ * To allow the hook to customize the browse dialog, we
+ * send OLEUI_MSG_BROWSE. If the hook returns FALSE
+ * we use the default, otherwise we trust that it retrieved
+ * a filename for us. This mechanism prevents hooks from
+ * trapping ID_IO_BROWSE to customize the dialog and from
+ * trying to figure out what we do after we have the name.
+ */
+
+ TCHAR szTemp[OLEUI_CCHPATHMAX];
+ TCHAR szInitialDir[OLEUI_CCHPATHMAX];
+ DWORD dwOfnFlags;
+ int nChars;
+ BOOL fUseInitialDir = FALSE;
+
+
+ nChars = GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPTSTR)szTemp, OLEUI_CCHPATHMAX);
+
+ if (FValidateInsertFile(hDlg, FALSE, &lpIO->nErrCode))
+ {
+
+ int istrlen;
+
+ GetFileTitle((LPTSTR)szTemp, lpIO->szFile, OLEUI_CCHPATHMAX);
+
+ istrlen = lstrlen(lpIO->szFile);
+
+ LSTRCPYN((LPTSTR)szInitialDir, szTemp, nChars - istrlen);
+ fUseInitialDir = TRUE;
+
+ }
+ else // file name isn't valid...lop off end of szTemp to get a
+ // valid directory
+ {
+#if defined( WIN32 )
+ TCHAR szBuffer[OLEUI_CCHPATHMAX];
+ DWORD Attribs;
+
+ LSTRCPYN(szBuffer, szTemp, OLEUI_CCHPATHMAX-1);
+ szBuffer[OLEUI_CCHPATHMAX-1] = TEXT('\0');
+
+ if (TEXT('\\') == szBuffer[nChars-1])
+ szBuffer[nChars-1] = TEXT('\0');
+
+ Attribs = GetFileAttributes(szBuffer);
+ if (Attribs != 0xffffffff &&
+ (Attribs & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ lstrcpy(szInitialDir, (LPTSTR)szBuffer);
+ fUseInitialDir = TRUE;
+ }
+#else
+ static TCHAR szBuffer[OLEUI_CCHPATHMAX];
+ static int attrib ;
+
+ LSTRCPYN(szBuffer, szTemp, OLEUI_CCHPATHMAX-1);
+ szBuffer[OLEUI_CCHPATHMAX-1] = TEXT('\0');
+
+ AnsiToOem(szBuffer, szBuffer);
+#if defined( OBSOLETE ) // fix bug# 3575
+ if (TEXT('\\') == szBuffer[nChars-1])
+ szBuffer[nChars-1] = TEXT('\0');
+
+ if(0 == _dos_getfileattr(szBuffer, &attrib))
+#endif // OBSOLETE
+ {
+ lstrcpy(szInitialDir, (LPTSTR)szBuffer);
+ fUseInitialDir = TRUE;
+ }
+#endif
+ *lpIO->szFile = TEXT('\0');
+ }
+
+ uRet=UStandardHook(lpIO, hDlg, uMsgBrowse
+ , OLEUI_CCHPATHMAX_SIZE, (LPARAM)(LPSTR)lpIO->szFile);
+
+ dwOfnFlags = OFN_FILEMUSTEXIST;
+
+ if (lpIO->lpOIO->dwFlags & IOF_SHOWHELP)
+ dwOfnFlags |= OFN_SHOWHELP;
+
+ if (0==uRet)
+ uRet=(UINT)Browse(hDlg,
+ lpIO->szFile,
+ fUseInitialDir ? (LPTSTR)szInitialDir : NULL,
+ OLEUI_CCHPATHMAX_SIZE,
+ IDS_FILTERS,
+ dwOfnFlags);
+
+ //Only update if the file changed.
+ if (0!=uRet && 0!=lstrcmpi(szTemp, lpIO->szFile))
+ {
+ SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, lpIO->szFile);
+ lpIO->fFileSelected=TRUE;
+
+ if (FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode))
+ {
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = TRUE;
+ UpdateClassIcon(hDlg, lpIO, NULL);
+ UpdateClassType(hDlg, lpIO, TRUE);
+ // auto set OK to be default button if valid file
+ SendMessage(hDlg, DM_SETDEFID,
+ (WPARAM)GetDlgItem(hDlg, IDOK), 0L);
+ SetFocus(GetDlgItem(hDlg, IDOK));
+ }
+ else // filename is invalid - set focus back to ec
+ {
+ HWND hWnd;
+
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = FALSE;
+ hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
+ SetFocus(hWnd);
+ SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
+ }
+
+ //Once we have a file, Display As Icon is always enabled
+ EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), TRUE);
+
+ //As well as OK
+ EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
+
+ }
+ }
+ break;
+
+
+ case IDOK:
+ {
+ HWND hListBox;
+ WORD iCurSel;
+ TCHAR szBuffer[OLEUI_CCHKEYMAX + OLEUI_CCHCLSIDSTRING];
+ LPTSTR lpszCLSID;
+
+ if ((HWND)(LOWORD(lParam)) != GetFocus())
+ SetFocus((HWND)(LOWORD(lParam)));
+
+
+
+ // If the file name is clean (already validated), or
+ // if Create New is selected, then we can skip this part.
+
+ if ( (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
+ && (TRUE == lpIO->fFileDirty) )
+ {
+
+ if (FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode))
+ {
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = TRUE;
+ UpdateClassIcon(hDlg, lpIO, NULL);
+ UpdateClassType(hDlg, lpIO, TRUE);
+ }
+ else // filename is invalid - set focus back to ec
+ {
+ HWND hWnd;
+
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = FALSE;
+ hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
+ SetFocus(hWnd);
+ SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
+ UpdateClassType(hDlg, lpIO, FALSE);
+ }
+
+ return TRUE; // eat this message
+ }
+ else if ( (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
+ && (FALSE == lpIO->fFileValid) )
+ {
+ // filename is invalid - set focus back to ec
+ HWND hWnd;
+ TCHAR szFile[OLEUI_CCHPATHMAX];
+
+ if (0!=GetDlgItemText(hDlg, ID_IO_FILEDISPLAY,
+ szFile, OLEUI_CCHPATHMAX))
+ {
+ OpenFileError(hDlg, lpIO->nErrCode, szFile);
+ }
+ lpIO->fFileDirty = FALSE;
+ lpIO->fFileValid = FALSE;
+ hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
+ SetFocus(hWnd);
+ SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
+ UpdateClassType(hDlg, lpIO, FALSE);
+ return TRUE; // eat this message
+ }
+
+ //Copy the necessary information back to the original struct
+ lpOIO=lpIO->lpOIO;
+ lpOIO->dwFlags=lpIO->dwFlags;
+
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ hListBox=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
+ iCurSel=(WORD)SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+
+ if (lpIO->dwFlags & IOF_CHECKDISPLAYASICON)
+ {
+ lpOIO->hMetaPict=(HGLOBAL)SendMessage(hListBox,
+ LB_GETITEMDATA, iCurSel, 0L);
+
+ /*
+ * Set the item data to 0 here so that the cleanup
+ * code doesn't delete the metafile.
+ */
+ SendMessage(hListBox, LB_SETITEMDATA, iCurSel, 0L);
+ }
+ else
+ lpOIO->hMetaPict = (HGLOBAL)NULL;
+
+ SendMessage(hListBox, LB_GETTEXT, iCurSel
+ , (LPARAM)(LPTSTR)szBuffer);
+
+ lpszCLSID=PointerToNthField((LPTSTR)szBuffer, 2, TEXT('\t'));
+ CLSIDFromStringA(lpszCLSID, &lpOIO->clsid);
+
+ }
+ else // IOF_SELECTCREATEFROMFILE
+ {
+ if (lpIO->dwFlags & IOF_CHECKDISPLAYASICON)
+ {
+ // get metafile here
+ lpOIO->hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg,
+ ID_IO_ICONDISPLAY,
+ IBXM_IMAGEGET,
+ 0, 0L);
+
+
+ }
+ else
+ lpOIO->hMetaPict = (HGLOBAL)NULL;
+
+ }
+
+ GetDlgItemText(hDlg, ID_IO_FILEDISPLAY,
+ lpIO->szFile, lpOIO->cchFile);
+
+ LSTRCPYN(lpOIO->lpszFile, lpIO->szFile, lpOIO->cchFile);
+
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ }
+ break;
+
+ case IDCANCEL:
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ break;
+
+ case ID_OLEUIHELP:
+ PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp
+ , (WPARAM)hDlg, MAKELPARAM(IDD_INSERTOBJECT, 0));
+ break;
+ }
+ break;
+
+ default:
+ {
+ if (lpIO && iMsg == lpIO->nBrowseHelpID) {
+ PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp,
+ (WPARAM)hDlg, MAKELPARAM(IDD_INSERTFILEBROWSE, 0));
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+ }
+
+
+
+
+/*
+ * FInsertObjectInit
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the Insert Object dialog box.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL FInsertObjectInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
+ {
+ LPOLEUIINSERTOBJECT lpOIO;
+ LPINSERTOBJECT lpIO;
+ RECT rc;
+ DWORD dw;
+ HFONT hFont;
+ HWND hList;
+ UINT u;
+ BOOL fCheck;
+ CHAR *pch; // pointer to current working directory
+ // ANSI string (to use with _getcwd)
+
+ //1. Copy the structure at lParam into our instance memory.
+ lpIO=(LPINSERTOBJECT)LpvStandardInit(hDlg, sizeof(INSERTOBJECT), TRUE, &hFont);
+
+ //PvStandardInit send a termination to us already.
+ if (NULL==lpIO)
+ return FALSE;
+
+ lpOIO=(LPOLEUIINSERTOBJECT)lParam;
+
+ //2. Save the original pointer and copy necessary information.
+ lpIO->lpOIO =lpOIO;
+ lpIO->dwFlags=lpOIO->dwFlags;
+ lpIO->clsid =lpOIO->clsid;
+
+ if ( (lpOIO->lpszFile) && (TEXT('\0') != *lpOIO->lpszFile) )
+ LSTRCPYN((LPTSTR)lpIO->szFile, lpOIO->lpszFile, OLEUI_CCHPATHMAX);
+ else
+ *(lpIO->szFile) = TEXT('\0');
+
+ lpIO->hMetaPictFile = (HGLOBAL)NULL;
+
+ //3. If we got a font, send it to the necessary controls.
+ if (NULL!=hFont)
+ {
+ SendDlgItemMessage(hDlg, ID_IO_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L);
+ SendDlgItemMessage(hDlg, ID_IO_FILETYPE, WM_SETFONT, (WPARAM)hFont, 0L);
+ }
+
+
+ //4. Fill the Object Type listbox with entries from the reg DB.
+ hList=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
+ UFillClassList(hList, lpOIO->cClsidExclude, lpOIO->lpClsidExclude
+ , (BOOL)(lpOIO->dwFlags & IOF_VERIFYSERVERSEXIST));
+
+ //Set the tab width in the list to push all the tabs off the side.
+ GetClientRect(hList, &rc);
+ dw=GetDialogBaseUnits();
+ rc.right =(8*rc.right)/LOWORD(dw); //Convert pixels to 2x dlg units.
+ SendMessage(hList, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&rc.right);
+
+
+ //5. Initilize the file name display to cwd if we don't have any name.
+ if (TEXT('\0') == *(lpIO->szFile))
+ {
+ TCHAR tch[OLEUI_CCHPATHMAX];
+
+ pch=_getcwd(NULL, OLEUI_CCHPATHMAX);
+ if (*(pch+strlen(pch)-1) != '\\')
+ strcat(pch, "\\"); // put slash on end of cwd
+#ifdef UNICODE
+ mbstowcs(tch, pch, OLEUI_CCHPATHMAX);
+#else
+ strcpy(tch, pch);
+#endif
+ SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, tch);
+ lpIO->fFileDirty = TRUE; // cwd is not a valid filename
+ #ifndef __TURBOC__
+ free(pch);
+ #endif
+ }
+ else
+ {
+ SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, lpIO->szFile);
+
+ if (FValidateInsertFile(hDlg, FALSE, &lpIO->nErrCode))
+ lpIO->fFileDirty = FALSE;
+ else
+ lpIO->fFileDirty = TRUE;
+ }
+
+
+ //6. Initialize the selected type radiobutton.
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ StandardShowDlgItem(hDlg, ID_IO_FILETEXT, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_FILETYPE, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_FILEDISPLAY, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_FILE, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_LINKFILE, SW_HIDE);
+
+ CheckRadioButton(hDlg, ID_IO_CREATENEW, ID_IO_CREATEFROMFILE, ID_IO_CREATENEW);
+
+ lpIO->fAsIconNew=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));
+ SetFocus(hList);
+ }
+ else
+ {
+ /*
+ * Use pszType as the initial File. If there's no initial
+ * file then we have to remove any check from Display As
+ * Icon. We also check Link if so indicated for this option.
+ */
+ StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPELIST, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPETEXT, SW_HIDE);
+
+ // Don't preselect display as icon if the filename isn't valid
+ if (TRUE == lpIO->fFileDirty)
+ lpIO->dwFlags &= ~(IOF_CHECKDISPLAYASICON);
+
+ if (IOF_DISABLELINK & lpIO->dwFlags)
+ StandardShowDlgItem(hDlg, ID_IO_LINKFILE, SW_HIDE);
+ else
+ {
+ CheckDlgButton(hDlg, ID_IO_LINKFILE
+ , (BOOL)(0L!=(lpIO->dwFlags & IOF_CHECKLINK)));
+ }
+
+ CheckRadioButton(hDlg, ID_IO_CREATENEW, ID_IO_CREATEFROMFILE, ID_IO_CREATEFROMFILE);
+
+ lpIO->fAsIconFile=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));
+ SetFocus(GetDlgItem(hDlg, ID_IO_FILEDISPLAY));
+ }
+
+
+ //7. Initialize the Display as Icon state
+ fCheck=(BOOL)(lpIO->dwFlags & IOF_CHECKDISPLAYASICON);
+ u=fCheck ? SW_SHOWNORMAL : SW_HIDE;
+
+ StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, u);
+ StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, u);
+
+ CheckDlgButton(hDlg, ID_IO_DISPLAYASICON, fCheck);
+
+
+ //8. Show or hide the help button
+ if (!(lpIO->dwFlags & IOF_SHOWHELP))
+ StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
+
+
+ //9. Initialize the result display
+ UpdateClassIcon(hDlg, lpIO, GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
+ SetInsertObjectResults(hDlg, lpIO);
+
+ //10. Change the caption
+ if (NULL!=lpOIO->lpszCaption)
+ SetWindowText(hDlg, lpOIO->lpszCaption);
+
+ //11. Hide all DisplayAsIcon related controls if it should be disabled
+ if ( lpIO->dwFlags & IOF_DISABLEDISPLAYASICON ) {
+ StandardShowDlgItem(hDlg, ID_IO_DISPLAYASICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, SW_HIDE);
+ }
+
+ lpIO->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);
+
+ //All Done: call the hook with lCustData
+ UStandardHook(lpIO, hDlg, WM_INITDIALOG, wParam, lpOIO->lCustData);
+
+ /*
+ * We either set focus to the listbox or the edit control. In either
+ * case we don't want Windows to do any SetFocus, so we return FALSE.
+ */
+ return FALSE;
+ }
+
+
+
+
+
+
+/*
+ * UFillClassList
+ *
+ * Purpose:
+ * Enumerates available OLE object classes from the registration
+ * database and fills a listbox with those names.
+ *
+ * Note that this function removes any prior contents of the listbox.
+ *
+ * Parameters:
+ * hList HWND to the listbox to fill.
+ * cIDEx UINT number of CLSIDs to exclude in lpIDEx
+ * lpIDEx LPCLSID to CLSIDs to leave out of the listbox.
+ * fVerify BOOL indicating if we are to validate existence of
+ * servers before putting them in the list.
+ *
+ * Return Value:
+ * UINT Number of strings added to the listbox, -1 on failure.
+ */
+
+UINT UFillClassList(HWND hList, UINT cIDEx, LPCLSID lpIDEx, BOOL fVerify)
+ {
+ DWORD dw;
+ UINT cStrings=0;
+ UINT i;
+ UINT cch;
+ HKEY hKey;
+ LONG lRet;
+ HFILE hFile;
+ OFSTRUCT of;
+ BOOL fExclude;
+ LPMALLOC pIMalloc;
+ LPTSTR pszExec;
+ LPTSTR pszClass;
+ LPTSTR pszKey;
+ LPTSTR pszID;
+ CLSID clsid;
+
+ //Get some work buffers
+ if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))
+ return (UINT)-1;
+
+ pszExec=(LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX_SIZE*4);
+
+ if (NULL==pszExec)
+ {
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ return (UINT)-1;
+ }
+
+ pszClass=pszExec+OLEUI_CCHKEYMAX;
+ pszKey=pszClass+OLEUI_CCHKEYMAX;
+ pszID=pszKey+OLEUI_CCHKEYMAX;
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ {
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszExec);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ return (UINT)-1;
+ }
+
+ //Clean out the existing strings.
+ SendMessage(hList, LB_RESETCONTENT, 0, 0L);
+
+ cStrings=0;
+
+ while (TRUE)
+ {
+ lRet=RegEnumKey(hKey, cStrings++, pszClass, OLEUI_CCHKEYMAX_SIZE);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ break;
+
+ //Cheat on lstrcat by using lstrcpy after this string, saving time
+ cch=lstrlen(pszClass);
+
+ // Check for \NotInsertable. if this is found then this overrides
+ // all other keys; this class will NOT be added to the InsertObject
+ // list.
+
+ lstrcpy(pszClass+cch, TEXT("\\NotInsertable"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);
+
+ if ((LONG)ERROR_SUCCESS==lRet)
+ continue; // NotInsertable IS found--skip this class
+
+ //Check for a \protocol\StdFileEditing\server entry.
+ lstrcpy(pszClass+cch, TEXT("\\protocol\\StdFileEditing\\server"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);
+
+ if ((LONG)ERROR_SUCCESS==lRet)
+ {
+ /*
+ * Check if the EXE actually exists. By default we don't do this
+ * to bring up the dialog faster. If an application wants to be
+ * stringent, they can provide IOF_VERIFYSERVERSEXIST.
+ */
+
+ hFile = !HFILE_ERROR;
+
+ if (fVerify)
+ hFile=DoesFileExist(pszKey, &of);
+
+ if (HFILE_ERROR!=hFile)
+ {
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ *(pszClass+cch)=0; // set back to rootkey
+ // Get full user type name
+ lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ continue; // error getting type name--skip this class
+
+ //Tell the code below to get the string for us.
+ pszID=NULL;
+ }
+ }
+ else
+ {
+ /*
+ * No \protocol\StdFileEditing\server entry. Look to see if
+ * there's an Insertable entry. If there is, then use the
+ * Clsid to look at CLSID\clsid\LocalServer and \InprocServer
+ */
+
+ lstrcpy(pszClass+cch, TEXT("\\Insertable"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ continue; // Insertable NOT found--skip this class
+
+ //Get memory for pszID
+ pszID=pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX_SIZE);
+
+ if (NULL==pszID)
+ continue;
+
+ *(pszClass+cch)=0; // set back to rootkey
+ lstrcat(pszClass+cch, TEXT("\\CLSID"));
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszClass, pszID, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ continue; // CLSID subkey not found
+
+ lstrcpy(pszExec, TEXT("CLSID\\"));
+ lstrcat(pszExec, pszID);
+
+ //CLSID\ is 6, dw contains pszID length.
+ cch=6+(UINT)dw;
+
+ lstrcpy(pszExec+cch, TEXT("\\LocalServer"));
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ {
+ //Try InprocServer
+ lstrcpy(pszExec+cch, TEXT("\\InProcServer"));
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ continue;
+ }
+
+ if (fVerify)
+ {
+ if (HFILE_ERROR==DoesFileExist(pszKey, &of))
+ continue;
+ }
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);
+ *(pszExec+cch)=0; //Remove \\*Server
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ continue;
+ }
+
+ //Get CLSID to add to listbox.
+ if (NULL==pszID)
+ {
+ CLSIDFromProgIDA(pszClass, &clsid);
+ StringFromCLSIDA(&clsid, &pszID);
+ }
+ else
+ CLSIDFromStringA(pszID, &clsid);
+
+ //Check if this CLSID is in the exclusion list.
+ fExclude=FALSE;
+
+ for (i=0; i < cIDEx; i++)
+ {
+ if (IsEqualCLSID(&clsid, (LPCLSID)(lpIDEx+i)))
+ {
+ fExclude=TRUE;
+ break;
+ }
+ }
+
+ if (fExclude)
+ continue;
+
+ //We go through all the conditions, add the string.
+ lstrcat(pszKey, TEXT("\t"));
+
+ // only add to listbox if not a duplicate
+ if (LB_ERR==SendMessage(hList,LB_FINDSTRING,0,(LPARAM)pszKey)) {
+ lstrcat(pszKey, pszID);
+ SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)pszKey);
+ }
+
+ //We always allocated this regardless of the path
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszID);
+ }
+
+
+ //Select the first item by default
+ SendMessage(hList, LB_SETCURSEL, 0, 0L);
+ RegCloseKey(hKey);
+
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszExec);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+
+ return cStrings;
+ }
+
+
+
+
+
+/*
+ * FToggleObjectSource
+ *
+ * Purpose:
+ * Handles enabling, disabling, showing, and flag manipulation when the
+ * user changes between Create New, Insert File, and Link File in the
+ * Insert Object dialog.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpIO LPINSERTOBJECT pointing to the dialog structure
+ * dwOption DWORD flag indicating the option just selected:
+ * IOF_SELECTCREATENEW or IOF_SELECTCREATEFROMFILE
+ *
+ * Return Value:
+ * BOOL TRUE if the option was already selected, FALSE otherwise.
+ */
+
+BOOL FToggleObjectSource(HWND hDlg, LPINSERTOBJECT lpIO, DWORD dwOption)
+ {
+ BOOL fTemp;
+ UINT uTemp;
+ DWORD dwTemp;
+ int i;
+
+ //Skip all of this if we're already selected.
+ if (lpIO->dwFlags & dwOption)
+ return TRUE;
+
+
+ // if we're switching from "from file" to "create new" and we've got
+ // an icon for "from file", then we need to save it so that we can
+ // show it if the user reselects "from file".
+
+ if ( (IOF_SELECTCREATENEW == dwOption) &&
+ (lpIO->dwFlags & IOF_CHECKDISPLAYASICON) )
+ lpIO->hMetaPictFile = (HGLOBAL)SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);
+
+ /*
+ * 1. Change the Display As Icon checked state to reflect the
+ * selection for this option, stored in the fAsIcon* flags.
+ */
+ fTemp=(IOF_SELECTCREATENEW==dwOption) ? lpIO->fAsIconNew : lpIO->fAsIconFile;
+
+ if (fTemp)
+ lpIO->dwFlags |=IOF_CHECKDISPLAYASICON;
+ else
+ lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;
+
+ CheckDlgButton(hDlg, ID_IO_DISPLAYASICON
+ , (BOOL)(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON)));
+
+ EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), fTemp);
+
+ /*
+ * 2. Display Icon: Enabled on Create New or on Create from File if
+ * there is a selected file.
+ */
+ fTemp=(IOF_SELECTCREATENEW==dwOption) ? TRUE : lpIO->fFileSelected;
+ EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), fTemp);
+
+ //OK and Link follow the same enabling as Display As Icon.
+ EnableWindow(GetDlgItem(hDlg, IDOK), fTemp);
+ EnableWindow(GetDlgItem(hDlg, ID_IO_LINKFILE), fTemp);
+
+ //3. Enable Browse... when Create from File is selected.
+ fTemp=(IOF_SELECTCREATENEW==dwOption);
+ EnableWindow(GetDlgItem(hDlg, ID_IO_FILE), !fTemp);
+ EnableWindow(GetDlgItem(hDlg, ID_IO_FILEDISPLAY), !fTemp);
+
+ /*
+ * 4. Switch between Object Type listbox on Create New and
+ * file buttons on others.
+ */
+ uTemp=(fTemp) ? SW_SHOWNORMAL : SW_HIDE;
+ StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPELIST, uTemp);
+ StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPETEXT, uTemp);
+
+ uTemp=(fTemp) ? SW_HIDE : SW_SHOWNORMAL;
+ StandardShowDlgItem(hDlg, ID_IO_FILETEXT, uTemp);
+ StandardShowDlgItem(hDlg, ID_IO_FILETYPE, uTemp);
+ StandardShowDlgItem(hDlg, ID_IO_FILEDISPLAY, uTemp);
+ StandardShowDlgItem(hDlg, ID_IO_FILE, uTemp);
+
+ //Link is always hidden if IOF_DISABLELINK is set.
+ if (IOF_DISABLELINK & lpIO->dwFlags)
+ uTemp=SW_HIDE;
+
+ StandardShowDlgItem(hDlg, ID_IO_LINKFILE, uTemp); //last use of uTemp
+
+
+ //5. Clear out existing any flags selection and set the new one
+ dwTemp=IOF_SELECTCREATENEW | IOF_SELECTCREATEFROMFILE;
+ lpIO->dwFlags=(lpIO->dwFlags & ~dwTemp) | dwOption;
+
+
+ /*
+ * Show or hide controls as appropriate. Do the icon
+ * display last because it will take some time to repaint.
+ * If we do it first then the dialog looks too sluggish.
+ */
+
+ i=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON) ? SW_SHOWNORMAL : SW_HIDE;
+ StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, i);
+ StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, i);
+
+
+ //6.Change result display
+ SetInsertObjectResults(hDlg, lpIO);
+
+ /*
+ * 7. For Create New, twiddle the listbox to think we selected it
+ * so it updates the icon from the object type. set the focus
+ * to the list box.
+ *
+ * For Insert or Link file, set the focus to the filename button
+ * and update the icon if necessary.
+ */
+ if (fTemp) {
+ UpdateClassIcon(hDlg, lpIO, GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
+ SetFocus(GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
+ }
+ else
+ {
+ if (lpIO->fAsIconFile && (NULL != lpIO->hMetaPictFile) )
+ {
+ SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)lpIO->hMetaPictFile, 0L);
+ lpIO->hMetaPictFile = 0;
+ }
+ else
+ UpdateClassIcon(hDlg, lpIO, NULL);
+
+ SetFocus(GetDlgItem(hDlg, ID_IO_FILE));
+ }
+
+ return FALSE;
+ }
+
+
+/*
+ * UpdateClassType
+ *
+ * Purpose:
+ * Updates static text control to reflect current file type. Assumes
+ * a valid filename.
+ *
+ * Parameters
+ * hDlg HWND of the dialog box.
+ * lpIO LPINSERTOBJECT pointing to the dialog structure
+ * fSet TRUE to set the text, FALSE to explicitly clear it
+ *
+ * Return Value:
+ * None
+ */
+
+void UpdateClassType(HWND hDlg, LPINSERTOBJECT lpIO, BOOL fSet)
+{
+
+ CLSID clsid;
+ TCHAR szFileName[OLEUI_CCHPATHMAX];
+ TCHAR szFileType[OLEUI_CCHLABELMAX];
+
+ *szFileType = TEXT('\0');
+
+ if (fSet)
+ {
+ GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPTSTR)szFileName, OLEUI_CCHPATHMAX);
+
+ if (NOERROR == GetClassFileA(szFileName, &clsid) )
+ OleStdGetUserTypeOfClass(&clsid, szFileType, OLEUI_CCHLABELMAX_SIZE, NULL);
+
+ }
+
+ SetDlgItemText(hDlg, ID_IO_FILETYPE, (LPTSTR)szFileType);
+
+ return;
+}
+
+
+/*
+ * UpdateClassIcon
+ *
+ * Purpose:
+ * Handles LBN_SELCHANGE for the Object Type listbox. On a selection
+ * change, we extract an icon from the server handling the currently
+ * selected object type using the utility function HIconFromClass.
+ * Note that we depend on the behavior of FillClassList to stuff the
+ * object class after a tab in the listbox string that we hide from
+ * view (see WM_INITDIALOG).
+ *
+ * Parameters
+ * hDlg HWND of the dialog box.
+ * lpIO LPINSERTOBJECT pointing to the dialog structure
+ * hList HWND of the Object Type listbox.
+ *
+ * Return Value:
+ * None
+ */
+
+void UpdateClassIcon(HWND hDlg, LPINSERTOBJECT lpIO, HWND hList)
+ {
+ UINT iSel;
+ DWORD cb;
+ LPMALLOC pIMalloc;
+ LPTSTR pszName, pszCLSID, pszTemp;
+ HGLOBAL hMetaPict;
+
+ LRESULT dwRet;
+
+
+ //If Display as Icon is not selected, exit
+ if (!(lpIO->dwFlags & IOF_CHECKDISPLAYASICON))
+ return;
+
+ /*
+ * When we change object type selection, get the new icon for that
+ * type into our structure and update it in the display. We use the
+ * class in the listbox when Create New is selected or the association
+ * with the extension in Create From File.
+ */
+
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+
+ if (LB_ERR==(int)iSel)
+ return;
+
+ //Check to see if we've already got the hMetaPict for this item
+ dwRet=SendMessage(hList, LB_GETITEMDATA, (WPARAM)iSel, 0L);
+
+ hMetaPict=(HGLOBAL)(UINT)dwRet;
+
+ if (hMetaPict)
+ {
+ //Yep, we've already got it, so just display it and return.
+ SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)hMetaPict, 0L);
+ return;
+ }
+
+ iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+
+ if (LB_ERR==(int)iSel)
+ return;
+
+ //Allocate a string to hold the entire listbox string
+ cb=SendMessage(hList, LB_GETTEXTLEN, iSel, 0L);
+ }
+ else
+ cb=OLEUI_CCHPATHMAX_SIZE;
+
+ if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))
+ return;
+
+ pszName=(LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, cb+1*sizeof(TCHAR) );
+
+ if (NULL==pszName)
+ {
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ return;
+ }
+
+ *pszName=0;
+
+ //Get the clsid we want.
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ //Grab the classname string from the list
+ SendMessage(hList, LB_GETTEXT, iSel, (LONG)pszName);
+
+ //Set pointer to CLSID (string)
+ pszCLSID=PointerToNthField(pszName, 2, TEXT('\t'));
+
+ //Null terminate pszName string
+#ifdef WIN32
+ // AnsiPrev is obsolete in Win32
+ pszTemp=CharPrev((LPCTSTR) pszName,(LPCTSTR) pszCLSID);
+#else
+ pszTemp=AnsiPrev((LPCTSTR) pszName,(LPCTSTR) pszCLSID);
+#endif
+ *pszTemp=TEXT('\0');
+ CLSIDFromStringA(pszCLSID, &lpIO->clsid);
+
+#ifdef OLE201
+ hMetaPict = GetIconOfClass(ghInst, &lpIO->clsid, NULL, TRUE);
+#endif
+ }
+
+ else
+ {
+ //Get the class from the filename
+ GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, pszName, OLEUI_CCHPATHMAX);
+
+#ifdef OLE201
+
+ hMetaPict = OleGetIconOfFileA(pszName,
+ lpIO->dwFlags & IOF_CHECKLINK ? TRUE : FALSE);
+
+#endif
+
+ }
+
+ //Replace the current display with this new one.
+ SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)hMetaPict, 0L);
+
+ //Enable or disable "Change Icon" button depending on whether
+ //we've got a valid filename or not.
+ EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), hMetaPict ? TRUE : FALSE);
+
+ //Save the hMetaPict so that we won't have to re-create
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ SendMessage(hList, LB_SETITEMDATA, (WPARAM)iSel, hMetaPict);
+
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszName);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ return;
+ }
+
+
+
+
+/*
+ * SetInsertObjectResults
+ *
+ * Purpose:
+ * Centralizes setting of the Result and icon displays in the Insert Object
+ * dialog. Handles loading the appropriate string from the module's
+ * resources and setting the text, displaying the proper result picture,
+ * and showing the proper icon.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog box so we can access controls.
+ * lpIO LPINSERTOBJECT in which we assume that the
+ * current radiobutton and Display as Icon selections
+ * are set. We use the state of those variables to
+ * determine which string we use.
+ *
+ * Return Value:
+ * None
+ */
+
+void SetInsertObjectResults(HWND hDlg, LPINSERTOBJECT lpIO)
+ {
+ LPTSTR pszT, psz1, psz2, psz3, psz4, pszTemp;
+ UINT i, iString1, iString2, iImage, cch;
+ LPMALLOC pIMalloc;
+ BOOL fAsIcon;
+
+ /*
+ * We need scratch memory for loading the stringtable string, loading
+ * the object type from the listbox, and constructing the final string.
+ * We therefore allocate three buffers as large as the maximum message
+ * length (512) plus the object type, guaranteeing that we have enough
+ * in all cases.
+ */
+ i=(UINT)SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETCURSEL, 0, 0L);
+ cch=512+
+ (UINT)SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETTEXTLEN, i, 0L);
+
+ if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))
+ return;
+
+ pszTemp=(LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)(4*cch*sizeof(TCHAR)));
+
+ if (NULL==pszTemp)
+ {
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ return;
+ }
+
+ psz1=pszTemp;
+ psz2=psz1+cch;
+ psz3=psz2+cch;
+ psz4=psz3+cch;
+
+ fAsIcon=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));
+
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ iString1 = fAsIcon ? IDS_IORESULTNEWICON : IDS_IORESULTNEW;
+ iString2 = 0;
+ iImage = fAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED;
+ }
+
+ if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
+ {
+ //Pay attention to Link checkbox
+ if (lpIO->dwFlags & IOF_CHECKLINK)
+ {
+ iString1 = fAsIcon ? IDS_IORESULTLINKFILEICON1 : IDS_IORESULTLINKFILE1;
+ iString2 = fAsIcon ? IDS_IORESULTLINKFILEICON2 : IDS_IORESULTLINKFILE2;
+ iImage =fAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK;
+ }
+ else
+ {
+ iString1 = IDS_IORESULTFROMFILE1;
+ iString2 = fAsIcon ? IDS_IORESULTFROMFILEICON2 : IDS_IORESULTFROMFILE2;
+ iImage =fAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED;
+ }
+ }
+
+ //Default is an empty string.
+ *psz1=0;
+
+ if (0!=LoadString(ghInst, iString1, psz1, cch))
+ {
+
+ // Load second string, if necessary
+ if ( (0 != iString2)
+ && (0 != LoadString(ghInst, iString2, psz4, cch)) )
+ {
+ lstrcat(psz1, psz4); // concatenate strings together.
+ }
+
+
+
+ //In Create New, do the extra step of inserting the object type string
+ if (lpIO->dwFlags & IOF_SELECTCREATENEW)
+ {
+ SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETTEXT
+ , i, (LONG)psz2);
+
+ //Null terminate at any tab (before the classname)
+ pszT=psz2;
+ while (TEXT('\t')!=*pszT && 0!=*pszT)
+ pszT++;
+ *pszT=0;
+
+ //Build the string and point psz1 to it.
+ wsprintf(psz3, psz1, psz2);
+ psz1=psz3;
+ }
+ }
+
+ //If LoadString failed, we simply clear out the results (*psz1=0 above)
+ SetDlgItemText(hDlg, ID_IO_RESULTTEXT, psz1);
+
+ //Go change the image and Presto! There you have it.
+ SendDlgItemMessage(hDlg, ID_IO_RESULTIMAGE, RIM_IMAGESET, iImage, 0L);
+
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszTemp);
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ return;
+ }
+
+
+
+/*
+ * FValidateInsertFile
+ *
+ * Purpose:
+ * Given a possibly partial pathname from the file edit control,
+ * attempt to locate the file and if found, store the full path
+ * in the edit control ID_IO_FILEDISPLAY.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog box.
+ * fTellUser BOOL TRUE if function should tell user, FALSE if
+ * function should validate silently.
+ *
+ * Return Value:
+ * BOOL TRUE if the file is acceptable, FALSE otherwise.
+ */
+
+BOOL FValidateInsertFile(HWND hDlg, BOOL fTellUser, UINT FAR* lpnErrCode)
+ {
+ OFSTRUCT of;
+ HFILE hFile;
+ TCHAR szFile[OLEUI_CCHPATHMAX];
+
+ *lpnErrCode = 0;
+ /*
+ * To validate we attempt OpenFile on the string. If OpenFile
+ * fails then we display an error. If not, OpenFile will store
+ * the complete path to that file in the OFSTRUCT which we can
+ * then stuff in the edit control.
+ */
+
+ if (0==GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, szFile, OLEUI_CCHPATHMAX))
+ return FALSE; // #4569 : return FALSE when there is no text in ctl
+
+ hFile=DoesFileExist(szFile, &of);
+
+ // if file is currently open (ie. sharing violation) OleCreateFromFile
+ // and OleCreateLinkToFile can still succeed; do not consider it an
+ // error.
+ if (HFILE_ERROR==hFile && 0x0020/*sharing violation*/!=of.nErrCode)
+ {
+ *lpnErrCode = of.nErrCode;
+ if (fTellUser)
+ OpenFileError(hDlg, of.nErrCode, szFile);
+ return FALSE;
+ }
+
+ //OFSTRUCT contains an OEM name, not ANSI as we need for the edit box.
+ OemToAnsi(of.szPathName, of.szPathName);
+
+ SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, of.szPathName);
+ return TRUE;
+ }
+
+
+/*
+ * InsertObjectCleanup
+ *
+ * Purpose:
+ * Clears cached icon metafiles from those stored in the listbox.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog.
+ *
+ * Return Value:
+ * None
+ */
+
+void InsertObjectCleanup(HWND hDlg)
+ {
+ HWND hList;
+ UINT iItems;
+ HGLOBAL hMetaPict;
+ LRESULT dwRet;
+ UINT i;
+
+ hList=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
+ iItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
+
+ for (i=0; i < iItems; i++)
+ {
+ dwRet=SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);
+
+ //Cast of LRESULT to UINT to HGLOBAL portable to Win32.
+ hMetaPict=(HGLOBAL)(UINT)dwRet;
+
+ if (hMetaPict)
+ OleUIMetafilePictIconFree(hMetaPict);
+ }
+
+ return;
+ }
diff --git a/private/oleutest/letest/ole2ui/insobj.dlg b/private/oleutest/letest/ole2ui/insobj.dlg
new file mode 100644
index 000000000..2f81811a0
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/insobj.dlg
@@ -0,0 +1,51 @@
+//DLGINCLUDE RCDATA DISCARDABLE
+//BEGIN
+// "OLE2UI.H\0"
+//END
+
+IDD_INSERTOBJECT DIALOG 6, 18, 291, 150
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Insert Object"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Create &New", ID_IO_CREATENEW, "Button",
+ BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 6, 18, 67, 10
+
+ CONTROL "Create from &File", ID_IO_CREATEFROMFILE, "Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP, 6, 36, 67, 10
+
+ LTEXT "Object &Type:", ID_IO_OBJECTTYPETEXT, 84, 4, 110, 8
+
+ LISTBOX ID_IO_OBJECTTYPELIST, 82, 16, 132, 73, LBS_SORT |
+ LBS_USETABSTOPS | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+
+ LTEXT "Fil&e:", ID_IO_FILETEXT, 82, 24, 20, 8
+ LTEXT "", ID_IO_FILETYPE, 120, 24, 80, 8
+
+ EDITTEXT ID_IO_FILEDISPLAY, 82, 34, 132, 12, ES_AUTOHSCROLL | ES_LOWERCASE | ES_OEMCONVERT
+
+ PUSHBUTTON "&Browse...", ID_IO_FILE, 82, 50, 48, 14
+
+ CONTROL "&Link", ID_IO_LINKFILE, "Button", BS_AUTOCHECKBOX |
+ WS_TABSTOP, 140, 52, 40, 10
+
+ DEFPUSHBUTTON "OK", IDOK, 222, 6, 66, 14, WS_GROUP
+
+ PUSHBUTTON "Cancel", IDCANCEL, 222, 24, 66, 14
+
+ PUSHBUTTON "&Help", ID_OLEUIHELP, 222, 42, 66, 14
+
+ CONTROL "&Display As Icon", ID_IO_DISPLAYASICON, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 222, 64, 66, 10
+
+ CONTROL "", ID_IO_ICONDISPLAY, SZCLASSICONBOX, 0, 220, 80, 66, 46
+
+ PUSHBUTTON "Change &Icon...", ID_IO_CHANGEICON, 222, 127, 66, 14
+
+ GROUPBOX "Result", ID_STATIC, 6, 96, 210, 47, WS_GROUP
+
+// CONTROL "", ID_IO_RESULTIMAGE, SZCLASSRESULTIMAGE, 0, 10, 106, 42, 34
+
+ LTEXT "Result", ID_IO_RESULTTEXT, 56, 106, 156, 32, SS_NOPREFIX |
+ NOT WS_GROUP
+END
diff --git a/private/oleutest/letest/ole2ui/insobj.h b/private/oleutest/letest/ole2ui/insobj.h
new file mode 100644
index 000000000..1958d7f4f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/insobj.h
@@ -0,0 +1,52 @@
+/*
+ * INSOBJ.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI Insert Object dialog.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ */
+
+
+#ifndef _INSOBJ_H_
+#define _INSOBJ_H_
+
+//Internally used structure
+typedef struct tagINSERTOBJECT
+ {
+ LPOLEUIINSERTOBJECT lpOIO; //Original structure passed.
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog but that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+ DWORD dwFlags;
+ CLSID clsid;
+ TCHAR szFile[OLEUI_CCHPATHMAX];
+ BOOL fFileSelected; //Enables Display As Icon for links
+ BOOL fAsIconNew;
+ BOOL fAsIconFile;
+ BOOL fFileDirty;
+ BOOL fFileValid;
+ UINT nErrCode;
+ HGLOBAL hMetaPictFile;
+ UINT nBrowseHelpID; // Help ID callback for Browse dlg
+ } INSERTOBJECT, *PINSERTOBJECT, FAR *LPINSERTOBJECT;
+
+
+
+//Internal function prototypes
+//INSOBJ.C
+BOOL CALLBACK EXPORT InsertObjectDialogProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FInsertObjectInit(HWND, WPARAM, LPARAM);
+UINT UFillClassList(HWND, UINT, LPCLSID, BOOL);
+BOOL FToggleObjectSource(HWND, LPINSERTOBJECT, DWORD);
+void UpdateClassIcon(HWND, LPINSERTOBJECT, HWND);
+void UpdateClassType(HWND, LPINSERTOBJECT, BOOL);
+void SetInsertObjectResults(HWND, LPINSERTOBJECT);
+BOOL FValidateInsertFile(HWND, BOOL, UINT FAR*);
+void InsertObjectCleanup(HWND);
+
+#endif //_INSOBJ_H_
diff --git a/private/oleutest/letest/ole2ui/links.c b/private/oleutest/letest/ole2ui/links.c
new file mode 100644
index 000000000..88c552754
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/links.c
@@ -0,0 +1,2146 @@
+/*
+ * links.c
+ *
+ * Implements the OleUIEditLinks function which invokes the complete
+ * Edit Links dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+
+#include "ole2ui.h"
+#include "common.h"
+#include "edlinks.h"
+#include "utility.h"
+#include <commdlg.h>
+#include <dlgs.h>
+#include <stdlib.h>
+
+OLEDBGDATA
+
+/*
+* OleUIEditLinks
+*
+* Purpose:
+* Invokes the standard OLE Edit Links dialog box allowing the user
+* to manipulate ole links (delete, update, change source, etc).
+*
+* Parameters:
+* lpEL LPOLEUIEditLinks pointing to the in-out structure
+* for this dialog.
+*
+* Return Value:
+* UINT One of the following codes, indicating success or error:
+* OLEUI_SUCCESS Success
+* OLEUI_ERR_STRUCTSIZE The dwStructSize value is wrong
+*/
+
+STDAPI_(UINT) OleUIEditLinks(LPOLEUIEDITLINKS lpEL)
+{
+ UINT uRet;
+ HGLOBAL hMemDlg=NULL;
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lpEL, sizeof(OLEUIEDITLINKS)
+ , &hMemDlg);
+
+ if (OLEUI_SUCCESS!=uRet)
+ return uRet;
+
+ /*
+ * PERFORM ANY STRUCTURE-SPECIFIC VALIDATION HERE!
+ * ON FAILURE:
+ * {
+ * if (NULL!=hMemDlg)
+ * FreeResource(hMemDlg)
+ *
+ * return OLEUI_<ABBREV>ERR_<ERROR>
+ * }
+ */
+
+ //Now that we've validated everything, we can invoke the dialog.
+ uRet=UStandardInvocation(EditLinksDialogProc, (LPOLEUISTANDARD)lpEL,
+ hMemDlg, MAKEINTRESOURCE(IDD_EDITLINKS));
+
+ /*
+ * IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.
+ */
+
+
+ return uRet;
+}
+
+
+
+/*
+* EditLinksDialogProc
+*
+* Purpose:
+* Implements the OLE Edit Links dialog as invoked through the
+* OleUIEditLinks function.
+*
+* Parameters:
+* Standard
+*
+* Return Value:
+* Standard
+*/
+
+BOOL CALLBACK EXPORT EditLinksDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ LPEDITLINKS lpEL = NULL;
+ BOOL fHook=FALSE;
+ UINT uRet=0;
+ HRESULT hErr;
+ static int nColPos[3];
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ lpEL=(LPEDITLINKS)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
+
+ //If the hook processed the message, we're done.
+ if (0!=uRet)
+ return (BOOL)uRet;
+
+ // Process help message from secondary dialog
+ if (iMsg == uMsgHelp) {
+
+ PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp, wParam, lParam);
+ return FALSE;
+
+ }
+
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog) {
+
+ //Free any specific allocations before calling StandardCleanup
+
+ StandardCleanup(lpEL, hDlg);
+
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ switch (iMsg) {
+ static int nHeightLine = -1;
+ static int nMaxCharWidth = -1;
+
+ case WM_INITDIALOG:
+ {
+ RECT rc;
+ int nStart;
+
+ /* calculate the column positions relative to the listbox */
+ GetWindowRect(GetDlgItem(hDlg, ID_EL_LINKSLISTBOX), (LPRECT)&rc);
+ nStart = rc.left;
+ GetWindowRect(GetDlgItem(hDlg, ID_EL_COL1), (LPRECT)&rc);
+ nColPos[0] = rc.left - nStart;
+ GetWindowRect(GetDlgItem(hDlg, ID_EL_COL2), (LPRECT)&rc);
+ nColPos[1] = rc.left - nStart;
+ GetWindowRect(GetDlgItem(hDlg, ID_EL_COL3), (LPRECT)&rc);
+ nColPos[2] = rc.left - nStart;
+
+ return FEditLinksInit(hDlg, wParam, lParam);
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ {
+ LPMEASUREITEMSTRUCT lpMIS;
+
+ lpMIS = (LPMEASUREITEMSTRUCT)lParam;
+
+ if (nHeightLine == -1) {
+ HFONT hFont;
+ HDC hDC;
+ TEXTMETRIC tm;
+
+ /* Attempt to get font dialog. If that fails,
+ use system font
+ */
+
+ hFont = (HANDLE)(UINT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
+
+ if (hFont == NULL)
+ hFont = GetStockObject(SYSTEM_FONT);
+
+ hDC = GetDC(hDlg);
+ hFont = SelectObject(hDC, hFont);
+
+ GetTextMetrics(hDC, &tm);
+ nHeightLine = tm.tmHeight;
+ nMaxCharWidth = tm.tmMaxCharWidth;
+
+ ReleaseDC(hDlg, hDC);
+ }
+
+ lpMIS->itemHeight = nHeightLine;
+ }
+ break;
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT lpDIS;
+ COLORREF crText;
+ LPLINKINFO lpLI;
+ HBRUSH hbr;
+ int nOldBkMode;
+ TCHAR tsz[OLEUI_CCHPATHMAX];
+ LPTSTR lpsz;
+ RECT rcClip;
+
+ lpDIS = (LPDRAWITEMSTRUCT)lParam;
+ lpLI = (LPLINKINFO)lpDIS->itemData;
+
+ if ((int)lpDIS->itemID < 0)
+ break;
+
+ if ((ODA_DRAWENTIRE | ODA_SELECT) & lpDIS->itemAction) {
+
+ if (ODS_SELECTED & lpDIS->itemState) {
+ /*Get proper txt colors */
+ crText = SetTextColor(lpDIS->hDC,
+ GetSysColor(COLOR_HIGHLIGHTTEXT));
+ hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
+ lpLI->fIsSelected = TRUE;
+ }
+ else {
+ hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
+ lpLI->fIsSelected = FALSE;
+ }
+
+ FillRect(lpDIS->hDC, &lpDIS->rcItem, hbr);
+ DeleteObject(hbr);
+
+ nOldBkMode = SetBkMode(lpDIS->hDC, TRANSPARENT);
+
+ if (lpLI->lpszDisplayName) {
+ lstrcpy((LPTSTR)tsz, lpLI->lpszDisplayName);
+ lpsz = ChopText(
+ lpDIS->hwndItem,
+ nColPos[1] - nColPos[0]
+ - (nMaxCharWidth > 0 ? nMaxCharWidth : 5),
+ tsz
+ );
+ rcClip.left = lpDIS->rcItem.left + nColPos[0];
+ rcClip.top = lpDIS->rcItem.top;
+ rcClip.right = lpDIS->rcItem.left + nColPos[1]
+ - (nMaxCharWidth > 0 ? nMaxCharWidth : 5);
+ rcClip.bottom = lpDIS->rcItem.bottom;
+ ExtTextOut(
+ lpDIS->hDC,
+ rcClip.left,
+ rcClip.top,
+ ETO_CLIPPED,
+ (LPRECT)&rcClip,
+ lpsz,
+ lstrlen(lpsz),
+ NULL
+ );
+ }
+ if (lpLI->lpszShortLinkType) {
+ rcClip.left = lpDIS->rcItem.left + nColPos[1];
+ rcClip.top = lpDIS->rcItem.top;
+ rcClip.right = lpDIS->rcItem.left + nColPos[2]
+ - (nMaxCharWidth > 0 ? nMaxCharWidth : 5);
+
+ rcClip.bottom = lpDIS->rcItem.bottom;
+ ExtTextOut(
+ lpDIS->hDC,
+ rcClip.left,
+ rcClip.top,
+ ETO_CLIPPED,
+ (LPRECT)&rcClip,
+ lpLI->lpszShortLinkType,
+ lstrlen(lpLI->lpszShortLinkType),
+ NULL
+ );
+ }
+ if (lpLI->lpszAMX) {
+ rcClip.left = lpDIS->rcItem.left + nColPos[2];
+ rcClip.top = lpDIS->rcItem.top;
+ rcClip.right = lpDIS->rcItem.right;
+ rcClip.bottom = lpDIS->rcItem.bottom;
+ ExtTextOut(
+ lpDIS->hDC,
+ rcClip.left,
+ rcClip.top,
+ ETO_CLIPPED,
+ (LPRECT)&rcClip,
+ lpLI->lpszAMX,
+ lstrlen(lpLI->lpszAMX),
+ NULL
+ );
+ }
+
+ SetBkMode(lpDIS->hDC, nOldBkMode);
+
+ // restore orig colors if we changed them
+ if (ODS_SELECTED & lpDIS->itemState)
+ SetTextColor(lpDIS->hDC, crText);
+
+ }
+
+ InitControls(hDlg, lpEL);
+
+ if (ODA_FOCUS & lpDIS->itemAction)
+ DrawFocusRect(lpDIS->hDC, &lpDIS->rcItem);
+
+ }
+ return TRUE;
+
+
+ case WM_DELETEITEM:
+ {
+ UINT idCtl;
+ LPDELETEITEMSTRUCT lpDIS;
+ LPLINKINFO lpLI;
+
+ lpDIS = (LPDELETEITEMSTRUCT)lParam;
+ idCtl = wParam;
+ lpLI = (LPLINKINFO)lpDIS->itemData;
+
+ if (lpLI->lpszDisplayName)
+ OleStdFree((LPVOID)lpLI->lpszDisplayName);
+ if (lpLI->lpszShortLinkType)
+ OleStdFree((LPVOID)lpLI->lpszShortLinkType);
+ if (lpLI->lpszFullLinkType)
+ OleStdFree((LPVOID)lpLI->lpszFullLinkType);
+
+ /* The ChangeSource processing reuses allocated space for
+ ** links that have been modified.
+ */
+ // Don't free the LINKINFO for the changed links
+ if (lpLI->fDontFree)
+ lpLI->fDontFree = FALSE;
+ else {
+ if (lpLI->lpszAMX)
+ OleStdFree((LPVOID)lpLI->lpszAMX);
+ OleStdFree((LPVOID)lpLI);
+ }
+
+ return TRUE;
+ }
+
+ case WM_COMPAREITEM:
+ {
+ LPCOMPAREITEMSTRUCT lpCIS = (LPCOMPAREITEMSTRUCT)lParam;
+ LPLINKINFO lpLI1 = (LPLINKINFO)lpCIS->itemData1;
+ LPLINKINFO lpLI2 = (LPLINKINFO)lpCIS->itemData2;
+
+ // Sort list entries by DisplayName
+ return lstrcmp(lpLI1->lpszDisplayName,lpLI2->lpszDisplayName);
+ }
+
+ case WM_COMMAND:
+ switch (wID) {
+
+ case ID_EL_CHANGESOURCE:
+ {
+ BOOL fRet = FALSE;
+
+ /* This will bring up the file open dlg with one
+ edit field containing the whole link name. The file part
+ will (eventually) be highlighted to indicate where the
+ file part is. We need to hook on OK here to be able to
+ send the changed string to the Parse function */
+
+ fRet = Container_ChangeSource(hDlg, lpEL);
+ if (!fRet)
+ PopupMessage(hDlg, IDS_LINKS, IDS_FAILED,
+ MB_ICONEXCLAMATION | MB_OK);
+ InitControls(hDlg, lpEL);
+ }
+ break;
+
+ case ID_EL_AUTOMATIC:
+ {
+ /* This is available for single or multi-select. There is
+ a flag in the structure that is set initially indicating
+ whether the link is auto or manual so that we need not
+ query the link each time we want to find out.
+
+ This command will make the link automatic if not already.
+ It will have no effect on links already set to auto.
+ */
+ // turn the button ON
+
+ CheckDlgButton(hDlg, ID_EL_AUTOMATIC, 1);
+ CheckDlgButton(hDlg, ID_EL_MANUAL, 0);
+
+ hErr = Container_AutomaticManual(hDlg, TRUE, lpEL);
+ if (hErr != NOERROR)
+ PopupMessage(hDlg, IDS_LINKS, IDS_FAILED,
+ MB_ICONEXCLAMATION | MB_OK);
+
+ InitControls(hDlg, lpEL);
+ }
+ break;
+
+ case ID_EL_MANUAL:
+ {
+ /* Same rules apply here as they do to auto link.
+ Additional note - just because something is changed does
+ not mean that it updates at the moment. It simply
+ reflects what kind of updating it does while it lives in
+ the document.
+ */
+ // turn the button ON
+
+ CheckDlgButton(hDlg, ID_EL_MANUAL, 1);
+ CheckDlgButton(hDlg, ID_EL_AUTOMATIC, 0);
+
+ hErr = Container_AutomaticManual(hDlg, FALSE, lpEL);
+ if (hErr != NOERROR)
+ PopupMessage(hDlg, IDS_LINKS, IDS_FAILED,
+ MB_ICONEXCLAMATION | MB_OK);
+
+ InitControls(hDlg, lpEL);
+ }
+ break;
+
+ case ID_EL_CANCELLINK:
+ {
+ /* This is Break Link now in the dlg. This sets the
+ moniker to null, thereby effectively breaking the link.
+ The object still has its data effective at the time of
+ breaking, but becomes a static object.
+ *****It will need to be deleted from the listbox
+ */
+
+ CancelLink(hDlg,lpEL);
+ InitControls(hDlg, lpEL);
+ }
+ break;
+
+ case ID_EL_UPDATENOW:
+ {
+ /* This forces an immediate update of the selected
+ links. This will start the server etc, so this is a very
+ expensive operation.
+ */
+ hErr = Container_UpdateNow(hDlg, lpEL);
+ InitControls(hDlg, lpEL);
+ }
+ break;
+
+ case ID_EL_OPENSOURCE:
+ {
+ /* This will only work on single selection. It makes no
+ sense to open multiple sources at the same time, since
+ the one opened will try to show itself and become the
+ primary operating target, so to speak. Button is greyed
+ if multi select.
+
+ Here we do not add the break because we want to exit the
+ dlg in this case.
+ */
+ hErr = Container_OpenSource(hDlg, lpEL);
+ if (hErr != NOERROR) {
+ InitControls(hDlg, lpEL);
+ break; // don't close dialog
+ }
+ } // fall through
+
+ case ID_EL_CLOSE:
+ {
+ /* The user is finished with their editing - they now
+ return to their container document.
+
+ */
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ }
+ break;
+
+ case IDCANCEL:
+ {
+ /* This changes to CLOSE after the user does even ONE
+ thing in the dlg. Nothing can really effectively be undone.
+ */
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ }
+ break;
+
+ case ID_OLEUIHELP:
+ {
+ PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp
+ , (WPARAM)hDlg, MAKELPARAM(IDD_EDITLINKS, 0));
+ break;
+ }
+ break;
+ }
+ break;
+
+ default:
+ {
+ if (lpEL && iMsg == lpEL->nChgSrcHelpID) {
+ PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp,
+ (WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0));
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * FEditLinksInit
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the Edit Links dialog box.
+ *
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL FEditLinksInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
+{
+ LPEDITLINKS lpEL;
+ LPOLEUIEDITLINKS lpOEL;
+ HFONT hFont;
+ BOOL fDlgItem = FALSE;
+ DWORD dwLink = 0;
+ ULONG cLinks;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr;
+ int n;
+ HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+
+
+
+ //1. Copy the structure at lParam into our instance memory.
+ lpEL = (LPEDITLINKS)LpvStandardInit(hDlg, sizeof(OLEUIEDITLINKS), TRUE,
+ &hFont);
+
+ //PvStandardInit send a termination to us already.
+ if (NULL==lpEL)
+ return FALSE;
+
+ lpOEL=(LPOLEUIEDITLINKS)lParam;
+
+ lpEL->lpOEL=lpOEL;
+
+ lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+
+ cLinks = LoadLinkLB(hListBox, lpOleUILinkCntr);
+ if (cLinks < 0)
+ return FALSE;
+
+ fDlgItem = (BOOL)cLinks;
+ lpEL->fItemsExist = (BOOL)cLinks;
+
+
+ InitControls(hDlg, lpEL);
+
+ //Copy other information from lpOEL that we might modify.
+
+ //2. If we got a font, send it to the necessary controls.
+ if (NULL != hFont) {
+ // Do this for as many controls as you need it for.
+ // SendDlgItemMessage(hDlg, ID_<UFILL>, WM_SETFONT, (WPARAM)hFont, 0L);
+ }
+
+
+ //3. Show or hide the help button
+ if (!(lpEL->lpOEL->dwFlags & ELF_SHOWHELP))
+ StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
+
+ /*
+ * PERFORM OTHER INITIALIZATION HERE. ON ANY LoadString
+ * FAILURE POST OLEUI_MSG_ENDDIALOG WITH OLEUI_ERR_LOADSTRING.
+ */
+
+ //4. If requested disable UpdateNow button
+ if ((lpEL->lpOEL->dwFlags & ELF_DISABLEUPDATENOW))
+ StandardShowDlgItem(hDlg, ID_EL_UPDATENOW, SW_HIDE);
+
+ //5. If requested disable OpenSource button
+ if ((lpEL->lpOEL->dwFlags & ELF_DISABLEOPENSOURCE))
+ StandardShowDlgItem(hDlg, ID_EL_OPENSOURCE, SW_HIDE);
+
+ //6. If requested disable UpdateNow button
+ if ((lpEL->lpOEL->dwFlags & ELF_DISABLECHANGESOURCE))
+ StandardShowDlgItem(hDlg, ID_EL_CHANGESOURCE, SW_HIDE);
+
+ //7. If requested disable CancelLink button
+ if ((lpEL->lpOEL->dwFlags & ELF_DISABLECANCELLINK))
+ StandardShowDlgItem(hDlg, ID_EL_CANCELLINK, SW_HIDE);
+
+ //8. Load 'Close' string used to rename Cancel button
+ n = LoadString(ghInst, IDS_CLOSE, lpEL->szClose, sizeof(lpEL->szClose)/sizeof(TCHAR));
+ if (!n)
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
+ return FALSE;
+ }
+
+ if (cLinks > 0)
+ SetFocus(hListBox);
+ else
+ SetFocus(GetDlgItem(hDlg, IDCANCEL));
+
+ lpEL->nChgSrcHelpID = RegisterWindowMessage(HELPMSGSTRING);
+
+ //n. Call the hook with lCustData in lParam
+ UStandardHook(lpEL, hDlg, WM_INITDIALOG, wParam, lpOEL->lCustData);
+
+ return FALSE;
+}
+
+
+
+/*
+ * ChangeSourceHook
+ *
+ * Purpose:
+ * Hooks the ChangeSource dialog to attempt to validate link source changes
+ * specified by the user.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * uMsg UINT Message
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * UNIT Zero = Do default processing;
+ * Non Zero = Don't do default processing.
+ */
+
+UINT CALLBACK EXPORT ChangeSourceHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LPCHANGESOURCEHOOKDATA lpCshData = NULL;
+ LPLINKINFO lpLI = NULL;
+ LPEDITLINKS lpEL = NULL;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr;
+ HRESULT hErr;
+ UINT uRet;
+ ULONG ulChEaten;
+ HGLOBAL gh;
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ if (NULL!=(gh = GetProp(hDlg, STRUCTUREPROP)))
+ {
+ // gh was locked previously, lock and unlock to get lpv
+ lpCshData=(LPCHANGESOURCEHOOKDATA)GlobalLock(gh);
+ GlobalUnlock(gh);
+ if (lpCshData)
+ {
+ lpLI = lpCshData->lpOCshData->lpLI;
+ lpEL = lpCshData->lpOCshData->lpEL;
+ }
+ }
+
+ //Process the temination message
+ if (uMsg==uMsgEndDialog)
+ {
+ if (NULL!=(gh = RemoveProp(hDlg, STRUCTUREPROP)))
+ {
+ GlobalUnlock(gh);
+ GlobalFree(gh);
+ }
+ return TRUE;
+ }
+
+ // User pressed the OK button
+ if (uMsg == uMsgFileOKString) {
+ lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+
+ /* NOTE: trigger the focus lost of the edit control. This is
+ ** not necessary if the user click OK with the mouse but is
+ ** needed when the user just press <Enter>. If the mouse was
+ ** used, no extra is done as the MODIFY flag of the edit control
+ ** has been cleared.
+ */
+ SendMessage(hDlg, WM_COMMAND, edt1,
+ MAKELPARAM(GetDlgItem(hDlg, edt1), EN_KILLFOCUS));
+ if (lpCshData->bItemNameStored) {
+ lpCshData->nFileLength = lstrlen((LPTSTR)lpCshData->szEdit) -
+ lstrlen((LPTSTR)lpCshData->szItemName);
+ }
+ else {
+ lpCshData->nFileLength = lstrlen((LPTSTR)lpCshData->szEdit);
+ }
+
+ // Try to validate link source change
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::SetLinkSource called\r\n"));
+ hErr = lpOleUILinkCntr->lpVtbl->SetLinkSource(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ (LPTSTR)lpCshData->szEdit,
+ (ULONG)lpCshData->nFileLength,
+ &ulChEaten,
+ TRUE
+ );
+ OLEDBG_END2
+
+ // Link source change not validated
+ if (hErr != NOERROR) {
+ uRet =PopupMessage(hDlg, IDS_CHANGESOURCE, IDS_INVALIDSOURCE,
+ MB_ICONQUESTION | MB_YESNO);
+
+ if (uRet == IDYES) {
+ /* User wants to correct invalid link. Set the edit
+ ** control selection to the invalid part of the contents.
+ */
+ SetFocus(GetDlgItem(hDlg, edt1));
+ SendDlgItemMessage(hDlg, edt1, EM_SETSEL, 0,
+ MAKELPARAM(ulChEaten, -1));
+ return 1; // Don't close ChangeSource dialog
+ }
+ else {
+ /* User does not want to correct invalid link. So set
+ ** the link source but don't validate the link.
+ */
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::SetLinkSource called\r\n"));
+ hErr = lpOleUILinkCntr->lpVtbl->SetLinkSource(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ (LPTSTR)lpCshData->szEdit,
+ (ULONG)lpCshData->nFileLength,
+ &ulChEaten,
+ FALSE
+ );
+ OLEDBG_END2
+ lpCshData->fValidLink = FALSE;
+ }
+ }
+ else { // Link source change validated
+ lpCshData->fValidLink = TRUE;
+ }
+
+ if (lpCshData->bItemNameStored && lpCshData->bFileNameStored) {
+ HWND hListBox = GetDlgItem(lpCshData->lpOfn->hwndOwner, ID_EL_LINKSLISTBOX);
+
+ DiffPrefix(
+ lpLI->lpszDisplayName,
+ (LPTSTR)lpCshData->szEdit,
+ (TCHAR FAR* FAR*)&lpCshData->lpszFrom,
+ (TCHAR FAR* FAR*)&lpCshData->lpszTo
+ );
+
+ /* we keep the strings if there is a difference between the
+ ** lpszFrom and lpszTo strings AND if the change is only
+ ** in the file portion otherwise free them and other
+ ** links won't be compared.
+ */
+ if ( (lstrcmp(lpCshData->lpszTo, lpCshData->lpszFrom)==0)
+ || (lstrlen(lpCshData->lpszTo)>lpCshData->nFileLength)) {
+ if (lpCshData->lpszFrom) {
+ OleStdFree(lpCshData->lpszFrom);
+ lpCshData->lpszFrom = NULL;
+ }
+ if (lpCshData->lpszTo) {
+ OleStdFree(lpCshData->lpszTo);
+ lpCshData->lpszTo = NULL;
+ }
+ }
+ }
+
+ // Copy OUT results to original structure
+ lpCshData->lpOCshData->lpszFrom = lpCshData->lpszFrom;
+ lpCshData->lpOCshData->lpszTo = lpCshData->lpszTo;
+ lpCshData->lpOCshData->fValidLink = lpCshData->fValidLink;
+
+ SendMessage(hDlg, uMsgEndDialog, 0, 0L); // do cleanup
+ return 0; // Close ChangeSource dialog
+ }
+
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ {
+ LPOPENFILENAME lpOfn = (LPOPENFILENAME)lParam;
+ LPOLEUICHANGESOURCEHOOKDATA lpOCshData =
+ (LPOLEUICHANGESOURCEHOOKDATA)lpOfn->lCustData;
+
+ gh=GlobalAlloc(
+ GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(CHANGESOURCEHOOKDATA));
+ if (NULL==gh)
+ {
+ // Memory allocation error; fail to bring up dialog
+ PostMessage(hDlg, uMsgEndDialog, 0, 0L);
+ return 0;
+ }
+ lpCshData = GlobalLock(gh);
+ SetProp(hDlg, STRUCTUREPROP, gh);
+
+ lpCshData->lpOCshData = lpOCshData;
+ lpCshData->lpOfn = lpOfn;
+ lpLI = lpCshData->lpOCshData->lpLI;
+
+ lpCshData->bFileNameStored = TRUE;
+ lpCshData->bItemNameStored = TRUE;
+ lpCshData->nFileLength = (int)lpLI->clenFileName;
+ if (lpLI->lpszDisplayName) {
+ LSTRCPYN((LPTSTR)lpCshData->szFileName, lpLI->lpszDisplayName,
+ lpCshData->nFileLength + 1);
+ lstrcpy((LPTSTR)lpCshData->szEdit, lpLI->lpszDisplayName);
+ } else {
+ lpCshData->szFileName[0] = TEXT('\0');
+ lpCshData->szEdit[0] = TEXT('\0');
+ }
+ if (lpLI->lpszItemName)
+ lstrcpy((LPTSTR)lpCshData->szItemName, lpLI->lpszItemName);
+ else
+ lpCshData->szItemName[0] = TEXT('\0');
+
+ return 0;
+ }
+
+ case WM_COMMAND:
+
+ // User pressed the CANCEL button
+ if (wParam == IDCANCEL)
+ {
+ if (lpCshData->lpszFrom)
+ {
+ OleStdFree(lpCshData->lpszFrom);
+ lpCshData->lpszFrom = NULL;
+ }
+ if (lpCshData->lpszTo)
+ {
+ OleStdFree(lpCshData->lpszTo);
+ lpCshData->lpszTo = NULL;
+ }
+
+ // Copy OUT results to original structure
+ lpCshData->lpOCshData->lpszFrom = NULL;
+ lpCshData->lpOCshData->lpszTo = NULL;
+ lpCshData->lpOCshData->fValidLink = FALSE;
+
+ SendMessage(hDlg, uMsgEndDialog, 0, 0L); // do cleanup
+ return 0; // Close ChangeSource dialog
+ }
+
+ if ((wParam == lst1) &&
+ (HIWORD(lParam) == LBN_SELCHANGE)) {
+
+ int nIndex;
+ HWND hListBox = (HWND)LOWORD(lParam);
+ static TCHAR szFileNameBuf[OLEUI_CCHPATHMAX];
+ static TCHAR szEditBuf[OLEUI_CCHPATHMAX];
+
+ nIndex = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0L);
+ SendMessage(hListBox, LB_GETTEXT,
+ (WPARAM)nIndex, (LPARAM)(LPTSTR)szFileNameBuf);
+
+ /* need to build the full path filename for the moniker */
+#ifdef WIN32
+ CharToOem(szFileNameBuf, szFileNameBuf);
+#else
+ AnsiToOem(szFileNameBuf, szFileNameBuf);
+#endif
+ _fullpath(szEditBuf, szFileNameBuf, sizeof(szEditBuf));
+#ifdef WIN32
+ OemToChar(szEditBuf, szEditBuf);
+#else
+ OemToAnsi(szEditBuf, szEditBuf);
+#endif
+
+ /* convert filename to lower case as it appears in the
+ ** listbox
+ */
+#ifdef WIN32
+ CharLower(szEditBuf);
+#else
+ AnsiLower(szEditBuf);
+#endif
+ LSTRCPYN((LPTSTR)lpCshData->szEdit, (LPTSTR)szEditBuf,
+ sizeof(lpCshData->szEdit) / sizeof(TCHAR));
+ LSTRCPYN((LPTSTR)lpCshData->szFileName,
+ (LPTSTR)lpCshData->szEdit,
+ sizeof(lpCshData->szFileName) / sizeof(TCHAR) );
+ lpCshData->nFileLength = lstrlen((LPTSTR)lpCshData->szEdit);
+ if (lpCshData->bItemNameStored)
+ lstrcat((LPTSTR)lpCshData->szEdit, lpCshData->szItemName);
+
+ SetDlgItemText(hDlg, edt1, (LPTSTR)lpCshData->szEdit);
+ lpCshData->nEditLength = lstrlen((LPTSTR)lpCshData->szEdit);
+ lpCshData->bFileNameStored = TRUE;
+
+ return 1;
+ }
+
+ if ((wParam == lst2) &&
+ (HIWORD(lParam) == LBN_SELCHANGE)) {
+
+ if (lpCshData->bItemNameStored)
+ SetDlgItemText(hDlg, edt1, (LPTSTR)lpCshData->szItemName);
+
+ return 1;
+ }
+
+ if ((wParam == cmb2) &&
+ (HIWORD(lParam) == CBN_SELCHANGE)) {
+
+ if (lpCshData->bItemNameStored)
+ SetDlgItemText(hDlg, edt1, (LPTSTR)lpCshData->szItemName);
+
+ return 1;
+ }
+
+ if (wParam == edt1) {
+ HWND hEdit = (HWND)LOWORD(lParam);
+
+ switch (HIWORD(lParam)) {
+ case EN_SETFOCUS:
+ SendMessage(hEdit, EM_SETSEL, 0,
+ MAKELPARAM(0, lpCshData->nFileLength));
+ return 1;
+
+ case EN_KILLFOCUS:
+ if (SendMessage(hEdit, EM_GETMODIFY, 0, 0L)) {
+ TCHAR szTmp[OLEUI_CCHPATHMAX];
+ int nItemLength = lstrlen((LPTSTR)lpCshData->szItemName);
+
+ *(LPWORD)lpCshData->szEdit = sizeof(lpCshData->szEdit)/
+ sizeof(TCHAR) - 1;
+ lpCshData->nEditLength = (int)SendMessage(hEdit,
+ EM_GETLINE, 0, (LPARAM)(LPTSTR)lpCshData->szEdit);
+ lpCshData->szEdit[lpCshData->nEditLength] = TEXT('\0');
+ LSTRCPYN((LPTSTR)szTmp, (LPTSTR)lpCshData->szEdit,
+ lpCshData->nFileLength + 1);
+
+ if (lpCshData->bFileNameStored &&
+ !lstrcmp((LPTSTR)lpCshData->szFileName, (LPTSTR)szTmp)) {
+ lstrcpy((LPTSTR)lpCshData->szItemName,
+ (LPTSTR)lpCshData->szEdit + lpCshData->nFileLength);
+ lpCshData->bItemNameStored = TRUE;
+ }
+ else if (lpCshData->bItemNameStored &&
+ !lstrcmp((LPTSTR)lpCshData->szItemName,
+ (LPTSTR)lpCshData->szEdit +
+ lpCshData->nEditLength -
+ nItemLength)) {
+ if (lpCshData->nEditLength==nItemLength) {
+
+ lpCshData->bFileNameStored = FALSE;
+ } else {
+ LSTRCPYN((LPTSTR)lpCshData->szFileName,
+ (LPTSTR)lpCshData->szEdit,
+ lpCshData->nEditLength -
+ nItemLength+1);
+ lpCshData->bFileNameStored = TRUE;
+ }
+ }
+ else {
+ lpCshData->bItemNameStored = FALSE;
+ lpCshData->bFileNameStored = FALSE;
+ }
+
+ SendMessage(hEdit, EM_SETMODIFY, FALSE, 0L);
+ }
+ return 0;
+ }
+ }
+ return 0;
+
+ default:
+ return 0;
+ }
+}
+
+
+/*
+* ChangeSource
+*
+* Purpose:
+* Displays the standard GetOpenFileName dialog with a customized template and
+* hook.
+*
+* Parameters:
+* hWndOwner HWND owning the dialog
+* lpszFile LPSTR specifying the initial file. If there is no
+* initial file the first character of this string should
+* be a null.
+* cchFile UINT length of pszFile
+* iFilterString UINT index into the stringtable for the filter string.
+* lpfnBrowseHook COMMDLGHOOKPROC hook to process link source information when user
+* presses OK
+* lpCshData LPCHANGESOURCEHOOKDATA custom data that is accessible to the hook
+*
+* Return Value:
+* BOOL TRUE if the user selected a file and pressed OK.
+* FALSE otherwise, such as on pressing Cancel.
+*/
+
+BOOL WINAPI ChangeSource(
+ HWND hWndOwner,
+ LPTSTR lpszFile,
+ UINT cchFile,
+ UINT iFilterString,
+ COMMDLGHOOKPROC lpfnBrowseHook,
+ LPOLEUICHANGESOURCEHOOKDATA lpCshData
+)
+{
+ UINT cch;
+ TCHAR szFilters[OLEUI_CCHPATHMAX];
+ TCHAR szDir[OLEUI_CCHPATHMAX];
+ TCHAR szTitle[OLEUI_CCHPATHMAX];
+ OPENFILENAME ofn;
+ BOOL fStatus;
+ LPTSTR lpszFileBuffer;
+
+ if (NULL==lpszFile || 0==cchFile)
+ return FALSE;
+
+ lpszFileBuffer = (LPTSTR)OleStdMalloc(cchFile * sizeof(TCHAR));
+ if (!lpszFileBuffer)
+ return FALSE;
+
+ lstrcpy(lpszFileBuffer, lpszFile);
+
+ // Get filters
+ if (0!=iFilterString)
+ cch = LoadString(ghInst, iFilterString, (LPTSTR)szFilters,
+ OLEUI_CCHPATHMAX);
+ else
+ {
+ szFilters[0]=0;
+ cch=1;
+ }
+ if (0==cch) {
+ fStatus = FALSE;
+ goto cleanup;
+ }
+
+ ReplaceCharWithNull(szFilters, szFilters[cch-1]);
+
+ LSTRCPYN((LPTSTR)szDir, lpszFile, OLEUI_CCHPATHMAX);
+ for (cch = lstrlen((LPTSTR)szDir) - 1; cch >= 0; cch--)
+ {
+ if ((szDir[cch]==TEXT('\\')) || (szDir[cch]==TEXT(':')) || (szDir[cch]==TEXT('/')))
+ break;
+ }
+ if (cch < 0)
+ cch = 0;
+
+ szDir[cch] = TEXT('\0');
+
+ LoadString(ghInst, IDS_CHANGESOURCE, (LPTSTR)szTitle, OLEUI_CCHPATHMAX);
+ _fmemset((LPOPENFILENAME)&ofn, 0, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hWndOwner;
+ ofn.lpstrFile = lpszFileBuffer;
+ ofn.nMaxFile = cchFile;
+ ofn.lpstrFilter = (LPTSTR)szFilters;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrTitle = (LPTSTR)szTitle;
+ ofn.lpstrInitialDir = (LPTSTR)szDir;
+ ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEOPEN);
+ ofn.lpfnHook = lpfnBrowseHook;
+ ofn.hInstance = ghInst;
+ ofn.lCustData = (LPARAM)lpCshData;
+ ofn.Flags = OFN_NOVALIDATE | OFN_HIDEREADONLY |
+ OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
+
+ // Only show help button if edit links dialog shows it.
+ if (lpCshData->lpEL->lpOEL->dwFlags & ELF_SHOWHELP)
+ ofn.Flags |= OFN_SHOWHELP;
+
+ fStatus = GetOpenFileName((LPOPENFILENAME)&ofn);
+
+cleanup:
+ OleStdFree((LPVOID)lpszFileBuffer);
+ return fStatus;
+
+}
+
+/*
+* Container_ChangeSource
+*
+* Purpose:
+* Tunnel to File Open type dlg and allow user to select new file
+* for file based monikers, OR to change the whole moniker to what
+* the user types into the editable field.
+*
+* Parameters:
+* hDlg HWND of the dialog
+* LPEDITLINKS Pointer to EditLinks structure (contains all nec.
+* info)
+*
+* Return Value:
+* BOOL for now, because we are not using any ole functions
+* to return an HRESULT.
+* HRESULT HRESULT value indicating success or failure of
+* changing the moniker value
+*/
+
+BOOL Container_ChangeSource(HWND hDlg, LPEDITLINKS lpEL)
+{
+ UINT uRet;
+ int cSelItems;
+ int FAR* rgIndex;
+ int i = 0;
+ LPLINKINFO lpLI;
+ HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+ LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+ OLEUICHANGESOURCEHOOKDATA cshData; // Data that needs to be accessed
+ // by the ChangeSource dialog hook
+
+ cSelItems = GetSelectedItems(hListBox, &rgIndex);
+
+ if (cSelItems < 0)
+ return FALSE;
+
+ if (!cSelItems)
+ return TRUE;
+
+ if (!lpEL->fClose) {
+ SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPTSTR)lpEL->szClose);
+ lpEL->fClose = TRUE;
+ }
+
+ _fmemset((LPOLEUICHANGESOURCEHOOKDATA)&cshData, 0, sizeof(cshData));
+ cshData.cbStruct=sizeof(cshData);
+ cshData.hWndOwner=hDlg;
+ cshData.lpEL = (LPEDITLINKS)lpEL;
+ cshData.lpszFrom = NULL;
+ cshData.lpszTo = NULL;
+
+ for (i = cSelItems-1; i >=0; i--) {
+ SendMessage(hListBox, LB_GETTEXT, rgIndex[i],
+ (LPARAM) (LPLINKINFO FAR*) &lpLI);
+
+ uRet = UStandardHook(lpEL, hDlg, uMsgBrowse,
+ OLEUI_CCHPATHMAX_SIZE, (LONG)(LPTSTR)lpLI->lpszDisplayName);
+
+ if (!uRet) {
+ cshData.lpLI = lpLI;
+ /* Bring up the ChangeSource dialog after hooking it so
+ ** that the user specified link source is verified
+ ** when OK is pressed.
+ */
+ uRet = (UINT)ChangeSource(hDlg, lpLI->lpszDisplayName,
+ OLEUI_CCHPATHMAX, IDS_FILTERS, ChangeSourceHook,
+ &cshData);
+ }
+
+ /* If Cancel is pressed in any ChangeSource dialog, stop
+ ** the ChangeSource processing for all links.
+ */
+ if (!uRet) {
+ if (rgIndex)
+ OleStdFree(rgIndex);
+ return TRUE;
+ }
+
+ UpdateLinkLBItem(hListBox, rgIndex[i], lpEL, TRUE);
+
+ if (cshData.lpszFrom && cshData.lpszTo) {
+ ChangeAllLinks(hListBox, lpOleUILinkCntr, cshData.lpszFrom,
+ cshData.lpszTo);
+ OleStdFree(cshData.lpszFrom);
+ OleStdFree(cshData.lpszTo);
+ }
+
+ } // end FOR
+
+
+ if (rgIndex)
+ OleStdFree(rgIndex);
+
+ return TRUE;
+
+}
+
+
+/*
+* Container_AutomaticManual
+*
+* Purpose:
+* To change the selected moniker to manual or automatic update.
+*
+* Parameters:
+* hDlg HWND of the dialog
+* FAutoMan Flag indicating AUTO (TRUE/1) or MANUAL(FALSE/0)
+* LPEDITLINKS Pointer to EditLinks structure (contains all nec.
+* info)
+* * this may change - don't know how the linked list
+* * of multi-selected items will work.
+* Return Value:
+* HRESULT HRESULT value indicating success or failure of
+* changing the moniker value
+*/
+
+HRESULT Container_AutomaticManual(HWND hDlg, BOOL fAutoMan, LPEDITLINKS lpEL)
+{
+
+ HRESULT hErr = NOERROR;
+ int cSelItems;
+ int FAR* rgIndex;
+ int i = 0;
+ LPLINKINFO lpLI;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+ HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+ BOOL bUpdate = FALSE;
+
+ OleDbgAssert(lpOleUILinkCntr);
+
+ /* Change so looks at flag in structure. Only update those that
+ need to be updated. Make sure to change flag if status changes.
+ */
+
+ cSelItems = GetSelectedItems(hListBox, &rgIndex);
+
+ if (cSelItems < 0)
+ return ResultFromScode(E_FAIL);
+
+ if (!cSelItems)
+ return NOERROR;
+
+ if (!lpEL->fClose)
+ SetDlgItemText(hDlg, IDCANCEL, (LPTSTR)lpEL->szClose);
+
+ for (i = 0; i < cSelItems; i++) {
+ SendMessage(hListBox, LB_GETTEXT, (WPARAM)rgIndex[i],
+ (LPARAM) (LPLINKINFO FAR*) &lpLI);
+
+ if (fAutoMan) { // If switching to AUTOMATIC
+ if (!lpLI->fIsAuto) { // Only change MANUAL links
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::SetLinkUpdateOptions called\r\n"));
+ hErr=lpOleUILinkCntr->lpVtbl->SetLinkUpdateOptions(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ OLEUPDATE_ALWAYS
+ );
+ OLEDBG_END2
+
+ lpLI->fIsAuto=TRUE;
+ lpLI->fIsMarked = TRUE;
+ bUpdate = TRUE;
+ }
+ }
+ else { // If switching to MANUAL
+ if (lpLI->fIsAuto) { // Only do AUTOMATIC Links
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::SetLinkUpdateOptions called\r\n"));
+ hErr=lpOleUILinkCntr->lpVtbl->SetLinkUpdateOptions(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ OLEUPDATE_ONCALL
+ );
+ OLEDBG_END2
+
+ lpLI->fIsAuto = FALSE;
+ lpLI->fIsMarked = TRUE;
+ bUpdate = TRUE;
+ }
+ }
+
+ if (hErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::SetLinkUpdateOptions returned"),hErr);
+ break;
+ }
+
+ }
+
+ if (bUpdate)
+ RefreshLinkLB(hListBox, lpOleUILinkCntr);
+
+ if (rgIndex)
+ OleStdFree((LPVOID)rgIndex);
+
+ return hErr;
+}
+
+
+HRESULT CancelLink(HWND hDlg, LPEDITLINKS lpEL)
+{
+ HRESULT hErr;
+ LPMONIKER lpmk;
+ int cSelItems;
+ int FAR* rgIndex;
+ int i = 0;
+ LPLINKINFO lpLI;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+ HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+ BOOL bUpdate = FALSE;
+
+ OleDbgAssert(lpOleUILinkCntr);
+
+ lpmk = NULL;
+
+ cSelItems = GetSelectedItems(hListBox, &rgIndex);
+
+ if (cSelItems < 0)
+ return ResultFromScode(E_FAIL);
+
+ if (!cSelItems)
+ return NOERROR;
+
+ if (!lpEL->fClose) {
+ SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPTSTR)lpEL->szClose);
+ lpEL->fClose = TRUE;
+ }
+
+ for (i = 0; i < cSelItems; i++) {
+ SendMessage(hListBox, LB_GETTEXT, (WPARAM)rgIndex[i],
+ (LPARAM)(LPLINKINFO FAR*) &lpLI);
+
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::CancelLink called\r\n"));
+ hErr = lpOleUILinkCntr->lpVtbl->CancelLink(
+ lpOleUILinkCntr,
+ lpLI->dwLink
+ );
+ OLEDBG_END2
+
+ if (hErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::CancelLink returned"),hErr);
+ lpLI->fIsMarked = TRUE;
+ bUpdate = TRUE;
+ }
+ else
+ // Delete links that we make null from listbox
+ SendMessage(hListBox, LB_DELETESTRING, (WPARAM) rgIndex[i], 0L);
+
+ }
+
+ if (bUpdate)
+ RefreshLinkLB(hListBox, lpOleUILinkCntr);
+
+ if (rgIndex)
+ OleStdFree((LPVOID)rgIndex);
+
+ return hErr;
+
+}
+
+
+/*
+ * Container_UpdateNow
+ *
+ * Purpose:
+ * Immediately force an update for all (manual) links
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * LPEDITLINKS Pointer to EditLinks structure (contains all nec. info)
+ * * this may change - don't know how the linked list
+ * * of multi-selected items will work.
+ * Return Value:
+ * HRESULT HRESULT value indicating success or failure of
+ * changing the moniker value
+ */
+
+HRESULT Container_UpdateNow(HWND hDlg, LPEDITLINKS lpEL)
+{
+ HRESULT hErr;
+ LPLINKINFO lpLI;
+ int cSelItems;
+ int FAR* rgIndex;
+ int i = 0;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+ HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+ BOOL bUpdate = FALSE;
+
+ OleDbgAssert(lpOleUILinkCntr);
+
+ cSelItems = GetSelectedItems(hListBox, &rgIndex);
+
+ if (cSelItems < 0)
+ return ResultFromScode(E_FAIL);
+
+ if (!cSelItems)
+ return NOERROR;
+
+ if (!lpEL->fClose) {
+ SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPTSTR)lpEL->szClose);
+ lpEL->fClose = TRUE;
+ }
+
+ for (i = 0; i < cSelItems; i++) {
+ SendMessage(hListBox, LB_GETTEXT,
+ (WPARAM)rgIndex[i], (LPARAM)(LPLINKINFO FAR*)&lpLI);
+
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::UpdateLink called\r\n"));
+ hErr = lpOleUILinkCntr->lpVtbl->UpdateLink(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ TRUE,
+ FALSE
+ );
+ OLEDBG_END2
+ bUpdate = TRUE;
+ lpLI->fIsMarked = TRUE;
+
+ if (hErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::UpdateLink returned"),hErr);
+ break;
+ }
+
+ }
+
+ if (bUpdate)
+ RefreshLinkLB(hListBox, lpOleUILinkCntr);
+
+ if (rgIndex)
+ OleStdFree((LPVOID)rgIndex);
+
+ return hErr;
+
+}
+
+/*
+ * Container_OpenSource
+ *
+ * Purpose:
+ * Immediately force an update for all (manual) links
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * LPEDITLINKS Pointer to EditLinks structure (contains all nec.
+ * info)
+ *
+ * Return Value:
+ * HRESULT HRESULT value indicating success or failure of
+ * changing the moniker value
+ */
+
+HRESULT Container_OpenSource(HWND hDlg, LPEDITLINKS lpEL)
+{
+ HRESULT hErr;
+ int cSelItems;
+ int FAR* rgIndex;
+ LPLINKINFO lpLI;
+ RECT rcPosRect;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+ HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+
+ OleDbgAssert(lpOleUILinkCntr);
+
+ rcPosRect.top = 0;
+ rcPosRect.left = 0;
+ rcPosRect.right = 0;
+ rcPosRect.bottom = 0;
+
+ cSelItems = GetSelectedItems(hListBox, &rgIndex);
+
+ if (cSelItems < 0)
+ return ResultFromScode(E_FAIL);
+
+ if (cSelItems != 1) // can't open source for multiple items
+ return NOERROR;
+
+ if (!lpEL->fClose) {
+ SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPTSTR)lpEL->szClose);
+ lpEL->fClose = TRUE;
+ }
+
+ SendMessage(hListBox, LB_GETTEXT, (WPARAM)rgIndex[0],
+ (LPARAM)(LPLINKINFO FAR*)&lpLI);
+
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::OpenLinkSource called\r\n"));
+ hErr = lpOleUILinkCntr->lpVtbl->OpenLinkSource(
+ lpOleUILinkCntr,
+ lpLI->dwLink
+ );
+ OLEDBG_END2
+
+ UpdateLinkLBItem(hListBox, rgIndex[0], lpEL, TRUE);
+ if (hErr != NOERROR)
+ OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::OpenLinkSource returned"),hErr);
+
+ if (rgIndex)
+ OleStdFree((LPVOID)rgIndex);
+
+ return hErr;
+}
+
+
+
+/* AddLinkLBItem
+** -------------
+**
+** Add the item pointed to by lpLI to the Link ListBox and return
+** the index of it in the ListBox
+*/
+int AddLinkLBItem(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPLINKINFO lpLI, BOOL fGetSelected)
+{
+ HRESULT hErr;
+ DWORD dwUpdateOpt;
+ int nIndex;
+
+ OleDbgAssert(lpOleUILinkCntr && hListBox && lpLI);
+
+ lpLI->fDontFree = FALSE;
+
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::GetLinkSource called\r\n"));
+ hErr = lpOleUILinkCntr->lpVtbl->GetLinkSource(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ (LPTSTR FAR*)&lpLI->lpszDisplayName,
+ (ULONG FAR*)&lpLI->clenFileName,
+ (LPTSTR FAR*)&lpLI->lpszFullLinkType,
+ (LPTSTR FAR*)&lpLI->lpszShortLinkType,
+ (BOOL FAR*)&lpLI->fSourceAvailable,
+ fGetSelected ? (BOOL FAR*)&lpLI->fIsSelected : NULL
+ );
+ OLEDBG_END2
+
+ if (hErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::GetLinkSource returned"),hErr);
+ PopupMessage(hListBox, IDS_LINKS, IDS_ERR_GETLINKSOURCE,
+ MB_ICONEXCLAMATION | MB_OK);
+
+ goto cleanup;
+ }
+
+ OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::GetLinkUpdateOptions called\r\n"));
+ hErr=lpOleUILinkCntr->lpVtbl->GetLinkUpdateOptions(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ (LPDWORD)&dwUpdateOpt
+ );
+ OLEDBG_END2
+
+
+ if (hErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::GetLinkUpdateOptions returned"),hErr);
+ PopupMessage(hListBox, IDS_LINKS, IDS_ERR_GETLINKUPDATEOPTIONS,
+ MB_ICONEXCLAMATION | MB_OK);
+
+ goto cleanup;
+ }
+
+ if (lpLI->fSourceAvailable) {
+ if (dwUpdateOpt == OLEUPDATE_ALWAYS) {
+ lpLI->fIsAuto = TRUE;
+ LoadString(ghInst, IDS_LINK_AUTO, lpLI->lpszAMX,
+ (int)OleStdGetSize((LPVOID)lpLI->lpszAMX));
+ }
+ else {
+ lpLI->fIsAuto = FALSE;
+ LoadString(ghInst, IDS_LINK_MANUAL, lpLI->lpszAMX,
+ (int)OleStdGetSize((LPVOID)lpLI->lpszAMX));
+ }
+ }
+ else
+ LoadString(ghInst, IDS_LINK_UNKNOWN, lpLI->lpszAMX,
+ (int)OleStdGetSize((LPVOID)lpLI->lpszAMX));
+
+ BreakString(lpLI);
+
+ nIndex = (int)SendMessage(hListBox, LB_ADDSTRING, (WPARAM)0,
+ (LPARAM)(DWORD)lpLI);
+
+ if (nIndex == LB_ERR) {
+ PopupMessage(hListBox, IDS_LINKS, IDS_ERR_ADDSTRING,
+ MB_ICONEXCLAMATION | MB_OK);
+
+ goto cleanup;
+ }
+
+ return nIndex;
+
+cleanup:
+ if (lpLI->lpszDisplayName)
+ OleStdFree((LPVOID)lpLI->lpszDisplayName);
+
+ if (lpLI->lpszShortLinkType)
+ OleStdFree((LPVOID)lpLI->lpszShortLinkType);
+
+ if (lpLI->lpszFullLinkType)
+ OleStdFree((LPVOID)lpLI->lpszFullLinkType);
+
+ return -1;
+}
+
+
+/* BreakString
+ * -----------
+ *
+ * Purpose:
+ * Break the lpszDisplayName into various parts
+ *
+ * Parameters:
+ * lpLI pointer to LINKINFO structure
+ *
+ * Returns:
+ *
+ */
+VOID BreakString(LPLINKINFO lpLI)
+{
+ LPTSTR lpsz;
+
+ if (!lpLI->clenFileName ||
+ (lstrlen(lpLI->lpszDisplayName)==(int)lpLI->clenFileName)) {
+
+ lpLI->lpszItemName = NULL;
+ }
+ else {
+ lpLI->lpszItemName = lpLI->lpszDisplayName + lpLI->clenFileName;
+ }
+
+ // search from last character of filename
+ lpsz = lpLI->lpszDisplayName + lstrlen(lpLI->lpszDisplayName);
+ while (lpsz > lpLI->lpszDisplayName) {
+#ifdef WIN32
+ // AnsiPrev is obsolete in Win32
+ lpsz = CharPrev(lpLI->lpszDisplayName, lpsz);
+#else
+ lpsz = AnsiPrev(lpLI->lpszDisplayName, lpsz);
+#endif
+ if ((*lpsz == TEXT('\\')) || (*lpsz == TEXT('/')) || (*lpsz == TEXT(':')))
+ break;
+ }
+
+ if (lpsz == lpLI->lpszDisplayName)
+ lpLI->lpszShortFileName = lpsz;
+ else
+#ifdef WIN32
+ // AnsiNext is obsolete in Win32
+ lpLI->lpszShortFileName = CharNext(lpsz);
+#else
+ lpLI->lpszShortFileName = AnsiNext(lpsz);
+#endif
+}
+
+
+/* GetSelectedItems
+ * ----------------
+ *
+ * Purpose:
+ * Retrieve the indices of the selected items in the listbox
+ * Note that *lprgIndex needed to be free after using the function
+ *
+ * Parameters:
+ * hListBox window handle of listbox
+ * lprgIndex pointer to an integer array to receive the indices
+ * must be freed afterwards
+ *
+ * Returns:
+ * number of indices retrieved, -1 if error
+ */
+int GetSelectedItems(HWND hListBox, int FAR* FAR* lprgIndex)
+{
+ DWORD cSelItems;
+ DWORD cCheckItems;
+
+ *lprgIndex = NULL;
+
+ cSelItems = SendMessage(hListBox, LB_GETSELCOUNT, 0, 0L);
+ if (cSelItems < 0) // error
+ return (int)cSelItems;
+
+ if (!cSelItems)
+ return 0;
+
+ *lprgIndex = (int FAR*)OleStdMalloc((int)cSelItems * sizeof(int));
+
+ cCheckItems = SendMessage(hListBox, LB_GETSELITEMS,
+ (WPARAM) cSelItems, (LPARAM) (int FAR*) *lprgIndex);
+
+ if (cCheckItems == cSelItems)
+ return (int)cSelItems;
+ else {
+ if (*lprgIndex)
+ OleStdFree((LPVOID)*lprgIndex);
+ *lprgIndex = NULL;
+ return 0;
+ }
+}
+
+
+/* InitControls
+ * ------------
+ *
+ * Purpose:
+ * Initialize the state of the Auto/Manual button, Link source/type
+ * static field, etc in the dialogs according to the selection in the
+ * listbox
+ *
+ * Parameters:
+ * hDlg handle to the dialog window
+ */
+VOID InitControls(HWND hDlg, LPEDITLINKS lpEL)
+{
+ int cSelItems;
+ HWND hListBox;
+ int i;
+ int FAR* rgIndex;
+ LPLINKINFO lpLI;
+ LPTSTR lpszType = NULL;
+ LPTSTR lpszSource = NULL;
+ int cAuto = 0;
+ int cManual = 0;
+ BOOL bSameType = TRUE;
+ BOOL bSameSource = TRUE;
+ TCHAR tsz[OLEUI_CCHPATHMAX];
+ LPTSTR lpsz;
+
+
+ hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);
+
+ cSelItems = GetSelectedItems(hListBox, &rgIndex);
+ if (cSelItems < 0)
+ return;
+
+ EnableWindow(GetDlgItem(hDlg, ID_EL_AUTOMATIC), (BOOL)cSelItems);
+ EnableWindow(GetDlgItem(hDlg, ID_EL_MANUAL), (BOOL)cSelItems);
+ if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLECANCELLINK))
+ EnableWindow(GetDlgItem(hDlg, ID_EL_CANCELLINK), (BOOL)cSelItems);
+ if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLEOPENSOURCE))
+ EnableWindow(GetDlgItem(hDlg, ID_EL_OPENSOURCE), cSelItems == 1);
+ if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLECHANGESOURCE))
+ EnableWindow(GetDlgItem(hDlg, ID_EL_CHANGESOURCE), cSelItems == 1);
+ if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLEUPDATENOW))
+ EnableWindow(GetDlgItem(hDlg, ID_EL_UPDATENOW), (BOOL)cSelItems);
+
+ for (i = 0; i < cSelItems; i++) {
+ SendDlgItemMessage(
+ hDlg,
+ ID_EL_LINKSLISTBOX,
+ LB_GETTEXT,
+ (WPARAM)rgIndex[i],
+ (LPARAM)(LPLINKINFO FAR*)&lpLI);
+
+ if (lpszSource && lpLI->lpszDisplayName) {
+ if (bSameSource && lstrcmp(lpszSource, lpLI->lpszDisplayName)) {
+ bSameSource = FALSE;
+ }
+ }
+ else
+ lpszSource = lpLI->lpszDisplayName;
+
+ if (lpszType && lpLI->lpszFullLinkType) {
+ if (bSameType && lstrcmp(lpszType, lpLI->lpszFullLinkType)) {
+ bSameType = FALSE;
+ }
+ }
+ else
+ lpszType = lpLI->lpszFullLinkType;
+
+ if (lpLI->fIsAuto)
+ cAuto++;
+ else
+ cManual++;
+ }
+
+ CheckDlgButton(hDlg, ID_EL_AUTOMATIC, cAuto && !cManual);
+ CheckDlgButton(hDlg, ID_EL_MANUAL, !cAuto && cManual);
+
+ /* fill full source in static text box
+ ** below list
+ */
+ if (!bSameSource || !lpszSource)
+ lpszSource = szNULL;
+ lstrcpy((LPTSTR)tsz, lpszSource);
+ lpsz = ChopText(GetDlgItem(hDlg, ID_EL_LINKSOURCE), 0, tsz);
+ SetDlgItemText(hDlg, ID_EL_LINKSOURCE, lpsz);
+
+ /* fill full link type name in static
+ ** "type" text box
+ */
+ if (!bSameType || !lpszType)
+ lpszType = szNULL;
+ SetDlgItemText(hDlg, ID_EL_LINKTYPE, lpszType);
+
+ if (rgIndex)
+ OleStdFree((LPVOID)rgIndex);
+}
+
+
+/* UpdateLinkLBItem
+ * -----------------
+ *
+ * Purpose:
+ * Update the linkinfo struct in the listbox to reflect the changes
+ * made by the last operation. It is done simply by removing the item
+ * from the listbox and add it back.
+ *
+ * Parameters:
+ * hListBox handle of listbox
+ * nIndex index of listbox item
+ * lpEL pointer to editlinks structure
+ * bSelect select the item or not after update
+ */
+VOID UpdateLinkLBItem(HWND hListBox, int nIndex, LPEDITLINKS lpEL, BOOL bSelect)
+{
+ LPLINKINFO lpLI;
+ DWORD dwErr;
+ LPOLEUILINKCONTAINER lpOleUILinkCntr;
+
+ if (!hListBox || (nIndex < 0) || !lpEL)
+ return;
+
+ lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;
+
+ dwErr = SendMessage(hListBox, LB_GETTEXT, nIndex,
+ (LPARAM)(LPLINKINFO FAR*) &lpLI);
+
+ if ((dwErr == LB_ERR) || !lpLI)
+ return;
+
+ /* Don't free the data associated with this listbox item
+ ** because we are going to reuse the allocated space for
+ ** the modified link. WM_DELETEITEM processing in the
+ ** dialog checks this flag before deleting data
+ ** associcated with list item.
+ */
+ lpLI->fDontFree = TRUE;
+ SendMessage(hListBox, LB_DELETESTRING, nIndex, 0L);
+
+ nIndex = AddLinkLBItem(hListBox, lpOleUILinkCntr, lpLI, FALSE);
+ if (bSelect) {
+ SendMessage(hListBox, LB_SETSEL, (WPARAM)TRUE, MAKELPARAM(nIndex, 0));
+ SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex, MAKELPARAM(TRUE, 0));
+ }
+}
+
+
+
+/* DiffPrefix
+ * ----------
+ *
+ * Purpose:
+ * Compare (case-insensitive) two strings and return the prefixes of the
+ * the strings formed by removing the common suffix string from them.
+ * Integrity of tokens (directory name, filename and object names) are
+ * preserved. Note that the prefixes are converted to upper case
+ * characters.
+ *
+ * Parameters:
+ * lpsz1 string 1
+ * lpsz2 string 2
+ * lplpszPrefix1 prefix of string 1
+ * lplpszPrefix2 prefix of string 2
+ *
+ * Returns:
+ *
+ */
+VOID DiffPrefix(LPCTSTR lpsz1, LPCTSTR lpsz2, TCHAR FAR* FAR* lplpszPrefix1, TCHAR FAR* FAR* lplpszPrefix2)
+{
+ LPTSTR lpstr1;
+ LPTSTR lpstr2;
+
+ OleDbgAssert(lpsz1 && lpsz2 && *lpsz1 && *lpsz2 && lplpszPrefix1 &&
+ lplpszPrefix2);
+
+ *lplpszPrefix1 = NULL;
+ *lplpszPrefix2 = NULL;
+#ifdef WIN32
+ *lplpszPrefix1 = OleStdMalloc((lstrlen(lpsz1)+1) * sizeof(TCHAR));
+#else
+ *lplpszPrefix1 = OleStdMalloc((lstrlen(lpsz1)+1) * sizeof(BYTE));
+#endif
+ if (!*lplpszPrefix1)
+ return;
+
+#ifdef WIN32
+ *lplpszPrefix2 = OleStdMalloc((lstrlen(lpsz2)+1) * sizeof(TCHAR));
+#else
+ *lplpszPrefix2 = OleStdMalloc((lstrlen(lpsz2)+1) * sizeof(BYTE));
+#endif
+ if (!*lplpszPrefix2) {
+ OleStdFree(*lplpszPrefix1);
+ *lplpszPrefix1 = NULL;
+ return;
+ }
+
+ lstrcpy(*lplpszPrefix1, lpsz1);
+ lstrcpy(*lplpszPrefix2, lpsz2);
+// AnsiLower(*lplpszPrefix1);
+// AnsiLower(*lplpszPrefix2);
+
+ lpstr1 = *lplpszPrefix1 + lstrlen(*lplpszPrefix1);
+ lpstr2 = *lplpszPrefix2 + lstrlen(*lplpszPrefix2);
+
+ while ((lpstr1>*lplpszPrefix1) && (lpstr2>*lplpszPrefix2)) {
+#ifdef WIN32
+ lpstr1 = CharPrev(*lplpszPrefix1, lpstr1);
+ lpstr2 = CharPrev(*lplpszPrefix2, lpstr2);
+#else
+ lpstr1 = AnsiPrev(*lplpszPrefix1, lpstr1);
+ lpstr2 = AnsiPrev(*lplpszPrefix2, lpstr2);
+#endif
+ if (*lpstr1 != *lpstr2) {
+#ifdef WIN32
+ // AnsiNext is obsolete in Win32
+ lpstr1 = CharNext(lpstr1);
+ lpstr2 = CharNext(lpstr2);
+#else
+ lpstr1 = AnsiNext(lpstr1);
+ lpstr2 = AnsiNext(lpstr2);
+#endif
+ break;
+ }
+ }
+
+ for (; *lpstr1 && *lpstr1!=TEXT('\\') && *lpstr1!=TEXT('!');
+#ifdef WIN32
+ lpstr1=CharNext(lpstr1));
+#else
+ lpstr1=AnsiNext(lpstr1));
+#endif
+ for (; *lpstr2 && *lpstr2!=TEXT('\\') && *lpstr2!=TEXT('!');
+#ifdef WIN32
+ lpstr2=CharNext(lpstr2));
+#else
+ lpstr2=AnsiNext(lpstr2));
+#endif
+
+ *lpstr1 = TEXT('\0');
+ *lpstr2 = TEXT('\0');
+}
+
+
+/* PopupMessage
+ * ------------
+ *
+ * Purpose:
+ * Popup s messagebox and get some response from the user. It is the same
+ * as MessageBox() except that the title and message string are loaded
+ * from the resource file.
+ *
+ * Parameters:
+ * hwndParent parent window of message box
+ * idTitle id of title string
+ * idMessage id of message string
+ * fuStyle style of message box
+ */
+int PopupMessage(HWND hwndParent, UINT idTitle, UINT idMessage, UINT fuStyle)
+{
+ TCHAR szTitle[256];
+ TCHAR szMsg[256];
+
+ LoadString(ghInst, idTitle, (LPTSTR)szTitle, sizeof(szTitle)/sizeof(TCHAR));
+ LoadString(ghInst, idMessage, (LPTSTR)szMsg, sizeof(szMsg)/sizeof(TCHAR));
+ return MessageBox(hwndParent, szMsg, szTitle, fuStyle);
+}
+
+
+/* ChangeAllLinks
+ * --------------
+ *
+ * Purpose:
+ * Enumerate all the links in the listbox and change those starting
+ * with lpszFrom to lpszTo.
+ *
+ * Parameters:
+ * hListBox window handle of
+ * lpOleUILinkCntr pointer to OleUI Link Container
+ * lpszFrom prefix for matching
+ * lpszTo prefix to substitution
+ *
+ * Returns:
+ */
+VOID ChangeAllLinks(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPTSTR lpszFrom, LPTSTR lpszTo)
+{
+ int cItems;
+ int nIndex;
+ int cFrom;
+ LPLINKINFO lpLI;
+ LPTSTR szTmp[OLEUI_CCHPATHMAX];
+ BOOL bFound;
+
+ cFrom = lstrlen(lpszFrom);
+
+ cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L);
+ OleDbgAssert(cItems >= 0);
+
+ bFound = FALSE;
+
+ OleDbgPrint(3, TEXT("From : "), lpszFrom, 0);
+ OleDbgPrint(3, TEXT(""), TEXT("\r\n"), 0);
+ OleDbgPrint(3, TEXT("To : "), lpszTo, 0);
+ OleDbgPrint(3, TEXT(""), TEXT("\r\n"), 0);
+
+ for (nIndex=0; nIndex<cItems; nIndex++) {
+ SendMessage(hListBox, LB_GETTEXT, nIndex,
+ (LPARAM)(LPLINKINFO FAR*)&lpLI);
+
+ // unmark the item
+ lpLI->fIsMarked = FALSE;
+
+ /* if the corresponding position for the end of lpszFrom in the
+ ** display name is not a separator. We stop comparing this
+ ** link.
+ */
+ if (!*(lpLI->lpszDisplayName + cFrom) ||
+ (*(lpLI->lpszDisplayName + cFrom) == TEXT('\\')) ||
+ (*(lpLI->lpszDisplayName + cFrom) == TEXT('!'))) {
+
+ LSTRCPYN((LPTSTR)szTmp, lpLI->lpszDisplayName, cFrom + 1);
+ if (!lstrcmp((LPTSTR)szTmp, lpszFrom)) {
+ HRESULT hErr;
+ int nFileLength;
+ ULONG ulDummy;
+
+ if (!bFound) {
+ TCHAR szTitle[256];
+ TCHAR szMsg[256];
+ TCHAR szBuf[256];
+ int uRet;
+
+ LoadString(ghInst, IDS_CHANGESOURCE, (LPTSTR)szTitle,
+ sizeof(szTitle)/sizeof(TCHAR));
+ LoadString(ghInst, IDS_CHANGEADDITIONALLINKS,
+ (LPTSTR)szMsg, sizeof(szMsg)/sizeof(TCHAR));
+ wsprintf((LPTSTR)szBuf, (LPTSTR)szMsg, lpszFrom);
+ uRet = MessageBox(hListBox, (LPTSTR)szBuf, (LPTSTR)szTitle,
+ MB_ICONQUESTION | MB_YESNO);
+ if (uRet == IDYES)
+ bFound = TRUE;
+ else
+ return; // exit function
+ }
+
+ lstrcpy((LPTSTR)szTmp, lpszTo);
+ lstrcat((LPTSTR)szTmp, lpLI->lpszDisplayName + cFrom);
+ nFileLength = lstrlen((LPTSTR)szTmp) -
+ (lpLI->lpszItemName ? lstrlen(lpLI->lpszItemName) : 0);
+
+
+ hErr = lpOleUILinkCntr->lpVtbl->SetLinkSource(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ (LPTSTR)szTmp,
+ (ULONG)nFileLength,
+ (ULONG FAR*)&ulDummy,
+ TRUE
+ );
+ if (hErr != NOERROR)
+ lpOleUILinkCntr->lpVtbl->SetLinkSource(
+ lpOleUILinkCntr,
+ lpLI->dwLink,
+ (LPTSTR)szTmp,
+ (ULONG)nFileLength,
+ (ULONG FAR*)&ulDummy,
+ FALSE
+ );
+ lpLI->fIsMarked = TRUE;
+ }
+ }
+ }
+
+ /* have to do the refreshing after processing all links, otherwise
+ ** the item positions will change during the process as the
+ ** listbox stores items in order
+ */
+ if (bFound)
+ RefreshLinkLB(hListBox, lpOleUILinkCntr);
+}
+
+
+
+/* LoadLinkLB
+ * ----------
+ *
+ * Purpose:
+ * Enumerate all links from the Link Container and build up the Link
+ * ListBox
+ *
+ * Parameters:
+ * hListBox window handle of
+ * lpOleUILinkCntr pointer to OleUI Link Container
+ * lpszFrom prefix for matching
+ * lpszTo prefix to substitution
+ *
+ * Returns:
+ * number of link items loaded, -1 if error
+ */
+int LoadLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr)
+{
+ DWORD dwLink = 0;
+ LPLINKINFO lpLI;
+ int nIndex;
+ int cLinks;
+
+ cLinks = 0;
+
+ while ((dwLink = lpOleUILinkCntr->lpVtbl->GetNextLink(lpOleUILinkCntr,
+ dwLink)) != 0) {
+ lpLI = (LPLINKINFO)OleStdMalloc(sizeof(LINKINFO));
+ if (NULL == lpLI)
+ return -1;
+
+ lpLI->fIsMarked = FALSE;
+ lpLI->fIsSelected = FALSE;
+ lpLI->fDontFree = FALSE;
+
+#ifdef WIN32
+ lpLI->lpszAMX = (LPTSTR)OleStdMalloc((LINKTYPELEN+1)*sizeof(TCHAR));
+#else
+ lpLI->lpszAMX = (LPTSTR)OleStdMalloc((LINKTYPELEN+1)*sizeof(BYTE));
+#endif
+
+ lpLI->dwLink = dwLink;
+ cLinks++;
+ if ((nIndex = AddLinkLBItem(hListBox,lpOleUILinkCntr,lpLI,TRUE)) < 0)
+ // can't load list box
+ return -1;
+
+ if (lpLI->fIsSelected) {
+ SendMessage(hListBox, LB_SETSEL, TRUE, MAKELPARAM(nIndex, 0));
+ }
+ }
+ if (SendMessage(hListBox,LB_GETSELITEMS,(WPARAM)1,(LPARAM)(int FAR*)&nIndex))
+ SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex, MAKELPARAM(TRUE, 0));
+
+ return cLinks;
+}
+
+
+/* RefreshLinkLB
+ * -------------
+ *
+ * Purpose:
+ * Enumerate all items in the links listbox and update those with
+ * fIsMarked set.
+ * Note that this is a time consuming routine as it keeps iterating
+ * all items in the listbox until all of them are unmarked.
+ *
+ * Parameters:
+ * hListBox window handle of listbox
+ * lpOleUILinkCntr pointer to OleUI Link Container
+ *
+ * Returns:
+ *
+ */
+VOID RefreshLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr)
+{
+ int cItems;
+ int nIndex;
+ LPLINKINFO lpLI;
+ BOOL bStop;
+
+ OleDbgAssert(hListBox);
+
+ cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L);
+ OleDbgAssert(cItems >= 0);
+
+ do {
+ bStop = TRUE;
+ for (nIndex=0; nIndex<cItems; nIndex++) {
+ SendMessage(hListBox, LB_GETTEXT, nIndex,
+ (LPARAM)(LPLINKINFO FAR*)&lpLI);
+ if (lpLI->fIsMarked) {
+ lpLI->fIsMarked = FALSE;
+ lpLI->fDontFree = TRUE;
+
+ SendMessage(hListBox, LB_DELETESTRING, nIndex, 0L);
+ nIndex=AddLinkLBItem(hListBox, lpOleUILinkCntr, lpLI, FALSE);
+ if (lpLI->fIsSelected) {
+ SendMessage(hListBox, LB_SETSEL, (WPARAM)TRUE,
+ MAKELPARAM(nIndex, 0));
+ SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex,
+ MAKELPARAM(TRUE, 0));
+ }
+ bStop = FALSE;
+ break;
+ }
+ }
+ } while (!bStop);
+}
+
+
diff --git a/private/oleutest/letest/ole2ui/links.dlg b/private/oleutest/letest/ole2ui/links.dlg
new file mode 100644
index 000000000..6bc8d7258
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/links.dlg
@@ -0,0 +1,35 @@
+// DLGINCLUDE RCDATA DISCARDABLE
+// BEGIN
+// "OLE2UI.H\0"
+// END
+
+IDD_EDITLINKS DIALOG 9, 25, 320, 158
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Links"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Links:", ID_EL_COL1, 11, 11, 26, 8
+ LTEXT "Type", ID_EL_COL2, 137, 12, 20, 8
+ LTEXT "Update", ID_EL_COL3, 201, 12, 25, 8
+ LISTBOX ID_EL_LINKSLISTBOX, 11, 23, 229, 81, LBS_OWNERDRAWFIXED
+ | LBS_EXTENDEDSEL | WS_VSCROLL | LBS_USETABSTOPS
+ | WS_TABSTOP | LBS_SORT | LBS_NOTIFY
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 249, 11, 66, 14
+ PUSHBUTTON "&Update Now", ID_EL_UPDATENOW, 249, 34, 66, 14
+ PUSHBUTTON "&Open Source", ID_EL_OPENSOURCE, 249, 54, 66, 14,
+ WS_GROUP
+ PUSHBUTTON "&Change Source...", ID_EL_CHANGESOURCE, 249, 73, 66, 14,
+ WS_GROUP
+ PUSHBUTTON "&Break Link", ID_EL_CANCELLINK, 249, 96, 66, 14
+ PUSHBUTTON "&Help", ID_OLEUIHELP, 249, 136, 66, 14
+ CONTROL "&Automatic", ID_EL_AUTOMATIC, "Button",
+ BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 61, 138, 65,
+ 10
+ CONTROL "&Manual", ID_EL_MANUAL, "Button", BS_AUTORADIOBUTTON,
+ 130, 138, 39, 10
+ LTEXT "Source:", 219, 9, 113, 30, 8
+ LTEXT "Type:", 220, 9, 125, 20, 8
+ LTEXT "Update:", ID_EL_UPDATE, 9, 139, 32, 8
+ LTEXT "", ID_EL_LINKSOURCE, 45, 113, 195, 8, SS_NOPREFIX
+ LTEXT "", ID_EL_LINKTYPE, 45, 125, 195, 8, SS_NOPREFIX
+END
diff --git a/private/oleutest/letest/ole2ui/makefile b/private/oleutest/letest/ole2ui/makefile
new file mode 100644
index 000000000..21eedcbe0
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/makefile
@@ -0,0 +1,12 @@
+#
+# 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
+#
+!ifdef NTMAKEENV
+all:
+ echo $(BUILDMSG)
+clean: all
+!else
+!INCLUDE $(NTMAKEENV)\makefile.def
+!endif
diff --git a/private/oleutest/letest/ole2ui/makefile.32 b/private/oleutest/letest/ole2ui/makefile.32
new file mode 100644
index 000000000..e69bb6ff8
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/makefile.32
@@ -0,0 +1,590 @@
+##########################################################################
+#
+# Makefile for OUTLUI.DLL
+#
+# Usage: NMAKE (builds DEBUG library)
+# or: NMAKE RELEASE=1 (builds RELEASE library -- no debug symbols)
+# or: NMAKE clean (erase all compiled files)
+#
+# Environment variables:
+# DEVROOT_DIR=<path> (root dir for sample code development)
+#
+##########################################################################
+
+LIBNAME = outlui
+
+!ifndef DEVROOT_DIR
+!error You must define DEVROOT_DIR (ole20 sub-tree)
+!endif
+!ifndef INCLUDE
+!error You must define INCLUDE (non ole20 include files)
+!endif
+!ifndef LIB
+!error You must deinfe LIB (non ole20 libraries)
+!endif
+!ifndef OLEBUILD
+OLEBUILD=NT
+!endif
+
+OLE2_H=$(DEVROOT_DIR)\h
+OLE2_LIB=$(DEVROOT_DIR)\lib
+
+!ifndef SAMPLE_DIR
+SAMPLE_DIR = $(DEVROOT_DIR)\samples
+!endif
+SRC_DIR = $(SAMPLE_DIR)\$(APP)
+
+MAKEFILE = makefile.32
+
+# ============================================================================
+# File: M A K E F I L E
+#
+# NMAKE description file for the OLE2.0 User Interface DLL
+#
+# Copyright (C) Microsoft Corporation, 1992-1993. All Rights Reserved.
+# Microsoft Confidential.
+# ============================================================================
+
+# ----------------------------------------------------------------------------
+# U I M A K E . I N I
+# ----------------------------------------------------------------------------
+
+
+!if "$(OLEBUILD)" == "DOS" || "$(OLEBUILD)" == ""
+DOS=1
+!endif
+
+!if "$(OLEBUILD)" == "NT"
+NT=1
+
+!if "$(MACHINE)" == "i386" || "$(MACHINE)" == ""
+MACHINE = i386
+MACHINE_D = _X86_
+MACHINE_CC = cl386
+!endif
+
+!if "$(MACHINE)" == "MIPS"
+MACHINE = mips
+MACHINE_D = _MIPS_
+MACHINE_CC = cc
+!endif
+
+!endif
+
+!include "uimake.ini"
+
+!ifndef LANG
+LANG=USA
+!endif
+
+!ifndef BUILD
+BUILD=dll
+!endif
+
+GOAL: MAKEINI
+ nmake -f $(MAKEFILE) PRELUDE SETFLAGS $(LIBNAME).$(BUILD)
+
+
+MAKEINI:
+ nmake -f $(MAKEFILE) LIBNAME=$(LIBNAME) LANG=$(LANG) BUILD=$(BUILD) RESOURCE=RESOUCE REL_DIR=$(OLEREL_DIR) DEBUG
+
+
+!if "$(INSTALL_DIR)"==""
+INSTALL_DIR = $(REL_DIR)
+!endif
+
+#use src/tok pairs to build if localized version
+!if ("$(LANG)"!="USA") && ("$(LANG)"!="usa")
+SRCTOK=1
+!endif
+
+# ----------------------------------------------------------------------------
+# O B J E C T F I L E L I S T
+# ----------------------------------------------------------------------------
+
+UI_COBJS = \
+ D^\busy.obj\
+ D^\common.obj\
+ D^\convert.obj\
+ D^\dbgutil.obj\
+ D^\drawicon.obj\
+ D^\hatch.obj\
+ D^\icon.obj\
+ D^\iconbox.obj\
+ D^\insobj.obj\
+ D^\links.obj\
+ D^\msgfiltr.obj\
+ D^\enumfetc.obj\
+ D^\objfdbk.obj\
+ D^\ole2ui.obj\
+ D^\olestd.obj\
+ D^\targtdev.obj\
+ D^\oleutl.obj\
+ D^\pastespl.obj\
+ D^\regdb.obj\
+ D^\resimage.obj\
+ D^\utility.obj\
+
+UI_NOPCOBJS = \
+ D^\geticon.obj\
+
+UI_DLLOBJS = \
+ D^\dllfuncs.obj\
+
+PRECOMPOBJ=$(O)precomp.obj
+
+PRECOMP=$(O)precomp.pch
+
+# ----------------------------------------------------------------------------
+# R E S O U R C E L I S T
+# ----------------------------------------------------------------------------
+RES = \
+ busy.h \
+ common.h \
+ convert.h \
+ edlinks.h \
+ geticon.h \
+ icon.h \
+ iconbox.h \
+ insobj.h \
+ msgfiltr.h \
+ enumfetc.h \
+ ole2ui.h \
+ pastespl.h \
+ resimage.h \
+ $(RESOURCE)\STATIC\default.ico \
+ $(RESOURCE)\STATIC\bang.ico \
+ $(RESOURCE)\STATIC\egares.bmp \
+ $(RESOURCE)\STATIC\hivgares.bmp \
+ $(RESOURCE)\STATIC\vgares.bmp \
+ $(RESOURCE)\$(LANG)\strings.rc \
+ $(RESOURCE)\$(LANG)\busy.dlg \
+ $(RESOURCE)\$(LANG)\convert.dlg \
+ $(RESOURCE)\$(LANG)\fileopen.dlg \
+ $(RESOURCE)\$(LANG)\icon.dlg \
+ $(RESOURCE)\$(LANG)\insobj.dlg \
+ $(RESOURCE)\$(LANG)\links.dlg \
+ $(RESOURCE)\$(LANG)\pastespl.dlg \
+ $(RESOURCE)\$(LANG)\prompt.dlg \
+ $(RESOURCE)\ole2ui.rcv \
+ $(RESOURCE)\$(LANG)\verlocal.h \
+
+# ----------------------------------------------------------------------------
+# D E B U G S T A T I C L I B M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+DEBUGLIB:
+ @echo Creating DEBUG LIB <<uimake.ini
+# This is the DEBUG static .LIB UILibrary INI file
+MSG=DEBUG Static LIB Version ($$(LANG))
+DEBUG=1
+MODEL=M
+# Make a static library called OLE2UI.LIB
+LIBNAME=OLE2UI
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=DEBUGLIB
+BUILD=LIB
+RESOURCE=RESOURCE
+CFLAGS=-c -Od -GA2s -W3 -Zpei -A$(MODEL) -D_DEBUG
+RFLAGS=-D DEBUG
+LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+LANG=$(LANG)
+LIBOBJS = $$(UI_COBJS:D^\=DEBUGLIB^\) $$(UI_NOPCOBJS:D^\=DEBUGLIB\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define OLEUICLASS1 "$(LIBNAME)Class1"
+#define OLEUICLASS2 "$(LIBNAME)Class2"
+<<KEEP
+ @echo Enter "$(MAKE)" to make Debug static LIB UILibrary
+
+
+# ----------------------------------------------------------------------------
+# R E T A I L S T A T I C L I B M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+RETAILIB:
+ @echo Creating RETAIL LIB <<uimake.ini
+# This is the RETAIL static .LIB UILibrary INI file
+MSG=RETAIL Static LIB Version ($$(LANG))
+RETAIL=1
+MODEL=M
+# Make a static library called OLE2UI.LIB
+LIBNAME=OLE2UI
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=RETAILIB
+BUILD=LIB
+RESOURCE=RESOURCE
+CFLAGS=-c -Os -GA2s -W3 -Zpe -A$(MODEL)
+RFLAGS=
+LFLAGS=/MAP:FULL /LINE /NOD /NOE /SE:300
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+LANG=$(LANG)
+LIBOBJS = $$(UI_COBJS:D^\=RETAILIB^\) $$(UI_NOPCOBJS:D^\=RETAILIB\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define OLEUICLASS1 "$(LIBNAME)Class1"
+#define OLEUICLASS2 "$(LIBNAME)Class2"
+<<KEEP
+ @echo Enter "$(MAKE)" to make Retail static LIB UILibrary
+
+# ----------------------------------------------------------------------------
+# D E B U G M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+!ifdef NT
+
+DEBUG:
+ @echo Creating DEBUG for NT <<uimake.ini
+# This is the DEBUG UILibrary INI file
+MSG=DEBUG Version ($$(LANG))
+DEBUG=1
+LIBNAME=$(LIBNAME)
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=DEBUG
+RESOURCE=RESOURCE
+
+CC = $(MACHINE_CC)
+DEFS1 = /D$(MACHINE_D) /D_DEBUG /D_DEBUGTRACE=0 /DWIN32 /DOLE2SHIP
+DEFS2 = /D$(MACHINE)=1 /D_NTWIN /D_WINDOWS /DWINVER=0x030A /D_NTDLL /D_DLL
+CFLAGS = $$(DEFS1) $$(DEFS2) /Z7 /Od /c /Fc /G3 /W3 /nologo $(CL)
+LFLAGS = -subsystem:windows -machine:$(MACHINE) -debug:mapped,full -debugtype:both
+RFLAGS = /DWIN32 /D_DEBUG
+UILIBS1 = mpr.lib crtdll.lib ntdll.lib
+UILIBS2 = ole2w32.lib storag32.lib
+UILIBS3 = kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib comdlg32.lib
+UILIBS = $$(UILIBS1) $$(UILIBS2) $$(UILIBS3)
+
+LK = link32
+
+LANG = $(LANG)
+RS = rc
+
+DLLOBJS = $$(UI_DLLOBJS:D^\=DEBUG^\)
+LIBOBJS = $$(UI_COBJS:D^\=DEBUG^\) $$(UI_NOPCOBJS:D^\=DEBUG\NOPC^\)
+<<KEEP
+ @echo Enter "$(MAKE)" to make Debug UILibrary
+
+!else
+
+DEBUG:
+ @echo Creating DEBUG <<uimake.ini
+# This is the DEBUG UILibrary INI file
+MSG=DEBUG DLL Version ($$(LANG))
+DEBUG=1
+MODEL=M
+LIBNAME=$(LIBNAME)
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=DEBUG
+BUILD=DLL
+RESOURCE=RESOURCE
+CFLAGS=-c -Od -GD2s -W3 -Zpei -AMw -D_DEBUG -DDLL_VER -D_WINDLL
+RFLAGS=-D DEBUG -D DLL_VER
+LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300
+UILIBS=mdllcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+RS=rc
+LK=link
+LANG=$(LANG)
+DLLOBJS = $$(UI_DLLOBJS:D^\=DEBUG^\)
+LIBOBJS = $$(UI_COBJS:D^\=DEBUG^\) $$(UI_NOPCOBJS:D^\=DEBUG\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define OLEUICLASS1 "$(LIBNAME)Class1"
+#define OLEUICLASS2 "$(LIBNAME)Class2"
+<<KEEP
+ @echo Enter "$(MAKE)" to make Debug UILibrary
+
+!endif
+# ----------------------------------------------------------------------------
+# R E T A I L D L L M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+RETAIL:
+ @echo Creating RETAIL <<uimake.ini
+# This is the RETAIL UILibrary INI file
+MSG=RETAIL DLL Version ($$(LANG))
+RETAIL=1
+MODEL=M
+LIBNAME=$(LIBNAME)
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=RETAIL
+BUILD=DLL
+RESOURCE=RESOURCE
+CFLAGS=-c -Os -GD2s -W3 -Zpe -AMw -DOPTIMIZE -DDLL_VER -D_WINDLL
+RFLAGS=-D DLL_VER
+LFLAGS=/MAP /NOD /NOE /SE:300 /AL:16
+UILIBS=mdllcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+RS=rc
+LK=link
+LANG=$(LANG)
+DLLOBJS = $$(UI_DLLOBJS:D^\=RETAIL^\)
+LIBOBJS = $$(UI_COBJS:D^\=RETAIL^\) $$(UI_NOPCOBJS:D^\=RETAIL\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define OLEUICLASS1 "$(LIBNAME)Class1"
+#define OLEUICLASS2 "$(LIBNAME)Class2"
+<<KEEP
+ @echo Enter "$(MAKE)" to make Retail UILibrary
+
+!if [if not exist $(OBJ)\*. md $(OBJ) >nul]
+!error Object subdirectory $(OBJ)\ could not be created
+!endif
+!if [if not exist $(OBJ)\NOPC\*. md $(OBJ)\NOPC > nul]
+!error non-precompiled header object subdirectory $(OBJ)\NOPC\ could not be created
+!endif
+
+#select language for version resource if localized version
+!if ("$(LANG)"!="USA") && ("$(LANG)"!="usa")
+RFLAGS=$(RFLAGS) -D VER_LOC
+!endif
+
+!if ("$(LIBNAME)"=="PUBOLEUI")
+RFLAGS=$(RFLAGS) -D PUBLISHER
+!endif
+
+.SUFFIXES: .c .asm .obj .res .rc .def .bmp .ico .exe .dll .cod .str
+
+O=.\$(OBJ)^\
+
+# ----------------------------------------------------------------------------
+# I N F E R E N C E R U L E S
+# ----------------------------------------------------------------------------
+# compile C file without precompiled headers into object directory\NOPC
+# dont compile c files etc for lcoalized builds.
+!ifndef SRCTOK
+
+{}.c{$(O)NOPC\}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).c
+!else
+ $(CC) $(CFLAGS) -Fo$(O)NOPC\$(@B) $(@B).c
+!endif
+
+# compile C file into object directory
+{}.c{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).c
+!else
+ $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -Fo$(O)$(@B) $(@B).c
+!endif
+
+!endif
+#endif SRCTOK
+
+{}.rc{$(O)}.res:
+ @echo ²²²²²²²²²²²²²²²²²²² Resource Compiling $(@B).res ²²²²²²²²²²²²²²²²²²²²
+ $(RS) -I $(RESOURCE)\$(LANG);$(RESOURCE)\static;$(RESOURCE) -FO $(O)$(@B).res -R $(RFLAGS) $(@B).rc
+ -del $(LIBNAME).dll
+
+!ifndef SRCTOK
+{}.c.cod:
+ @echo ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ Making $(@B).cod ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
+!ifdef DOS
+ SET CL=$(CFLAGS) -f -Fc
+ $(CC) $(@B).c
+!else
+ $(CC) $(CFLAGS) -f- -Fc $(@B).c
+!endif
+!endif
+#endif SRCTOK
+
+
+# rules for creating rc & dlg files for localized verisons from src/tok pairs
+!ifdef SRCTOK
+
+$(RESOURCE)\$(LANG)\busy.dlg : $(RESOURCE)\$(LANG)\busy.tok $(RESOURCE)\src\busy.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\convert.dlg : $(RESOURCE)\$(LANG)\convert.tok $(RESOURCE)\src\convert.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\fileopen.dlg : $(RESOURCE)\$(LANG)\fileopen.tok $(RESOURCE)\src\fileopen.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\icon.dlg : $(RESOURCE)\$(LANG)\icon.tok $(RESOURCE)\src\icon.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\insobj.dlg : $(RESOURCE)\$(LANG)\insobj.tok $(RESOURCE)\src\insobj.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\links.dlg : $(RESOURCE)\$(LANG)\links.tok $(RESOURCE)\src\links.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\pastespl.dlg : $(RESOURCE)\$(LANG)\pastespl.tok $(RESOURCE)\src\pastespl.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\prompt.dlg : $(RESOURCE)\$(LANG)\prompt.tok $(RESOURCE)\src\prompt.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\strings.rc : $(RESOURCE)\$(LANG)\strings.tok $(RESOURCE)\src\strings.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+!endif
+
+# ----------------------------------------------------------------------------
+# D E P E N D F I L E C R E A T I O N
+# ----------------------------------------------------------------------------
+UI_CFILE = $(UI_COBJS:.obj=.c) $(UI_DLLOBJS:.obj=.c)
+UI_NOPCFILE = $(UI_NOPCOBJS:.obj=.c)
+DEPEND: nul
+ @echo Making a NEW dependancy file.
+ mkdep -p $$(O) -s .obj $(UI_CFILE:D^\=) > tmp.tmp
+ sed "s/:/: $$(PRECOMP)/g" < tmp.tmp > depend
+ -del tmp.tmp
+ mkdep -p $$(O)NOPC\ -s .obj $(UI_NOPCFILE:D^\=) >> depend
+ mkdep -p $$(O) -s .pch precomp.c >> depend
+
+# ----------------------------------------------------------------------------
+# W E L C O M E B A N N E R
+# ----------------------------------------------------------------------------
+PRELUDE:
+ @echo ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
+ @echo º Makefile for UILibrary º
+ @echo ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
+ @echo $(MSG)
+!ifndef SRCTOK
+ set INCLUDE=$(OLEREL_DIR);$(INCLUDE)
+ set LIB=$(OLEREL_DIR);$(LIB)
+!endif
+
+SETFLAGS:
+ set INCLUDE=$(INCLUDE);$(OLE2_H)
+ set LIB=$(LIB);$(OLE2_LIB)
+
+
+# ----------------------------------------------------------------------------
+# G O A L T A R G E T S
+# ----------------------------------------------------------------------------
+!include "depend"
+
+CLEAN: CleanUp GOAL
+
+CleanUp: MAKEINI
+ nmake -f $(MAKEFILE) SETFLAGS Delete
+
+Delete:
+ -echo y|del .\$(OBJ)\*.*
+ -del $(LIBNAME).dll
+ -del $(LIBNAME).lib
+
+!ifndef SRCTOK
+
+$(O)precomp.pch: precomp.c
+!ifdef DOS
+ SET CL=$(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h
+ $(CC) -Fo$(O)$(@B) precomp.c
+!else
+ $(CC) $(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h -Fo$(O)$(@B) precomp.c
+!endif
+!endif
+#endif SRCTOK
+
+$(O)ole2ui.res: ole2ui.rc $(RES)
+
+ole2ui.rc : $(RESOURCE)\$(LANG)\strings.rc
+
+#
+# Build .LIB static library
+#
+
+$(LIBNAME).lib: $(LIBOBJS) $(PRECOMPOBJ)
+ -del $(O)$(LIBNAME).lib
+ lib @<<
+$(O)$(LIBNAME).lib
+y
+$(PRECOMPOBJ: = +) $(LIBOBJS: = +)
+
+<<
+ copy $(O)$(LIBNAME).lib $(LIBNAME).lib
+
+#
+# Build .DLL dynamic-link library
+#
+
+!if "$(OLEBUILD)" == "NT"
+!else
+$(O)$(LIBNAME).lib: $(LIBOBJS) $(PRECOMPOBJS)
+ -del $(O)$(LIBNAME).lib
+ lib @<<
+$(O)$(LIBNAME).lib
+y
+$(PRECOMPOBJ: = +) $(LIBOBJS: = +)
+
+<<
+!endif
+
+!if "$(OLEBUILD)" == "NT"
+
+$(LIBNAME).dll: $(LIBNAME).d32 $(PRECOMPOBJS) $(LIBOBJS) $(DLLOBJS) $(O)ole2ui.res
+ @echo Linking ...
+ lib32 -out:$*.lib -def:$(LIBNAME).d32 -machine:$(MACHINE) $(LIBOBJS) $(DLLOBJS)
+ cvtres -$(MACHINE) $(O)ole2ui.res -o $*.rs
+ link32 $(LFLAGS) -entry:LibMain@12 @<<$(BUILD_DIR)\ole2util.lnk
+ $(LIBNAME).exp $(LIBOBJS) $(DLLOBJS) $(PRECOMPOBJ) $(UILIBS) $*.rs -out:$@ -map:$*.map -dll $(UILIBS)
+<<KEEP
+
+!else
+$(O)$(LIBNAME).exe: $(O)$(LIBNAME).lib $(DLLOBJS) $(O)ole2ui.res
+ @echo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄį Linking UILibrary ®ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+ @echo Creating <<$(O)$(@B).lnk
+$(LFLAGS) +
+$(PRECOMPOBJ: = +^
+)+
+$(DLLOBJS: = +^
+)+
+
+$(O)$(@B)
+$(@B).map
+$(UILIBS) $(O)$(LIBNAME).lib
+$(LIBNAME).def
+<<KEEP
+
+ $(LK) @$(O)$(@B).lnk
+ $(RS) -31 $(RFLAGS) $(O)ole2ui.res $(O)$(LIBNAME).exe
+
+!ifndef SRCTOK
+$(LIBNAME).dll: $(O)$(LIBNAME).exe ole2ui.def
+ copy $(O)$(LIBNAME).exe $(LIBNAME).dll
+ mapsym -n -l $(LIBNAME).map
+ implib $(LIBNAME).lib $(LIBNAME).dll
+!else
+$(LIBNAME).dll: $(O)ole2ui.res
+ copy $(RESOURCE)\USA\$(LIBNAME).dll $(LIBNAME).dll
+ $(RS) -31 -K $(RFLAGS) $(O)ole2ui.res $(LIBNAME).dll
+!endif
+!endif
+#endif SRCTOK
+
+
+install: MAKEINI
+ nmake -f $(MAKEFILE) SETFLAGS InstallAll
+
+# install built library to $(INSTALL_DIR) dir
+InstallAll:
+ copy $(LIBNAME).dll $(INSTALL_DIR)
+ copy $(LIBNAME).lib $(INSTALL_DIR)
+ copy $(LIBNAME).sym $(INSTALL_DIR)
+ copy ole2ui.h $(INSTALL_DIR)
+ copy msgfiltr.h $(INSTALL_DIR)
+ copy enumfetc.h $(INSTALL_DIR)
+ copy regdb.h $(INSTALL_DIR)
+ copy olestd.h $(INSTALL_DIR)
+ copy geticon.h $(INSTALL_DIR)
+ copy ole2ui.rc $(INSTALL_DIR)
+ copy uiclass.h $(INSTALL_DIR)
+
+# EOF ========================================================================
diff --git a/private/oleutest/letest/ole2ui/makefile.old b/private/oleutest/letest/ole2ui/makefile.old
new file mode 100644
index 000000000..3fadaf177
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/makefile.old
@@ -0,0 +1,607 @@
+# ============================================================================
+# File: M A K E F I L E
+#
+# NMAKE description file for the OLE2.0 User Interface DLL
+#
+# Copyright (C) Microsoft Corporation, 1992-1993. All Rights Reserved.
+# ============================================================================
+#
+# Usage Notes:
+# -----------
+#
+# This makefile is designed to be used in two steps. The first time you
+# call the makefile, it generates a file called UIMAKE.INI. The second time
+# you call the makefile, it reads settings from UIMAKE.INI and actually
+# performs the build. See the section below "UIMAKE.INI" for more information
+# on this file.
+#
+# 1. Initial Step -- Before building your library for the first time, you
+# need to run one of the following commands. (This step will only be needed
+# to run again if you want to build a different variant of the library, for
+# instance if you want to switch from a DEBUG to a RETAIL build).
+#
+# NMAKE DEBUG - Prepares for building DEBUG DLL version
+# NMAKE RETAIL - Prepares for building RETAIL DLL version
+# NMAKE DEBUGLIB - Prepares for building DEBUG static LIB version
+# NMAKE RETAILIB - Prepares for building RETAIL static LIB version
+#
+# This step builds the UIMAKE.INI file, which contains the settings
+# which specify what version of the library you want to build.
+#
+# 2. Build Step
+#
+# NMAKE
+#
+# This second step reads the settings in the UIMAKE.INI file and builds
+# the requested library.
+#
+#
+# UIMAKE.INI
+# ----------
+#
+# This file is used to specify which variant of the library to build,
+# as well as details like which compiler and linker options to use. The
+# file is created based on the settings in the "MAKE PARAMETERS" section
+# of this makefile.
+#
+# For most builds, using the default settings will work fine, but if you
+# need to change how you build the library, the UIMAKE.INI file is a
+# simple way to make this change without changing the makefile.
+#
+# The following lists a few of the settings in the UIMAKE.INI file which
+# you might change, and what effect those changes might have. For a
+# complete listing of all the available options and how they are used,
+# see the makefile below.
+#
+# MODEL=[S|M|C|L] -- The memory model. Only available
+# on static .LIB version. This flag is
+# also included (but not used) in the DLL
+# version of UIMAKE.INI in order to allow
+# switching between the DLL and LIB version.
+# LIBNAME= -- The library name. For building your own
+# library (other than the ones for the samples),
+# this must be set to a unique name for your
+# application.
+# LANG= -- Used for international versions of this
+# library. Specifies which directory the
+# resources come from. Default is USA
+#
+# ============================================================================
+
+
+# ----------------------------------------------------------------------------
+# U I M A K E . I N I
+# ----------------------------------------------------------------------------
+# XXXXXXX DOS=1
+!ifndef LANG
+LANG=USA
+!endif
+
+!if [if not exist uimake.ini dir uimake.ini >nul] != 0
+#!if [test -f uimake.ini] != 0
+LIBNAME=
+MODEL=M
+RESOURCE=RESOURCE
+!ifndef REL_DIR
+@echo REL_DIR not defined
+REL_DIR=c:\ole2samp\release
+!endif
+!ifndef OLERELDIR
+@echo OLEREL_DIR not defined
+OLEREL_DIR=c:\ole2samp\release
+!endif
+GOAL: DEBUG
+!else
+!include "uimake.ini"
+GOAL: PRELUDE $(LIBNAME).$(BUILD)
+!endif
+
+!if "$(INSTALL_DIR)"==""
+INSTALL_DIR = $(REL_DIR)
+!endif
+
+#use src/tok pairs to build if localized version
+!if ("$(LANG)"!="USA") && ("$(LANG)"!="usa")
+SRCTOK=1
+!endif
+# ----------------------------------------------------------------------------
+# O B J E C T F I L E L I S T
+# ----------------------------------------------------------------------------
+
+UI_COBJS = \
+ D^\ole2ui.obj\
+ D^\busy.obj\
+ D^\common.obj\
+ D^\convert.obj\
+ D^\dbgutil.obj\
+ D^\drawicon.obj\
+ D^\hatch.obj\
+ D^\icon.obj\
+ D^\iconbox.obj\
+ D^\insobj.obj\
+ D^\links.obj\
+ D^\msgfiltr.obj\
+ D^\enumfetc.obj\
+ D^\enumstat.obj\
+ D^\objfdbk.obj\
+ D^\olestd.obj\
+ D^\targtdev.obj\
+ D^\oleutl.obj\
+ D^\pastespl.obj\
+ D^\regdb.obj\
+ D^\resimage.obj\
+ D^\utility.obj\
+
+UI_NOPCOBJS = \
+ D^\geticon.obj\
+ D^\dballoc.obj\
+ D^\suminfo.obj\
+ D^\stdpal.obj\
+
+UI_DLLOBJS = \
+ D^\dllfuncs.obj\
+
+PRECOMPOBJ= $(O)precomp.obj
+
+PRECOMP=$(O)precomp.pch
+
+# ----------------------------------------------------------------------------
+# R E S O U R C E L I S T
+# ----------------------------------------------------------------------------
+RES = \
+ busy.h \
+ common.h \
+ convert.h \
+ edlinks.h \
+ geticon.h \
+ icon.h \
+ iconbox.h \
+ insobj.h \
+ msgfiltr.h \
+ enumfetc.h \
+ ole2ui.h \
+ pastespl.h \
+ resimage.h \
+ dballoc.h \
+ suminfo.h \
+ stdpal.h \
+ $(RESOURCE)\STATIC\default.ico \
+ $(RESOURCE)\STATIC\bang.ico \
+ $(RESOURCE)\STATIC\egares.bmp \
+ $(RESOURCE)\STATIC\hivgares.bmp \
+ $(RESOURCE)\STATIC\vgares.bmp \
+ $(RESOURCE)\$(LANG)\strings.rc \
+ $(RESOURCE)\$(LANG)\busy.dlg \
+ $(RESOURCE)\$(LANG)\convert.dlg \
+ $(RESOURCE)\$(LANG)\fileopen.dlg \
+ $(RESOURCE)\$(LANG)\icon.dlg \
+ $(RESOURCE)\$(LANG)\insobj.dlg \
+ $(RESOURCE)\$(LANG)\links.dlg \
+ $(RESOURCE)\$(LANG)\pastespl.dlg \
+ $(RESOURCE)\$(LANG)\prompt.dlg \
+ $(RESOURCE)\ole2ui.rcv \
+ $(RESOURCE)\$(LANG)\verlocal.h \
+
+# ----------------------------------------------------------------------------
+# D E B U G S T A T I C L I B M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+DEBUGLIB: DbgUI
+
+DbgUI:
+ @echo Creating DEBUG LIB <<uimake.ini
+# This is the DEBUG static .LIB UILibrary INI file
+MSG=DEBUG Static LIB Version ($$(LANG))
+DEBUG=1
+MODEL=M
+# Make a static library called OLE2UI.LIB
+LIBNAME=OLE2UI
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=DEBUGLIB
+BUILD=LIB
+RESOURCE=RESOURCE
+
+# 16 bit CFLAGS=-c -Od -GA2s -W3 -Zpei -A$(MODEL) -D_DEBUG -DWIN32 -DUNICODE
+
+CFLAGS=-c -Od -Gs -W3 -Zpei -D_DEBUG -DWIN32 -DUNICODE
+RFLAGS=-D DEBUG
+LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300 /NOPACKCODE
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+LANG=$(LANG)
+LIBOBJS = $$(UI_COBJS:D^\=DEBUGLIB^\) $$(UI_NOPCOBJS:D^\=DEBUGLIB\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define SZCLASSICONBOX TEXT("$(LIBNAME)IBClass")
+#define SZCLASSRESULTIMAGE TEXT("$(LIBNAME)RIClass")
+<<KEEP
+ @echo Enter "$(MAKE)" to make Debug static LIB UILibrary
+
+
+# ----------------------------------------------------------------------------
+# R E T A I L S T A T I C L I B M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+RETAILIB:
+ @echo Creating RETAIL LIB <<uimake.ini
+# This is the RETAIL static .LIB UILibrary INI file
+MSG=RETAIL Static LIB Version ($$(LANG))
+RETAIL=1
+MODEL=M
+# Make a static library called OLE2UI.LIB
+LIBNAME=OLE2UI
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=RETAILIB
+BUILD=LIB
+RESOURCE=RESOURCE
+
+# 16 bit CFLAGS=-c -Os -GA2s -W3 -Zpe -A$(MODEL) -DWIN32 -DUNICODE
+
+CFLAGS=-c -Os -Gs -W3 -Zpe -DWIN32 -DUNICODE
+RFLAGS=
+LFLAGS=/MAP:FULL /LINE /NOD /NOE /SE:300 /NOPACKCODE
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+LANG=$(LANG)
+LIBOBJS = $$(UI_COBJS:D^\=RETAILIB^\) $$(UI_NOPCOBJS:D^\=RETAILIB\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define SZCLASSICONBOX TEXT("$(LIBNAME)IBClass")
+#define SZCLASSRESULTIMAGE TEXT("$(LIBNAME)RIClass")
+<<KEEP
+ @echo Enter "$(MAKE)" to make Retail static LIB UILibrary
+
+# ----------------------------------------------------------------------------
+# D E B U G D L L M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+DEBUG: Dbg
+
+Dbg:
+ @echo Creating DEBUG <<uimake.ini
+# This is the DEBUG UILibrary INI file
+MSG=DEBUG DLL Version ($$(LANG))
+DEBUG=1
+MODEL=M
+LIBNAME=$(LIBNAME)
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=DEBUG
+BUILD=DLL
+RESOURCE=RESOURCE
+#CFLAGS=-c -Od -GD2s -W3 -Zpei -AMw -D_DEBUG -DDLL_VER -D_WINDLL
+
+# 16 bit CFLAGS=-c -Od -GA2s -GEd -W3 -Zpei -AMw -D_DEBUG -DDLL_VER -D_WINDLL -DWIN32 -DUNICODE
+
+CFLAGS=-c -Od -Gs -Gd -W3 -Zpei -AMw -D_DEBUG -DDLL_VER -D_WINDLL -DWIN32 -DUNICODE -DNOASSERT
+RFLAGS=-D DEBUG -D DLL_VER
+
+# 16 bit LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300 /NOPACKCODE
+LFLAGS=/MAP:$(LIBNAME).map /NOD /DLL /IMPLIB:$(LIBNAME).lib
+
+# 16 bit UILIBS=mdllcew libw ole2 storage shell commdlg toolhelp
+UILIBS= $(IMPORT)\nt475\lib\objind\advapi32.lib \
+ $(IMPORT)\nt475\lib\objind\comdlg32.lib \
+ $(IMPORT)\nt475\lib\objind\crtdll.lib \
+ $(IMPORT)\nt475\lib\objind\gdi32.lib \
+ $(IMPORT)\nt475\lib\objind\kernel32.lib \
+ $(IMPORT)\nt475\lib\objind\libcnt.lib \
+ $(IMPORT)\nt475\lib\objind\shell32.lib \
+ $(IMPORT)\nt475\lib\objind\user32.lib \
+ $(COMMON)\ilib\OBJind\ole232.lib \
+ $(COMMON)\types\OBJind\uuid.lib \
+ $(COMMON)\ilib\OBJind\storag32.lib \
+ $(COMMON)\ilib\OBJind\compob32.lib
+CC=cl
+RS=rc
+LK=link
+LANG=$(LANG)
+DLLOBJS = $$(UI_DLLOBJS:D^\=DEBUG^\)
+LIBOBJS = $$(UI_COBJS:D^\=DEBUG^\) $$(UI_NOPCOBJS:D^\=DEBUG\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define SZCLASSICONBOX "$(LIBNAME)IBClass"
+#define SZCLASSRESULTIMAGE "$(LIBNAME)RIClass"
+<<KEEP
+ @echo Enter "$(MAKE)" to make Debug UILibrary
+
+# ----------------------------------------------------------------------------
+# R E T A I L M A K E P A R A M E T E R S
+# ----------------------------------------------------------------------------
+RETAIL:
+ @echo Creating RETAIL <<uimake.ini
+# This is the RETAIL UILibrary INI file
+MSG=RETAIL DLL Version ($$(LANG))
+RETAIL=1
+MODEL=M
+LIBNAME=$(LIBNAME)
+REL_DIR=$(REL_DIR)
+OLEREL_DIR=$(OLEREL_DIR)
+OBJ=RETAIL
+BUILD=DLL
+RESOURCE=RESOURCE
+#CFLAGS=-c -Os -GD2s -W3 -Zpe -AMw -DOPTIMIZE -DDLL_VER -D_WINDLL
+
+# 16 bit CFLAGS=-c -Os -GA2s -GEd -W3 -Zpe -AMw -DOPTIMIZE -DDLL_VER -D_WINDLL -DWIN32 -DUNICODE
+
+CFLAGS=-c -Os -Gs -Gd -W3 -Zpe -DOPTIMIZE -DDLL_VER -D_WINDLL -DWIN32 -DUNICODE
+RFLAGS=-D DLL_VER
+LFLAGS=/MAP /NOD /NOE /SE:300 /AL:16 /NOPACKCODE
+UILIBS=mdllcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+RS=rc
+LK=link
+LANG=$(LANG)
+DLLOBJS = $$(UI_DLLOBJS:D^\=RETAIL^\)
+LIBOBJS = $$(UI_COBJS:D^\=RETAIL^\) $$(UI_NOPCOBJS:D^\=RETAIL\NOPC^\)
+<<KEEP
+ @echo Creating <<uiclass.h
+#define SZCLASSICONBOX TEXT("$(LIBNAME)IBClass")
+#define SZCLASSRESULTIMAGE TEXT("$(LIBNAME)RIClass")
+<<KEEP
+ @echo Enter "$(MAKE)" to make Retail UILibrary
+
+!if [if not exist $(OBJ)\*. md $(OBJ) >nul]
+!error Object subdirectory $(OBJ)\ could not be created
+!endif
+!if [if not exist $(OBJ)\NOPC\*. md $(OBJ)\NOPC > nul]
+!error non-precompiled header object subdirectory $(OBJ)\NOPC\ could not be created
+!endif
+
+#select language for version resource if localized version
+!if ("$(LANG)"!="USA") && ("$(LANG)"!="usa")
+RFLAGS=$(RFLAGS) -D VER_LOC
+!endif
+
+.SUFFIXES: .c .asm .obj .res .rc .def .bmp .ico .exe .dll .cod .str
+
+O=.\$(OBJ)^\
+
+# ----------------------------------------------------------------------------
+# I N F E R E N C E R U L E S
+# ----------------------------------------------------------------------------
+!ifndef SRCTOK
+
+# compile C file without precompiled headers into object directory\NOPC
+# dont compile c files etc for lcoalized builds.
+{}.c{$(O)NOPC\}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).c
+!else
+!undef _FILE_
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).c\" -Fo$(O)NOPC\$(@B) $(@B).c
+!endif
+
+# compile C file into object directory
+{}.c{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).c
+!else
+!undef _FILE_
+# $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -D_FILE_=\"$(*B).c\" -Fo$(O)$(@B) $(@B).c
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).c\" -Fo$(O)$(@B) $(@B).c
+!endif
+
+# compile CPP file without precompiled headers into object directory\NOPC
+# dont compile cpp files etc for lcoalized builds.
+{}.cpp{$(O)NOPC\}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).cpp °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).cpp
+!else
+!undef _FILE_
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).cpp\" -Fo$(O)NOPC\$(@B) $(@B).cpp
+!endif
+
+# compile CPP file into object directory
+{}.cpp{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).cpp °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).cpp
+!else
+!undef _FILE_
+# $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -D_FILE_=\"$(*B).cpp\" -Fo$(O)$(@B) $(@B).cpp
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).cpp\" -Fo$(O)$(@B) $(@B).cpp
+!endif
+
+!endif
+#endif SRCTOK
+
+{}.rc{$(O)}.res:
+ @echo ²²²²²²²²²²²²²²²²²²² Resource Compiling $(@B).res ²²²²²²²²²²²²²²²²²²²²
+ $(RS) -I $(RESOURCE)\$(LANG);$(RESOURCE)\static;$(RESOURCE) -FO $(O)$(@B).res -DWIN32 -DUNICODE -R $(RFLAGS) $(@B).rc
+ -del $(LIBNAME).dll
+
+!ifndef SRCTOK
+{}.c.cod:
+ @echo ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ Making $(@B).cod ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
+!ifdef DOS
+ SET CL=$(CFLAGS) -f -Fc
+ $(CC) $(@B).c
+!else
+!undef _FILE_
+ $(CC) $(CFLAGS) -f- -Fc -D_FILE_=\"$(*B).c\" $(@B).c
+!endif
+!endif
+
+
+# rules for creating rc & dlg files for localized verisons from src/tok pairs
+!ifdef SRCTOK
+
+$(RESOURCE)\$(LANG)\busy.dlg : $(RESOURCE)\$(LANG)\busy.tok $(RESOURCE)\src\busy.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\convert.dlg : $(RESOURCE)\$(LANG)\convert.tok $(RESOURCE)\src\convert.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\fileopen.dlg : $(RESOURCE)\$(LANG)\fileopen.tok $(RESOURCE)\src\fileopen.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\icon.dlg : $(RESOURCE)\$(LANG)\icon.tok $(RESOURCE)\src\icon.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\insobj.dlg : $(RESOURCE)\$(LANG)\insobj.tok $(RESOURCE)\src\insobj.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\links.dlg : $(RESOURCE)\$(LANG)\links.tok $(RESOURCE)\src\links.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\pastespl.dlg : $(RESOURCE)\$(LANG)\pastespl.tok $(RESOURCE)\src\pastespl.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\prompt.dlg : $(RESOURCE)\$(LANG)\prompt.tok $(RESOURCE)\src\prompt.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+
+$(RESOURCE)\$(LANG)\strings.rc : $(RESOURCE)\$(LANG)\strings.tok $(RESOURCE)\src\strings.src
+ tok -q -f $*.tok $(RESOURCE)\src\$(@B).src > $@
+!endif
+
+# ----------------------------------------------------------------------------
+# D E P E N D F I L E C R E A T I O N
+# ----------------------------------------------------------------------------
+UI_CFILE = $(UI_COBJS:.obj=.c) $(UI_DLLOBJS:.obj=.c)
+UI_NOPCFILE = $(UI_NOPCOBJS:.obj=.c)
+DEPEND: nul
+ @echo Making a NEW dependancy file.
+ mkdep -p $$(O) -s .obj $(UI_CFILE:D^\=) > tmp.tmp
+ sed "s/:/: $$(PRECOMP)/g" < tmp.tmp > depend
+ -del tmp.tmp
+ mkdep -p $$(O)NOPC\ -s .obj $(UI_NOPCFILE:D^\=) >> depend
+ mkdep -p $$(O) -s .pch precomp.c >> depend
+
+# ----------------------------------------------------------------------------
+# W E L C O M E B A N N E R
+# ----------------------------------------------------------------------------
+PRELUDE:
+ @echo ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
+ @echo º Makefile for UILibrary º
+ @echo ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
+ @echo $(MSG)
+!ifndef SRCTOK
+ set INCLUDE=$(OLEREL_DIR);$(INCLUDE)
+ set LIB=$(OLEREL_DIR);$(LIB)
+!endif
+
+
+# ----------------------------------------------------------------------------
+# G O A L T A R G E T S
+# ----------------------------------------------------------------------------
+!include "depend"
+
+CLEAN: CleanUp GOAL
+CleanUp:
+ -echo y|del .\$(OBJ)\*.*
+ -del $(LIBNAME).dll
+ -del $(LIBNAME).lib
+
+!ifndef SRCTOK
+
+$(O)precomp.pch: precomp.c
+!ifdef DOS
+ SET CL=$(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h
+ $(CC) -Fo$(O)$(@B) precomp.c
+!else
+!undef _FILE_
+ @echo Precompiling Header Files....
+ $(CC) $(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h -D_FILE_=\"precomp.c\" -Fo$(O)$(@B) precomp.c
+!endif
+!endif
+
+$(O)ole2ui.res: ole2ui.rc $(RES)
+
+ole2ui.rc : $(RESOURCE)\$(LANG)\strings.rc
+
+#
+# Build .LIB static library
+#
+
+$(LIBNAME).lib: $(LIBOBJS) $(PRECOMPOBJ)
+ -del $(O)$(LIBNAME).lib
+ lib @<<
+$(O)$(LIBNAME).lib
+y
+$(PRECOMPOBJ: = +) $(LIBOBJS: = +)
+
+<<
+ copy $(O)$(LIBNAME).lib $(LIBNAME).lib
+
+#
+# Build .DLL dynamic-link library
+#
+
+# HACK!
+# XXXXX
+# after echo LIBRARY $(LIBNAME) INITINSTANCE
+$(O)$(LIBNAME).exe: $(LIBOBJS) $(PRECOMPOBJ) $(DLLOBJS) $(O)ole2ui.res defoleui.def
+ @echo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄį Linking UILibrary ®ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+ -del $(LIBNAME).def
+ @echo Creating <<$(LIBNAME).def
+LIBRARY ole2ui
+DESCRIPTION 'OLE 2.0 UI Support Library.'
+<<KEEP
+ type defoleui.def >> $(LIBNAME).def
+ $(LK) @<<
+$(LFLAGS)
+$(LIBOBJS: = ^
+)
+$(DLLOBJS: = ^
+)
+$(O)$(LIBNAME).res
+$(UILIBS)
+/DEF:$(LIBNAME).def
+<<KEEP
+# $(RS) $(O)ole2ui.res $(O)$(LIBNAME).dll
+
+
+#$(LIBOBJS: = +^
+#) +
+#$(DLLOBJS: = +^
+#)+
+#$(PRECOMPOBJ: = +^
+#)
+#$(LFLAGS)
+#$(O)$(@B)
+#$(@B).map
+#$(UILIBS)
+#$(LIBNAME).def
+#<<KEEP
+# $(RS) -31 -K $(RFLAGS) $(O)ole2ui.res $(O)$(LIBNAME).exe
+
+!ifndef SRCTOK
+$(LIBNAME).dll: $(O)$(LIBNAME).exe ole2ui.def
+# copy $(O)$(LIBNAME).exe $(LIBNAME).dll
+ mapsym -n -l $(LIBNAME).map
+# implib -NOWEP $(LIBNAME).lib $(LIBNAME).dll
+!else
+$(LIBNAME).dll: $(O)ole2ui.res
+ copy $(RESOURCE)\USA\$(LIBNAME).dll $(LIBNAME).dll
+# 16 bit $(RS) -31 -K $(RFLAGS) $(O)ole2ui.res $(LIBNAME).dll
+ $(RS) $(O)ole2ui.res $(LIBNAME).dll
+!endif
+
+
+# install built library to $(INSTALL_DIR) dir
+install:
+ @echo Gets HERE!!!!!!
+ copy $(LIBNAME).dll $(RESOURCE)\USA
+ copy $(LIBNAME).dll $(INSTALL_DIR)
+ copy $(LIBNAME).lib $(INSTALL_DIR)
+ copy $(LIBNAME).sym $(INSTALL_DIR)
+ copy ole2ui.h $(INSTALL_DIR)
+ copy olestd.h $(INSTALL_DIR)
+ copy msgfiltr.h $(INSTALL_DIR)
+ copy enumfetc.h $(INSTALL_DIR)
+ copy uiclass.h $(INSTALL_DIR)
+
+# EOF ========================================================================
diff --git a/private/oleutest/letest/ole2ui/makelib b/private/oleutest/letest/ole2ui/makelib
new file mode 100644
index 000000000..f7729d5d3
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/makelib
@@ -0,0 +1,503 @@
+# ============================================================================
+# File: MAKELIB
+#
+# NMAKE description file to build STATIC version of OLE2.0 User Interface LIB
+#
+# Copyright (C) Microsoft Corporation, 1992-1993. All Rights Reserved.
+# ============================================================================
+#
+# Usage Notes:
+# -----------
+#
+# This makefile is designed to be used in one step. This makefile does
+# NOT use the file called UIMAKE.INI. This makefile builds the following
+# libraries (depending on the value of "LIBFORDLL" and "DEBUG"):
+# OLE2UIX.LIB -- static RETAIL library to be used with EXE's
+# OLE2UIXD.LIB -- static DEBUG library to be used with EXE's
+#
+# OLE2UID.LIB -- static RETAIL library to be used with DLL's
+# OLE2UIDD.LIB -- static DEBUG library to be used with DLL's
+#
+# It is NOT necessary to build custom versions of the static
+# library version of OLE2UI. Everyone can use the same static OLE2UI
+# libraries as built by this makefile.
+#
+# NMAKE -F MAKELIB
+# NMAKE -F MAKELIB DEBUG=0
+# NMAKE -F MAKELIB LIBFORDLL=1
+# NMAKE -F MAKELIB LIBFORDLL=1 DEBUG=0
+#
+#
+# The following lists a few of the settings in this makefile file which
+# you might change, and what effect those changes might have. For a
+# complete listing of all the available options and how they are used,
+# see the makefile below.
+#
+# MODEL=[M|L] -- The memory model. (Default: M)
+# DEBUG=[0|1] -- Enable DEBUG or RETAIL version (Default: 1)
+# LIBFORDLL=[0|1] -- Enable DEBUG or RETAIL version (Default: 0)
+# SAMPLIB_DIR -- Directory to install built .LIB file
+# (Default: \ole2\samp\bin)
+# SAMPINC_DIR -- Directory to install public header files
+# (Default: \ole2\samp\include)
+# OLELIB_DIR -- Directory for OLE2 libraries
+# (Default: \ole2\bin)
+# OLEINC_DIR -- Directory for OLE2 public header files
+# (Default: \ole2\include)
+#
+# Comments:
+# --------
+#
+# In order to use the static library form of the OLE2UI library then you must
+# include "ole2ui.rc" resource file in your applications resource file. Also
+# "OleUIInitialize" must be called before calling any library functions.
+# This is called typically before entering the main message loop in an EXE
+# and called from LibMain for an in-proc server (DLL). Two unique strings
+# should be passed as paramters to OleUIInitialize. These strings are used
+# as class names for two custom controls used in the OLE2UI dialogs.
+# Before shutting down "OleUIUninitialize" must be called in order to clean up
+# resources used by the OLE2UI library. In an EXE, this is typically called
+# after leaving the main message loop; in an DLL, this is typically called
+# from the DLL's WEP function.
+# If the OLE2UI library is used in DLL form then explicitly including the
+# "ole2ui.rc" resource file and calling OleUIInitialize/OleUIUninitialize
+# is NOT necessary.
+# ============================================================================
+
+DEBUG=1
+MODEL=M
+LIBFORDLL=0
+NOASSERT=1
+OLE201=1
+DOS=1
+
+!if "$(OPSYS)"=="DOS"
+OBJDIR=objidd
+!else
+OBJDIR=obji1d
+!endif
+
+!ifndef SAMPINC_DIR
+SAMPINC_DIR=..\include
+!endif
+
+!ifndef SAMPLIB_DIR
+SAMPLIB_DIR=..\lib
+!endif
+
+!ifndef OLEINC_DIR
+!if "$(OPSYS)"=="DOS"
+OLEINC_DIR=..\..\include;$(CAIROLE)\h\export;$(IMPORT)\CHICAGO\h;\
+ $(IMPORT)\CHICAGO\h\crt;$(COMMON)\ih;$(COMMON)\types
+!else
+OLEINC_DIR=..\..\include;$(CAIROLE)\h\export;$(IMPORT)\$(OPSYS)\h\sdk;\
+ $(IMPORT)\$(OPSYS)\h\sdk\crt;$(COMMON)\ih;$(COMMON)\types
+!endif
+!endif
+
+!ifndef OLELIB_DIR
+!if "$(OPSYS)"=="DOS"
+OLELIB_DIR=..\..\lib;$(CAIROLE)\ilib\$(OBJDIR);$(IMPORT)\chicago\lib
+!else
+OLELIB_DIR=..\..\lib;$(CAIROLE)\ilib\$(OBJDIR)
+!endif
+!endif
+
+!if ("$(OLE201)"=="1")
+MISCFLAGS=/DOLE201
+!endif
+
+!if ("$(NOASSERT)"=="1")
+MISCFLAGS=$(MISCFLAGS) /DNOASSERT
+!endif
+
+!if ("$(DEBUG)"=="1")
+MSG=DEBUG Static LIB Version
+#CFLAGS=-c -Od -GA2s -W3 -Zpei -A$(MODEL) -D_DEBUG
+
+!ifdef WIN16
+LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300 /NOPACKCODE
+!else
+LFLAGS=/MAP:$(O)$(LIBNAME).map /DEBUGTYPE:CV /NOD /NOPACK
+!endif
+
+CC=$(IMPORT)\n386\bin\cl
+AS=$(IMPORT)\n386\bin\masm
+RS=$(IMPORT)\n386\bin\rc
+LINK=$(COMMON)\bin\link $(LFLAGS)
+LIB=lib
+
+!if ("$(LIBFORDLL)"=="1")
+#
+# Build DEBUG OLE2UI library for use with DLL's (eg. in-proc server objects)
+#
+MSG=DEBUG Static LIB Version (for use with DLL's)
+LIBNAME=OLE2UIDD
+OBJ=OLE2UIDD
+
+CFLAGS=-c -Od -W3 -Zpei -D_DEBUG -DDLL_VER -D_WINDLL -DLIBNAME=\"$$(LIBNAME)\"
+!ifdef WIN16
+CFLAGS=$(CFLAGS) -GD -GEd -AMw
+UILIBS=ldllcew libw ole2 storage shell
+!else
+CFLAGS=$(CFLAGS) -Gd -DWIN32 -DUNICODE -D_UNICODE -D_INC_OLE -D_X86_ $(MISCFLAGS)
+UILIBS=libw32.lib storag32.lib shell32.lib
+!if "$(OLE201)"=="1"
+UILIBS=$(UILIBS) ole2w32.lib
+!else
+UILIBS=$(UILIBS) ole232.lib
+!endif
+
+!endif
+
+LIBOBJS = $(UI_COBJS:D^\=OLE2UIDD^\) $(UI_NOPCOBJS:D^\=OLE2UIDD\NOPC^\)
+!else
+#
+# Build DEBUG OLE2UI library for use with EXE's
+#
+MSG=DEBUG Static LIB Version (for use with EXE's)
+LIBNAME=OLE2UIXD
+OBJ=OLE2UIXD
+
+CFLAGS=-c -Od -W3 -Zpei #-D_DEBUG
+!ifdef WIN16
+CFLAGS=$(CFLAGS) -GA2s -A$(MODEL)
+UILIBS=mlibcew libw ole2 storage shell
+!else
+CFLAGS=$(CFLAGS) -Gs -DWIN32 -DUNICODE -D_UNICODE -D_INC_OLE -D_X86_ $(MISCFLAGS)
+
+!if "$(OPSYS)"=="DOS"
+UILIBS= $(IMPORT)\CHICAGO\lib\advapi32.lib \
+ $(IMPORT)\CHICAGO\lib\comdlg32.lib \
+ $(IMPORT)\CHICAGO\lib\crtdll.lib \
+ $(IMPORT)\CHICAGO\lib\gdi32.lib \
+ $(IMPORT)\CHICAGO\lib\kernel32.lib \
+ $(IMPORT)\CHICAGO\lib\libcmt.lib \
+ $(IMPORT)\CHICAGO\lib\shell32.lib \
+ $(IMPORT)\CHICAGO\lib\user32.lib \
+ $(IMPORT)\CHICAGO\lib\wsock32.lib
+!else
+UILIBS= $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\advapi32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\comdlg32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\crtdll.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\gdi32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\kernel32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\libcmt.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\shell32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\user32.lib
+!endif
+UILIBS= $(UILIBS) \
+ $(CAIROLE)\ilib\$(OBJDIR)\ole2w32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\storag32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\compob32.lib
+
+!endif
+
+LIBOBJS = $(UI_COBJS:D^\=OLE2UIXD^\) $(UI_NOPCOBJS:D^\=OLE2UIXD\NOPC^\)
+!endif
+
+!else
+
+#CFLAGS=-c -Os -GA2s -W3 -Zpe -A$(MODEL)
+
+!ifdef WIN16
+LFLAGS=/MAP:FULL /LINE /NOD /NOE /SE:300 /NOPACKCODE
+!else
+LFLAGS=/MAP:$(O)$(LIBNAME).map /NOD /NOPACK
+!endif
+
+CC=$(IMPORT)\n386\bin\cl
+AS=$(IMPORT)\n386\bin\masm
+RS=$(IMPORT)\n386\bin\rc
+LINK=$(COMMON)\bin\link $(LFLAGS)
+LIB=lib
+
+!if ("$(LIBFORDLL)"=="1")
+#
+# Build RETAIL OLE2UI library for use with DLL's (eg. in-proc server objects)
+#
+MSG=RETAIL Static LIB Version (for use with DLL's)
+LIBNAME=OLE2UID
+OBJ=OLE2UID
+
+CFLAGS=-c -Os -D_WINDLL -W3 -Zpe
+!ifdef WIN16
+CFLAGS=$(CFLAGS) -GD -GEd -A$(MODEL)
+UILIBS=ldllcew libw ole2 storage shell
+!else
+CFLAGS=$(CFLAGS) -Gd -DWIN32 -DUNICODE -D_UNICODE -D_INC_OLE -D_X86_ $(MISCFLAGS)
+
+!if "$(OPSYS)"=="DOS"
+UILIBS= $(IMPORT)\CHICAGO\lib\advapi32.lib \
+ $(IMPORT)\CHICAGO\lib\comdlg32.lib \
+ $(IMPORT)\CHICAGO\lib\crtdll.lib \
+ $(IMPORT)\CHICAGO\lib\gdi32.lib \
+ $(IMPORT)\CHICAGO\lib\kernel32.lib \
+ $(IMPORT)\CHICAGO\lib\libcmt.lib \
+ $(IMPORT)\CHICAGO\lib\shell32.lib \
+ $(IMPORT)\CHICAGO\lib\user32.lib
+!else
+UILIBS= $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\advapi32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\comdlg32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\crtdll.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\gdi32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\kernel32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\libcmt.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\shell32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\user32.lib
+!endif
+UILIBS= $(UILIBS) \
+ $(CAIROLE)\ilib\$(OBJDIR)\ole2w32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\storag32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\compob32.lib
+
+!endif
+
+LIBOBJS = $(UI_COBJS:D^\=OLE2UID^\) $(UI_NOPCOBJS:D^\=OLE2UID\NOPC^\)
+!else
+#
+# Build RETAIL OLE2UI library for use with EXE's
+#
+MSG=RETAIL Static LIB Version (for use with EXE's)
+LIBNAME=OLE2UIX
+OBJ=OLE2UIX
+
+CFLAGS=-c -Os -W3 -Zpe
+!ifdef WIN16
+CFLAGS=$(CFLAGS) -GA2s -GEs -A$(MODEL)
+UILIBS=mlibcew libw ole2 storage shell
+!else
+CFLAGS=$(CFLAGS) -Gs -DWIN32 -DUNICODE -D_UNICODE -D_INC_OLE -D_X86_ $(MISCFLAGS)
+
+!if "$(OPSYS)"=="DOS"
+UILIBS= $(IMPORT)\CHICAGO\lib\advapi32.lib \
+ $(IMPORT)\CHICAGO\lib\comdlg32.lib \
+ $(IMPORT)\CHICAGO\lib\crtdll.lib \
+ $(IMPORT)\CHICAGO\lib\gdi32.lib \
+ $(IMPORT)\CHICAGO\lib\kernel32.lib \
+ $(IMPORT)\CHICAGO\lib\libcmt.lib \
+ $(IMPORT)\CHICAGO\lib\shell32.lib \
+ $(IMPORT)\CHICAGO\lib\user32.lib
+!else
+UILIBS= $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\advapi32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\comdlg32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\crtdll.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\gdi32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\kernel32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\libcmt.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\shell32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\user32.lib
+!endif
+UILIBS= $(UILIBS) \
+ $(CAIROLE)\ilib\$(OBJDIR)\ole2w32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\storag32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\compob32.lib
+
+!endif
+
+LIBOBJS = $(UI_COBJS:D^\=OLE2UIX^\) $(UI_NOPCOBJS:D^\=OLE2UIX\NOPC^\)
+!endif
+
+!endif
+
+GOAL: PRELUDE $(LIBNAME).LIB
+
+# ----------------------------------------------------------------------------
+# O B J E C T F I L E L I S T
+# ----------------------------------------------------------------------------
+
+UI_COBJS = \
+ D^\busy.obj\
+ D^\common.obj\
+ D^\convert.obj\
+ D^\dbgutil.obj\
+ D^\drawicon.obj\
+ D^\hatch.obj\
+ D^\icon.obj\
+ D^\iconbox.obj\
+ D^\insobj.obj\
+ D^\links.obj\
+ D^\msgfiltr.obj\
+ D^\enumfetc.obj\
+ D^\enumstat.obj\
+ D^\objfdbk.obj\
+ D^\ole2ui.obj\
+ D^\olestd.obj\
+ D^\targtdev.obj\
+ D^\oleutl.obj\
+ D^\pastespl.obj\
+ D^\regdb.obj\
+ D^\resimage.obj\
+ D^\utility.obj\
+
+UI_NOPCOBJS = \
+ D^\geticon.obj\
+ D^\dballoc.obj\
+ D^\suminfo.obj\
+ D^\stdpal.obj\
+
+PRECOMPOBJ= $(O)precomp.obj
+
+PRECOMP=$(O)precomp.pch
+
+# ----------------------------------------------------------------------------
+# R E S O U R C E L I S T
+# ----------------------------------------------------------------------------
+RES = \
+ busy.h \
+ common.h \
+ convert.h \
+ edlinks.h \
+ geticon.h \
+ icon.h \
+ iconbox.h \
+ insobj.h \
+ msgfiltr.h \
+ enumfetc.h \
+ ole2ui.h \
+ pastespl.h \
+ resimage.h \
+ dballoc.h \
+ suminfo.h \
+ stdpal.h \
+
+
+.SUFFIXES: .c .cpp .obj
+
+O=.\$(OBJ)^\
+
+!if [if not exist $(OBJ)\*. md $(OBJ) >nul]
+!error Object subdirectory $(OBJ)\ could not be created
+!endif
+!if [if not exist $(OBJ)\NOPC\*. md $(OBJ)\NOPC > nul]
+!error non-precompiled header object subdirectory $(OBJ)\NOPC\ could not be created
+!endif
+
+# ----------------------------------------------------------------------------
+# I N F E R E N C E R U L E S
+# ----------------------------------------------------------------------------
+
+# compile C file without precompiled headers into object directory\NOPC
+# dont compile c files etc for lcoalized builds.
+{}.c{$(O)NOPC\}.obj:
+ @echo Are you compiling with OLE 2.01 ??????
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).c
+!else
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).c\" -Fo$(O)NOPC\$(@B) $(@B).c
+!endif
+
+# compile C file into object directory
+{}.c{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).c
+!else
+ $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -D_FILE_=\"$(*B).c\" -Fo$(O)$(@B) $(@B).c
+!endif
+
+# compile CPP file without precompiled headers into object directory\NOPC
+# dont compile cpp files etc for lcoalized builds.
+{}.cpp{$(O)NOPC\}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).cpp °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).cpp
+!else
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).cpp\" -Fo$(O)NOPC\$(@B) $(@B).cpp
+!endif
+
+# compile CPP file into object directory
+{}.cpp{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).cpp °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).cpp
+!else
+ $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -D_FILE_=\"$(*B).cpp\" -Fo$(O)$(@B) $(@B).cpp
+!endif
+
+
+# ----------------------------------------------------------------------------
+# D E P E N D F I L E C R E A T I O N
+# ----------------------------------------------------------------------------
+UI_CFILE = $(UI_COBJS:.obj=.c) $(UI_DLLOBJS:.obj=.c)
+UI_NOPCFILE = $(UI_NOPCOBJS:.obj=.c)
+DEPEND: nul
+ @echo Making a NEW dependancy file.
+ mkdep -p $$(O) -s .obj $(UI_CFILE:D^\=) > tmp.tmp
+ sed "s/:/: $$(PRECOMP)/g" < tmp.tmp > depend
+ -del tmp.tmp
+ mkdep -p $$(O)NOPC\ -s .obj $(UI_NOPCFILE:D^\=) >> depend
+ mkdep -p $$(O) -s .pch precomp.c >> depend
+
+# ----------------------------------------------------------------------------
+# W E L C O M E B A N N E R
+# ----------------------------------------------------------------------------
+PRELUDE:
+ @echo ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
+ @echo º Makefile for UILibrary º
+ @echo ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
+ @echo $(MSG)
+!ifndef SRCTOK
+ set INCLUDE=$(OLEINC_DIR);$(INCLUDE)
+ set LIB=$(OLELIB_DIR);$(LIB)
+!endif
+
+
+# ----------------------------------------------------------------------------
+# G O A L T A R G E T S
+# ----------------------------------------------------------------------------
+!include "depend"
+
+CLEAN: CleanUp
+CleanUp:
+ -echo y|del .\$(OBJ)\*.*
+ -echo y|del .\$(OBJ)\NOPC\*.*
+ -del $(LIBNAME).lib
+
+$(O)precomp.pch: precomp.c
+!ifdef DOS
+ SET CL=$(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h
+ $(CC) -Fo$(O)$(@B) precomp.c
+!else
+ $(CC) $(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h -D_FILE_=\"precomp.c\" -Fo$(O)$(@B) precomp.c
+!endif
+
+#
+# Build .LIB static library
+#
+
+$(LIBNAME).lib: $(LIBOBJS) $(PRECOMPOBJ)
+ -del $(O)$(LIBNAME).lib
+!ifdef WIN16
+ lib @<<
+$(O)$(LIBNAME).lib
+y
+$(PRECOMPOBJ: = +) $(LIBOBJS: = +)
+
+<<
+!else
+ $(LINK) @<<
+/OUT:$(O)$(LIBNAME).lib
+/MACHINE:i386
+$(PRECOMPOBJ: = ) $(LIBOBJS: = ) $(UILIBS)
+
+<<
+!endif
+ copy $(O)$(LIBNAME).lib $(LIBNAME).lib
+
+
+# install built library and public header files to release directories
+install:
+ copy $(LIBNAME).lib $(SAMPLIB_DIR)
+ copy ole2ui.h $(SAMPINC_DIR)
+ copy olestd.h $(SAMPINC_DIR)
+ copy msgfiltr.h $(SAMPINC_DIR)
+ copy enumfetc.h $(SAMPINC_DIR)
+
+# EOF ========================================================================
+ \ No newline at end of file
diff --git a/private/oleutest/letest/ole2ui/msgfiltr.c b/private/oleutest/letest/ole2ui/msgfiltr.c
new file mode 100644
index 000000000..562dfb802
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/msgfiltr.c
@@ -0,0 +1,809 @@
+/*
+ * MSGFILTR.C
+ *
+ * This file contains a standard implementation of IMessageFilter
+ * interface.
+ * This file is part of the OLE 2.0 User Interface support library.
+ *
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ *
+ */
+
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "msgfiltr.h"
+
+OLEDBGDATA
+
+
+typedef struct tagOLESTDMESSAGEFILTER {
+ IMessageFilterVtbl FAR* m_lpVtbl;
+ UINT m_cRef;
+ HWND m_hWndParent;
+ DWORD m_dwInComingCallStatus; // Status to return from
+ // HandleIncomingCall
+ HANDLEINCOMINGCALLBACKPROC m_lpfnHandleInComingCallback;
+ // Callback function
+ // to selectively handle
+ // interface method calls
+ BOOL m_fEnableBusyDialog; // enable RetryRejected
+ // Call dialog
+ BOOL m_fEnableNotRespondingDialog; // enable
+ // MessagePending dialog
+ MSGPENDINGPROC m_lpfnMessagePendingCallback; // MessagePending
+ // Callback function
+ LPFNOLEUIHOOK m_lpfnBusyDialogHookCallback; // Busy dialog hook
+ LPTSTR m_lpszAppName; // Name of application
+ // installing filter
+ HWND m_hWndBusyDialog; // HWND of busy dialog. Used
+ // to tear down dialog.
+ BOOL m_bUnblocking;
+
+ }OLESTDMESSAGEFILTER, FAR* LPOLESTDMESSAGEFILTER;
+
+/* interface IMessageFilter implementation */
+STDMETHODIMP OleStdMsgFilter_QueryInterface(
+ LPMESSAGEFILTER lpThis, REFIID riid, LPVOID FAR* ppvObj);
+STDMETHODIMP_(ULONG) OleStdMsgFilter_AddRef(LPMESSAGEFILTER lpThis);
+STDMETHODIMP_(ULONG) OleStdMsgFilter_Release(LPMESSAGEFILTER lpThis);
+STDMETHODIMP_(DWORD) OleStdMsgFilter_HandleInComingCall (
+ LPMESSAGEFILTER lpThis,
+ DWORD dwCallType,
+ HTASK htaskCaller,
+ DWORD dwTickCount,
+#ifdef WIN32
+ LPINTERFACEINFO dwReserved
+#else
+ DWORD dwReserved
+#endif
+);
+STDMETHODIMP_(DWORD) OleStdMsgFilter_RetryRejectedCall (
+ LPMESSAGEFILTER lpThis,
+ HTASK htaskCallee,
+ DWORD dwTickCount,
+ DWORD dwRejectType
+);
+STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending (
+ LPMESSAGEFILTER lpThis,
+ HTASK htaskCallee,
+ DWORD dwTickCount,
+ DWORD dwPendingType
+);
+
+
+static IMessageFilterVtbl g_OleStdMessageFilterVtbl = {
+ OleStdMsgFilter_QueryInterface,
+ OleStdMsgFilter_AddRef,
+ OleStdMsgFilter_Release,
+ OleStdMsgFilter_HandleInComingCall,
+ OleStdMsgFilter_RetryRejectedCall,
+ OleStdMsgFilter_MessagePending
+};
+
+
+/* GetTopWindowInWindowsTask
+** -------------------------
+** Get the top most window that has focus in the given task to be
+** used as the parent for the busy dialog. we do this to handle the
+** case where a dialog window is currently up when we need to give
+** the busy dialog. if we use the current assigned parent window
+** (which typically will be the frame window of the app), then the
+** busy dialog will not be modal to the current active dialog
+** window.
+*/
+static HWND GetTopWindowInWindowsTask(HWND hwnd)
+{
+ HWND hwndActive = GetActiveWindow();
+ if (!hwndActive)
+ return hwnd;
+
+ if (GetWindowTask(hwnd) == GetWindowTask(hwndActive))
+ return hwndActive;
+ else
+ return hwnd;
+}
+
+STDAPI_(LPMESSAGEFILTER) OleStdMsgFilter_Create(
+ HWND hWndParent,
+ LPTSTR szAppName,
+ MSGPENDINGPROC lpfnCallback,
+ LPFNOLEUIHOOK lpfnOleUIHook // Busy dialog hook callback
+)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter;
+ LPMALLOC lpMalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)
+ return NULL;
+
+ lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpMalloc->lpVtbl->Alloc(
+ lpMalloc, (sizeof(OLESTDMESSAGEFILTER)));
+ lpMalloc->lpVtbl->Release(lpMalloc);
+ if (! lpStdMsgFilter) return NULL;
+
+ lpStdMsgFilter->m_lpVtbl = &g_OleStdMessageFilterVtbl;
+ lpStdMsgFilter->m_cRef = 1;
+ lpStdMsgFilter->m_hWndParent = hWndParent;
+ lpStdMsgFilter->m_dwInComingCallStatus = SERVERCALL_ISHANDLED;
+ lpStdMsgFilter->m_lpfnHandleInComingCallback = NULL;
+ lpStdMsgFilter->m_fEnableBusyDialog = TRUE;
+ lpStdMsgFilter->m_fEnableNotRespondingDialog = TRUE;
+ lpStdMsgFilter->m_lpszAppName = szAppName;
+ lpStdMsgFilter->m_lpfnMessagePendingCallback = lpfnCallback;
+ lpStdMsgFilter->m_lpfnBusyDialogHookCallback = lpfnOleUIHook;
+ lpStdMsgFilter->m_hWndBusyDialog = NULL;
+ lpStdMsgFilter->m_bUnblocking = FALSE;
+
+ return (LPMESSAGEFILTER)lpStdMsgFilter;
+}
+
+
+/* OleStdMsgFilter_SetInComingStatus
+** ---------------------------------
+** This is a private function that allows the caller to control what
+** value is returned from the IMessageFilter::HandleInComing method.
+**
+** if a HandleInComingCallbackProc is installed by a call to
+** OleStdMsgFilter_SetHandleInComingCallbackProc, then this
+** overrides the dwIncomingCallStatus established by a call to
+** OleStdMsgFilter_SetInComingStatus. Using
+** OleStdMsgFilter_SetInComingStatus allows the app to reject or
+** accept ALL in coming calls. Using a HandleInComingCallbackProc
+** allows the app to selectively handle or reject particular method
+** calls.
+*/
+
+STDAPI_(void) OleStdMsgFilter_SetInComingCallStatus(
+ LPMESSAGEFILTER lpThis, DWORD dwInComingCallStatus)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+
+ if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
+ lpStdMsgFilter->m_dwInComingCallStatus = dwInComingCallStatus;
+ else
+ OleDbgAssert(
+ TEXT("OleStdMsgFilter_SetIncomingCallStatus: Invalid IMessageFilter*"));
+
+#if defined( _DEBUG )
+ {
+ TCHAR szBuf[80];
+ TCHAR *szReturn;
+
+ switch(dwInComingCallStatus) {
+ case SERVERCALL_ISHANDLED:
+ szReturn = TEXT("SERVERCALL_ISHANDLED");
+ break;
+ case SERVERCALL_REJECTED:
+ szReturn = TEXT("SERVERCALL_REJECTED");
+ break;
+ case SERVERCALL_RETRYLATER:
+ szReturn = TEXT("SERVERCALL_RETRYLATER");
+ break;
+ default:
+ szReturn = TEXT("** ERROR: UNKNOWN **");
+ break;
+ }
+ wsprintf(
+ szBuf,
+ TEXT("OleStdMsgFilter_SetInComingCallStatus: Status set to %s.\r\n"),
+ (LPTSTR)szReturn
+ );
+ OleDbgOut3(szBuf);
+ }
+#endif
+
+}
+
+
+/* OleStdMsgFilter_SetHandleInComingCallbackProc
+** ---------------------------------------------
+** This is a private function that allows the caller to install (or
+** de-install) a special callback function to selectively
+** handle/reject specific incoming method calls on particular
+** interfaces.
+**
+** if a HandleInComingCallbackProc is installed by a call to
+** OleStdMsgFilter_SetHandleInComingCallbackProc, then this
+** overrides the dwIncomingCallStatus established by a call to
+** OleStdMsgFilter_SetInComingStatus. Using
+** OleStdMsgFilter_SetInComingStatus allows the app to reject or
+** accept ALL in coming calls. Using a HandleInComingCallbackProc
+** allows the app to selectively handle or reject particular method
+** calls.
+**
+** to de-install the HandleInComingCallbackProc, call
+** OleStdMsgFilter_SetHandleInComingCallbackProc(NULL);
+**
+** Returns previous callback proc in effect.
+*/
+
+STDAPI_(HANDLEINCOMINGCALLBACKPROC)
+ OleStdMsgFilter_SetHandleInComingCallbackProc(
+ LPMESSAGEFILTER lpThis,
+ HANDLEINCOMINGCALLBACKPROC lpfnHandleInComingCallback)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ HANDLEINCOMINGCALLBACKPROC lpfnPrevCallback =
+ lpStdMsgFilter->m_lpfnHandleInComingCallback;
+
+ if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER))) {
+ lpStdMsgFilter->m_lpfnHandleInComingCallback =
+ lpfnHandleInComingCallback;
+ } else {
+ OleDbgAssert(
+ TEXT("OleStdMsgFilter_SetIncomingCallStatus: Invalid IMessageFilter*"));
+ }
+
+#if defined( _DEBUG )
+ {
+ if (lpfnHandleInComingCallback)
+ OleDbgOut3(
+ TEXT("OleStdMsgFilter_SetHandleInComingCallbackProc SET\r\n"));
+ else
+ OleDbgOut3(
+ TEXT("OleStdMsgFilter_SetHandleInComingCallbackProc CLEARED\r\n"));
+
+ }
+#endif // _DEBUG
+
+ return lpfnPrevCallback;
+}
+
+
+/* OleStdMsgFilter_GetInComingStatus
+** ---------------------------------
+** This is a private function that returns the current
+** incoming call status. Can be used to disable/enable options
+** in the calling application.
+**
+** Returns: one of
+**
+** SERVERCALL_ISHANDLED
+** SERVERCALL_REJECTED
+** SERVERCALL_RETRYLATER
+** or -1 for ERROR
+**
+*/
+
+STDAPI_(DWORD) OleStdMsgFilter_GetInComingCallStatus(
+ LPMESSAGEFILTER lpThis)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ DWORD dwReturn;
+
+ if (!IsBadReadPtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
+ dwReturn = lpStdMsgFilter->m_dwInComingCallStatus;
+ else
+ {
+ OleDbgAssert(
+ TEXT("OleStdMsgFilter_GetIncomingCallStatus: Invalid IMessageFilter*"));
+ dwReturn = (DWORD)-1;
+ }
+
+#if defined( _DEBUG )
+ {
+ TCHAR szBuf[80];
+ TCHAR *szReturn;
+
+ switch(dwReturn) {
+ case SERVERCALL_ISHANDLED:
+ szReturn = TEXT("SERVERCALL_ISHANDLED");
+ break;
+ case SERVERCALL_REJECTED:
+ szReturn = TEXT("SERVERCALL_REJECTED");
+ break;
+ case SERVERCALL_RETRYLATER:
+ szReturn = TEXT("SERVERCALL_RETRYLATER");
+ break;
+ default:
+ szReturn = TEXT("-1");
+ break;
+ }
+ wsprintf(
+ szBuf,
+ TEXT("OleStdMsgFilter_GetInComingCallStatus returns %s.\r\n"),
+ (LPTSTR)szReturn
+ );
+ OleDbgOut3(szBuf);
+ }
+#endif
+
+ return dwReturn;
+}
+
+
+/* OleStdMsgFilter_EnableBusyDialog
+** --------------------------------
+** This function allows the caller to control whether
+** the busy dialog is enabled. this is the dialog put up when
+** IMessageFilter::RetryRejectedCall is called because the server
+** responded SERVERCALL_RETRYLATER or SERVERCALL_REJECTED.
+**
+** if the busy dialog is NOT enabled, then the rejected call is
+** immediately canceled WITHOUT prompting the user. in this situation
+** OleStdMsgFilter_RetryRejectedCall always retuns
+** OLESTDCANCELRETRY canceling the outgoing LRPC call.
+** If the busy dialog is enabled, then the user is given the choice
+** of whether to retry, switch to, or cancel.
+**
+** Returns previous dialog enable state
+*/
+
+STDAPI_(BOOL) OleStdMsgFilter_EnableBusyDialog(
+ LPMESSAGEFILTER lpThis, BOOL fEnable)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ BOOL fPrevEnable = lpStdMsgFilter->m_fEnableBusyDialog;
+
+ if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
+ lpStdMsgFilter->m_fEnableBusyDialog = fEnable;
+ else
+ OleDbgAssert(
+ TEXT("OleStdMsgFilter_EnableBusyDialog: Invalid IMessageFilter*"));
+
+#if defined( _DEBUG )
+ {
+ TCHAR szBuf[80];
+ wsprintf(
+ szBuf,
+ TEXT("OleStdMsgFilter_EnableBusyDialog: Dialog is %s.\r\n"),
+ fEnable ? (LPTSTR) TEXT("ENABLED") : (LPTSTR) TEXT("DISABLED")
+ );
+ OleDbgOut3(szBuf);
+ }
+#endif
+
+ return fPrevEnable;
+}
+
+
+/* OleStdMsgFilter_EnableNotRespondingDialog
+** -----------------------------------------
+** This function allows the caller to control whether
+** the app "NotResponding" (Blocked) dialog is enabled. this is the
+** dialog put up when IMessageFilter::MessagePending is called.
+** If the NotResponding dialog is enabled, then the user is given
+** the choice of whether to retry or switch to, but NOT to cancel.
+**
+** Returns previous dialog enable state
+*/
+
+STDAPI_(BOOL) OleStdMsgFilter_EnableNotRespondingDialog(
+ LPMESSAGEFILTER lpThis, BOOL fEnable)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ BOOL fPrevEnable = lpStdMsgFilter->m_fEnableNotRespondingDialog;
+
+ if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
+ lpStdMsgFilter->m_fEnableNotRespondingDialog = fEnable;
+ else
+ OleDbgAssert(
+ TEXT("OleStdMsgFilter_EnableNotRespondingDialog: Invalid IMessageFilter*"));
+
+#if defined( _DEBUG )
+ {
+ TCHAR szBuf[80];
+ wsprintf(
+ szBuf,
+ TEXT("OleStdMsgFilter_EnableNotRespondingDialog: Dialog is %s.\r\n"),
+ fEnable ? (LPTSTR) TEXT("ENABLED") : (LPTSTR) TEXT("DISABLED")
+ );
+ OleDbgOut3(szBuf);
+ }
+#endif
+
+ return fPrevEnable;
+}
+
+
+/* OleStdMsgFilter_SetParentWindow
+** -------------------------------
+** This function allows caller to set which window will be used as
+** the parent for the busy dialog.
+**
+** OLE2NOTE: it would be inportant for an in-place active server to
+** reset this to its current in-place frame window when in-place
+** activated. if the hWndParent is set to NULL then the dialogs will
+** be parented to the desktop.
+**
+** Returns: previous parent window
+*/
+
+STDAPI_(HWND) OleStdMsgFilter_SetParentWindow(
+ LPMESSAGEFILTER lpThis, HWND hWndParent)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ HWND hWndPrev = lpStdMsgFilter->m_hWndParent;
+
+ lpStdMsgFilter->m_hWndParent = hWndParent;
+ return hWndPrev;
+}
+
+
+STDMETHODIMP OleStdMsgFilter_QueryInterface(
+ LPMESSAGEFILTER lpThis, REFIID riid, LPVOID FAR* ppvObj)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ SCODE scode;
+
+ /* Two interfaces supported: IUnknown, IMessageFilter
+ */
+
+ if (IsEqualIID(riid, &IID_IMessageFilter) || IsEqualIID(riid, &IID_IUnknown)) {
+ lpStdMsgFilter->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) OleStdMsgFilter_AddRef(LPMESSAGEFILTER lpThis)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ return ++lpStdMsgFilter->m_cRef;
+}
+
+STDMETHODIMP_(ULONG) OleStdMsgFilter_Release(LPMESSAGEFILTER lpThis)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ LPMALLOC lpMalloc;
+
+ if (--lpStdMsgFilter->m_cRef != 0) // Still used by others
+ return lpStdMsgFilter->m_cRef;
+
+ // Free storage
+ if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)
+ return (ULONG)0;
+
+ lpMalloc->lpVtbl->Free(lpMalloc, lpStdMsgFilter);
+ lpMalloc->lpVtbl->Release(lpMalloc);
+ return (ULONG)0;
+}
+
+
+STDMETHODIMP_(DWORD) OleStdMsgFilter_HandleInComingCall (
+ LPMESSAGEFILTER lpThis,
+ DWORD dwCallType,
+ HTASK htaskCaller,
+ DWORD dwTickCount,
+#ifdef WIN32
+ LPINTERFACEINFO dwReserved
+#else
+ DWORD dwReserved
+#endif
+)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+
+ /* if a HandleInComingCallbackProc is in effect, then this
+ ** overrides dwIncomingCallStatus established by a call to
+ ** OleStdMsgFilter_SetInComingStatus. we will call this
+ ** callback to allow the app to selectively handle or reject
+ ** incoming method calls. the LPINTERFACEINFO parameter
+ ** describes which method is being called.
+ */
+ if (lpStdMsgFilter->m_lpfnHandleInComingCallback &&
+ !IsBadCodePtr((FARPROC)lpStdMsgFilter->m_lpfnHandleInComingCallback)){
+ return lpStdMsgFilter->m_lpfnHandleInComingCallback(
+ dwCallType,
+ htaskCaller,
+ dwTickCount,
+ dwReserved
+ );
+ }
+
+ switch (dwCallType) {
+ case CALLTYPE_TOPLEVEL:
+ /* OLE2NOTE: we currently have NO pending outgoing call and
+ ** there is a new toplevel incoming call.
+ ** this call may be rejected.
+ */
+ return lpStdMsgFilter->m_dwInComingCallStatus;
+
+ case CALLTYPE_TOPLEVEL_CALLPENDING:
+ /* OLE2NOTE: we currently HAVE a pending outgoing call and
+ ** there is a new toplevel incoming call.
+ ** this call may be rejected.
+ */
+ return lpStdMsgFilter->m_dwInComingCallStatus;
+
+ case CALLTYPE_NESTED:
+ /* OLE2NOTE: we currently HAVE a pending outgoing call and
+ ** there callback on behalf of the previous outgoing
+ ** call. this type of call should ALWAYS be handled.
+ */
+ return SERVERCALL_ISHANDLED;
+
+ case CALLTYPE_ASYNC:
+ /* OLE2NOTE: we currently have NO pending outgoing call and
+ ** there is a new asyncronis incoming call.
+ ** this call can NEVER be rejected. OLE actually ignores
+ ** the return code in this case and always allows the
+ ** call through.
+ */
+ return SERVERCALL_ISHANDLED; // value returned does not matter
+
+ case CALLTYPE_ASYNC_CALLPENDING:
+ /* OLE2NOTE: we currently HAVE a pending outgoing call and
+ ** there is a new asyncronis incoming call.
+ ** this call can NEVER be rejected. OLE ignore the
+ ** return code in this case.
+ */
+ return SERVERCALL_ISHANDLED; // value returned does not
+
+ default:
+ OleDbgAssert(
+ TEXT("OleStdMsgFilter_HandleInComingCall: Invalid CALLTYPE"));
+ return lpStdMsgFilter->m_dwInComingCallStatus;
+ }
+}
+
+STDMETHODIMP_(DWORD) OleStdMsgFilter_RetryRejectedCall (
+ LPMESSAGEFILTER lpThis,
+ HTASK htaskCallee,
+ DWORD dwTickCount,
+ DWORD dwRejectType
+)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ DWORD dwRet = 0;
+ UINT uRet;
+#if defined( _DEBUG )
+ TCHAR szBuf[80];
+#endif
+ OLEDBG_BEGIN2(TEXT("OleStdMsgFilter_RetryRejectedCall\r\n"))
+
+ /* OLE2NOTE: we should only put up the application busy dialog when
+ ** the callee has responded SERVERCALL_RETRYLATER. if the
+ ** dwRejectType is SERVERCALL_REJECTED then there is something
+ ** seriously wrong with the callee (perhaps a severe low memory
+ ** situation). we don't want to even try to "Switch To" this app
+ ** or even try to "Retry".
+ */
+ if (dwRejectType == SERVERCALL_RETRYLATER &&
+ lpStdMsgFilter->m_fEnableBusyDialog) {
+
+ OLEUIBUSY bz;
+
+ /* OLE2NOTE: we do not want to put up the Busy dialog immediately
+ ** the when an app says RETRYLATER. we should continue retrying
+ ** for a while in case the app can un-busy itself in a
+ ** reasonable amount of time.
+ */
+ if (dwTickCount <= (DWORD)OLESTDRETRYDELAY) {
+ dwRet = 500; // Retry after .5 sec
+ OLEDBG_END2
+ return dwRet;
+ }
+
+ /*
+ ** Set up structure for calling OLEUIBUSY dialog
+ */
+
+ bz.cbStruct = sizeof(OLEUIBUSY);
+ bz.dwFlags = 0L;
+ bz.hWndOwner =GetTopWindowInWindowsTask(lpStdMsgFilter->m_hWndParent);
+ bz.lpszCaption = lpStdMsgFilter->m_lpszAppName;
+ bz.lpfnHook = lpStdMsgFilter->m_lpfnBusyDialogHookCallback;
+ bz.lCustData = 0;
+ bz.hInstance = NULL;
+ bz.lpszTemplate = NULL;
+ bz.hResource = 0;
+ bz.hTask = htaskCallee;
+ bz.lphWndDialog = NULL; // We don't need the hDlg for this call
+
+ uRet = OleUIBusy(&bz);
+
+ switch (uRet) {
+ case OLEUI_BZ_RETRYSELECTED:
+ dwRet = 0; // Retry immediately
+ break;
+
+ case OLEUI_CANCEL:
+ dwRet = OLESTDCANCELRETRY; // Cancel pending outgoing call
+ break;
+
+ case OLEUI_BZERR_HTASKINVALID:
+ // Htask was invalid, return OLESTDRETRYDELAY anyway
+ dwRet = OLESTDRETRYDELAY; // Retry after <retry delay> msec
+
+#if defined( _DEBUG )
+ wsprintf(
+ szBuf,
+ TEXT("OleStdMsgFilter_RetryRejectedCall, HTASK 0x%x invalid\r\n"),
+ htaskCallee
+ );
+ OleDbgOut3(szBuf);
+#endif
+ break;
+ }
+ } else {
+ dwRet = OLESTDCANCELRETRY; // Cancel pending outgoing call
+ }
+
+#if defined( _DEBUG )
+ wsprintf(szBuf,
+ TEXT("OleStdMsgFilter_RetryRejectedCall returns %d\r\n"),
+ dwRet);
+ OleDbgOut3(szBuf);
+#endif
+
+ OLEDBG_END2
+ return dwRet;
+}
+
+
+
+/* a significant message is consider a mouse click or keyboard input. */
+#define IS_SIGNIFICANT_MSG(lpmsg) \
+ ( \
+ (PeekMessage((lpmsg), NULL, WM_LBUTTONDOWN, WM_LBUTTONDOWN, \
+ PM_NOREMOVE | PM_NOYIELD)) \
+ || (PeekMessage((lpmsg), NULL, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, \
+ PM_NOREMOVE | PM_NOYIELD)) \
+ || (PeekMessage((lpmsg), NULL, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, \
+ PM_NOREMOVE | PM_NOYIELD)) \
+ || (PeekMessage((lpmsg), NULL, WM_NCLBUTTONDBLCLK, WM_NCLBUTTONDBLCLK, \
+ PM_NOREMOVE | PM_NOYIELD)) \
+ || (PeekMessage((lpmsg), NULL, WM_KEYDOWN, WM_KEYDOWN, \
+ PM_NOREMOVE | PM_NOYIELD)) \
+ || (PeekMessage((lpmsg), NULL, WM_SYSKEYDOWN, WM_SYSKEYDOWN, \
+ PM_NOREMOVE | PM_NOYIELD)) \
+ )
+
+STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending (
+ LPMESSAGEFILTER lpThis,
+ HTASK htaskCallee,
+ DWORD dwTickCount,
+ DWORD dwPendingType
+)
+{
+ LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
+ DWORD dwReturn = PENDINGMSG_WAITDEFPROCESS;
+ MSG msg;
+ BOOL fIsSignificantMsg = IS_SIGNIFICANT_MSG(&msg);
+ UINT uRet;
+
+#if defined( _DEBUG )
+ TCHAR szBuf[128];
+ wsprintf(
+ szBuf,
+ TEXT("OleStdMsgFilter_MessagePending, dwTickCount = 0x%lX\r\n"),
+ (DWORD)dwTickCount
+ );
+ OleDbgOut4(szBuf);
+#endif
+
+ /* OLE2NOTE: If our tick count for this call exceeds our standard retry
+ ** delay, then we need to put up the dialog. We will only
+ ** consider putting up the dialog if the user has issued a
+ ** "significant" event (ie. mouse click or keyboard event). a
+ ** simple mouse move should NOT trigger this dialog.
+ ** Since our call to
+ ** OleUIBusy below enters a DialogBox() message loop, there's a
+ ** possibility that another call will be initiated during the dialog,
+ ** and this procedure will be re-entered. Just so we don't put up
+ ** two dialogs at a time, we use the m_bUnblocking varable
+ ** to keep track of this situation.
+ */
+
+ if (dwTickCount > (DWORD)OLESTDRETRYDELAY && fIsSignificantMsg
+ && !lpStdMsgFilter->m_bUnblocking)
+ {
+
+ if (lpStdMsgFilter->m_fEnableNotRespondingDialog)
+ {
+ OLEUIBUSY bz;
+
+ lpStdMsgFilter->m_bUnblocking = TRUE;
+
+ // Eat messages in our queue that we do NOT want to be dispatched
+ while (PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_REMOVE | PM_NOYIELD));
+
+ /* Set up structure for calling OLEUIBUSY dialog,
+ ** using the "not responding" variety
+ */
+
+ bz.cbStruct = sizeof(OLEUIBUSY);
+ bz.dwFlags = BZ_NOTRESPONDINGDIALOG;
+ bz.hWndOwner =GetTopWindowInWindowsTask(lpStdMsgFilter->m_hWndParent);
+ bz.lpszCaption = lpStdMsgFilter->m_lpszAppName;
+ bz.lpfnHook = lpStdMsgFilter->m_lpfnBusyDialogHookCallback;
+ bz.lCustData = 0;
+ bz.hInstance = NULL;
+ bz.lpszTemplate = NULL;
+ bz.hResource = 0;
+ bz.hTask = htaskCallee;
+
+ /* Set up the address to the hWnd in our MsgFilter structure. The
+ ** call to OleUIBusy will fill this in with the hWnd of the busy
+ ** dialog box
+ */
+
+ bz.lphWndDialog = (HWND FAR *)&(lpStdMsgFilter->m_hWndBusyDialog);
+ uRet = OleUIBusy(&bz);
+
+ lpStdMsgFilter->m_bUnblocking = FALSE;
+
+ return PENDINGMSG_WAITNOPROCESS;
+ }
+#if defined( _DEBUG )
+ else {
+ OleDbgOut3(TEXT("OleStdMsgFilter_MessagePending: BLOCKED but dialog Disabled\r\n"));
+ }
+#endif
+ }
+
+ /* If we're already unblocking, we're being re-entered. Don't
+ ** process message
+ */
+
+ if (lpStdMsgFilter->m_bUnblocking)
+ return PENDINGMSG_WAITDEFPROCESS;
+
+ /* OLE2NOTE: If we have a callback function set up, call it with the
+ ** current message. If not, tell OLE LPRC mechanism to automatically
+ ** handle all messages.
+ */
+ if (lpStdMsgFilter->m_lpfnMessagePendingCallback &&
+ !IsBadCodePtr((FARPROC)lpStdMsgFilter->m_lpfnMessagePendingCallback)){
+ MSG msg;
+
+ /* OLE2NOTE: the app provided a MessagePendingCallback
+ ** function. we will PeekMessage for the first message in
+ ** the queue and pass it to the app. the app in its callback
+ ** function can decide to Dispatch this message or it can
+ ** PeekMessage on its own giving particular message filter
+ ** criteria. if the app returns TRUE then we return
+ ** PENDINGMSG_WAITNOPROCESS to OLE telling OLE to leave the
+ ** message in the queue. If the app returns FALSE, then we
+ ** return PENDINGMSG_WAITDEFPROCESS to OLE telling OLE to do
+ ** its default processing with the message. by default OLE
+ ** dispatches system messages and eats other messages and
+ ** beeps.
+ */
+ if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD)) {
+
+ if (lpStdMsgFilter->m_lpfnMessagePendingCallback(&msg)) {
+ /* TRUE return means that the app processed message.
+ **
+ ** NOTE: (CHANGE FROM OLE2.0 VERSION) we leave it up to
+ ** the callback routine to remove the message if it
+ ** wants.
+ */
+ dwReturn = PENDINGMSG_WAITNOPROCESS;
+ } else {
+ /* FALSE means that the app did not process the
+ ** message. we will let OLE take its
+ ** default action.
+ **
+ ** NOTE: (CHANGE FROM OLE2.0 VERSION) we used to return
+ ** PENDINGMSG_WAITNOPROCESS to leave the message in
+ ** the queue; now we return PENDINGMSG_WAITDEFPROCESS
+ ** to let OLE do default processing.
+ */
+ dwReturn = PENDINGMSG_WAITDEFPROCESS;
+
+#if defined( _DEBUG )
+ wsprintf(
+ szBuf,
+ TEXT("Message (0x%x) (wParam=0x%x, lParam=0x%lx) using WAITDEFPROCESS while blocked\r\n"),
+ msg.message,
+ msg.lParam,
+ msg.wParam
+ );
+ OleDbgOut2(szBuf);
+#endif // _DEBUG
+ }
+ }
+ }
+
+ return dwReturn;
+}
diff --git a/private/oleutest/letest/ole2ui/msgfiltr.h b/private/oleutest/letest/ole2ui/msgfiltr.h
new file mode 100644
index 000000000..a542d5294
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/msgfiltr.h
@@ -0,0 +1,64 @@
+/*************************************************************************
+**
+** OLE 2 Utility Code
+**
+** msgfiltr.h
+**
+** This file contains Private definitions, structures, types, and
+** function prototypes for the OleStdMessageFilter implementation of
+** the IMessageFilter interface.
+** This file is part of the OLE 2.0 User Interface support library.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#if !defined( _MSGFILTR_H_ )
+#define _MSGFILTR_H_
+
+#ifndef RC_INVOKED
+#pragma message ("INCLUDING MSGFILTR.H from " __FILE__)
+#endif /* RC_INVOKED */
+
+// Message Pending callback procedure
+typedef BOOL (CALLBACK* MSGPENDINGPROC)(MSG FAR *);
+
+// HandleInComingCall callback procedure
+typedef DWORD (CALLBACK* HANDLEINCOMINGCALLBACKPROC)
+ (
+ DWORD dwCallType,
+ HTASK htaskCaller,
+ DWORD dwTickCount,
+ LPINTERFACEINFO lpInterfaceInfo
+ );
+
+/* PUBLIC FUNCTIONS */
+STDAPI_(LPMESSAGEFILTER) OleStdMsgFilter_Create(
+ HWND hWndParent,
+ LPTSTR szAppName,
+ MSGPENDINGPROC lpfnCallback,
+ LPFNOLEUIHOOK lpfnOleUIHook // Busy dialog hook callback
+);
+
+STDAPI_(void) OleStdMsgFilter_SetInComingCallStatus(
+ LPMESSAGEFILTER lpThis, DWORD dwInComingCallStatus);
+
+STDAPI_(DWORD) OleStdMsgFilter_GetInComingCallStatus(
+ LPMESSAGEFILTER lpThis);
+
+STDAPI_(HANDLEINCOMINGCALLBACKPROC)
+ OleStdMsgFilter_SetHandleInComingCallbackProc(
+ LPMESSAGEFILTER lpThis,
+ HANDLEINCOMINGCALLBACKPROC lpfnHandleInComingCallback);
+
+STDAPI_(BOOL) OleStdMsgFilter_EnableBusyDialog(
+ LPMESSAGEFILTER lpThis, BOOL fEnable);
+
+STDAPI_(BOOL) OleStdMsgFilter_EnableNotRespondingDialog(
+ LPMESSAGEFILTER lpThis, BOOL fEnable);
+
+STDAPI_(HWND) OleStdMsgFilter_SetParentWindow(
+ LPMESSAGEFILTER lpThis, HWND hWndParent);
+
+
+#endif // _MSGFILTR_H_
diff --git a/private/oleutest/letest/ole2ui/objfdbk.c b/private/oleutest/letest/ole2ui/objfdbk.c
new file mode 100644
index 000000000..65e30f907
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/objfdbk.c
@@ -0,0 +1,246 @@
+/*
+ * OBJFDBK.C
+ *
+ * Miscellaneous API's to generate UI feedback effects for OLE objects. This
+ * is part of the OLE 2.0 User Interface Support Library.
+ * The following feedback effects are supported:
+ * 1. Object selection handles (OleUIDrawHandles)
+ * 2. Open Object window shading (OleUIDrawShading)
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+
+static void DrawHandle(HDC hdc, int x, int y, UINT cSize, BOOL bInvert, BOOL fDraw);
+
+/*
+ * OleUIDrawHandles
+ *
+ * Purpose:
+ * Draw handles or/and boundary around Container Object when selected
+ *
+ * Parameters:
+ * lpRect Dimensions of Container Object
+ * hdc HDC of Container Object (MM_TEXT mapping mode)
+ * dwFlags-
+ * Exclusive flags
+ * OLEUI_HANDLES_INSIDE Draw handles on inside of rect
+ * OLEUI_HANDLES_OUTSIDE Draw handles on outside of rect
+ * Optional flags
+ * OLEUI_HANDLES_NOBORDER Draw handles only, no rect
+ * OLEUI_HANDLES_USEINVERSE
+ * use invert for handles and rect, o.t. use COLOR_WINDOWTEXT
+ * cSize size of handle box
+ * fDraw Draw if TRUE, erase if FALSE
+ *
+ * Return Value: null
+ *
+ */
+STDAPI_(void) OleUIDrawHandles(
+ LPRECT lpRect,
+ HDC hdc,
+ DWORD dwFlags,
+ UINT cSize,
+ BOOL fDraw
+)
+{
+ HBRUSH hbr;
+ RECT rc;
+ int bkmodeOld;
+ BOOL bInvert = (BOOL) (dwFlags & OLEUI_HANDLES_USEINVERSE);
+
+ CopyRect((LPRECT)&rc, lpRect);
+
+ bkmodeOld = SetBkMode(hdc, TRANSPARENT);
+
+ if (dwFlags & OLEUI_HANDLES_OUTSIDE)
+ InflateRect((LPRECT)&rc, cSize - 1, cSize - 1);
+
+ // Draw the handles inside the rectangle boundary
+ DrawHandle(hdc, rc.left, rc.top, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.left, rc.top+(rc.bottom-rc.top-cSize)/2, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.left, rc.bottom-cSize, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.left+(rc.right-rc.left-cSize)/2, rc.top, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.left+(rc.right-rc.left-cSize)/2, rc.bottom-cSize, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.right-cSize, rc.top, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.right-cSize, rc.top+(rc.bottom-rc.top-cSize)/2, cSize, bInvert, fDraw);
+ DrawHandle(hdc, rc.right-cSize, rc.bottom-cSize, cSize, bInvert, fDraw);
+
+ if (!(dwFlags & OLEUI_HANDLES_NOBORDER)) {
+ if (fDraw)
+ hbr = GetStockObject(BLACK_BRUSH);
+ else
+ hbr = GetStockObject(WHITE_BRUSH);
+
+ FrameRect(hdc, lpRect, hbr);
+ }
+
+ SetBkMode(hdc, bkmodeOld);
+}
+
+
+
+/*
+ * DrawHandle
+ *
+ * Purpose:
+ * Draw a handle box at the specified coordinate
+ *
+ * Parameters:
+ * hdc HDC to be drawn into
+ * x, y upper left corner coordinate of the handle box
+ * cSize size of handle box
+ * bInvert use InvertRect() if TRUE, otherwise use Rectangle()
+ * fDraw Draw if TRUE, erase if FALSE, ignored if bInvert is TRUE
+ *
+ * Return Value: null
+ *
+ */
+static void DrawHandle(HDC hdc, int x, int y, UINT cSize, BOOL bInvert, BOOL fDraw)
+{
+ HBRUSH hbr;
+ HBRUSH hbrOld;
+ HPEN hpen;
+ HPEN hpenOld;
+ RECT rc;
+
+
+ if (!bInvert) {
+ if (fDraw) {
+ hpen = GetStockObject(BLACK_PEN);
+ hbr = GetStockObject(BLACK_BRUSH);
+ } else {
+ hpen = GetStockObject(WHITE_PEN);
+ hbr = GetStockObject(WHITE_PEN);
+ }
+
+ hpenOld = SelectObject(hdc, hpen);
+ hbrOld = SelectObject(hdc, hbr);
+ Rectangle(hdc, x, y, x+cSize, y+cSize);
+ SelectObject(hdc, hpenOld);
+ SelectObject(hdc, hbrOld);
+ }
+ else {
+ rc.left = x;
+ rc.top = y;
+ rc.right = x + cSize;
+ rc.bottom = y + cSize;
+ InvertRect(hdc, (LPRECT)&rc);
+ }
+}
+
+
+/*
+ * OleUIDrawShading
+ *
+ * Purpose:
+ * Shade the object when it is in in-place editing. Borders are drawn
+ * on the Object rectangle. The right and bottom edge of the rectangle
+ * are excluded in the drawing.
+ *
+ * Parameters:
+ * lpRect Dimensions of Container Object
+ * hdc HDC for drawing
+ * dwFlags-
+ * Exclusive flags
+ * OLEUI_SHADE_FULLRECT Shade the whole rectangle
+ * OLEUI_SHADE_BORDERIN Shade cWidth pixels inside rect
+ * OLEUI_SHADE_BORDEROUT Shade cWidth pixels outside rect
+ * Optional flags
+ * OLEUI_SHADE_USEINVERSE
+ * use PATINVERT instead of the hex value
+ * cWidth width of border in pixel
+ *
+ * Return Value: null
+ *
+ */
+STDAPI_(void) OleUIDrawShading(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cWidth)
+{
+ HBRUSH hbr;
+ HBRUSH hbrOld;
+ HBITMAP hbm;
+ RECT rc;
+ WORD wHatchBmp[] = {0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88};
+ COLORREF cvText;
+ COLORREF cvBk;
+
+ hbm = CreateBitmap(8, 8, 1, 1, wHatchBmp);
+ hbr = CreatePatternBrush(hbm);
+ hbrOld = SelectObject(hdc, hbr);
+
+ rc = *lpRect;
+
+ if (dwFlags == OLEUI_SHADE_FULLRECT) {
+ cvText = SetTextColor(hdc, RGB(255, 255, 255));
+ cvBk = SetBkColor(hdc, RGB(0, 0, 0));
+ PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
+ 0x00A000C9L /* DPa */ );
+
+ } else { // either inside or outside rect
+
+ if (dwFlags == OLEUI_SHADE_BORDEROUT)
+ InflateRect((LPRECT)&rc, cWidth - 1, cWidth - 1);
+
+ cvText = SetTextColor(hdc, RGB(255, 255, 255));
+ cvBk = SetBkColor(hdc, RGB(0, 0, 0));
+ PatBlt(hdc, rc.left, rc.top, rc.right - rc.left,
+ cWidth, 0x00A000C9L /* DPa */);
+ PatBlt(hdc, rc.left, rc.top, cWidth, rc.bottom - rc.top,
+ 0x00A000C9L /* DPa */);
+ PatBlt(hdc, rc.right - cWidth, rc.top, cWidth,
+ rc.bottom - rc.top, 0x00A000C9L /* DPa */);
+ PatBlt(hdc, rc.left, rc.bottom - cWidth, rc.right-rc.left,
+ cWidth, 0x00A000C9L /* DPa */);
+ }
+
+ SetTextColor(hdc, cvText);
+ SetBkColor(hdc, cvBk);
+ SelectObject(hdc, hbrOld);
+ DeleteObject(hbr);
+ DeleteObject(hbm);
+}
+
+
+/*
+ * OleUIShowObject
+ *
+ * Purpose:
+ * Draw the ShowObject effect around the object
+ *
+ * Parameters:
+ * lprc rectangle for drawing
+ * hdc HDC for drawing
+ * fIsLink linked object (TRUE) or embedding object (FALSE)
+ *
+ * Return Value: null
+ *
+ */
+STDAPI_(void) OleUIShowObject(LPCRECT lprc, HDC hdc, BOOL fIsLink)
+{
+ HPEN hpen;
+ HPEN hpenOld;
+ HBRUSH hbrOld;
+
+ if (!lprc || !hdc)
+ return;
+
+ hpen = fIsLink ? CreatePen(PS_DASH, 1, RGB(0,0,0)) :
+ GetStockObject(BLACK_PEN);
+
+ if (!hpen)
+ return;
+
+ hpenOld = SelectObject(hdc, hpen);
+ hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
+
+ Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);
+
+ SelectObject(hdc, hpenOld);
+ SelectObject(hdc, hbrOld);
+
+ if (fIsLink)
+ DeleteObject(hpen);
+
+}
diff --git a/private/oleutest/letest/ole2ui/ole2ui.c b/private/oleutest/letest/ole2ui/ole2ui.c
new file mode 100644
index 000000000..fd1fc57bc
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/ole2ui.c
@@ -0,0 +1,971 @@
+/*
+ * OLE2UI.C
+ *
+ * Contains initialization routines and miscellaneous API implementations for
+ * the OLE 2.0 User Interface Support Library.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+
+#include "ole2ui.h"
+#include "common.h"
+#include "utility.h"
+#include "resimage.h"
+#include "iconbox.h"
+#include <commdlg.h>
+
+#define WINDLL 1 // make far pointer version of stdargs.h
+#include <stdarg.h>
+
+// NOTE: If this code is being compiled for a DLL, then we need to define
+// our OLE2UI debug symbols here (with the OLEDBGDATA_MAIN macro). If we're
+// compiling for a static LIB, then the application we link to must
+// define these symbols -- we just need to make an external reference here
+// (with the macro OLEDBGDATA).
+
+#ifdef DLL_VER
+OLEDBGDATA_MAIN(TEXT("OLE2UI"))
+#else
+OLEDBGDATA
+#endif
+
+//The DLL instance handle shared amongst all dialogs.
+HINSTANCE ghInst;
+
+//Registered messages for use with all the dialogs, registered in LibMain
+UINT uMsgHelp=0;
+UINT uMsgEndDialog=0;
+UINT uMsgBrowse=0;
+UINT uMsgChangeIcon=0;
+UINT uMsgFileOKString=0;
+UINT uMsgCloseBusyDlg=0;
+
+//Clipboard formats used by PasteSpecial
+UINT cfObjectDescriptor;
+UINT cfLinkSrcDescriptor;
+UINT cfEmbedSource;
+UINT cfEmbeddedObject;
+UINT cfLinkSource;
+UINT cfOwnerLink;
+UINT cfFileName;
+
+// local function prototypes
+BOOL CALLBACK EXPORT PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK EXPORT UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
+
+
+// local definition
+#define WM_U_UPDATELINK WM_USER
+
+
+// local structure definition
+typedef struct tagUPDATELINKS
+{
+ LPOLEUILINKCONTAINER lpOleUILinkCntr; // pointer to Link Container
+ UINT cLinks; // total number of links
+ UINT cUpdated; // number of links updated
+ DWORD dwLink; // pointer to link
+ BOOL fError; // error flag
+ LPTSTR lpszTitle; // caption for dialog box
+} UPDATELINKS, *PUPDATELINKS, FAR *LPUPDATELINKS;
+
+
+/*
+ * OleUIInitialize
+ *
+ * NOTE: This function should only be called by your application IF it is
+ * using the static-link version of this library. If the DLL version is
+ * being used, this function is automatically called from the OLE2UI DLL's
+ * LibMain.
+ *
+ * Purpose:
+ * Initializes the OLE UI Library. Registers the OLE clipboard formats
+ * used in the Paste Special dialog, registers private custom window
+ * messages, and registers window classes of the "Result Image"
+ * and "Icon Box" custom controls used in the UI dialogs.
+ *
+ * Parameters:
+ *
+ * hInstance HINSTANCE of the module where the UI library resources
+ * and Dialog Procedures are contained. If you are calling
+ * this function yourself, this should be the instance handle
+ * of your application.
+ *
+ * hPrevInst HINSTANCE of the previous application instance.
+ * This is the parameter passed in to your WinMain. For
+ * the DLL version, this should always be set to zero (for
+ * WIN16 DLLs).
+ *
+ * lpszClassIconBox
+ * LPTSTR containing the name you assigned to the symbol
+ * SZCLASSICONBOX (this symbol is defined in UICLASS.H
+ * which is generated in the MAKEFILE).
+ *
+ * This name is used as the window class name
+ * when registering the IconBox custom control used in the
+ * UI dialogs. In order to handle mutliple apps running
+ * with this library, you must make this name unique to your
+ * application.
+ *
+ * For the DLL version: Do NOT call this function directly
+ * from your application, it is called automatically from
+ * the DLL's LibMain.
+ *
+ * For the static library version: This should be set to
+ * the symbol SZCLASSICONBOX. This symbol is defined in
+ * UICLASS.H.
+ *
+ * lpszClassResImage
+ * LPTSTR containing the name you assigned to the symbol
+ * SZCLASSRESULTIMAGE. See the description of
+ * lpszClassIconBox above for more info.
+ *
+ * Return Value:
+ * BOOL TRUE if initialization was successful.
+ * FALSE if either the "Magic Number" did not verify, or one of
+ * the window classes could not be registered. If the
+ * "Magic Number" did not verify, then the resources
+ * in your module are of a different version than the
+ * ones you compiled with.
+ */
+
+STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance,
+ HINSTANCE hPrevInst,
+ LPTSTR lpszClassIconBox,
+ LPTSTR lpszClassResImage)
+{
+ HRSRC hr;
+ HGLOBAL hg;
+ LPWORD lpdata;
+
+ OleDbgOut1(TEXT("OleUIInitialize called.\r\n"));
+ ghInst=hInstance;
+
+ // Verify that we have the correct resources added to our application
+ // by checking the "VERIFICATION" resource with the magic number we've
+ // compiled into our app.
+
+ OutputDebugString(TEXT("Entering OleUIInitialize\n"));
+
+ if ((hr = FindResource(hInstance, TEXT("VERIFICATION"), RT_RCDATA)) == NULL)
+ goto ResourceLoadError;
+
+ if ((hg = LoadResource(hInstance, hr)) == NULL)
+ goto ResourceLoadError;
+
+ if ((lpdata = (LPWORD)LockResource(hg)) == NULL)
+ goto ResourceLockError;
+
+ if ((WORD)*lpdata != (WORD)OLEUI_VERSION_MAGIC)
+ goto ResourceReadError;
+
+ // OK, resource versions match. Contine on.
+ UnlockResource(hg);
+ FreeResource(hg);
+ OleDbgOut1(TEXT("OleUIInitialize: Resource magic number verified.\r\n"));
+
+ // Register messages we need for the dialogs. If
+ uMsgHelp =RegisterWindowMessage(SZOLEUI_MSG_HELP);
+ uMsgEndDialog =RegisterWindowMessage(SZOLEUI_MSG_ENDDIALOG);
+ uMsgBrowse =RegisterWindowMessage(SZOLEUI_MSG_BROWSE);
+ uMsgChangeIcon=RegisterWindowMessage(SZOLEUI_MSG_CHANGEICON);
+ uMsgFileOKString = RegisterWindowMessage(FILEOKSTRING);
+ uMsgCloseBusyDlg = RegisterWindowMessage(SZOLEUI_MSG_CLOSEBUSYDIALOG);
+
+ // Register Clipboard Formats used by PasteSpecial dialog.
+ cfObjectDescriptor = RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
+ cfLinkSrcDescriptor= RegisterClipboardFormat(CF_LINKSRCDESCRIPTOR);
+ cfEmbedSource = RegisterClipboardFormat(CF_EMBEDSOURCE);
+ cfEmbeddedObject = RegisterClipboardFormat(CF_EMBEDDEDOBJECT);
+ cfLinkSource = RegisterClipboardFormat(CF_LINKSOURCE);
+ cfOwnerLink = RegisterClipboardFormat(CF_OWNERLINK);
+ cfFileName = RegisterClipboardFormat(CF_FILENAME);
+
+ if (!FResultImageInitialize(hInstance, hPrevInst, lpszClassResImage))
+ {
+ OleDbgOut1(TEXT("OleUIInitialize: FResultImageInitialize failed. Terminating.\r\n"));
+ return 0;
+ }
+
+ if (!FIconBoxInitialize(hInstance, hPrevInst, lpszClassIconBox))
+ {
+ OleDbgOut1(TEXT("OleUIInitialize: FIconBoxInitialize failed. Terminating.\r\n"));
+ return 0;
+ }
+
+ return TRUE;
+
+ResourceLoadError:
+ OleDbgOut1(TEXT("OleUIInitialize: ERROR - Unable to find version verification resource.\r\n"));
+ return FALSE;
+
+ResourceLockError:
+ OleDbgOut1(TEXT("OleUIInitialize: ERROR - Unable to lock version verification resource.\r\n"));
+ FreeResource(hg);
+ return FALSE;
+
+ResourceReadError:
+ OleDbgOut1(TEXT("OleUIInitialize: ERROR - Version verification values did not compare.\r\n"));
+
+ {TCHAR buf[255];
+ wsprintf(buf, TEXT("resource read 0x%X, my value is 0x%X\n"), (WORD)*lpdata, (WORD)OLEUI_VERSION_MAGIC);
+ OutputDebugString(buf);
+ }
+
+ UnlockResource(hg);
+ FreeResource(hg);
+ return FALSE;
+}
+
+
+/*
+ * OleUIUnInitialize
+ *
+ * NOTE: This function should only be called by your application IF it is using
+ * the static-link version of this library. If the DLL version is being used,
+ * this function is automatically called from the DLL's LibMain.
+ *
+ * Purpose:
+ * Uninitializes OLE UI libraries. Deletes any resources allocated by the
+ * library.
+ *
+ * Return Value:
+ * BOOL TRUE if successful, FALSE if not. Current implementation always
+ * returns TRUE.
+ */
+
+
+STDAPI_(BOOL) OleUIUnInitialize()
+{
+ IconBoxUninitialize();
+ ResultImageUninitialize();
+
+ return TRUE;
+}
+
+
+/*
+ * OleUIAddVerbMenu
+ *
+ * Purpose:
+ * Add the Verb menu for the specified object to the given menu. If the
+ * object has one verb, we directly add the verb to the given menu. If
+ * the object has multiple verbs we create a cascading sub-menu.
+ *
+ * Parameters:
+ * lpObj LPOLEOBJECT pointing to the selected object. If this
+ * is NULL, then we create a default disabled menu item.
+ *
+ * lpszShortType LPTSTR with short type name (AuxName==2) corresponding
+ * to the lpOleObj. if the string is NOT known, then NULL
+ * may be passed. if NULL is passed, then
+ * IOleObject::GetUserType will be called to retrieve it.
+ * if the caller has the string handy, then it is faster
+ * to pass it in.
+ *
+ * hMenu HMENU in which to make modifications.
+ *
+ * uPos Position of the menu item
+ *
+ * uIDVerbMin UINT ID value at which to start the verbs.
+ * verb_0 = wIDMVerbMin + verb_0
+ * verb_1 = wIDMVerbMin + verb_1
+ * verb_2 = wIDMVerbMin + verb_2
+ * etc.
+ * uIDVerbMax UINT maximum ID value allowed for object verbs.
+ * if uIDVerbMax==0 then any ID value is allowed
+ *
+ * bAddConvert BOOL specifying whether or not to add a "Convert" item
+ * to the bottom of the menu (with a separator).
+ *
+ * idConvert UINT ID value to use for the Convert menu item, if
+ * bAddConvert is TRUE.
+ *
+ * lphMenu HMENU FAR * of the cascading verb menu if it's created.
+ * If there is only one verb, this will be filled with NULL.
+ *
+ *
+ * Return Value:
+ * BOOL TRUE if lpObj was valid and we added at least one verb
+ * to the menu. FALSE if lpObj was NULL and we created
+ * a disabled default menu item
+ */
+
+STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,
+ LPTSTR lpszShortType,
+ HMENU hMenu,
+ UINT uPos,
+ UINT uIDVerbMin,
+ UINT uIDVerbMax,
+ BOOL bAddConvert,
+ UINT idConvert,
+ HMENU FAR *lphMenu)
+{
+ LPPERSISTSTORAGE lpPS=NULL;
+ LPENUMOLEVERB lpEnumOleVerb = NULL;
+ OLEVERB oleverb;
+ LPUNKNOWN lpUnk;
+ LPTSTR lpszShortTypeName = lpszShortType;
+ LPTSTR lpszVerbName = NULL;
+ HRESULT hrErr;
+ BOOL fStatus;
+ BOOL fIsLink = FALSE;
+ BOOL fResult = TRUE;
+ BOOL fAddConvertItem = FALSE;
+ int cVerbs = 0;
+ UINT uFlags = MF_BYPOSITION;
+ static BOOL fFirstTime = TRUE;
+ static TCHAR szBuffer[OLEUI_OBJECTMENUMAX];
+ static TCHAR szNoObjectCmd[OLEUI_OBJECTMENUMAX];
+ static TCHAR szObjectCmd1Verb[OLEUI_OBJECTMENUMAX];
+ static TCHAR szLinkCmd1Verb[OLEUI_OBJECTMENUMAX];
+ static TCHAR szObjectCmdNVerb[OLEUI_OBJECTMENUMAX];
+ static TCHAR szLinkCmdNVerb[OLEUI_OBJECTMENUMAX];
+ static TCHAR szUnknown[OLEUI_OBJECTMENUMAX];
+ static TCHAR szEdit[OLEUI_OBJECTMENUMAX];
+ static TCHAR szConvert[OLEUI_OBJECTMENUMAX];
+
+ *lphMenu=NULL;
+
+ // Set fAddConvertItem flag
+ if (bAddConvert & (idConvert != 0))
+ fAddConvertItem = TRUE;
+
+ // only need to load the strings the 1st time
+ if (fFirstTime) {
+ if (0 == LoadString(ghInst, IDS_OLE2UIEDITNOOBJCMD,
+ (LPTSTR)szNoObjectCmd, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+ if (0 == LoadString(ghInst, IDS_OLE2UIEDITLINKCMD_1VERB,
+ (LPTSTR)szLinkCmd1Verb, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+ if (0 == LoadString(ghInst, IDS_OLE2UIEDITOBJECTCMD_1VERB,
+ (LPTSTR)szObjectCmd1Verb, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+
+ if (0 == LoadString(ghInst, IDS_OLE2UIEDITLINKCMD_NVERB,
+ (LPTSTR)szLinkCmdNVerb, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+ if (0 == LoadString(ghInst, IDS_OLE2UIEDITOBJECTCMD_NVERB,
+ (LPTSTR)szObjectCmdNVerb, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+
+ if (0 == LoadString(ghInst, IDS_OLE2UIUNKNOWN,
+ (LPTSTR)szUnknown, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+
+ if (0 == LoadString(ghInst, IDS_OLE2UIEDIT,
+ (LPTSTR)szEdit, OLEUI_OBJECTMENUMAX))
+ return FALSE;
+
+ if ( (0 == LoadString(ghInst, IDS_OLE2UICONVERT,
+ (LPTSTR)szConvert, OLEUI_OBJECTMENUMAX)) && fAddConvertItem)
+ return FALSE;
+
+ fFirstTime = FALSE;
+ }
+
+ // Delete whatever menu may happen to be here already.
+ DeleteMenu(hMenu, uPos, uFlags);
+
+ if (!lpOleObj)
+ goto AVMError;
+
+ if (! lpszShortTypeName) {
+ // get the Short form of the user type name for the menu
+ OLEDBG_BEGIN2(TEXT("IOleObject::GetUserType called\r\n"))
+ hrErr = CallIOleObjectGetUserTypeA(
+ lpOleObj,
+ USERCLASSTYPE_SHORT,
+ (LPTSTR FAR*)&lpszShortTypeName
+ );
+ OLEDBG_END2
+
+ if (NOERROR != hrErr) {
+ OleDbgOutHResult(TEXT("IOleObject::GetUserType returned"), hrErr);
+ }
+ }
+
+ // check if the object is a link (it is a link if it support IOleLink)
+ hrErr = lpOleObj->lpVtbl->QueryInterface(
+ lpOleObj,
+ &IID_IOleLink,
+ (LPVOID FAR*)&lpUnk
+ );
+ if (NOERROR == hrErr) {
+ fIsLink = TRUE;
+ OleStdRelease(lpUnk);
+ }
+
+ // Get the verb enumerator from the OLE object
+ OLEDBG_BEGIN2(TEXT("IOleObject::EnumVerbs called\r\n"))
+ hrErr = lpOleObj->lpVtbl->EnumVerbs(
+ lpOleObj,
+ (LPENUMOLEVERB FAR*)&lpEnumOleVerb
+ );
+ OLEDBG_END2
+
+ if (NOERROR != hrErr) {
+ OleDbgOutHResult(TEXT("IOleObject::EnumVerbs returned"), hrErr);
+ }
+
+ if (!(*lphMenu = CreatePopupMenu()))
+ goto AVMError;
+
+ // loop through all verbs
+ while (lpEnumOleVerb != NULL) { // forever
+ hrErr = lpEnumOleVerb->lpVtbl->Next(
+ lpEnumOleVerb,
+ 1,
+ (LPOLEVERB)&oleverb,
+ NULL
+ );
+ if (NOERROR != hrErr)
+ break; // DONE! no more verbs
+
+ /* OLE2NOTE: negative verb numbers and verbs that do not
+ ** indicate ONCONTAINERMENU should NOT be put on the verb menu
+ */
+ if (oleverb.lVerb < 0 ||
+ ! (oleverb.grfAttribs & OLEVERBATTRIB_ONCONTAINERMENU)) {
+
+ /* OLE2NOTE: we must still free the verb name string */
+ if (oleverb.lpszVerbName)
+ OleStdFree(oleverb.lpszVerbName);
+ continue;
+ }
+
+ // we must free the previous verb name string
+ if (lpszVerbName)
+ OleStdFreeString(lpszVerbName, NULL);
+
+ CopyAndFreeOLESTR(oleverb.lpszVerbName, &lpszVerbName);
+
+ if ( 0 == uIDVerbMax ||
+ (uIDVerbMax >= uIDVerbMin+(UINT)oleverb.lVerb) ) {
+ fStatus = InsertMenu(
+ *lphMenu,
+ (UINT)-1,
+ MF_BYPOSITION | (UINT)oleverb.fuFlags,
+ uIDVerbMin+(UINT)oleverb.lVerb,
+ (LPTSTR)lpszVerbName
+ );
+ if (! fStatus)
+ goto AVMError;
+
+ cVerbs++;
+ }
+ }
+
+ // Add the separator and "Convert" menu item.
+ if (fAddConvertItem) {
+
+ if (0 == cVerbs) {
+ LPTSTR lpsz;
+
+ // if object has no verbs, then use "Convert" as the obj's verb
+ lpsz = lpszVerbName = OleStdCopyString(szConvert, NULL);
+ uIDVerbMin = idConvert;
+
+ // remove "..." from "Convert..." string; it will be added later
+ if (lpsz) {
+ while(*lpsz && *lpsz != TEXT('.'))
+ lpsz++;
+ *lpsz = TEXT('\0');
+ }
+ }
+
+ if (cVerbs > 0) {
+ fStatus = InsertMenu(*lphMenu,
+ (UINT)-1,
+ MF_BYPOSITION | MF_SEPARATOR,
+ (UINT)0,
+ (LPCTSTR)NULL);
+ if (! fStatus)
+ goto AVMError;
+ }
+
+ /* add convert menu */
+ fStatus = InsertMenu(*lphMenu,
+ (UINT)-1,
+ MF_BYPOSITION,
+ idConvert,
+ (LPCTSTR)szConvert);
+ if (! fStatus)
+ goto AVMError;
+
+ cVerbs++;
+ }
+
+
+ /*
+ * Build the appropriate menu based on the number of verbs found
+ *
+ * NOTE: Localized verb menus may require a different format.
+ * to assist in localization of the single verb case, the
+ * szLinkCmd1Verb and szObjectCmd1Verb format strings start
+ * with either a '0' (note: NOT '\0'!) or a '1':
+ * leading '0' -- verb type
+ * leading '1' -- type verb
+ */
+
+ if (cVerbs == 0) {
+
+ // there are NO verbs (not even Convert...). set the menu to be
+ // "<short type> &Object/Link" and gray it out.
+ wsprintf(
+ szBuffer,
+ (fIsLink ? (LPTSTR)szLinkCmdNVerb:(LPTSTR)szObjectCmdNVerb),
+ (lpszShortTypeName ? lpszShortTypeName : (LPTSTR) TEXT(""))
+ );
+ uFlags |= MF_GRAYED;
+
+#if defined( OBSOLETE )
+ //No verbs. Create a default using Edit as the verb.
+ LPTSTR lpsz = (fIsLink ? szLinkCmd1Verb : szObjectCmd1Verb);
+
+ if (*lpsz == TEXT('0')) {
+ wsprintf(szBuffer, lpsz+1, (LPSTR)szEdit,
+ (lpszShortTypeName ? lpszShortTypeName : (LPTSTR) TEXT(""))
+ );
+ }
+ else {
+ wsprintf(szBuffer, lpsz+1,
+ (lpszShortTypeName ? lpszShortTypeName : (LPTSTR) TEXT("")),
+ (LPTSTR)szEdit
+ );
+ }
+#endif
+
+ fResult = FALSE;
+ DestroyMenu(*lphMenu);
+ *lphMenu = NULL;
+
+ }
+ else if (cVerbs == 1) {
+ //One verb without Convert, one item.
+ LPTSTR lpsz = (fIsLink ? szLinkCmd1Verb : szObjectCmd1Verb);
+
+ if (*lpsz == TEXT('0')) {
+ wsprintf(szBuffer, lpsz+1, lpszVerbName,
+ (lpszShortTypeName ? lpszShortTypeName : (LPTSTR) TEXT(""))
+ );
+ }
+ else {
+ wsprintf(szBuffer, lpsz+1,
+ (lpszShortTypeName ? lpszShortTypeName : (LPTSTR) TEXT("")),
+ lpszVerbName
+ );
+ }
+
+ // if only "verb" is "Convert..." then append the ellipses
+ if (fAddConvertItem)
+ lstrcat(szBuffer, TEXT("..."));
+
+ DestroyMenu(*lphMenu);
+ *lphMenu=NULL;
+ }
+ else {
+
+ //Multiple verbs or one verb with Convert, add the cascading menu
+ wsprintf(
+ szBuffer,
+ (fIsLink ? (LPTSTR)szLinkCmdNVerb:(LPTSTR)szObjectCmdNVerb),
+ (lpszShortTypeName ? lpszShortTypeName : (LPTSTR) TEXT(""))
+ );
+ uFlags |= MF_ENABLED | MF_POPUP;
+ uIDVerbMin=(UINT)*lphMenu;
+ }
+
+ if (!InsertMenu(hMenu, uPos, uFlags, uIDVerbMin, (LPTSTR)szBuffer))
+
+AVMError:
+ {
+ InsertMenu(hMenu, uPos, MF_GRAYED | uFlags,
+ uIDVerbMin, (LPTSTR)szNoObjectCmd);
+#if defined( OBSOLETE )
+ HMENU hmenuDummy = CreatePopupMenu();
+
+ InsertMenu(hMenu, uPos, MF_GRAYED | MF_POPUP | uFlags,
+ (UINT)hmenuDummy, (LPTSTR)szNoObjectCmd);
+#endif
+ fResult = FALSE;
+ }
+
+ if (lpszVerbName)
+ OleStdFreeString(lpszVerbName, NULL);
+ if (!lpszShortType && lpszShortTypeName)
+ OleStdFreeString(lpszShortTypeName, NULL);
+ if (lpEnumOleVerb)
+ lpEnumOleVerb->lpVtbl->Release(lpEnumOleVerb);
+ return fResult;
+}
+
+
+/* PromptUserDlgProc
+ * -----------------
+ *
+ * Purpose:
+ * Dialog procedure used by OleUIPromptUser(). Returns when a button is
+ * clicked in the dialog box and the button id is return.
+ *
+ * Parameters:
+ * hDlg
+ * iMsg
+ * wParam
+ * lParam
+ *
+ * Returns:
+ *
+ */
+BOOL CALLBACK EXPORT PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (iMsg) {
+ case WM_INITDIALOG:
+ {
+ LPTSTR lpszTitle;
+ TCHAR szBuf[256];
+ TCHAR szFormat[256];
+ va_list *parglist;
+
+ if (!lParam) {
+ EndDialog(hDlg, -1);
+ return FALSE;
+ }
+
+ //
+ // lParam is really a va_list *. We called va_start and va_end in
+ // the function that calls this.
+ //
+
+ parglist = (va_list *) lParam;
+
+ lpszTitle = va_arg(*parglist, LPTSTR);
+ SetWindowText(hDlg, lpszTitle);
+
+ GetDlgItemText(hDlg, ID_PU_TEXT,(LPTSTR)szFormat,sizeof(szFormat)/sizeof(TCHAR));
+ wvsprintf((LPTSTR)szBuf, (LPTSTR)szFormat, *parglist);
+
+
+ SetDlgItemText(hDlg, ID_PU_TEXT, (LPTSTR)szBuf);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ EndDialog(hDlg, wParam);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+
+/* OleUIPromptUser
+ * ---------------
+ *
+ * Purpose:
+ * Popup a dialog box with the specified template and returned the
+ * response (button id) from the user.
+ *
+ * Parameters:
+ * nTemplate resource number of the dialog
+ * hwndParent parent of the dialog box
+ * ... title of the dialog box followed by argument list
+ * for the format string in the static control
+ * (ID_PU_TEXT) of the dialog box.
+ * The caller has to make sure that the correct number
+ * and type of argument are passed in.
+ *
+ * Returns:
+ * button id selected by the user (template dependent)
+ *
+ * Comments:
+ * the following message dialog boxes are supported:
+ *
+ * IDD_LINKSOURCEUNAVAILABLE -- Link source is unavailable
+ * VARARG Parameters:
+ * None.
+ * Used for the following error codes:
+ * OLE_E_CANT_BINDTOSOURCE
+ * STG_E_PATHNOTFOUND
+ * (sc >= MK_E_FIRST) && (sc <= MK_E_LAST) -- any Moniker error
+ * any unknown error if object is a link
+ *
+ * IDD_SERVERNOTFOUND -- server registered but NOT found
+ * VARARG Parameters:
+ * LPSTR lpszUserType -- user type name of object
+ * Used for the following error codes:
+ * CO_E_APPNOTFOUND
+ * CO_E_APPDIDNTREG
+ * any unknown error if object is an embedded object
+ *
+ * IDD_SERVERNOTREG -- server NOT registered
+ * VARARG Parameters:
+ * LPSTR lpszUserType -- user type name of object
+ * Used for the following error codes:
+ * REGDB_E_CLASSNOTREG
+ * OLE_E_STATIC -- static object with no server registered
+ *
+ * IDD_LINKTYPECHANGED -- class of link source changed since last binding
+ * VARARG Parameters:
+ * LPSTR lpszUserType -- user type name of ole link source
+ * Used for the following error codes:
+ * OLE_E_CLASSDIFF
+ *
+ * IDD_LINKTYPECHANGED -- class of link source changed since last binding
+ * VARARG Parameters:
+ * LPSTR lpszUserType -- user type name of ole link source
+ * Used for the following error codes:
+ * OLE_E_CLASSDIFF
+ *
+ * IDD_OUTOFMEMORY -- out of memory
+ * VARARG Parameters:
+ * None.
+ * Used for the following error codes:
+ * E_OUTOFMEMORY
+ *
+ */
+int EXPORT FAR CDECL OleUIPromptUser(int nTemplate, HWND hwndParent, ...)
+{
+ int nRet;
+ va_list arglist;
+ LPARAM lParam;
+
+ //
+ // We want to pass the variable list of arguments to PrompUserDlgProc,
+ // but we can't just pass arglist because arglist is not always the
+ // same size as an LPARAM (e.g. on Alpha va_list is a structure).
+ // So, we pass the a pointer to the arglist instead.
+ //
+
+ va_start(arglist, hwndParent);
+ lParam = (LPARAM) &arglist;
+
+ nRet = DialogBoxParam(ghInst, MAKEINTRESOURCE(nTemplate), hwndParent,
+ PromptUserDlgProc, lParam);
+
+ va_end(arglist);
+
+ return nRet;
+}
+
+
+
+/* UpdateLinksDlgProc
+ * ------------------
+ *
+ * Purpose:
+ * Dialog procedure used by OleUIUpdateLinks(). It will enumerate all
+ * all links in the container and updates all automatic links.
+ * Returns when the Stop Button is clicked in the dialog box or when all
+ * links are updated
+ *
+ * Parameters:
+ * hDlg
+ * iMsg
+ * wParam
+ * lParam pointer to the UPDATELINKS structure
+ *
+ * Returns:
+ *
+ */
+BOOL CALLBACK EXPORT UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ LPUPDATELINKS FAR* lplpUL = NULL;
+ HANDLE gh;
+ static BOOL fAbort = FALSE;
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ gh = RemoveProp(hDlg, STRUCTUREPROP);
+ if (NULL!=gh) {
+ GlobalUnlock(gh);
+ GlobalFree(gh);
+ }
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ switch (iMsg) {
+ case WM_INITDIALOG:
+ {
+ gh=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(LPUPDATELINKS));
+ SetProp(hDlg, STRUCTUREPROP, gh);
+
+ if (NULL==gh)
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);
+ return FALSE;
+ }
+
+ fAbort = FALSE;
+ lplpUL = (LPUPDATELINKS FAR*)GlobalLock(gh);
+
+ if (lplpUL) {
+ *lplpUL = (LPUPDATELINKS)lParam;
+ SetWindowText(hDlg, (*lplpUL)->lpszTitle);
+ SetTimer(hDlg, 1, UPDATELINKS_STARTDELAY, NULL);
+ return TRUE;
+ } else {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);
+ return FALSE;
+ }
+ }
+
+ case WM_TIMER:
+ KillTimer(hDlg, 1);
+ gh = GetProp(hDlg, STRUCTUREPROP);
+
+ if (NULL!=gh) {
+ // gh was locked previously, lock and unlock to get lplpUL
+ lplpUL = GlobalLock(gh);
+ GlobalUnlock(gh);
+ }
+ if (! fAbort && lplpUL)
+ PostMessage(hDlg, WM_U_UPDATELINK, 0, (LPARAM)(*lplpUL));
+ else
+ PostMessage(hDlg,uMsgEndDialog,OLEUI_CANCEL,0L);
+
+ return 0;
+
+ case WM_COMMAND: // Stop button
+ fAbort = TRUE;
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ return TRUE;
+
+ case WM_U_UPDATELINK:
+ {
+ HRESULT hErr;
+ int nPercent;
+ RECT rc;
+ TCHAR szPercent[5]; // 0% to 100%
+ HBRUSH hbr;
+ HDC hDC;
+ HWND hwndMeter;
+ MSG msg;
+ DWORD dwUpdateOpt;
+ LPUPDATELINKS lpUL = (LPUPDATELINKS)lParam;
+
+ lpUL->dwLink=lpUL->lpOleUILinkCntr->lpVtbl->GetNextLink(
+ lpUL->lpOleUILinkCntr,
+ lpUL->dwLink
+ );
+
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (! IsDialogMessage(hDlg, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ if (fAbort)
+ return FALSE;
+
+ if (!lpUL->dwLink) { // all links processed
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ return TRUE;
+ }
+
+ hErr = lpUL->lpOleUILinkCntr->lpVtbl->GetLinkUpdateOptions(
+ lpUL->lpOleUILinkCntr,
+ lpUL->dwLink,
+ (LPDWORD)&dwUpdateOpt
+ );
+
+ if ((hErr == NOERROR) && (dwUpdateOpt == OLEUPDATE_ALWAYS)) {
+
+ hErr = lpUL->lpOleUILinkCntr->lpVtbl->UpdateLink(
+ lpUL->lpOleUILinkCntr,
+ lpUL->dwLink,
+ FALSE, // fMessage
+ FALSE // ignored
+ );
+ lpUL->fError |= (hErr != NOERROR);
+ lpUL->cUpdated++;
+
+ nPercent = lpUL->cUpdated * 100 / lpUL->cLinks;
+ if (nPercent <= 100) { // do NOT advance % beyond 100%
+ // update percentage
+ wsprintf((LPTSTR)szPercent, TEXT("%d%%"), nPercent);
+ SetDlgItemText(hDlg, ID_PU_PERCENT, (LPTSTR)szPercent);
+
+ // update indicator
+ hwndMeter = GetDlgItem(hDlg, ID_PU_METER);
+ GetClientRect(hwndMeter, (LPRECT)&rc);
+ InflateRect((LPRECT)&rc, -1, -1);
+ rc.right = (rc.right - rc.left) * nPercent / 100 + rc.left;
+ hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
+ if (hbr) {
+ hDC = GetDC(hwndMeter);
+ if (hDC) {
+ FillRect(hDC, (LPRECT)&rc, hbr);
+ ReleaseDC(hwndMeter, hDC);
+ }
+ DeleteObject(hbr);
+ }
+ }
+ }
+
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (! IsDialogMessage(hDlg, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ PostMessage(hDlg, WM_U_UPDATELINK, 0, lParam);
+
+ return TRUE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+
+/* OleUIUpdateLink
+ * ---------------
+ *
+ * Purpose:
+ * Update all links in the Link Container and popup a dialog box which
+ * shows the progress of the updating.
+ * The process is stopped when the user press Stop button or when all
+ * links are processed.
+ *
+ * Parameters:
+ * lpOleUILinkCntr pointer to Link Container
+ * hwndParent parent window of the dialog
+ * lpszTitle title of the dialog box
+ * cLinks total number of links
+ *
+ * Returns:
+ * TRUE all links updated successfully
+ * FALSE otherwise
+ */
+STDAPI_(BOOL) OleUIUpdateLinks(LPOLEUILINKCONTAINER lpOleUILinkCntr, HWND hwndParent, LPTSTR lpszTitle, int cLinks)
+{
+ LPUPDATELINKS lpUL = (LPUPDATELINKS)OleStdMalloc(sizeof(UPDATELINKS));
+ BOOL fError;
+
+ OleDbgAssert(lpOleUILinkCntr && hwndParent && lpszTitle && (cLinks>0));
+ OleDbgAssert(lpUL);
+
+ lpUL->lpOleUILinkCntr = lpOleUILinkCntr;
+ lpUL->cLinks = cLinks;
+ lpUL->cUpdated = 0;
+ lpUL->dwLink = 0;
+ lpUL->fError = FALSE;
+ lpUL->lpszTitle = lpszTitle;
+
+ DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_UPDATELINKS),
+ hwndParent, UpdateLinksDlgProc, (LPARAM)lpUL);
+
+ fError = lpUL->fError;
+ OleStdFree((LPVOID)lpUL);
+
+ return !fError;
+}
diff --git a/private/oleutest/letest/ole2ui/ole2ui.h b/private/oleutest/letest/ole2ui/ole2ui.h
new file mode 100644
index 000000000..9990c79e0
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/ole2ui.h
@@ -0,0 +1,958 @@
+/*
+ * OLE2UI.H
+ *
+ * Published definitions, structures, types, and function prototypes for the
+ * OLE 2.0 User Interface support library.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ */
+
+
+#ifndef _OLE2UI_H_
+#define _OLE2UI_H_
+
+#undef UNICODE
+#undef _UNICODE
+
+#if DBG == 1
+// Lazy way to avoid going through all the files and changing to the
+// new standard.
+#define _DEBUG 1
+#endif // DBG == 1
+
+#ifndef RC_INVOKED
+#pragma message ("Including OLE2UI.H from " __FILE__)
+#endif //RC_INVOKED
+
+// Macro to ensure strings to be UNICODEd in OLE
+#ifdef UNICODE
+ #define OLETEXT(quote) TEXT(quote)
+#else
+ #define OLETEXT(quote) L##quote
+#endif
+
+#if !defined(__cplusplus) && !defined( __TURBOC__)
+// #define NONAMELESSUNION // use strict ANSI standard (for DVOBJ.H)
+#endif
+
+#ifndef INC_OLE2
+ #define INC_OLE2
+#endif
+#include <windows.h>
+#include <shellapi.h>
+#include <ole2.h>
+#include <string.h>
+#include <dlgs.h> //For fileopen dlg; standard include
+#include "olestd.h"
+#include <olethunk.h>
+
+#ifdef __TURBOC__
+#define _getcwd getcwd
+#define _itoa itoa
+#define __max max
+#define _find_t find_t
+#endif // __TURBOC__
+
+#ifdef WIN32
+ #define _fmemset memset
+ #define _fmemcpy memcpy
+ #define _fmemcmp memcmp
+
+ #ifdef UNICODE
+ // UNICODE stuff
+ #define _fstrcpy wcscpy
+ #define _fstrlen wcslen
+ #define _fstrrchr wcschr
+ #define _fstrtok wcstok
+
+ #define _fstrchr wcscpy
+ #define _fstrcpy wcscpy
+
+ // BUGBUG32: isspace function does not seem to work properly
+ //
+ // XXXXX
+ // create a wide character image to match the ANSI isspace
+ #undef isspace
+ #undef iswspace
+ #define iswspace(j) (j==TEXT(' ') || j==TEXT('\t') || j==TEXT('\n'))
+ #define isspace(j) (j==' ' || j=='\t' || j=='\n')
+
+ #else
+ // Win32 doesn't support the following _fstrxxx functions
+ #define _fstrcpy strcpy
+ #define _fstrlen strlen
+ #define _fstrrchr strrchr
+ #define _fstrtok strtok
+
+ #define _fstrchr strchr
+ #define _fstrcpy strcpy
+
+ #endif // UNICODE
+
+#endif // WIN32
+
+#if !defined( EXPORT )
+#ifdef WIN32
+#define EXPORT
+#else
+#define EXPORT __export
+#endif // WIN32
+#endif // !EXPORT
+
+/*
+ * Initialization / Uninitialization routines. OleUIInitialize
+ * must be called prior to using any functions in OLE2UI, and OleUIUnInitialize
+ * must be called before you app shuts down and when you are done using the
+ * library.
+ *
+ * NOTE: If you are using the DLL version of this library, these functions
+ * are automatically called in the DLL's LibMain and WEP, so you should
+ * not call them directly from your application.
+ */
+
+// Backward compatibility with older library
+#define OleUIUninitialize OleUIUnInitialize
+
+STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance,
+ HINSTANCE hPrevInst,
+ LPTSTR lpszClassIconBox,
+ LPTSTR lpszClassResImage);
+STDAPI_(BOOL) OleUIUninitialize(void);
+
+//Dialog Identifiers as passed in Help messages to identify the source.
+#define IDD_INSERTOBJECT 1000
+#define IDD_CHANGEICON 1001
+#define IDD_CONVERT 1002
+#define IDD_PASTESPECIAL 1003
+#define IDD_EDITLINKS 1004
+#define IDD_FILEOPEN 1005
+#define IDD_BUSY 1006
+#define IDD_UPDATELINKS 1007
+#define IDD_CANNOTUPDATELINK 1008
+#define IDD_CHANGESOURCE 1009
+#define IDD_INSERTFILEBROWSE 1010
+#define IDD_CHANGEICONBROWSE 1011
+
+// The following Dialogs are message dialogs used by OleUIPromptUser API
+#define IDD_LINKSOURCEUNAVAILABLE 1020
+#define IDD_SERVERNOTREG 1021
+#define IDD_LINKTYPECHANGED 1022
+#define IDD_SERVERNOTFOUND 1023
+#define IDD_OUTOFMEMORY 1024
+
+// Stringtable identifers
+#define IDS_OLE2UIUNKNOWN 300
+#define IDS_OLE2UILINK 301
+#define IDS_OLE2UIOBJECT 302
+#define IDS_OLE2UIEDIT 303
+#define IDS_OLE2UICONVERT 304
+#define IDS_OLE2UIEDITLINKCMD_1VERB 305
+#define IDS_OLE2UIEDITOBJECTCMD_1VERB 306
+#define IDS_OLE2UIEDITLINKCMD_NVERB 307
+#define IDS_OLE2UIEDITOBJECTCMD_NVERB 308
+#define IDS_OLE2UIEDITNOOBJCMD 309
+// def. icon label (usu. "Document")
+#define IDS_DEFICONLABEL 310
+#define IDS_OLE2UIPASTELINKEDTYPE 311
+
+
+#define IDS_FILTERS 64
+#define IDS_ICONFILTERS 65
+#define IDS_BROWSE 66
+
+//Resource identifiers for bitmaps
+#define IDB_RESULTSEGA 10
+#define IDB_RESULTSVGA 11
+#define IDB_RESULTSHIRESVGA 12
+
+
+//Missing from windows.h
+#ifndef PVOID
+typedef VOID *PVOID;
+#endif
+
+
+//Hook type used in all structures.
+typedef UINT (CALLBACK *LPFNOLEUIHOOK)(HWND, UINT, WPARAM, LPARAM);
+
+
+//Strings for registered messages
+#define SZOLEUI_MSG_HELP TEXT("OLEUI_MSG_HELP")
+#define SZOLEUI_MSG_ENDDIALOG TEXT("OLEUI_MSG_ENDDIALOG")
+#define SZOLEUI_MSG_BROWSE TEXT("OLEUI_MSG_BROWSE")
+#define SZOLEUI_MSG_CHANGEICON TEXT("OLEUI_MSG_CHANGEICON")
+#define SZOLEUI_MSG_CLOSEBUSYDIALOG TEXT("OLEUI_MSG_CLOSEBUSYDIALOG")
+#define SZOLEUI_MSG_FILEOKSTRING TEXT("OLEUI_MSG_FILEOKSTRING")
+
+//Standard error definitions
+#define OLEUI_FALSE 0
+#define OLEUI_SUCCESS 1 //No error, same as OLEUI_OK
+#define OLEUI_OK 1 //OK button pressed
+#define OLEUI_CANCEL 2 //Cancel button pressed
+
+#define OLEUI_ERR_STANDARDMIN 100
+#define OLEUI_ERR_STRUCTURENULL 101 //Standard field validation
+#define OLEUI_ERR_STRUCTUREINVALID 102
+#define OLEUI_ERR_CBSTRUCTINCORRECT 103
+#define OLEUI_ERR_HWNDOWNERINVALID 104
+#define OLEUI_ERR_LPSZCAPTIONINVALID 105
+#define OLEUI_ERR_LPFNHOOKINVALID 106
+#define OLEUI_ERR_HINSTANCEINVALID 107
+#define OLEUI_ERR_LPSZTEMPLATEINVALID 108
+#define OLEUI_ERR_HRESOURCEINVALID 109
+
+#define OLEUI_ERR_FINDTEMPLATEFAILURE 110 //Initialization errors
+#define OLEUI_ERR_LOADTEMPLATEFAILURE 111
+#define OLEUI_ERR_DIALOGFAILURE 112
+#define OLEUI_ERR_LOCALMEMALLOC 113
+#define OLEUI_ERR_GLOBALMEMALLOC 114
+#define OLEUI_ERR_LOADSTRING 115
+
+#define OLEUI_ERR_STANDARDMAX 116 //Start here for specific errors.
+
+
+
+//Help Button Identifier
+#define ID_OLEUIHELP 99
+
+// Help button for fileopen.dlg (need this for resizing) 1038 is pshHelp
+#undef IDHELP
+#define IDHELP 1038
+
+// Static text control (use this instead of -1 so things work correctly for
+// localization
+#define ID_STATIC 98
+
+/******************
+ * The followings are defined in the fashion that the first
+ * definition is the number of CHARACTERS, while the second one (XXX_SIZE)
+ * is the number of bytes. The number of bytes definition is needed for
+ * UNICODE handling purpose.
+ * Also, please note the prefix of variables cch means that it is the
+ * count of characters and cb means the count of bytes.
+ ******************/
+
+//Maximum key size we read from the RegDB.
+#define OLEUI_CCHKEYMAX 256 // make any changes to this in geticon.c too
+#define OLEUI_CCHKEYMAX_SIZE OLEUI_CCHKEYMAX*sizeof(TCHAR) // # of bytes
+
+//Maximum verb length and length of Object menu
+#define OLEUI_CCHVERBMAX 32
+#define OLEUI_CCHVERBMAX_SIZE OLEUI_CCHVERBMAX*sizeof(TCHAR) // # of bytes
+#define OLEUI_OBJECTMENUMAX 256
+#define OLEUI_OBJECTMENUMAX_SIZE OLEUI_OBJECTMENUMAX*sizeof(TCHAR) // # of bytes
+
+//Maximum MS-DOS pathname.
+#define OLEUI_CCHPATHMAX 256 // make any changes to this in geticon.c too
+#define OLEUI_CCHPATHMAX_SIZE OLEUI_CCHPATHMAX*sizeof(TCHAR) // # of bytes
+#define OLEUI_CCHFILEMAX 13
+#define OLEUI_CCHFILEMAX_SIZE OLEUI_CCHFILEMAX*sizeof(TCHAR) // # of bytes
+
+//Icon label length
+#define OLEUI_CCHLABELMAX 40 // make any changes to this in geticon.c too
+#define OLEUI_CCHLABELMAX_SIZE OLEUI_CCHLABELMAX*sizeof(TCHAR) // # of bytes
+
+//Length of the CLSID string
+#define OLEUI_CCHCLSIDSTRING 39
+#define OLEUI_CCHCLSIDSTRING_SIZE OLEUI_CCHCLSIDSTRING*sizeof(TCHAR) // # of bytes
+
+
+/*
+ * What follows here are first function prototypes for general utility
+ * functions, then sections laid out by dialog. Each dialog section
+ * defines the dialog structure, the API prototype, flags for the dwFlags
+ * field, the dialog-specific error values, and dialog control IDs (for
+ * hooks and custom templates.
+ */
+
+
+//Miscellaneous utility functions.
+STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,
+ LPTSTR lpszShortType,
+ HMENU hMenu,
+ UINT uPos,
+ UINT uIDVerbMin,
+ UINT uIDVerbMax,
+ BOOL bAddConvert,
+ UINT idConvert,
+ HMENU FAR *lphMenu);
+
+//Metafile utility functions
+#ifndef WIN32
+STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON, LPTSTR, LPTSTR, UINT);
+#endif
+STDAPI_(void) OleUIMetafilePictIconFree(HGLOBAL);
+STDAPI_(BOOL) OleUIMetafilePictIconDraw(HDC, LPRECT, HGLOBAL, BOOL);
+STDAPI_(UINT) OleUIMetafilePictExtractLabel(HGLOBAL, LPTSTR, UINT, LPDWORD);
+STDAPI_(HICON) OleUIMetafilePictExtractIcon(HGLOBAL);
+STDAPI_(BOOL) OleUIMetafilePictExtractIconSource(HGLOBAL,LPTSTR,UINT FAR *);
+
+
+
+
+
+/*************************************************************************
+** INSERT OBJECT DIALOG
+*************************************************************************/
+
+
+typedef struct tagOLEUIINSERTOBJECT
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUIINSERTOBJECT. All are IN-OUT unless otherwise spec.
+ CLSID clsid; //Return space for class ID
+ LPTSTR lpszFile; //Filename for inserts or links
+ UINT cchFile; //Size of lpszFile buffer: OLEUI_CCHPATHMAX
+ UINT cClsidExclude; //IN only: CLSIDs in lpClsidExclude
+ LPCLSID lpClsidExclude; //List of CLSIDs to exclude from listing.
+
+ //Specific to create objects if flags say so
+ IID iid; //Requested interface on creation.
+ DWORD oleRender; //Rendering option
+ LPFORMATETC lpFormatEtc; //Desired format
+ LPOLECLIENTSITE lpIOleClientSite; //Site to be use for the object.
+ LPSTORAGE lpIStorage; //Storage used for the object
+ LPVOID FAR *ppvObj; //Where the object is returned.
+ SCODE sc; //Result of creation calls.
+ HGLOBAL hMetaPict; //OUT: METAFILEPICT containing iconic aspect.
+ //IFF we couldn't stuff it in the cache.
+ } OLEUIINSERTOBJECT, *POLEUIINSERTOBJECT, FAR *LPOLEUIINSERTOBJECT;
+
+//API prototype
+STDAPI_(UINT) OleUIInsertObject(LPOLEUIINSERTOBJECT);
+
+
+//Insert Object flags
+#define IOF_SHOWHELP 0x00000001L
+#define IOF_SELECTCREATENEW 0x00000002L
+#define IOF_SELECTCREATEFROMFILE 0x00000004L
+#define IOF_CHECKLINK 0x00000008L
+#define IOF_CHECKDISPLAYASICON 0x00000010L
+#define IOF_CREATENEWOBJECT 0x00000020L
+#define IOF_CREATEFILEOBJECT 0x00000040L
+#define IOF_CREATELINKOBJECT 0x00000080L
+#define IOF_DISABLELINK 0x00000100L
+#define IOF_VERIFYSERVERSEXIST 0x00000200L
+#define IOF_DISABLEDISPLAYASICON 0x00000400L
+
+
+//Insert Object specific error codes
+#define OLEUI_IOERR_LPSZFILEINVALID (OLEUI_ERR_STANDARDMAX+0)
+#define OLEUI_IOERR_LPSZLABELINVALID (OLEUI_ERR_STANDARDMAX+1)
+#define OLEUI_IOERR_HICONINVALID (OLEUI_ERR_STANDARDMAX+2)
+#define OLEUI_IOERR_LPFORMATETCINVALID (OLEUI_ERR_STANDARDMAX+3)
+#define OLEUI_IOERR_PPVOBJINVALID (OLEUI_ERR_STANDARDMAX+4)
+#define OLEUI_IOERR_LPIOLECLIENTSITEINVALID (OLEUI_ERR_STANDARDMAX+5)
+#define OLEUI_IOERR_LPISTORAGEINVALID (OLEUI_ERR_STANDARDMAX+6)
+#define OLEUI_IOERR_SCODEHASERROR (OLEUI_ERR_STANDARDMAX+7)
+#define OLEUI_IOERR_LPCLSIDEXCLUDEINVALID (OLEUI_ERR_STANDARDMAX+8)
+#define OLEUI_IOERR_CCHFILEINVALID (OLEUI_ERR_STANDARDMAX+9)
+
+
+//Insert Object Dialog identifiers
+#define ID_IO_CREATENEW 2100
+#define ID_IO_CREATEFROMFILE 2101
+#define ID_IO_LINKFILE 2102
+#define ID_IO_OBJECTTYPELIST 2103
+#define ID_IO_DISPLAYASICON 2104
+#define ID_IO_CHANGEICON 2105
+#define ID_IO_FILE 2106
+#define ID_IO_FILEDISPLAY 2107
+#define ID_IO_RESULTIMAGE 2108
+#define ID_IO_RESULTTEXT 2109
+#define ID_IO_ICONDISPLAY 2110
+#define ID_IO_OBJECTTYPETEXT 2111
+#define ID_IO_FILETEXT 2112
+#define ID_IO_FILETYPE 2113
+
+// Strings in OLE2UI resources
+#define IDS_IORESULTNEW 256
+#define IDS_IORESULTNEWICON 257
+#define IDS_IORESULTFROMFILE1 258
+#define IDS_IORESULTFROMFILE2 259
+#define IDS_IORESULTFROMFILEICON2 260
+#define IDS_IORESULTLINKFILE1 261
+#define IDS_IORESULTLINKFILE2 262
+#define IDS_IORESULTLINKFILEICON1 263
+#define IDS_IORESULTLINKFILEICON2 264
+
+/*************************************************************************
+** PASTE SPECIAL DIALOG
+*************************************************************************/
+
+// Maximum number of link types
+#define PS_MAXLINKTYPES 8
+
+//NOTE: OLEUIPASTEENTRY and OLEUIPASTEFLAG structs are defined in OLESTD.H
+
+typedef struct tagOLEUIPASTESPECIAL
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUIPASTESPECIAL.
+
+ //IN fields
+ LPDATAOBJECT lpSrcDataObj; //Source IDataObject* (on the
+ // clipboard) for data to paste
+
+ LPOLEUIPASTEENTRY arrPasteEntries; //OLEUIPASTEENTRY array which
+ // specifies acceptable formats. See
+ // OLEUIPASTEENTRY for more info.
+ int cPasteEntries; //No. of OLEUIPASTEENTRY array entries
+
+ UINT FAR *arrLinkTypes; //List of link types that are
+ // acceptable. Link types are referred
+ // to using OLEUIPASTEFLAGS in
+ // arrPasteEntries
+ int cLinkTypes; //Number of link types
+ UINT cClsidExclude; //Number of CLSIDs in lpClsidExclude
+ LPCLSID lpClsidExclude; //List of CLSIDs to exclude from list.
+
+ //OUT fields
+ int nSelectedIndex; //Index of arrPasteEntries[] that the
+ // user selected
+ BOOL fLink; //Indicates if Paste or Paste Link was
+ // selected by the user
+ HGLOBAL hMetaPict; //Handle to Metafile containing icon
+ // and icon title selected by the user
+ // Use the Metafile utility functions
+ // defined in this header to
+ // manipulate hMetaPict
+ SIZEL sizel; // size of object/link in its source
+ // if the display aspect chosen by
+ // the user matches the aspect
+ // displayed in the source. if
+ // different aspect is chosen then
+ // sizel.cx=sizel.cy=0 is returned.
+ // sizel displayed in source is
+ // retrieved from the
+ // ObjectDescriptor if fLink is FALSE
+ // LinkSrcDescriptor if fLink is TRUE
+ } OLEUIPASTESPECIAL, *POLEUIPASTESPECIAL, FAR *LPOLEUIPASTESPECIAL;
+
+
+//API to bring up PasteSpecial dialog
+STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL);
+
+
+//Paste Special flags
+// Show Help button. IN flag.
+#define PSF_SHOWHELP 0x00000001L
+
+//Select Paste radio button at dialog startup. This is the default if
+// PSF_SELECTPASTE or PSF_SELECTPASTELINK are not specified. Also specifies
+// state of button on dialog termination. IN/OUT flag.
+#define PSF_SELECTPASTE 0x00000002L
+
+//Select PasteLink radio button at dialog startup. Also specifies state of
+// button on dialog termination. IN/OUT flag.
+#define PSF_SELECTPASTELINK 0x00000004L
+
+//Specfies if DisplayAsIcon button was checked on dialog termination. OUT flag
+#define PSF_CHECKDISPLAYASICON 0x00000008L
+#define PSF_DISABLEDISPLAYASICON 0x00000010L
+
+
+//Paste Special specific error codes
+#define OLEUI_IOERR_SRCDATAOBJECTINVALID (OLEUI_ERR_STANDARDMAX+0)
+#define OLEUI_IOERR_ARRPASTEENTRIESINVALID (OLEUI_ERR_STANDARDMAX+1)
+#define OLEUI_IOERR_ARRLINKTYPESINVALID (OLEUI_ERR_STANDARDMAX+2)
+#define OLEUI_PSERR_CLIPBOARDCHANGED (OLEUI_ERR_STANDARDMAX+3)
+
+//Paste Special Dialog identifiers
+#define ID_PS_PASTE 500
+#define ID_PS_PASTELINK 501
+#define ID_PS_SOURCETEXT 502
+#define ID_PS_PASTELIST 503
+#define ID_PS_PASTELINKLIST 504
+#define ID_PS_DISPLAYLIST 505
+#define ID_PS_DISPLAYASICON 506
+#define ID_PS_ICONDISPLAY 507
+#define ID_PS_CHANGEICON 508
+#define ID_PS_RESULTIMAGE 509
+#define ID_PS_RESULTTEXT 510
+#define ID_PS_RESULTGROUP 511
+#define ID_PS_STXSOURCE 512
+#define ID_PS_STXAS 513
+
+// Paste Special String IDs
+#define IDS_PSPASTEDATA 400
+#define IDS_PSPASTEOBJECT 401
+#define IDS_PSPASTEOBJECTASICON 402
+#define IDS_PSPASTELINKDATA 403
+#define IDS_PSPASTELINKOBJECT 404
+#define IDS_PSPASTELINKOBJECTASICON 405
+#define IDS_PSNONOLE 406
+#define IDS_PSUNKNOWNTYPE 407
+#define IDS_PSUNKNOWNSRC 408
+#define IDS_PSUNKNOWNAPP 409
+
+
+/*************************************************************************
+** EDIT LINKS DIALOG
+*************************************************************************/
+
+
+
+/* IOleUILinkContainer Interface
+** -----------------------------
+** This interface must be implemented by container applications that
+** want to use the EditLinks dialog. the EditLinks dialog calls back
+** to the container app to perform the OLE functions to manipulate
+** the links within the container.
+*/
+
+#define LPOLEUILINKCONTAINER IOleUILinkContainer FAR*
+
+#undef INTERFACE
+#define INTERFACE IOleUILinkContainer
+
+DECLARE_INTERFACE_(IOleUILinkContainer, IUnknown)
+{
+ //*** IUnknown methods ***/
+ STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ STDMETHOD_(DWORD,GetNextLink) (THIS_ DWORD dwLink) PURE;
+ STDMETHOD(SetLinkUpdateOptions) (THIS_ DWORD dwLink, DWORD dwUpdateOpt) PURE;
+ STDMETHOD(GetLinkUpdateOptions) (THIS_ DWORD dwLink, DWORD FAR* lpdwUpdateOpt) PURE;
+ STDMETHOD(SetLinkSource) (THIS_
+ DWORD dwLink,
+ LPTSTR lpszDisplayName,
+ ULONG lenFileName,
+ ULONG FAR* pchEaten,
+ BOOL fValidateSource) PURE;
+ STDMETHOD(GetLinkSource) (THIS_
+ DWORD dwLink,
+ LPTSTR FAR* lplpszDisplayName,
+ ULONG FAR* lplenFileName,
+ LPTSTR FAR* lplpszFullLinkType,
+ LPTSTR FAR* lplpszShortLinkType,
+ BOOL FAR* lpfSourceAvailable,
+ BOOL FAR* lpfIsSelected) PURE;
+ STDMETHOD(OpenLinkSource) (THIS_ DWORD dwLink) PURE;
+ STDMETHOD(UpdateLink) (THIS_
+ DWORD dwLink,
+ BOOL fErrorMessage,
+ BOOL fErrorAction) PURE;
+ STDMETHOD(CancelLink) (THIS_ DWORD dwLink) PURE;
+};
+
+
+typedef struct tagOLEUIEDITLINKS
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUI<STRUCT>. All are IN-OUT unless otherwise spec.
+
+ LPOLEUILINKCONTAINER lpOleUILinkContainer; //IN: Interface to manipulate
+ //links in the container
+ } OLEUIEDITLINKS, *POLEUIEDITLINKS, FAR *LPOLEUIEDITLINKS;
+
+
+//API Prototype
+STDAPI_(UINT) OleUIEditLinks(LPOLEUIEDITLINKS);
+
+
+// Edit Links flags
+#define ELF_SHOWHELP 0x00000001L
+#define ELF_DISABLEUPDATENOW 0x00000002L
+#define ELF_DISABLEOPENSOURCE 0x00000004L
+#define ELF_DISABLECHANGESOURCE 0x00000008L
+#define ELF_DISABLECANCELLINK 0x00000010L
+
+// Edit Links Dialog identifiers
+#define ID_EL_CHANGESOURCE 201
+#define ID_EL_AUTOMATIC 202
+#define ID_EL_CLOSE 208
+#define ID_EL_CANCELLINK 209
+#define ID_EL_UPDATENOW 210
+#define ID_EL_OPENSOURCE 211
+#define ID_EL_MANUAL 212
+#define ID_EL_LINKSOURCE 216
+#define ID_EL_LINKTYPE 217
+#define ID_EL_UPDATE 218
+#define ID_EL_NULL -1
+#define ID_EL_LINKSLISTBOX 206
+#define ID_EL_COL1 220
+#define ID_EL_COL2 221
+#define ID_EL_COL3 222
+
+
+
+/*************************************************************************
+** CHANGE ICON DIALOG
+*************************************************************************/
+
+typedef struct tagOLEUICHANGEICON
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUICHANGEICON. All are IN-OUT unless otherwise spec.
+ HGLOBAL hMetaPict; //Current and final image. Source of the
+ //icon is embedded in the metafile itself.
+ CLSID clsid; //IN only: class used to get Default icon
+ TCHAR szIconExe[OLEUI_CCHPATHMAX];
+ int cchIconExe;
+ } OLEUICHANGEICON, *POLEUICHANGEICON, FAR *LPOLEUICHANGEICON;
+
+
+//API prototype
+STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON);
+
+
+//Change Icon flags
+#define CIF_SHOWHELP 0x00000001L
+#define CIF_SELECTCURRENT 0x00000002L
+#define CIF_SELECTDEFAULT 0x00000004L
+#define CIF_SELECTFROMFILE 0x00000008L
+#define CIF_USEICONEXE 0x0000000aL
+
+
+//Change Icon specific error codes
+#define OLEUI_CIERR_MUSTHAVECLSID (OLEUI_ERR_STANDARDMAX+0)
+#define OLEUI_CIERR_MUSTHAVECURRENTMETAFILE (OLEUI_ERR_STANDARDMAX+1)
+#define OLEUI_CIERR_SZICONEXEINVALID (OLEUI_ERR_STANDARDMAX+2)
+
+
+//Change Icon Dialog identifiers
+#define ID_GROUP 120
+#define ID_CURRENT 121
+#define ID_CURRENTICON 122
+#define ID_DEFAULT 123
+#define ID_DEFAULTICON 124
+#define ID_FROMFILE 125
+#define ID_FROMFILEEDIT 126
+#define ID_ICONLIST 127
+#define ID_LABEL 128
+#define ID_LABELEDIT 129
+#define ID_BROWSE 130
+#define ID_RESULTICON 132
+#define ID_RESULTLABEL 133
+
+// Stringtable defines for Change Icon
+#define IDS_CINOICONSINFILE 288
+#define IDS_CIINVALIDFILE 289
+#define IDS_CIFILEACCESS 290
+#define IDS_CIFILESHARE 291
+#define IDS_CIFILEOPENFAIL 292
+
+
+
+/*************************************************************************
+** CONVERT DIALOG
+*************************************************************************/
+
+typedef struct tagOLEUICONVERT
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUICONVERT. All are IN-OUT unless otherwise spec.
+ CLSID clsid; //Class ID sent in to dialog: IN only
+ CLSID clsidConvertDefault; //Class ID to use as convert default: IN only
+ CLSID clsidActivateDefault; //Class ID to use as activate default: IN only
+
+ CLSID clsidNew; //Selected Class ID: OUT only
+ DWORD dvAspect; //IN-OUT, either DVASPECT_CONTENT or
+ //DVASPECT_ICON
+ WORD wFormat; //Original data format
+ BOOL fIsLinkedObject; //IN only; true if object is linked
+ HGLOBAL hMetaPict; //IN-OUT: METAFILEPICT containing iconic aspect.
+ LPTSTR lpszUserType; //IN-OUT: user type name of original class.
+ // We'll do lookup if it's NULL.
+ // This gets freed on exit.
+ BOOL fObjectsIconChanged; // OUT; TRUE if ChangeIcon was called (and not cancelled)
+ LPTSTR lpszDefLabel; //IN-OUT: default label to use for icon.
+ // if NULL, the short user type name
+ // will be used. if the object is a
+ // link, the caller should pass the
+ // DisplayName of the link source
+ // This gets freed on exit.
+
+ UINT cClsidExclude; //IN: No. of CLSIDs in lpClsidExclude
+ LPCLSID lpClsidExclude; //IN: List of CLSIDs to exclude from list
+ } OLEUICONVERT, *POLEUICONVERT, FAR *LPOLEUICONVERT;
+
+
+//API prototype
+STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT);
+
+// Determine if there is at least one class that can Convert or ActivateAs
+// the given clsid.
+STDAPI_(BOOL) OleUICanConvertOrActivateAs(
+ REFCLSID rClsid,
+ BOOL fIsLinkedObject,
+ WORD wFormat
+);
+
+//Convert Dialog flags
+
+// IN only: Shows "HELP" button
+#define CF_SHOWHELPBUTTON 0x00000001L
+
+// IN only: lets you set the convert default object - the one that is
+// selected as default in the convert listbox.
+#define CF_SETCONVERTDEFAULT 0x00000002L
+
+
+// IN only: lets you set the activate default object - the one that is
+// selected as default in the activate listbox.
+
+#define CF_SETACTIVATEDEFAULT 0x00000004L
+
+
+// IN/OUT: Selects the "Convert To" radio button, is set on exit if
+// this button was selected
+#define CF_SELECTCONVERTTO 0x00000008L
+
+// IN/OUT: Selects the "Activate As" radio button, is set on exit if
+// this button was selected
+#define CF_SELECTACTIVATEAS 0x00000010L
+#define CF_DISABLEDISPLAYASICON 0x00000020L
+#define CF_DISABLEACTIVATEAS 0x00000040L
+
+
+//Convert specific error codes
+#define OLEUI_CTERR_CLASSIDINVALID (OLEUI_ERR_STANDARDMAX+1)
+#define OLEUI_CTERR_DVASPECTINVALID (OLEUI_ERR_STANDARDMAX+2)
+#define OLEUI_CTERR_CBFORMATINVALID (OLEUI_ERR_STANDARDMAX+3)
+#define OLEUI_CTERR_HMETAPICTINVALID (OLEUI_ERR_STANDARDMAX+4)
+#define OLEUI_CTERR_STRINGINVALID (OLEUI_ERR_STANDARDMAX+5)
+
+
+//Convert Dialog identifiers
+#define IDCV_OBJECTTYPE 150
+#define IDCV_DISPLAYASICON 152
+#define IDCV_CHANGEICON 153
+#define IDCV_ACTIVATELIST 154
+#define IDCV_CONVERTTO 155
+#define IDCV_ACTIVATEAS 156
+#define IDCV_RESULTTEXT 157
+#define IDCV_CONVERTLIST 158
+#define IDCV_ICON 159
+#define IDCV_ICONLABEL1 160
+#define IDCV_ICONLABEL2 161
+#define IDCV_STXCURTYPE 162
+#define IDCV_GRPRESULT 163
+#define IDCV_STXCONVERTTO 164
+
+// String IDs for Convert dialog
+#define IDS_CVRESULTCONVERTLINK 500
+#define IDS_CVRESULTCONVERTTO 501
+#define IDS_CVRESULTNOCHANGE 502
+#define IDS_CVRESULTDISPLAYASICON 503
+#define IDS_CVRESULTACTIVATEAS 504
+#define IDS_CVRESULTACTIVATEDIFF 505
+
+
+/*************************************************************************
+** BUSY DIALOG
+*************************************************************************/
+
+typedef struct tagOLEUIBUSY
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags ** NOTE ** this dialog has no flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUIBUSY.
+ HTASK hTask; //IN: HTask which is blocking
+ HWND FAR * lphWndDialog; //IN: Dialog's HWND is placed here
+ } OLEUIBUSY, *POLEUIBUSY, FAR *LPOLEUIBUSY;
+
+//API prototype
+STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY);
+
+// Flags for this dialog
+
+// IN only: Disables "Cancel" button
+#define BZ_DISABLECANCELBUTTON 0x00000001L
+
+// IN only: Disables "Switch To..." button
+#define BZ_DISABLESWITCHTOBUTTON 0x00000002L
+
+// IN only: Disables "Retry" button
+#define BZ_DISABLERETRYBUTTON 0x00000004L
+
+// IN only: Generates a "Not Responding" dialog as opposed to the
+// "Busy" dialog. The wording in the text is slightly different, and
+// the "Cancel" button is grayed out if you set this flag.
+#define BZ_NOTRESPONDINGDIALOG 0x00000008L
+
+// Busy specific error/return codes
+#define OLEUI_BZERR_HTASKINVALID (OLEUI_ERR_STANDARDMAX+0)
+
+// SWITCHTOSELECTED is returned when user hit "switch to"
+#define OLEUI_BZ_SWITCHTOSELECTED (OLEUI_ERR_STANDARDMAX+1)
+
+// RETRYSELECTED is returned when user hit "retry"
+#define OLEUI_BZ_RETRYSELECTED (OLEUI_ERR_STANDARDMAX+2)
+
+// CALLUNBLOCKED is returned when call has been unblocked
+#define OLEUI_BZ_CALLUNBLOCKED (OLEUI_ERR_STANDARDMAX+3)
+
+// Busy dialog identifiers
+#define IDBZ_RETRY 600
+#define IDBZ_ICON 601
+#define IDBZ_MESSAGE1 602
+#define IDBZ_SWITCHTO 604
+
+// Busy dialog stringtable defines
+#define IDS_BZRESULTTEXTBUSY 601
+#define IDS_BZRESULTTEXTNOTRESPONDING 602
+
+// Links dialog stringtable defines
+#define IDS_LINK_AUTO 800
+#define IDS_LINK_MANUAL 801
+#define IDS_LINK_UNKNOWN 802
+#define IDS_LINKS 803
+#define IDS_FAILED 804
+#define IDS_CHANGESOURCE 805
+#define IDS_INVALIDSOURCE 806
+#define IDS_ERR_GETLINKSOURCE 807
+#define IDS_ERR_GETLINKUPDATEOPTIONS 808
+#define IDS_ERR_ADDSTRING 809
+#define IDS_CHANGEADDITIONALLINKS 810
+#define IDS_CLOSE 811
+
+
+/*************************************************************************
+** PROMPT USER DIALOGS
+*************************************************************************/
+#define ID_PU_LINKS 900
+#define ID_PU_TEXT 901
+#define ID_PU_CONVERT 902
+#define ID_PU_BROWSE 904
+#define ID_PU_METER 905
+#define ID_PU_PERCENT 906
+#define ID_PU_STOP 907
+
+// used for -1 ids in dialogs:
+#define ID_DUMMY 999
+
+/* inside ole2ui.c */
+#ifdef __cplusplus
+extern "C"
+#endif
+int EXPORT FAR CDECL OleUIPromptUser(int nTemplate, HWND hwndParent, ...);
+
+#define UPDATELINKS_STARTDELAY 2000 // Delay before 1st link updates
+ // to give the user a chance to
+ // dismiss the dialog before any
+ // links update.
+
+STDAPI_(BOOL) OleUIUpdateLinks(
+ LPOLEUILINKCONTAINER lpOleUILinkCntr,
+ HWND hwndParent,
+ LPTSTR lpszTitle,
+ int cLinks);
+
+
+/*************************************************************************
+** OLE OBJECT FEEDBACK EFFECTS
+*************************************************************************/
+
+#define OLEUI_HANDLES_USEINVERSE 0x00000001L
+#define OLEUI_HANDLES_NOBORDER 0x00000002L
+#define OLEUI_HANDLES_INSIDE 0x00000004L
+#define OLEUI_HANDLES_OUTSIDE 0x00000008L
+
+
+#define OLEUI_SHADE_FULLRECT 1
+#define OLEUI_SHADE_BORDERIN 2
+#define OLEUI_SHADE_BORDEROUT 3
+
+/* objfdbk.c function prototypes */
+STDAPI_(void) OleUIDrawHandles(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cSize, BOOL fDraw);
+STDAPI_(void) OleUIDrawShading(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cWidth);
+STDAPI_(void) OleUIShowObject(LPCRECT lprc, HDC hdc, BOOL fIsLink);
+
+
+/*************************************************************************
+** Hatch window definitions and prototypes **
+*************************************************************************/
+#define DEFAULT_HATCHBORDER_WIDTH 4
+
+STDAPI_(BOOL) RegisterHatchWindowClass(HINSTANCE hInst);
+STDAPI_(HWND) CreateHatchWindow(HWND hWndParent, HINSTANCE hInst);
+STDAPI_(UINT) GetHatchWidth(HWND hWndHatch);
+STDAPI_(void) GetHatchRect(HWND hWndHatch, LPRECT lpHatchRect);
+STDAPI_(void) SetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect);
+STDAPI_(void) SetHatchWindowSize(
+ HWND hWndHatch,
+ LPRECT lprcIPObjRect,
+ LPRECT lprcClipRect,
+ LPPOINT lpptOffset
+);
+
+
+
+/*************************************************************************
+** VERSION VERIFICATION INFORMATION
+*************************************************************************/
+
+// The following magic number is used to verify that the resources we bind
+// to our EXE are the same "version" as the LIB (or DLL) file which
+// contains these routines. This is not the same as the Version information
+// resource that we place in OLE2UI.RC, this is a special ID that we will
+// have compiled in to our EXE. Upon initialization of OLE2UI, we will
+// look in our resources for an RCDATA called "VERIFICATION" (see OLE2UI.RC),
+// and make sure that the magic number there equals the magic number below.
+
+#define OLEUI_VERSION_MAGIC 0x4D42
+
+#endif //_OLE2UI_H_
diff --git a/private/oleutest/letest/ole2ui/ole2ui.mak b/private/oleutest/letest/ole2ui/ole2ui.mak
new file mode 100644
index 000000000..f8308fa23
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/ole2ui.mak
@@ -0,0 +1,272 @@
+# ============================================================================
+# File: OLE2UI.MAK
+#
+# NMAKE description file to build STATIC version of OLE2.0 User Interface LIB
+#
+# Copyright (C) Microsoft Corporation, 1992-1993. All Rights Reserved.
+# ============================================================================
+#
+# Usage Notes:
+# -----------
+#
+# This makefile is designed to be used in one step. This makefile does
+# NOT use the file called UIMAKE.INI. This makefile builds the OLE2UI.LIB
+# library. It is NOT necessary to build custom versions of the static
+# library version of OLE2UI. Everyone can use the same OLE2UI.LIB library
+# as built by this makefile.
+#
+# NMAKE -F OLE2UI.MAK
+#
+#
+# The following lists a few of the settings in this makefile file which
+# you might change, and what effect those changes might have. For a
+# complete listing of all the available options and how they are used,
+# see the makefile below.
+#
+# MODEL=[S|M|C|L] -- The memory model.
+#
+# ============================================================================
+
+
+# ----------------------------------------------------------------------------
+# U I M A K E . I N I
+# ----------------------------------------------------------------------------
+DOS=1
+
+# Make a static library called OLE2UI.LIB
+DEBUG=0
+MODEL=M
+RESOURCE=RESOURCE
+
+!ifndef REL_DIR
+REL_DIR=c:\ole2samp\release
+!endif
+!ifndef OLERELDIR
+OLEREL_DIR=c:\ole2samp\release
+!endif
+
+!if "$(INSTALL_DIR)"==""
+INSTALL_DIR = $(REL_DIR)
+!endif
+
+# ----------------------------------------------------------------------------
+# O B J E C T F I L E L I S T
+# ----------------------------------------------------------------------------
+
+UI_COBJS = \
+ D^\busy.obj\
+ D^\common.obj\
+ D^\convert.obj\
+ D^\dbgutil.obj\
+ D^\drawicon.obj\
+ D^\hatch.obj\
+ D^\icon.obj\
+ D^\iconbox.obj\
+ D^\insobj.obj\
+ D^\links.obj\
+ D^\msgfiltr.obj\
+ D^\enumfetc.obj\
+ D^\enumstat.obj\
+ D^\objfdbk.obj\
+ D^\ole2ui.obj\
+ D^\olestd.obj\
+ D^\targtdev.obj\
+ D^\oleutl.obj\
+ D^\pastespl.obj\
+ D^\regdb.obj\
+ D^\resimage.obj\
+ D^\utility.obj\
+
+UI_NOPCOBJS = \
+ D^\geticon.obj\
+ D^\dballoc.obj\
+ D^\suminfo.obj\
+ D^\stdpal.obj\
+
+PRECOMPOBJ= $(O)precomp.obj
+
+PRECOMP=$(O)precomp.pch
+
+!if ("$(DEBUG)"=="1")
+MSG=DEBUG Static LIB Version
+LIBNAME=$(MODEL)OLE2UID
+CFLAGS=-c -Od -GA2s -W3 -Zpei -A$(MODEL) -D_DEBUG
+RFLAGS=-D DEBUG
+LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300 /NOPACKCODE
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+OBJ=DEBUGLIB
+LIBOBJS = $(UI_COBJS:D^\=DEBUGLIB^\) $(UI_NOPCOBJS:D^\=DEBUGLIB\NOPC^\)
+
+!else
+
+MSG=RETAIL Static LIB Version
+LIBNAME=$(MODEL)OLE2UI
+CFLAGS=-c -Os -GA2s -W3 -Zpe -A$(MODEL)
+RFLAGS=
+LFLAGS=/MAP:FULL /LINE /NOD /NOE /SE:300 /NOPACKCODE
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+OBJ=RETAILIB
+LIBOBJS = $(UI_COBJS:D^\=RETAILIB^\) $(UI_NOPCOBJS:D^\=RETAILIB\NOPC^\)
+
+!endif
+
+!if [if not exist $(OBJ)\*. md $(OBJ) >nul]
+!error Object subdirectory $(OBJ)\ could not be created
+!endif
+!if [if not exist $(OBJ)\NOPC\*. md $(OBJ)\NOPC > nul]
+!error non-precompiled header object subdirectory $(OBJ)\NOPC\ could not be created
+!endif
+
+# ----------------------------------------------------------------------------
+# R E S O U R C E L I S T
+# ----------------------------------------------------------------------------
+RES = \
+ busy.h \
+ common.h \
+ convert.h \
+ edlinks.h \
+ geticon.h \
+ icon.h \
+ iconbox.h \
+ insobj.h \
+ msgfiltr.h \
+ enumfetc.h \
+ ole2ui.h \
+ pastespl.h \
+ resimage.h \
+ dballoc.h \
+ suminfo.h \
+ stdpal.h \
+
+
+.SUFFIXES: .c .cpp .obj
+
+O=.\$(OBJ)^\
+
+GOAL: PRELUDE $(LIBNAME).LIB
+
+# ----------------------------------------------------------------------------
+# I N F E R E N C E R U L E S
+# ----------------------------------------------------------------------------
+
+# compile C file without precompiled headers into object directory\NOPC
+# dont compile c files etc for lcoalized builds.
+{}.c{$(O)NOPC\}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).c
+!else
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).c\" -Fo$(O)NOPC\$(@B) $(@B).c
+!endif
+
+# compile C file into object directory
+{}.c{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).c °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).c
+!else
+ $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -D_FILE_=\"$(*B).c\" -Fo$(O)$(@B) $(@B).c
+!endif
+
+# compile CPP file without precompiled headers into object directory\NOPC
+# dont compile cpp files etc for lcoalized builds.
+{}.cpp{$(O)NOPC\}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).cpp °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS)
+ $(CC) -Fo$(O)NOPC\$(@B) $(@B).cpp
+!else
+ $(CC) $(CFLAGS) -D_FILE_=\"$(*B).cpp\" -Fo$(O)NOPC\$(@B) $(@B).cpp
+!endif
+
+# compile CPP file into object directory
+{}.cpp{$(O)}.obj:
+ @echo °°°°°°°°°°°°°°°°°°°°°°°°° Compiling $(@B).cpp °°°°°°°°°°°°°°°°°°°°°°°°°
+!ifdef DOS
+ SET CL=$(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch
+ $(CC) -Fo$(O)$(@B) $(@B).cpp
+!else
+ $(CC) $(CFLAGS) -Yuole2ui.h -Fp$(O)precomp.pch -D_FILE_=\"$(*B).cpp\" -Fo$(O)$(@B) $(@B).cpp
+!endif
+
+
+# ----------------------------------------------------------------------------
+# D E P E N D F I L E C R E A T I O N
+# ----------------------------------------------------------------------------
+UI_CFILE = $(UI_COBJS:.obj=.c) $(UI_DLLOBJS:.obj=.c)
+UI_NOPCFILE = $(UI_NOPCOBJS:.obj=.c)
+DEPEND: nul
+ @echo Making a NEW dependancy file.
+ mkdep -p $$(O) -s .obj $(UI_CFILE:D^\=) > tmp.tmp
+ sed "s/:/: $$(PRECOMP)/g" < tmp.tmp > depend
+ -del tmp.tmp
+ mkdep -p $$(O)NOPC\ -s .obj $(UI_NOPCFILE:D^\=) >> depend
+ mkdep -p $$(O) -s .pch precomp.c >> depend
+
+# ----------------------------------------------------------------------------
+# W E L C O M E B A N N E R
+# ----------------------------------------------------------------------------
+PRELUDE:
+ @echo ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
+ @echo º Makefile for UILibrary º
+ @echo ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
+ @echo $(MSG)
+!ifndef SRCTOK
+ set INCLUDE=$(OLEREL_DIR);$(INCLUDE)
+ set LIB=$(OLEREL_DIR);$(LIB)
+!endif
+
+
+# ----------------------------------------------------------------------------
+# G O A L T A R G E T S
+# ----------------------------------------------------------------------------
+!include "depend"
+
+CLEAN: CleanUp GOAL
+CleanUp:
+ -echo y|del .\$(OBJ)\*.*
+ -del $(LIBNAME).lib
+
+$(O)precomp.pch: precomp.c
+!ifdef DOS
+ SET CL=$(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h
+ $(CC) -Fo$(O)$(@B) precomp.c
+!else
+ $(CC) $(CFLAGS) -Fp$(O)precomp.pch -Ycole2ui.h -D_FILE_=\"precomp.c\" -Fo$(O)$(@B) precomp.c
+!endif
+
+#
+# Build .LIB static library
+#
+
+$(LIBNAME).lib: $(LIBOBJS) $(PRECOMPOBJ)
+ -del $(O)$(LIBNAME).lib
+ lib @<<
+$(O)$(LIBNAME).lib
+y
+$(PRECOMPOBJ: = +) $(LIBOBJS: = +)
+
+<<
+ copy $(O)$(LIBNAME).lib $(LIBNAME).lib
+
+
+# install built library to $(INSTALL_DIR) dir
+install:
+ copy $(LIBNAME).lib $(INSTALL_DIR)
+ copy ole2ui.h $(INSTALL_DIR)
+ copy olestd.h $(INSTALL_DIR)
+ copy msgfiltr.h $(INSTALL_DIR)
+ copy enumfetc.h $(INSTALL_DIR)
+ copy uiclass.h $(INSTALL_DIR)
+
+# EOF ========================================================================
diff --git a/private/oleutest/letest/ole2ui/ole2ui.rc b/private/oleutest/letest/ole2ui/ole2ui.rc
new file mode 100644
index 000000000..469608e3d
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/ole2ui.rc
@@ -0,0 +1,65 @@
+/*
+ * OLE2UI.RC
+ *
+ * Icon, menus, strings, and dialogs for the OLE 2.0 UI Support Library.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#undef PURE
+
+//fix bug when building on daytona 567
+//BUGBUG: this is hacky, we need a better long term solution, the basic
+//problem is that the rpc header file makes rc choke and die
+#define __RPCNDR_H__
+
+#include "ole2ui.h"
+
+#if defined( IBCLS )
+#define SZCLASSICONBOX IBCLS
+#define SZCLASSRESULTIMAGE RICLS
+#endif
+
+/* If "IBCLS" and "RICLS" are NOT defined as command line arguments to the
+ * RC command, then we assume there is a "uiclass.h" file which defines the
+ * two symbols "SZCLASSICONBOX" and "SZCLASSRESULTIMAGE". These need to be
+ * unique strings; they are normally built by composing the name of the
+ * "LIBNAME" or "APPNAME" with the strings "IBCls" and "RICls"
+ * respectively.
+ */
+#if !defined( SZCLASSICONBOX )
+#include "uiclass.h"
+#endif
+
+//Default 'document' icon
+//DefIcon ICON default.ico
+
+//Bitmaps for ResultImage control
+IDB_RESULTSEGA BITMAP egares.bmp
+IDB_RESULTSVGA BITMAP vgares.bmp
+IDB_RESULTSHIRESVGA BITMAP hivgares.bmp
+
+// Version Verification Resource (see OLE2UI.H)
+VERIFICATION RCDATA
+ BEGIN
+ OLEUI_VERSION_MAGIC
+ END
+
+//Include string tables here.
+#include "strings.rc"
+
+//Include each dialog template here.
+#include "insobj.dlg"
+#include "icon.dlg"
+#include "links.dlg"
+#include "pastespl.dlg"
+#include "busy.dlg"
+#include "convert.dlg"
+#include "fileopen.dlg"
+#include "prompt.dlg"
+
+// Only include the version resource if we are compiling the DLL version
+#ifdef DLL_VER
+//Version Information
+#include "OLE2UI.RCV"
+#endif
diff --git a/private/oleutest/letest/ole2ui/olestd.c b/private/oleutest/letest/ole2ui/olestd.c
new file mode 100644
index 000000000..d41a42b8d
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/olestd.c
@@ -0,0 +1,3048 @@
+/*************************************************************************
+**
+** OLE 2 Standard Utilities
+**
+** olestd.c
+**
+** This file contains utilities that are useful for most standard
+** OLE 2.0 compound document type applications.
+**
+** (c) Copyright Microsoft Corp. 1992 All Rights Reserved
+**
+*************************************************************************/
+
+// #define NONAMELESSUNION // use strict ANSI standard (for DVOBJ.H)
+
+#define STRICT 1
+#include "ole2ui.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <shellapi.h>
+#include "regdb.h"
+#include "geticon.h"
+#include "common.h"
+
+OLEDBGDATA
+
+static TCHAR szAssertMemAlloc[] = TEXT("CoGetMalloc failed");
+
+static int IsCloseFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight);
+
+
+/* OleStdSetupAdvises
+** ------------------
+** Setup the standard View advise required by a standard,
+** compound document-oriented container. Such a container relies on
+** Ole to manage the presentation of the Ole object. The container
+** call IViewObject::Draw to render (display) the object.
+**
+** This helper routine performs the following tasks:
+** setup View advise
+** Call IOleObject::SetHostNames
+** Call OleSetContainedObject
+**
+** fCreate should be set to TRUE if the object is being created. if
+** an existing object is being loaded, then fCreate should be FALSE.
+** if it is a creation situation, then the ADVF_PRIMEFIRST flag is
+** used when settinp up the IViewObject::Advise. This will result in
+** the immediate sending of the initial picture.
+**
+** OLE2NOTE: the standard container does NOT need to set up an OLE
+** Advise (IOleObject::Advise). this routine does NOT set up an OLE
+** Advise (a previous version of this function used to setup this
+** advise, but it was not useful).
+*/
+STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,
+ LPTSTR lpszContainerApp, LPTSTR lpszContainerObj,
+ LPADVISESINK lpAdviseSink, BOOL fCreate)
+{
+ LPVIEWOBJECT lpViewObject;
+ HRESULT hrErr;
+ BOOL fStatus = TRUE;
+#if defined( SPECIAL_CONTAINER )
+ DWORD dwTemp;
+#endif
+
+ hrErr = lpOleObject->lpVtbl->QueryInterface(
+ lpOleObject,
+ &IID_IViewObject,
+ (LPVOID FAR*)&lpViewObject
+ );
+
+ /* Setup View advise */
+ if (hrErr == NOERROR) {
+
+ OLEDBG_BEGIN2(TEXT("IViewObject::SetAdvise called\r\n"))
+ lpViewObject->lpVtbl->SetAdvise(
+ lpViewObject,
+ dwDrawAspect,
+ (fCreate ? ADVF_PRIMEFIRST : 0),
+ lpAdviseSink
+ );
+ OLEDBG_END2
+
+ OleStdRelease((LPUNKNOWN)lpViewObject);
+ } else {
+ fStatus = FALSE;
+ }
+
+#if defined( SPECIAL_CONTAINER )
+ /* Setup OLE advise.
+ ** OLE2NOTE: normally containers do NOT need to setup an OLE
+ ** advise. this advise connection is only useful for the OLE's
+ ** DefHandler and the OleLink object implementation. some
+ ** special container's might need to setup this advise for
+ ** programatic reasons.
+ **
+ ** NOTE: this advise will be torn down automatically by the
+ ** server when we release the object, therefore we do not need
+ ** to store the connection id.
+ */
+ OLEDBG_BEGIN2(TEXT("IOleObject::Advise called\r\n"))
+ hrErr = lpOleObject->lpVtbl->Advise(
+ lpOleObject,
+ lpAdviseSink,
+ (DWORD FAR*)&dwTemp
+ );
+ OLEDBG_END2
+ if (hrErr != NOERROR) fStatus = FALSE;
+#endif
+
+ /* Setup the host names for the OLE object. */
+ OLEDBG_BEGIN2(TEXT("IOleObject::SetHostNames called\r\n"))
+
+ hrErr = CallIOleObjectSetHostNamesA(
+ lpOleObject,
+ lpszContainerApp,
+ lpszContainerObj
+ );
+
+ OLEDBG_END2
+
+ if (hrErr != NOERROR) fStatus = FALSE;
+
+ /* Inform the loadded object's handler/inproc-server that it is in
+ ** its embedding container's process.
+ */
+ OLEDBG_BEGIN2(TEXT("OleSetContainedObject(TRUE) called\r\n"))
+ OleSetContainedObject((LPUNKNOWN)lpOleObject, TRUE);
+ OLEDBG_END2
+
+ return fStatus;
+}
+
+
+/* OleStdSwitchDisplayAspect
+** -------------------------
+** Switch the currently cached display aspect between DVASPECT_ICON
+** and DVASPECT_CONTENT.
+**
+** NOTE: when setting up icon aspect, any currently cached content
+** cache is discarded and any advise connections for content aspect
+** are broken.
+**
+** RETURNS:
+** S_OK -- new display aspect setup successfully
+** E_INVALIDARG -- IOleCache interface is NOT supported (this is
+** required).
+** <other SCODE> -- any SCODE that can be returned by
+** IOleCache::Cache method.
+** NOTE: if an error occurs then the current display aspect and
+** cache contents unchanged.
+*/
+STDAPI OleStdSwitchDisplayAspect(
+ LPOLEOBJECT lpOleObj,
+ LPDWORD lpdwCurAspect,
+ DWORD dwNewAspect,
+ HGLOBAL hMetaPict,
+ BOOL fDeleteOldAspect,
+ BOOL fSetupViewAdvise,
+ LPADVISESINK lpAdviseSink,
+ BOOL FAR* lpfMustUpdate
+)
+{
+ LPOLECACHE lpOleCache = NULL;
+ LPVIEWOBJECT lpViewObj = NULL;
+ LPENUMSTATDATA lpEnumStatData = NULL;
+ STATDATA StatData;
+ FORMATETC FmtEtc;
+ STGMEDIUM Medium;
+ DWORD dwAdvf;
+ DWORD dwNewConnection;
+ DWORD dwOldAspect = *lpdwCurAspect;
+ HRESULT hrErr;
+
+ if (lpfMustUpdate)
+ *lpfMustUpdate = FALSE;
+
+ lpOleCache = (LPOLECACHE)OleStdQueryInterface(
+ (LPUNKNOWN)lpOleObj,&IID_IOleCache);
+
+ // if IOleCache* is NOT available, do nothing
+ if (! lpOleCache)
+ return ResultFromScode(E_INVALIDARG);
+
+ // Setup new cache with the new aspect
+ FmtEtc.cfFormat = (CLIPFORMAT) NULL; // whatever is needed to draw
+ FmtEtc.ptd = NULL;
+ FmtEtc.dwAspect = dwNewAspect;
+ FmtEtc.lindex = -1;
+ FmtEtc.tymed = TYMED_NULL;
+
+ /* OLE2NOTE: if we are setting up Icon aspect with a custom icon
+ ** then we do not want DataAdvise notifications to ever change
+ ** the contents of the data cache. thus we set up a NODATA
+ ** advise connection. otherwise we set up a standard DataAdvise
+ ** connection.
+ */
+ if (dwNewAspect == DVASPECT_ICON && hMetaPict)
+ dwAdvf = ADVF_NODATA;
+ else
+ dwAdvf = ADVF_PRIMEFIRST;
+
+ OLEDBG_BEGIN2(TEXT("IOleCache::Cache called\r\n"))
+ hrErr = lpOleCache->lpVtbl->Cache(
+ lpOleCache,
+ (LPFORMATETC)&FmtEtc,
+ dwAdvf,
+ (LPDWORD)&dwNewConnection
+ );
+ OLEDBG_END2
+
+ if (! SUCCEEDED(hrErr)) {
+ OleDbgOutHResult(TEXT("IOleCache::Cache returned"), hrErr);
+ OleStdRelease((LPUNKNOWN)lpOleCache);
+ return hrErr;
+ }
+
+ *lpdwCurAspect = dwNewAspect;
+
+ /* OLE2NOTE: if we are setting up Icon aspect with a custom icon,
+ ** then stuff the icon into the cache. otherwise the cache must
+ ** be forced to be updated. set the *lpfMustUpdate flag to tell
+ ** caller to force the object to Run so that the cache will be
+ ** updated.
+ */
+ if (dwNewAspect == DVASPECT_ICON && hMetaPict) {
+
+ FmtEtc.cfFormat = CF_METAFILEPICT;
+ FmtEtc.ptd = NULL;
+ FmtEtc.dwAspect = DVASPECT_ICON;
+ FmtEtc.lindex = -1;
+ FmtEtc.tymed = TYMED_MFPICT;
+
+ Medium.tymed = TYMED_MFPICT;
+ Medium.hGlobal = hMetaPict;
+ Medium.pUnkForRelease = NULL;
+
+ OLEDBG_BEGIN2(TEXT("IOleCache::SetData called\r\n"))
+ hrErr = lpOleCache->lpVtbl->SetData(
+ lpOleCache,
+ (LPFORMATETC)&FmtEtc,
+ (LPSTGMEDIUM)&Medium,
+ FALSE /* fRelease */
+ );
+ OLEDBG_END2
+ } else {
+ if (lpfMustUpdate)
+ *lpfMustUpdate = TRUE;
+ }
+
+ if (fSetupViewAdvise && lpAdviseSink) {
+ /* OLE2NOTE: re-establish the ViewAdvise connection */
+ lpViewObj = (LPVIEWOBJECT)OleStdQueryInterface(
+ (LPUNKNOWN)lpOleObj,&IID_IViewObject);
+
+ if (lpViewObj) {
+
+ OLEDBG_BEGIN2(TEXT("IViewObject::SetAdvise called\r\n"))
+ lpViewObj->lpVtbl->SetAdvise(
+ lpViewObj,
+ dwNewAspect,
+ 0,
+ lpAdviseSink
+ );
+ OLEDBG_END2
+
+ OleStdRelease((LPUNKNOWN)lpViewObj);
+ }
+ }
+
+ /* OLE2NOTE: remove any existing caches that are set up for the old
+ ** display aspect. It WOULD be possible to retain the caches set
+ ** up for the old aspect, but this would increase the storage
+ ** space required for the object and possibly require additional
+ ** overhead to maintain the unused cachaes. For these reasons the
+ ** strategy to delete the previous caches is prefered. if it is a
+ ** requirement to quickly switch between Icon and Content
+ ** display, then it would be better to keep both aspect caches.
+ */
+
+ if (fDeleteOldAspect) {
+ OLEDBG_BEGIN2(TEXT("IOleCache::EnumCache called\r\n"))
+ hrErr = lpOleCache->lpVtbl->EnumCache(
+ lpOleCache,
+ (LPENUMSTATDATA FAR*)&lpEnumStatData
+ );
+ OLEDBG_END2
+
+ while(hrErr == NOERROR) {
+ hrErr = lpEnumStatData->lpVtbl->Next(
+ lpEnumStatData,
+ 1,
+ (LPSTATDATA)&StatData,
+ NULL
+ );
+ if (hrErr != NOERROR)
+ break; // DONE! no more caches.
+
+ if (StatData.formatetc.dwAspect == dwOldAspect) {
+
+ // Remove previous cache with old aspect
+ OLEDBG_BEGIN2(TEXT("IOleCache::Uncache called\r\n"))
+ lpOleCache->lpVtbl->Uncache(lpOleCache,StatData.dwConnection);
+ OLEDBG_END2
+ }
+ }
+
+ if (lpEnumStatData) {
+ OleStdVerifyRelease(
+ (LPUNKNOWN)lpEnumStatData,
+ TEXT("OleStdSwitchDisplayAspect: Cache enumerator NOT released")
+ );
+ }
+ }
+
+ if (lpOleCache)
+ OleStdRelease((LPUNKNOWN)lpOleCache);
+
+ return NOERROR;
+}
+
+
+/* OleStdSetIconInCache
+** --------------------
+** SetData a new icon into the existing DVASPECT_ICON cache.
+**
+** RETURNS:
+** HRESULT returned from IOleCache::SetData
+*/
+STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict)
+{
+ LPOLECACHE lpOleCache = NULL;
+ FORMATETC FmtEtc;
+ STGMEDIUM Medium;
+ HRESULT hrErr;
+
+ if (! hMetaPict)
+ return FALSE; // invalid icon
+
+ lpOleCache = (LPOLECACHE)OleStdQueryInterface(
+ (LPUNKNOWN)lpOleObj,&IID_IOleCache);
+ if (! lpOleCache)
+ return FALSE; // if IOleCache* is NOT available, do nothing
+
+ FmtEtc.cfFormat = CF_METAFILEPICT;
+ FmtEtc.ptd = NULL;
+ FmtEtc.dwAspect = DVASPECT_ICON;
+ FmtEtc.lindex = -1;
+ FmtEtc.tymed = TYMED_MFPICT;
+
+ // stuff the icon into the cache.
+ Medium.tymed = TYMED_MFPICT;
+ Medium.hGlobal = hMetaPict;
+ Medium.pUnkForRelease = NULL;
+
+ OLEDBG_BEGIN2(TEXT("IOleCache::SetData called\r\n"))
+ hrErr = lpOleCache->lpVtbl->SetData(
+ lpOleCache,
+ (LPFORMATETC)&FmtEtc,
+ (LPSTGMEDIUM)&Medium,
+ FALSE /* fRelease */
+ );
+ OLEDBG_END2
+
+ OleStdRelease((LPUNKNOWN)lpOleCache);
+
+ return hrErr;
+}
+
+
+
+/* OleStdDoConvert
+** ---------------
+** Do the container-side responsibilities for converting an object.
+** This function would be used in conjunction with the OleUIConvert
+** dialog. If the user selects to convert an object then the
+** container must do the following:
+** 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 of the object to force the actual
+** conversion of the data bits.
+**
+** This function takes care of step 2.
+*/
+STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew)
+{
+ HRESULT error;
+ CLSID clsidOld;
+ CLIPFORMAT cfOld;
+ LPTSTR lpszOld = NULL;
+ TCHAR szNew[OLEUI_CCHKEYMAX];
+
+ if ((error = ReadClassStg(lpStg, &clsidOld)) != NOERROR) {
+ clsidOld = CLSID_NULL;
+ goto errRtn;
+ }
+
+ // read old fmt/old user type; sets out params to NULL on error
+ {
+ LPOLESTR polestr;
+
+ error = ReadFmtUserTypeStg(lpStg, &cfOld, &polestr);
+
+ CopyAndFreeOLESTR(polestr, &lpszOld);
+ }
+
+ OleDbgAssert(error == NOERROR || (cfOld == 0 && lpszOld == NULL));
+
+ // get new user type name; if error, set to NULL string
+ if (OleStdGetUserTypeOfClass(
+ // (LPCLSID)
+ rClsidNew, szNew,sizeof(szNew),NULL /* hKey */) == 0)
+ szNew[0] = TEXT('\0');
+
+ // write class stg
+ if ((error = WriteClassStg(lpStg, rClsidNew)) != NOERROR)
+ goto errRtn;
+
+ // write old fmt/new user type;
+#ifdef UNICODE
+ if ((error = WriteFmtUserTypeStg(lpStg, cfOld, szNew)) != NOERROR)
+ goto errRewriteInfo;
+#else
+ {
+ // Chicago OLE is using UNICODE, so we need to convert the string to
+ // UNICODE.
+ WCHAR szNewT[OLEUI_CCHKEYMAX];
+ mbstowcs(szNewT, szNew, sizeof(szNew));
+ if ((error = WriteFmtUserTypeStg(lpStg, cfOld, szNewT)) != NOERROR)
+ goto errRewriteInfo;
+ }
+#endif
+
+ // set convert bit
+ if ((error = SetConvertStg(lpStg, TRUE)) != NOERROR)
+ goto errRewriteInfo;
+
+ goto okRtn;
+
+errRewriteInfo:
+ (void)WriteClassStg(lpStg, &clsidOld);
+
+ (void)WriteFmtUserTypeStgA(lpStg, cfOld, lpszOld);
+
+errRtn:
+
+okRtn:
+ OleStdFreeString(lpszOld, NULL);
+ return error;
+}
+
+
+/* OleStdGetTreatAsFmtUserType
+** ---------------------------
+** Determine if the application should perform a TreatAs (ActivateAs
+** object or emulation) operation for the object that is stored in
+** the storage.
+**
+** if the CLSID written in the storage is not the same as the
+** application's own CLSID (clsidApp), then a TreatAs operation
+** should take place. if so determine the format the data should be
+** written and the user type name of the object the app should
+** emulate (ie. pretend to be). if this information is not written
+** in the storage then it is looked up in the REGDB. if it can not
+** be found in the REGDB, then the TreatAs operation can NOT be
+** executed.
+**
+** RETURNS: TRUE -- if TreatAs should be performed.
+** valid lpclsid, lplpszType, lpcfFmt to TreatAs are returned
+** (NOTE: lplpszType must be freed by caller)
+** FALSE -- NO TreatAs. lpszType will be NULL.
+** lpclsid = CLSID_NULL; lplpszType = lpcfFmt = NULL;
+*/
+STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(
+ REFCLSID rclsidApp,
+ LPSTORAGE lpStg,
+ CLSID FAR* lpclsid,
+ CLIPFORMAT FAR* lpcfFmt,
+ LPTSTR FAR* lplpszType
+)
+{
+ HRESULT hrErr;
+ HKEY hKey;
+ LONG lRet;
+ UINT lSize;
+ TCHAR szBuf[OLEUI_CCHKEYMAX];
+
+ *lpclsid = CLSID_NULL;
+ *lpcfFmt = 0;
+ *lplpszType = NULL;
+
+ hrErr = ReadClassStg(lpStg, lpclsid);
+ if (hrErr == NOERROR &&
+ ! IsEqualCLSID(lpclsid, &CLSID_NULL) &&
+ ! IsEqualCLSID(lpclsid, rclsidApp)) {
+
+ hrErr = ReadFmtUserTypeStgA(lpStg,(CLIPFORMAT FAR*)lpcfFmt, lplpszType);
+
+ if (hrErr == NOERROR && lplpszType && *lpcfFmt != 0)
+ return TRUE; // Do TreatAs. info was in lpStg.
+
+ /* read info from REGDB
+ ** *lpcfFmt = value of field: CLSID\{...}\DataFormats\DefaultFile
+ ** *lplpszType = value of field: CLSID\{...}
+ */
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+ if (lRet != (LONG)ERROR_SUCCESS)
+ return FALSE;
+ *lpcfFmt = OleStdGetDefaultFileFormatOfClass(lpclsid, hKey);
+ if (*lpcfFmt == 0)
+ return FALSE;
+ lSize = OleStdGetUserTypeOfClass(lpclsid,szBuf,sizeof(szBuf),hKey);
+ if (lSize == 0)
+ return FALSE;
+ *lplpszType = OleStdCopyString(szBuf, NULL);
+ } else {
+ return FALSE; // NO TreatAs
+ }
+}
+
+
+
+/* OleStdDoTreatAsClass
+** --------------------
+** Do the container-side responsibilities for "ActivateAs" (aka.
+** TreatAs) for an object.
+** This function would be used in conjunction with the OleUIConvert
+** dialog. If the user selects to ActivateAs an object then the
+** container must do the following:
+** 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.
+**
+** This function takes care of step 2.
+*/
+STDAPI OleStdDoTreatAsClass(LPTSTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew)
+{
+ HRESULT hrErr;
+ LPTSTR lpszCLSID = NULL;
+ LONG lRet;
+ HKEY hKey;
+
+ OLEDBG_BEGIN2(TEXT("CoTreatAsClass called\r\n"))
+ hrErr = CoTreatAsClass(rclsid, rclsidNew);
+ OLEDBG_END2
+
+ if ((hrErr != NOERROR) && lpszUserType) {
+ lRet = RegOpenKey(HKEY_CLASSES_ROOT, (LPCTSTR) TEXT("CLSID"),
+ (HKEY FAR *)&hKey);
+ StringFromCLSIDA(rclsid, &lpszCLSID);
+
+ RegSetValue(hKey, lpszCLSID, REG_SZ, lpszUserType,
+ lstrlen(lpszUserType));
+
+ if (lpszCLSID)
+ OleStdFreeString(lpszCLSID, NULL);
+
+ hrErr = CoTreatAsClass(rclsid, rclsidNew);
+ RegCloseKey(hKey);
+ }
+
+ return hrErr;
+}
+
+
+
+/* OleStdIsOleLink
+** ---------------
+** Returns TRUE if the OleObject is infact an OLE link object. this
+** checks if IOleLink interface is supported. if so, the object is a
+** link, otherwise not.
+*/
+STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk)
+{
+ LPOLELINK lpOleLink;
+
+ lpOleLink = (LPOLELINK)OleStdQueryInterface(lpUnk, &IID_IOleLink);
+
+ if (lpOleLink) {
+ OleStdRelease((LPUNKNOWN)lpOleLink);
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+
+/* OleStdQueryInterface
+** --------------------
+** Returns the desired interface pointer if exposed by the given object.
+** Returns NULL if the interface is not available.
+** eg.:
+** lpDataObj = OleStdQueryInterface(lpOleObj, &IID_DataObject);
+*/
+STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid)
+{
+ LPUNKNOWN lpInterface;
+ HRESULT hrErr;
+
+ hrErr = lpUnk->lpVtbl->QueryInterface(
+ lpUnk,
+ riid,
+ (LPVOID FAR*)&lpInterface
+ );
+
+ if (hrErr == NOERROR)
+ return lpInterface;
+ else
+ return NULL;
+}
+
+
+/* OleStdGetData
+** -------------
+** Retrieve data from an IDataObject in a specified format on a
+** global memory block. This function ALWAYS returns a private copy
+** of the data to the caller. if necessary a copy is made of the
+** data (ie. if lpMedium->pUnkForRelease != NULL). The caller assumes
+** ownership of the data block in all cases and must free the data
+** when done with it. The caller may directly free the data handle
+** returned (taking care whether it is a simple HGLOBAL or a HANDLE
+** to a MetafilePict) or the caller may call
+** ReleaseStgMedium(lpMedium). this OLE helper function will do the
+** right thing.
+**
+** PARAMETERS:
+** LPDATAOBJECT lpDataObj -- object on which GetData should be
+** called.
+** CLIPFORMAT cfFormat -- desired clipboard format (eg. CF_TEXT)
+** DVTARGETDEVICE FAR* lpTargetDevice -- target device for which
+** the data should be composed. This may
+** be NULL. NULL can be used whenever the
+** data format is insensitive to target
+** device or when the caller does not care
+** what device is used.
+** LPSTGMEDIUM lpMedium -- ptr to STGMEDIUM struct. the
+** resultant medium from the
+** IDataObject::GetData call is
+** returned.
+**
+** RETURNS:
+** HGLOBAL -- global memory handle of retrieved data block.
+** NULL -- if error.
+*/
+STDAPI_(HGLOBAL) OleStdGetData(
+ LPDATAOBJECT lpDataObj,
+ CLIPFORMAT cfFormat,
+ DVTARGETDEVICE FAR* lpTargetDevice,
+ DWORD dwDrawAspect,
+ LPSTGMEDIUM lpMedium
+)
+{
+ HRESULT hrErr;
+ FORMATETC formatetc;
+ HGLOBAL hGlobal = NULL;
+ HGLOBAL hCopy;
+ LPVOID lp;
+
+ formatetc.cfFormat = cfFormat;
+ formatetc.ptd = lpTargetDevice;
+ formatetc.dwAspect = dwDrawAspect;
+ formatetc.lindex = -1;
+
+ switch (cfFormat) {
+ case CF_METAFILEPICT:
+ formatetc.tymed = TYMED_MFPICT;
+ break;
+
+ case CF_BITMAP:
+ formatetc.tymed = TYMED_GDI;
+ break;
+
+ default:
+ formatetc.tymed = TYMED_HGLOBAL;
+ break;
+ }
+
+ OLEDBG_BEGIN2(TEXT("IDataObject::GetData called\r\n"))
+ hrErr = lpDataObj->lpVtbl->GetData(
+ lpDataObj,
+ (LPFORMATETC)&formatetc,
+ lpMedium
+ );
+ OLEDBG_END2
+
+ if (hrErr != NOERROR)
+ return NULL;
+
+ if ((hGlobal = lpMedium->hGlobal) == NULL)
+ return NULL;
+
+ // Check if hGlobal really points to valid memory
+ if ((lp = GlobalLock(hGlobal)) != NULL) {
+ if (IsBadReadPtr(lp, 1)) {
+ GlobalUnlock(hGlobal);
+ return NULL; // ERROR: memory is NOT valid
+ }
+ GlobalUnlock(hGlobal);
+ }
+
+ if (hGlobal != NULL && lpMedium->pUnkForRelease != NULL) {
+ /* OLE2NOTE: the callee wants to retain ownership of the data.
+ ** this is indicated by passing a non-NULL pUnkForRelease.
+ ** thus, we will make a copy of the data and release the
+ ** callee's copy.
+ */
+
+ hCopy = OleDuplicateData(hGlobal, cfFormat, GHND|GMEM_SHARE);
+ ReleaseStgMedium(lpMedium); // release callee's copy of data
+
+ hGlobal = hCopy;
+ lpMedium->hGlobal = hCopy;
+ lpMedium->pUnkForRelease = NULL;
+ }
+ return hGlobal;
+}
+
+
+/* OleStdMalloc
+** ------------
+** allocate memory using the currently active IMalloc* allocator
+*/
+STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize)
+{
+ LPVOID pout;
+ LPMALLOC pmalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
+ OleDbgAssertSz(0, szAssertMemAlloc);
+ return NULL;
+ }
+
+ pout = (LPVOID)pmalloc->lpVtbl->Alloc(pmalloc, ulSize);
+
+ if (pmalloc != NULL) {
+ ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
+ }
+
+ return pout;
+}
+
+
+/* OleStdRealloc
+** -------------
+** re-allocate memory using the currently active IMalloc* allocator
+*/
+STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize)
+{
+ LPVOID pout;
+ LPMALLOC pmalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
+ OleDbgAssertSz(0, szAssertMemAlloc);
+ return NULL;
+ }
+
+ pout = (LPVOID)pmalloc->lpVtbl->Realloc(pmalloc, pmem, ulSize);
+
+ if (pmalloc != NULL) {
+ ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
+ }
+
+ return pout;
+}
+
+
+/* OleStdFree
+** ----------
+** free memory using the currently active IMalloc* allocator
+*/
+STDAPI_(void) OleStdFree(LPVOID pmem)
+{
+ LPMALLOC pmalloc;
+
+ if (pmem == NULL)
+ return;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
+ OleDbgAssertSz(0, szAssertMemAlloc);
+ return;
+ }
+
+ pmalloc->lpVtbl->Free(pmalloc, pmem);
+
+ if (pmalloc != NULL) {
+ ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
+ }
+}
+
+
+/* OleStdGetSize
+** -------------
+** Get the size of a memory block that was allocated using the
+** currently active IMalloc* allocator.
+*/
+STDAPI_(ULONG) OleStdGetSize(LPVOID pmem)
+{
+ ULONG ulSize;
+ LPMALLOC pmalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
+ OleDbgAssertSz(0, szAssertMemAlloc);
+ return (ULONG)-1;
+ }
+
+ ulSize = pmalloc->lpVtbl->GetSize(pmalloc, pmem);
+
+ if (pmalloc != NULL) {
+ ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
+ }
+
+ return ulSize;
+}
+
+
+/* OleStdFreeString
+** ----------------
+** Free a string that was allocated with the currently active
+** IMalloc* allocator.
+**
+** if the caller has the current IMalloc* handy, then it can be
+** passed as a argument, otherwise this function will retrieve the
+** active allocator and use it.
+*/
+STDAPI_(void) OleStdFreeString(LPTSTR lpsz, LPMALLOC lpMalloc)
+{
+ BOOL fMustRelease = FALSE;
+
+ if (! lpMalloc) {
+ if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)
+ return;
+ fMustRelease = TRUE;
+ }
+
+ lpMalloc->lpVtbl->Free(lpMalloc, lpsz);
+
+ if (fMustRelease)
+ lpMalloc->lpVtbl->Release(lpMalloc);
+}
+
+
+/* OleStdCopyString
+** ----------------
+** Copy a string into memory allocated with the currently active
+** IMalloc* allocator.
+**
+** if the caller has the current IMalloc* handy, then it can be
+** passed as a argument, otherwise this function will retrieve the
+** active allocator and use it.
+*/
+STDAPI_(LPTSTR) OleStdCopyString(LPTSTR lpszSrc, LPMALLOC lpMalloc)
+{
+ LPTSTR lpszDest = NULL;
+ BOOL fMustRelease = FALSE;
+ UINT lSize = lstrlen(lpszSrc);
+
+ if (! lpMalloc) {
+ if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)
+ return NULL;
+ fMustRelease = TRUE;
+ }
+
+ lpszDest = lpMalloc->lpVtbl->Alloc(lpMalloc, (lSize+1)*sizeof(TCHAR));
+
+ if (lpszDest)
+ lstrcpy(lpszDest, lpszSrc);
+
+ if (fMustRelease)
+ lpMalloc->lpVtbl->Release(lpMalloc);
+ return lpszDest;
+}
+
+
+/*
+ * OleStdCreateStorageOnHGlobal()
+ *
+ * Purpose:
+ * Create a memory based IStorage*.
+ *
+ * OLE2NOTE: if fDeleteOnRelease==TRUE, then the ILockBytes is created
+ * such that it will delete them memory on its last release.
+ * the IStorage on created on top of the ILockBytes in NOT
+ * created with STGM_DELETEONRELEASE. when the IStorage receives
+ * its last release, it will release the ILockBytes which will
+ * in turn free the memory. it is in fact an error to specify
+ * STGM_DELETEONRELEASE in this situation.
+ *
+ * Parameters:
+ * hGlobal -- handle to MEM_SHARE allocated memory. may be NULL and
+ * memory will be automatically allocated.
+ * fDeleteOnRelease -- controls if the memory is freed on the last release.
+ * grfMode -- flags passed to StgCreateDocfileOnILockBytes
+ *
+ * NOTE: if hGlobal is NULL, then a new IStorage is created and
+ * STGM_CREATE flag is passed to StgCreateDocfileOnILockBytes.
+ * if hGlobal is non-NULL, then it is assumed that the hGlobal already
+ * has an IStorage inside it and STGM_CONVERT flag is passed
+ * to StgCreateDocfileOnILockBytes.
+ *
+ * Return Value:
+ * SCODE - S_OK if successful
+ */
+STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(
+ HANDLE hGlobal,
+ BOOL fDeleteOnRelease,
+ DWORD grfMode
+)
+{
+ DWORD grfCreateMode=grfMode | (hGlobal==NULL ? STGM_CREATE:STGM_CONVERT);
+ HRESULT hrErr;
+ LPLOCKBYTES lpLockBytes = NULL;
+ DWORD reserved = 0;
+ LPSTORAGE lpStg = NULL;
+
+ hrErr = CreateILockBytesOnHGlobal(
+ hGlobal,
+ fDeleteOnRelease,
+ (LPLOCKBYTES FAR*)&lpLockBytes
+ );
+ if (hrErr != NOERROR)
+ return NULL;
+
+ hrErr = StgCreateDocfileOnILockBytes(
+ lpLockBytes,
+ grfCreateMode,
+ reserved,
+ (LPSTORAGE FAR*)&lpStg
+ );
+ if (hrErr != NOERROR) {
+ OleStdRelease((LPUNKNOWN)lpLockBytes);
+ return NULL;
+ }
+ return lpStg;
+}
+
+
+
+/*
+ * OleStdCreateTempStorage()
+ *
+ * Purpose:
+ * Create a temporay IStorage* that will DeleteOnRelease.
+ * this can be either memory based or file based.
+ *
+ * Parameters:
+ * fUseMemory -- controls if memory-based or file-based stg is created
+ * grfMode -- storage mode flags
+ *
+ * Return Value:
+ * LPSTORAGE - if successful, NULL otherwise
+ */
+STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode)
+{
+ LPSTORAGE lpstg;
+ HRESULT hrErr;
+ DWORD reserved = 0;
+
+ if (fUseMemory) {
+ lpstg = OleStdCreateStorageOnHGlobal(
+ NULL, /* auto allocate */
+ TRUE, /* delete on release */
+ grfMode
+ );
+ } else {
+ /* allocate a temp docfile that will delete on last release */
+ hrErr = StgCreateDocfile(
+ NULL,
+ grfMode | STGM_DELETEONRELEASE | STGM_CREATE,
+ reserved,
+ &lpstg
+ );
+ if (hrErr != NOERROR)
+ return NULL;
+ }
+ return lpstg;
+}
+
+
+/* OleStdGetOleObjectData
+** ----------------------
+** Render CF_EMBEDSOURCE/CF_EMBEDDEDOBJECT data on an TYMED_ISTORAGE
+** medium by asking the object to save into the storage.
+** the object must support IPersistStorage.
+**
+** if lpMedium->tymed == TYMED_NULL, then a delete-on-release
+** storage is allocated (either file-based or memory-base depending
+** the value of fUseMemory). this is useful to support an
+** IDataObject::GetData call where the callee must allocate the
+** medium.
+**
+** if lpMedium->tymed == TYMED_ISTORAGE, then the data is writen
+** into the passed in IStorage. this is useful to support an
+** IDataObject::GetDataHere call where the caller has allocated his
+** own IStorage.
+*/
+STDAPI OleStdGetOleObjectData(
+ LPPERSISTSTORAGE lpPStg,
+ LPFORMATETC lpformatetc,
+ LPSTGMEDIUM lpMedium,
+ BOOL fUseMemory
+)
+{
+ LPSTORAGE lpstg = NULL;
+ DWORD reserved = 0;
+ SCODE sc = S_OK;
+ HRESULT hrErr;
+
+ lpMedium->pUnkForRelease = NULL;
+
+ if (lpMedium->tymed == TYMED_NULL) {
+
+ if (lpformatetc->tymed & TYMED_ISTORAGE) {
+
+ /* allocate a temp docfile that will delete on last release */
+ lpstg = OleStdCreateTempStorage(
+ TRUE /*fUseMemory*/,
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE
+ );
+ if (!lpstg)
+ return ResultFromScode(E_OUTOFMEMORY);
+
+ lpMedium->pstg = lpstg;
+ lpMedium->tymed = TYMED_ISTORAGE;
+ lpMedium->pUnkForRelease = NULL;
+ } else {
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+ } else if (lpMedium->tymed == TYMED_ISTORAGE) {
+ lpMedium->tymed = TYMED_ISTORAGE;
+ } else {
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+
+ // OLE2NOTE: even if OleSave returns an error you should still call
+ // SaveCompleted.
+
+ OLEDBG_BEGIN2(TEXT("OleSave called\r\n"))
+ hrErr = OleSave(lpPStg, lpMedium->pstg, FALSE /* fSameAsLoad */);
+ OLEDBG_END2
+
+ if (hrErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: OleSave returned"), hrErr);
+ sc = GetScode(hrErr);
+ }
+ OLEDBG_BEGIN2(TEXT("IPersistStorage::SaveCompleted called\r\n"))
+ hrErr = lpPStg->lpVtbl->SaveCompleted(lpPStg, NULL);
+ OLEDBG_END2
+
+ if (hrErr != NOERROR) {
+ OleDbgOutHResult(TEXT("WARNING: SaveCompleted returned"),hrErr);
+ if (sc == S_OK)
+ sc = GetScode(hrErr);
+ }
+
+ return ResultFromScode(sc);
+}
+
+
+STDAPI OleStdGetLinkSourceData(
+ LPMONIKER lpmk,
+ LPCLSID lpClsID,
+ LPFORMATETC lpformatetc,
+ LPSTGMEDIUM lpMedium
+)
+{
+ LPSTREAM lpstm = NULL;
+ DWORD reserved = 0;
+ HRESULT hrErr;
+
+ if (lpMedium->tymed == TYMED_NULL) {
+ if (lpformatetc->tymed & TYMED_ISTREAM) {
+ hrErr = CreateStreamOnHGlobal(
+ NULL, /* auto allocate */
+ TRUE, /* delete on release */
+ (LPSTREAM FAR*)&lpstm
+ );
+ if (hrErr != NOERROR) {
+ lpMedium->pUnkForRelease = NULL;
+ return ResultFromScode(E_OUTOFMEMORY);
+ }
+ lpMedium->pstm = lpstm;
+ lpMedium->tymed = TYMED_ISTREAM;
+ lpMedium->pUnkForRelease = NULL;
+ } else {
+ lpMedium->pUnkForRelease = NULL;
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+ } else {
+ if (lpMedium->tymed == TYMED_ISTREAM) {
+ lpMedium->tymed = TYMED_ISTREAM;
+ lpMedium->pstm = lpMedium->pstm;
+ lpMedium->pUnkForRelease = NULL;
+ } else {
+ lpMedium->pUnkForRelease = NULL;
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+ }
+
+ hrErr = OleSaveToStream((LPPERSISTSTREAM)lpmk, lpMedium->pstm);
+ if (hrErr != NOERROR) return hrErr;
+ return WriteClassStm(lpMedium->pstm, lpClsID);
+}
+
+/*
+ * OleStdGetObjectDescriptorData
+ *
+ * Purpose:
+ * Fills and returns a OBJECTDESCRIPTOR structure.
+ * See OBJECTDESCRIPTOR for more information.
+ *
+ * Parameters:
+ * clsid CLSID CLSID of object being transferred
+ * dwDrawAspect DWORD Display Aspect of object
+ * sizel SIZEL Size of object in HIMETRIC
+ * pointl POINTL Offset from upper-left corner of object where mouse went
+ * down for drag. Meaningful only when drag-drop is used.
+ * dwStatus DWORD OLEMISC flags
+ * lpszFullUserTypeName LPSTR Full User Type Name
+ * lpszSrcOfCopy LPSTR Source of Copy
+ *
+ * Return Value:
+ * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
+ */
+STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(
+ CLSID clsid,
+ DWORD dwDrawAspect,
+ SIZEL sizel,
+ POINTL pointl,
+ DWORD dwStatus,
+ LPTSTR lpszFullUserTypeNameA,
+ LPTSTR lpszSrcOfCopyA
+)
+{
+ HGLOBAL hMem = NULL;
+ IBindCtx FAR *pbc = NULL;
+ LPOBJECTDESCRIPTOR lpOD;
+ DWORD dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen;
+ LPOLESTR lpszFullUserTypeName,
+ lpszSrcOfCopy;
+
+ // convert out strings to UNICODE
+
+ if( lpszSrcOfCopyA )
+ {
+ lpszSrcOfCopy = CreateOLESTR(lpszSrcOfCopyA);
+ }
+
+ lpszFullUserTypeName = CreateOLESTR(lpszFullUserTypeNameA);
+
+ // Get the length of Full User Type Name; Add 1 for the null terminator
+ dwFullUserTypeNameLen = lpszFullUserTypeName ? wcslen(lpszFullUserTypeName)+1 : 0;
+
+ // Get the Source of Copy string and it's length; Add 1 for the null terminator
+ if (lpszSrcOfCopy)
+ dwSrcOfCopyLen = wcslen(lpszSrcOfCopy)+1;
+ else {
+ // No src moniker so use user type name as source string.
+ lpszSrcOfCopy = lpszFullUserTypeName;
+ dwSrcOfCopyLen = dwFullUserTypeNameLen;
+ }
+
+ // Allocate space for OBJECTDESCRIPTOR and the additional string data
+ dwObjectDescSize = sizeof(OBJECTDESCRIPTOR);
+ hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwObjectDescSize +
+ (dwFullUserTypeNameLen + dwSrcOfCopyLen)*sizeof(OLECHAR));
+ if (NULL == hMem)
+ goto error;
+
+ lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);
+
+ // Set the FullUserTypeName offset and copy the string
+ if (lpszFullUserTypeName)
+ {
+ lpOD->dwFullUserTypeName = dwObjectDescSize;
+ wcscpy((LPOLESTR)(((BYTE FAR *)lpOD)+lpOD->dwFullUserTypeName),
+ lpszFullUserTypeName);
+ }
+ else lpOD->dwFullUserTypeName = 0; // zero offset indicates that string is not present
+
+ // Set the SrcOfCopy offset and copy the string
+ if (lpszSrcOfCopy)
+ {
+ lpOD->dwSrcOfCopy = dwObjectDescSize +
+ dwFullUserTypeNameLen*sizeof(OLECHAR);
+ wcscpy((LPOLESTR)(((BYTE FAR *)lpOD)+lpOD->dwSrcOfCopy), lpszSrcOfCopy);
+ }
+ else lpOD->dwSrcOfCopy = 0; // zero offset indicates that string is not present
+
+ // Initialize the rest of the OBJECTDESCRIPTOR
+ lpOD->cbSize = dwObjectDescSize +
+ (dwFullUserTypeNameLen + dwSrcOfCopyLen)*sizeof(OLECHAR);
+ lpOD->clsid = clsid;
+ lpOD->dwDrawAspect = dwDrawAspect;
+ lpOD->sizel = sizel;
+ lpOD->pointl = pointl;
+ lpOD->dwStatus = dwStatus;
+
+ GlobalUnlock(hMem);
+
+ FREEOLESTR(lpszFullUserTypeName);
+ FREEOLESTR(lpszSrcOfCopy);
+
+ return hMem;
+
+error:
+ if (hMem)
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+ return NULL;
+}
+
+/*
+ * OleStdGetObjectDescriptorDataFromOleObject
+ *
+ * Purpose:
+ * Fills and returns a OBJECTDESCRIPTOR structure. Information for the structure is
+ * obtained from an OLEOBJECT.
+ * See OBJECTDESCRIPTOR for more information.
+ *
+ * Parameters:
+ * lpOleObj LPOLEOBJECT OleObject from which ONJECTDESCRIPTOR info
+ * is obtained.
+ * lpszSrcOfCopy LPSTR string to identify source of copy.
+ * May be NULL in which case IOleObject::GetMoniker is called
+ * to get the moniker of the object. if the object is loaded
+ * as part of a data transfer document, then usually
+ * lpOleClientSite==NULL is passed to OleLoad when loading
+ * the object. in this case the IOleObject:GetMoniker call
+ * will always fail (it tries to call back to the object's
+ * client site). in this situation a non-NULL lpszSrcOfCopy
+ * parameter should be passed.
+ * dwDrawAspect DWORD Display Aspect of object
+ * pointl POINTL Offset from upper-left corner of object where
+ * mouse went down for drag. Meaningful only when drag-drop
+ * is used.
+ * lpSizelHim SIZEL (optional) If the object is being scaled in its
+ * container, then the container should pass the extents
+ * that it is using to display the object.
+ * May be NULL if the object is NOT being scaled. in this
+ * case, IViewObject2::GetExtent will be called to get the
+ * extents from the object.
+ *
+ * Return Value:
+ * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
+ */
+
+STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(
+ LPOLEOBJECT lpOleObj,
+ LPTSTR lpszSrcOfCopy,
+ DWORD dwDrawAspect,
+ POINTL pointl,
+ LPSIZEL lpSizelHim
+)
+{
+ CLSID clsid;
+ LPTSTR lpszFullUserTypeName = NULL;
+ LPMONIKER lpSrcMonikerOfCopy = NULL;
+ HGLOBAL hObjDesc;
+ IBindCtx FAR *pbc = NULL;
+ HRESULT hrErr;
+ SIZEL sizelHim;
+ BOOL fFreeSrcOfCopy = FALSE;
+ LPOLELINK lpOleLink = (LPOLELINK)
+ OleStdQueryInterface((LPUNKNOWN)lpOleObj,&IID_IOleLink);
+
+#ifdef OLE201
+ LPVIEWOBJECT2 lpViewObj2 = (LPVIEWOBJECT2)
+ OleStdQueryInterface((LPUNKNOWN)lpOleObj, &IID_IViewObject2);
+#endif
+
+ BOOL fIsLink = (lpOleLink ? TRUE : FALSE);
+ TCHAR szLinkedTypeFmt[80];
+ LPTSTR lpszBuf = NULL;
+ DWORD dwStatus = 0;
+
+ // Get CLSID
+ OLEDBG_BEGIN2(TEXT("IOleObject::GetUserClassID called\r\n"))
+ hrErr = lpOleObj->lpVtbl->GetUserClassID(lpOleObj, &clsid);
+ OLEDBG_END2
+ if (hrErr != NOERROR)
+ clsid = CLSID_NULL;
+
+ // Get FullUserTypeName
+ OLEDBG_BEGIN2(TEXT("IOleObject::GetUserType called\r\n"))
+ {
+ LPOLESTR polestr;
+
+ hrErr = lpOleObj->lpVtbl->GetUserType(
+ lpOleObj,
+ USERCLASSTYPE_FULL,
+ &polestr
+ );
+
+ CopyAndFreeOLESTR(polestr, &lpszFullUserTypeName);
+ }
+
+ OLEDBG_END2
+
+// REVIEW: added IDS_OLE2UILINKEDTYPE to strings.rc
+ /* if object is a link, then expand usertypename to be "Linked %s" */
+ if (fIsLink && lpszFullUserTypeName) {
+ if (0 == LoadString(ghInst, IDS_OLE2UIPASTELINKEDTYPE,
+ (LPTSTR)szLinkedTypeFmt, sizeof(szLinkedTypeFmt)/sizeof(TCHAR)))
+ lstrcpy(szLinkedTypeFmt, (LPTSTR) TEXT("Linked %s"));
+ lpszBuf = OleStdMalloc(
+ (lstrlen(lpszFullUserTypeName)+lstrlen(szLinkedTypeFmt)+1) *
+ sizeof(TCHAR));
+ if (lpszBuf) {
+ wsprintf(lpszBuf, szLinkedTypeFmt, lpszFullUserTypeName);
+ OleStdFreeString(lpszFullUserTypeName, NULL);
+ lpszFullUserTypeName = lpszBuf;
+ }
+ }
+
+ /* Get Source Of Copy
+ ** if the object is an embedding, then get the object's moniker
+ ** if the object is a link, then get the link source moniker
+ */
+ if (fIsLink) {
+
+ OLEDBG_BEGIN2(TEXT("IOleLink::GetSourceDisplayName called\r\n"))
+
+ {
+ LPOLESTR polestr;
+
+ hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(
+ lpOleLink, &polestr );
+
+ CopyAndFreeOLESTR(polestr, &lpszSrcOfCopy);
+ }
+ OLEDBG_END2
+ fFreeSrcOfCopy = TRUE;
+
+ } else {
+
+ if (lpszSrcOfCopy == NULL) {
+ OLEDBG_BEGIN2(TEXT("IOleObject::GetMoniker called\r\n"))
+ hrErr = lpOleObj->lpVtbl->GetMoniker(
+ lpOleObj,
+ OLEGETMONIKER_TEMPFORUSER,
+ OLEWHICHMK_OBJFULL,
+ (LPMONIKER FAR*)&lpSrcMonikerOfCopy
+ );
+ OLEDBG_END2
+ if (hrErr == NOERROR)
+ {
+#ifdef OLE201
+ CreateBindCtx(0, (LPBC FAR*)&pbc);
+#endif
+ CallIMonikerGetDisplayNameA(
+ lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);
+
+ pbc->lpVtbl->Release(pbc);
+ fFreeSrcOfCopy = TRUE;
+ }
+ }
+ }
+
+ // Get SIZEL
+ if (lpSizelHim) {
+ // Use extents passed by the caller
+ sizelHim = *lpSizelHim;
+ } else if (lpViewObj2) {
+ // Get the current extents from the object
+ OLEDBG_BEGIN2(TEXT("IViewObject2::GetExtent called\r\n"))
+ hrErr = lpViewObj2->lpVtbl->GetExtent(
+ lpViewObj2,
+ dwDrawAspect,
+ -1, /*lindex*/
+ NULL, /*ptd*/
+ (LPSIZEL)&sizelHim
+ );
+ OLEDBG_END2
+ if (hrErr != NOERROR)
+ sizelHim.cx = sizelHim.cy = 0;
+ } else {
+ sizelHim.cx = sizelHim.cy = 0;
+ }
+
+ // Get DWSTATUS
+ OLEDBG_BEGIN2(TEXT("IOleObject::GetMiscStatus called\r\n"))
+ hrErr = lpOleObj->lpVtbl->GetMiscStatus(
+ lpOleObj,
+ dwDrawAspect,
+ &dwStatus
+ );
+ OLEDBG_END2
+ if (hrErr != NOERROR)
+ dwStatus = 0;
+
+ // Get OBJECTDESCRIPTOR
+ hObjDesc = OleStdGetObjectDescriptorData(
+ clsid,
+ dwDrawAspect,
+ sizelHim,
+ pointl,
+ dwStatus,
+ lpszFullUserTypeName,
+ lpszSrcOfCopy
+ );
+ if (! hObjDesc)
+ goto error;
+
+ // Clean up
+ if (lpszFullUserTypeName)
+ OleStdFreeString(lpszFullUserTypeName, NULL);
+ if (fFreeSrcOfCopy && lpszSrcOfCopy)
+ OleStdFreeString(lpszSrcOfCopy, NULL);
+ if (lpSrcMonikerOfCopy)
+ OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);
+ if (lpOleLink)
+ OleStdRelease((LPUNKNOWN)lpOleLink);
+ if (lpViewObj2)
+ OleStdRelease((LPUNKNOWN)lpViewObj2);
+
+ return hObjDesc;
+
+error:
+ if (lpszFullUserTypeName)
+ OleStdFreeString(lpszFullUserTypeName, NULL);
+ if (fFreeSrcOfCopy && lpszSrcOfCopy)
+ OleStdFreeString(lpszSrcOfCopy, NULL);
+ if (lpSrcMonikerOfCopy)
+ OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);
+ if (lpOleLink)
+ OleStdRelease((LPUNKNOWN)lpOleLink);
+ if (lpViewObj2)
+ OleStdRelease((LPUNKNOWN)lpViewObj2);
+
+ return NULL;
+}
+
+/*
+ * OleStdFillObjectDescriptorFromData
+ *
+ * Purpose:
+ * Fills and returns a OBJECTDESCRIPTOR structure. The source object will
+ * offer CF_OBJECTDESCRIPTOR if it is an OLE2 object, CF_OWNERLINK if it
+ * is an OLE1 object, or CF_FILENAME if it has been copied to the clipboard
+ * by FileManager.
+ *
+ * Parameters:
+ * lpDataObject LPDATAOBJECT Source object
+ * lpmedium LPSTGMEDIUM Storage medium
+ * lpcfFmt CLIPFORMAT FAR * Format offered by lpDataObject
+ * (OUT parameter)
+ *
+ * Return Value:
+ * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
+ */
+
+STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(
+ LPDATAOBJECT lpDataObject,
+ LPSTGMEDIUM lpmedium,
+ CLIPFORMAT FAR* lpcfFmt
+)
+{
+ CLSID clsid;
+ SIZEL sizelHim;
+ POINTL pointl;
+ LPTSTR lpsz, szFullUserTypeName, szSrcOfCopy, szClassName, szDocName, szItemName;
+ int nClassName, nDocName, nItemName, nFullUserTypeName;
+ LPTSTR szBuf = NULL;
+ HGLOBAL hMem = NULL;
+ HKEY hKey = NULL;
+ LPMALLOC pIMalloc = NULL;
+ DWORD dw = OLEUI_CCHKEYMAX_SIZE;
+ HGLOBAL hObjDesc;
+ HRESULT hrErr;
+
+
+ // GetData CF_OBJECTDESCRIPTOR format from the object on the clipboard.
+ // Only OLE 2 objects on the clipboard will offer CF_OBJECTDESCRIPTOR
+ if (hMem = OleStdGetData(
+ lpDataObject,
+ (CLIPFORMAT) cfObjectDescriptor,
+ NULL,
+ DVASPECT_CONTENT,
+ lpmedium))
+ {
+ *lpcfFmt = cfObjectDescriptor;
+ return hMem; // Don't drop to clean up at the end of this function
+ }
+ // If CF_OBJECTDESCRIPTOR is not available, i.e. if this is not an OLE2 object,
+ // check if this is an OLE 1 object. OLE 1 objects will offer CF_OWNERLINK
+ else if (hMem = OleStdGetData(
+ lpDataObject,
+ (CLIPFORMAT) cfOwnerLink,
+ NULL,
+ DVASPECT_CONTENT,
+ lpmedium))
+ {
+ *lpcfFmt = cfOwnerLink;
+ // CF_OWNERLINK contains null-terminated strings for class name, document name
+ // and item name with two null terminating characters at the end
+ szClassName = (LPTSTR)GlobalLock(hMem);
+ nClassName = lstrlen(szClassName);
+ szDocName = szClassName + nClassName + 1;
+ nDocName = lstrlen(szDocName);
+ szItemName = szDocName + nDocName + 1;
+ nItemName = lstrlen(szItemName);
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+ if (hrErr != NOERROR)
+ goto error;
+
+ // Find FullUserTypeName from Registration database using class name
+ if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS)
+ goto error;
+
+ // Allocate space for szFullUserTypeName & szSrcOfCopy. Maximum length of FullUserTypeName
+ // is OLEUI_CCHKEYMAX_SIZE. SrcOfCopy is constructed by concatenating FullUserTypeName, Document
+ // Name and ItemName separated by spaces.
+ szBuf = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc,
+ (DWORD)2*OLEUI_CCHKEYMAX_SIZE+
+ (nDocName+nItemName+4)*sizeof(TCHAR));
+ if (NULL == szBuf)
+ goto error;
+ szFullUserTypeName = szBuf;
+ szSrcOfCopy = szFullUserTypeName+OLEUI_CCHKEYMAX_SIZE+1;
+
+ // Get FullUserTypeName
+ if (RegQueryValue(hKey, NULL, szFullUserTypeName, &dw) != ERROR_SUCCESS)
+ goto error;
+
+ // Build up SrcOfCopy string from FullUserTypeName, DocumentName & ItemName
+ lpsz = szSrcOfCopy;
+ lstrcpy(lpsz, szFullUserTypeName);
+ nFullUserTypeName = lstrlen(szFullUserTypeName);
+ lpsz[nFullUserTypeName]= TEXT(' ');
+ lpsz += nFullUserTypeName+1;
+ lstrcpy(lpsz, szDocName);
+ lpsz[nDocName] = TEXT(' ');
+ lpsz += nDocName+1;
+ lstrcpy(lpsz, szItemName);
+
+ sizelHim.cx = sizelHim.cy = 0;
+ pointl.x = pointl.y = 0;
+
+ CLSIDFromProgIDA(szClassName, &clsid);
+
+ hObjDesc = OleStdGetObjectDescriptorData(
+ clsid,
+ DVASPECT_CONTENT,
+ sizelHim,
+ pointl,
+ 0,
+ szFullUserTypeName,
+ szSrcOfCopy
+ );
+ if (!hObjDesc)
+ goto error;
+ }
+ // Check if object is CF_FILENAME
+ else if (hMem = OleStdGetData(
+ lpDataObject,
+ (CLIPFORMAT) cfFileName,
+ NULL,
+ DVASPECT_CONTENT,
+ lpmedium))
+ {
+ *lpcfFmt = cfFileName;
+ lpsz = (LPTSTR)GlobalLock(hMem);
+
+ hrErr = GetClassFileA(lpsz, &clsid);
+
+ /* OLE2NOTE: if the file does not have an OLE class
+ ** associated, then use the OLE 1 Packager as the class of
+ ** the object to be created. this is the behavior of
+ ** OleCreateFromData API
+ */
+ if (hrErr != NOERROR)
+ CLSIDFromProgIDA("Package", &clsid);
+ sizelHim.cx = sizelHim.cy = 0;
+ pointl.x = pointl.y = 0;
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+ if (hrErr != NOERROR)
+ goto error;
+ szBuf = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)OLEUI_CCHKEYMAX_SIZE);
+ if (NULL == szBuf)
+ goto error;
+
+ OleStdGetUserTypeOfClass(&clsid, szBuf, OLEUI_CCHKEYMAX_SIZE, NULL);
+
+ hObjDesc = OleStdGetObjectDescriptorData(
+ clsid,
+ DVASPECT_CONTENT,
+ sizelHim,
+ pointl,
+ 0,
+ szBuf,
+ lpsz
+ );
+ if (!hObjDesc)
+ goto error;
+ }
+ else goto error;
+
+ // Clean up
+ if (szBuf)
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);
+ if (pIMalloc)
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ if (hMem)
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+ if (hKey)
+ RegCloseKey(hKey);
+ return hObjDesc;
+
+error:
+ if (szBuf)
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);
+ if (pIMalloc)
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ if (hMem)
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+ if (hKey)
+ RegCloseKey(hKey);
+ return NULL;
+}
+
+
+#if defined( OBSOLETE )
+
+/*************************************************************************
+** The following API's have been converted into macros:
+** OleStdQueryOleObjectData
+** OleStdQueryLinkSourceData
+** OleStdQueryObjectDescriptorData
+** OleStdQueryFormatMedium
+** OleStdCopyMetafilePict
+** OleStdGetDropEffect
+**
+** These macros are defined in olestd.h
+*************************************************************************/
+
+STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc)
+{
+ if (lpformatetc->tymed & TYMED_ISTORAGE) {
+ return NOERROR;
+ } else {
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+}
+
+
+STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc)
+{
+ if (lpformatetc->tymed & TYMED_ISTREAM) {
+ return NOERROR;
+ } else {
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+}
+
+
+STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc)
+{
+ if (lpformatetc->tymed & TYMED_HGLOBAL) {
+ return NOERROR;
+ } else {
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+}
+
+
+STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed)
+{
+ if (lpformatetc->tymed & tymed) {
+ return NOERROR;
+ } else {
+ return ResultFromScode(DATA_E_FORMATETC);
+ }
+}
+
+
+/*
+ * OleStdCopyMetafilePict()
+ *
+ * Purpose:
+ * Make an independent copy of a MetafilePict
+ * Parameters:
+ *
+ * Return Value:
+ * TRUE if successful, else FALSE.
+ */
+STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout)
+{
+ HANDLE hpictout;
+ LPMETAFILEPICT ppictin, ppictout;
+
+ if (hpictin == NULL || phpictout == NULL) {
+ OleDbgAssert(hpictin == NULL || phpictout == NULL);
+ return FALSE;
+ }
+
+ *phpictout = NULL;
+
+ if ((ppictin = (LPMETAFILEPICT)GlobalLock(hpictin)) == NULL) {
+ return FALSE;
+ }
+
+ hpictout = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
+
+ if (hpictout && (ppictout = (LPMETAFILEPICT)GlobalLock(hpictout))){
+ ppictout->hMF = CopyMetaFile(ppictin->hMF, NULL);
+ ppictout->xExt = ppictin->xExt;
+ ppictout->yExt = ppictin->yExt;
+ ppictout->mm = ppictin->mm;
+ GlobalUnlock(hpictout);
+ }
+
+ *phpictout = hpictout;
+
+ return TRUE;
+
+}
+
+
+/* OleStdGetDropEffect
+** -------------------
+**
+** Convert a keyboard state into a DROPEFFECT.
+**
+** returns the DROPEFFECT value derived from the key state.
+** the following is the standard interpretation:
+** no modifier -- Default Drop (NULL is returned)
+** CTRL -- DROPEFFECT_COPY
+** SHIFT -- DROPEFFECT_MOVE
+** CTRL-SHIFT -- DROPEFFECT_LINK
+**
+** Default Drop: this depends on the type of the target application.
+** this is re-interpretable by each target application. a typical
+** interpretation is if the drag is local to the same document
+** (which is source of the drag) then a MOVE operation is
+** performed. if the drag is not local, then a COPY operation is
+** performed.
+*/
+STDAPI_(DWORD) OleStdGetDropEffect( DWORD grfKeyState )
+{
+
+ if (grfKeyState & MK_CONTROL) {
+
+ if (grfKeyState & MK_SHIFT)
+ return DROPEFFECT_LINK;
+ else
+ return DROPEFFECT_COPY;
+
+ } else if (grfKeyState & MK_SHIFT)
+ return DROPEFFECT_MOVE;
+
+ return 0; // no modifier -- do default operation
+}
+#endif // OBSOLETE
+
+
+/*
+ * OleStdGetMetafilePictFromOleObject()
+ *
+ * Purpose:
+ * Generate a MetafilePict by drawing the OLE object.
+ * Parameters:
+ * lpOleObj LPOLEOBJECT pointer to OLE Object
+ * dwDrawAspect DWORD Display Aspect of object
+ * lpSizelHim SIZEL (optional) If the object is being scaled in its
+ * container, then the container should pass the extents
+ * that it is using to display the object.
+ * May be NULL if the object is NOT being scaled. in this
+ * case, IViewObject2::GetExtent will be called to get the
+ * extents from the object.
+ * ptd TARGETDEVICE FAR* (optional) target device to render
+ * metafile for. May be NULL.
+ *
+ * Return Value:
+ * HANDLE -- handle of allocated METAFILEPICT
+ */
+STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(
+ LPOLEOBJECT lpOleObj,
+ DWORD dwDrawAspect,
+ LPSIZEL lpSizelHim,
+ DVTARGETDEVICE FAR* ptd
+)
+{
+ LPVIEWOBJECT2 lpViewObj2 = NULL;
+ HDC hDC;
+ HMETAFILE hmf;
+ HANDLE hMetaPict;
+ LPMETAFILEPICT lpPict;
+ RECT rcHim;
+ RECTL rclHim;
+ SIZEL sizelHim;
+ HRESULT hrErr;
+ SIZE size;
+ POINT point;
+
+#ifdef OLE201
+ lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(
+ (LPUNKNOWN)lpOleObj, &IID_IViewObject2);
+#endif
+
+ if (! lpViewObj2)
+ return NULL;
+
+ // Get SIZEL
+ if (lpSizelHim) {
+ // Use extents passed by the caller
+ sizelHim = *lpSizelHim;
+ } else {
+ // Get the current extents from the object
+ OLEDBG_BEGIN2(TEXT("IViewObject2::GetExtent called\r\n"))
+ hrErr = lpViewObj2->lpVtbl->GetExtent(
+ lpViewObj2,
+ dwDrawAspect,
+ -1, /*lindex*/
+ ptd, /*ptd*/
+ (LPSIZEL)&sizelHim
+ );
+ OLEDBG_END2
+ if (hrErr != NOERROR)
+ sizelHim.cx = sizelHim.cy = 0;
+ }
+
+ hDC = CreateMetaFile(NULL);
+
+ rclHim.left = 0;
+ rclHim.top = 0;
+ rclHim.right = sizelHim.cx;
+ rclHim.bottom = sizelHim.cy;
+
+ rcHim.left = (int)rclHim.left;
+ rcHim.top = (int)rclHim.top;
+ rcHim.right = (int)rclHim.right;
+ rcHim.bottom = (int)rclHim.bottom;
+
+ SetWindowOrgEx(hDC, rcHim.left, rcHim.top, &point);
+ SetWindowExtEx(hDC, rcHim.right-rcHim.left, rcHim.bottom-rcHim.top,&size);
+
+ OLEDBG_BEGIN2(TEXT("IViewObject::Draw called\r\n"))
+ hrErr = lpViewObj2->lpVtbl->Draw(
+ lpViewObj2,
+ dwDrawAspect,
+ -1,
+ NULL,
+ ptd,
+ NULL,
+ hDC,
+ (LPRECTL)&rclHim,
+ (LPRECTL)&rclHim,
+ NULL,
+ 0
+ );
+ OLEDBG_END2
+
+ OleStdRelease((LPUNKNOWN)lpViewObj2);
+ if (hrErr != NOERROR) {
+ OleDbgOutHResult(TEXT("IViewObject::Draw returned"), hrErr);
+ }
+
+ hmf = CloseMetaFile(hDC);
+
+ hMetaPict = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
+
+ if (hMetaPict && (lpPict = (LPMETAFILEPICT)GlobalLock(hMetaPict))){
+ lpPict->hMF = hmf;
+ lpPict->xExt = (int)sizelHim.cx ;
+ lpPict->yExt = (int)sizelHim.cy ;
+ lpPict->mm = MM_ANISOTROPIC;
+ GlobalUnlock(hMetaPict);
+ }
+
+ return hMetaPict;
+}
+
+
+/* Call Release on the object that is expected to go away.
+** if the refcnt of the object did no go to 0 then give a debug message.
+*/
+STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPTSTR lpszMsg)
+{
+ ULONG cRef;
+
+ cRef = lpUnk->lpVtbl->Release(lpUnk);
+
+#if defined( _DEBUG )
+ if (cRef != 0) {
+ TCHAR szBuf[80];
+ if (lpszMsg)
+ MessageBox(NULL, lpszMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
+ wsprintf(
+ (LPTSTR)szBuf,
+ TEXT("refcnt (%ld) != 0 after object (0x%lx) release\n"),
+ cRef,
+ lpUnk
+ );
+ if (lpszMsg)
+ OleDbgOut1(lpszMsg);
+ OleDbgOut1((LPTSTR)szBuf);
+ OleDbgAssertSz(cRef == 0, (LPTSTR)szBuf);
+ } else {
+ TCHAR szBuf[80];
+ wsprintf(
+ (LPTSTR)szBuf,
+ TEXT("refcnt = 0 after object (0x%lx) release\n"), lpUnk
+ );
+ OleDbgOut4((LPTSTR)szBuf);
+ }
+#endif
+ return cRef;
+}
+
+
+/* Call Release on the object that is NOT necessarily expected to go away.
+*/
+STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk)
+{
+ ULONG cRef;
+
+ cRef = lpUnk->lpVtbl->Release(lpUnk);
+
+#if defined( _DEBUG )
+ {
+ TCHAR szBuf[80];
+ wsprintf(
+ (LPTSTR)szBuf,
+ TEXT("refcnt = %ld after object (0x%lx) release\n"),
+ cRef,
+ lpUnk
+ );
+ OleDbgOut4((LPTSTR)szBuf);
+ }
+#endif
+ return cRef;
+}
+
+
+/* OleStdInitVtbl
+** --------------
+**
+** Initialize an interface Vtbl to ensure that there are no NULL
+** function pointers in the Vtbl. All entries in the Vtbl are
+** set to a valid funtion pointer (OleStdNullMethod) that issues
+** debug assert message (message box) and returns E_NOTIMPL if called.
+**
+** NOTE: this funtion does not initialize the Vtbl with usefull
+** function pointers, only valid function pointers to avoid the
+** horrible run-time crash when a call is made through the Vtbl with
+** a NULL function pointer. this API is only necessary when
+** initializing the Vtbl's in C. C++ guarantees that all interface
+** functions (in C++ terms -- pure virtual functions) are implemented.
+*/
+
+STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl)
+{
+ LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;
+ UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);
+ UINT i;
+
+ for (i = 0; i < nMethods; i++) {
+ lpFuncPtrArr[i] = OleStdNullMethod;
+ }
+}
+
+
+/* OleStdCheckVtbl
+** ---------------
+**
+** Check if all entries in the Vtbl are properly initialized with
+** valid function pointers. If any entries are either NULL or
+** OleStdNullMethod, then this function returns FALSE. If compiled
+** for _DEBUG this function reports which function pointers are
+** invalid.
+**
+** RETURNS: TRUE if all entries in Vtbl are valid
+** FALSE otherwise.
+*/
+
+STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPTSTR lpszIface)
+{
+ LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;
+ UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);
+ UINT i;
+ BOOL fStatus = TRUE;
+ int nChar = 0;
+
+ for (i = 0; i < nMethods; i++) {
+ if (lpFuncPtrArr[i] == NULL || lpFuncPtrArr[i] == OleStdNullMethod) {
+#if defined( _DEBUG )
+ TCHAR szBuf[256];
+ wsprintf(szBuf, TEXT("%s::method# %d NOT valid!"), lpszIface, i);
+ OleDbgOut1((LPTSTR)szBuf);
+#endif
+ fStatus = FALSE;
+ }
+ }
+ return fStatus;
+}
+
+
+/* OleStdNullMethod
+** ----------------
+** Dummy method used by OleStdInitVtbl to initialize an interface
+** Vtbl to ensure that there are no NULL function pointers in the
+** Vtbl. All entries in the Vtbl are set to this function. this
+** function issues a debug assert message (message box) and returns
+** E_NOTIMPL if called. If all is done properly, this function will
+** NEVER be called!
+*/
+STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis)
+{
+ MessageBox(
+ NULL,
+ TEXT("ERROR: INTERFACE METHOD NOT IMPLEMENTED!\r\n"),
+ NULL,
+ MB_SYSTEMMODAL | MB_ICONHAND | MB_OK
+ );
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+
+
+static BOOL GetFileTimes(LPTSTR lpszFileName, FILETIME FAR* pfiletime)
+{
+#ifdef WIN32
+ WIN32_FIND_DATA fd;
+ HANDLE hFind;
+ hFind = FindFirstFile(lpszFileName,&fd);
+ if (hFind == NULL || hFind == INVALID_HANDLE_VALUE) {
+ return FALSE;
+ }
+ FindClose(hFind);
+ *pfiletime = fd.ftLastWriteTime;
+ return TRUE;
+#else // !Win32
+ static char sz[256];
+ static struct _find_t fileinfo;
+
+ LSTRCPYN((LPTSTR)sz, lpszFileName, sizeof(sz)-1);
+ sz[sizeof(sz)-1]= TEXT('\0');
+ AnsiToOem(sz, sz);
+ return (_dos_findfirst(sz,_A_NORMAL|_A_HIDDEN|_A_SUBDIR|_A_SYSTEM,
+ (struct _find_t *)&fileinfo) == 0 &&
+ CoDosDateTimeToFileTime(fileinfo.wr_date,fileinfo.wr_time,pfiletime));
+#endif // Win32
+}
+
+
+
+/* OleStdRegisterAsRunning
+** -----------------------
+** Register a moniker in the RunningObjectTable.
+** if there is an existing registration (*lpdwRegister!=NULL), then
+** first revoke that registration.
+**
+** new dwRegister key is returned via *lpdwRegister parameter.
+*/
+STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister)
+{
+ LPRUNNINGOBJECTTABLE lpROT;
+ HRESULT hrErr;
+ DWORD dwOldRegister = *lpdwRegister;
+
+ OLEDBG_BEGIN2(TEXT("OleStdRegisterAsRunning\r\n"))
+
+ OLEDBG_BEGIN2(TEXT("GetRunningObjectTable called\r\n"))
+ hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
+ OLEDBG_END2
+
+ if (hrErr == NOERROR) {
+
+ /* register as running if a valid moniker is passed
+ **
+ ** OLE2NOTE: we deliberately register the new moniker BEFORE
+ ** revoking the old moniker just in case the object
+ ** currently has no external locks. if the object has no
+ ** locks then revoking it from the running object table will
+ ** cause the object's StubManager to initiate shutdown of
+ ** the object.
+ */
+ if (lpmkFull) {
+
+ OLEDBG_BEGIN2(TEXT("IRunningObjectTable::Register called\r\n"))
+ lpROT->lpVtbl->Register(lpROT, 0, lpUnk,lpmkFull,lpdwRegister);
+ OLEDBG_END2
+
+#if defined(_DEBUG)
+ {
+ TCHAR szBuf[512];
+ LPTSTR lpszDisplay;
+ LPBC lpbc;
+
+#ifdef OLE201
+ CreateBindCtx(0, (LPBC FAR*)&lpbc);
+#endif
+
+ CallIMonikerGetDisplayNameA(
+ lpmkFull,
+ lpbc,
+ NULL,
+ &lpszDisplay
+ );
+ OleStdRelease((LPUNKNOWN)lpbc);
+ wsprintf(
+ szBuf,
+ TEXT("Moniker '%s' REGISTERED as [0x%lx] in ROT\r\n"),
+ lpszDisplay,
+ *lpdwRegister
+ );
+ OleDbgOut2(szBuf);
+ OleStdFreeString(lpszDisplay, NULL);
+ }
+#endif // _DEBUG
+
+ }
+
+ // if already registered, revoke
+ if (dwOldRegister != 0) {
+
+#if defined(_DEBUG)
+ {
+ TCHAR szBuf[512];
+
+ wsprintf(
+ szBuf,
+ TEXT("Moniker [0x%lx] REVOKED from ROT\r\n"),
+ dwOldRegister
+ );
+ OleDbgOut2(szBuf);
+ }
+#endif // _DEBUG
+
+ OLEDBG_BEGIN2(TEXT("IRunningObjectTable::Revoke called\r\n"))
+ lpROT->lpVtbl->Revoke(lpROT, dwOldRegister);
+ OLEDBG_END2
+ }
+
+ OleStdRelease((LPUNKNOWN)lpROT);
+ } else {
+ OleDbgAssertSz(
+ lpROT != NULL,
+ TEXT("OleStdRegisterAsRunning: GetRunningObjectTable FAILED\r\n")
+ );
+ }
+
+ OLEDBG_END2
+}
+
+
+
+/* OleStdRevokeAsRunning
+** ---------------------
+** Revoke a moniker from the RunningObjectTable if there is an
+** existing registration (*lpdwRegister!=NULL).
+**
+** *lpdwRegister parameter will be set to NULL.
+*/
+STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister)
+{
+ LPRUNNINGOBJECTTABLE lpROT;
+ HRESULT hrErr;
+
+ OLEDBG_BEGIN2(TEXT("OleStdRevokeAsRunning\r\n"))
+
+ // if still registered, then revoke
+ if (*lpdwRegister != 0) {
+
+ OLEDBG_BEGIN2(TEXT("GetRunningObjectTable called\r\n"))
+ hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
+ OLEDBG_END2
+
+ if (hrErr == NOERROR) {
+
+#if defined(_DEBUG)
+ {
+ TCHAR szBuf[512];
+
+ wsprintf(
+ szBuf,
+ TEXT("Moniker [0x%lx] REVOKED from ROT\r\n"),
+ *lpdwRegister
+ );
+ OleDbgOut2(szBuf);
+ }
+#endif // _DEBUG
+
+ OLEDBG_BEGIN2(TEXT("IRunningObjectTable::Revoke called\r\n"))
+ lpROT->lpVtbl->Revoke(lpROT, *lpdwRegister);
+ OLEDBG_END2
+
+ *lpdwRegister = 0;
+
+ OleStdRelease((LPUNKNOWN)lpROT);
+ } else {
+ OleDbgAssertSz(
+ lpROT != NULL,
+ TEXT("OleStdRevokeAsRunning: GetRunningObjectTable FAILED\r\n")
+ );
+ }
+ }
+ OLEDBG_END2
+}
+
+
+/* OleStdNoteFileChangeTime
+** ------------------------
+** Note the time a File-Based object has been saved in the
+** RunningObjectTable. These change times are used as the basis for
+** IOleObject::IsUpToDate.
+** It is important to set the time of the file-based object
+** following a save operation to exactly the time of the saved file.
+** this helps IOleObject::IsUpToDate to give the correct answer
+** after a file has been saved.
+*/
+STDAPI_(void) OleStdNoteFileChangeTime(LPTSTR lpszFileName, DWORD dwRegister)
+{
+ if (dwRegister != 0) {
+
+ LPRUNNINGOBJECTTABLE lprot;
+ FILETIME filetime;
+
+ if (GetFileTimes(lpszFileName, &filetime) &&
+ GetRunningObjectTable(0,&lprot) == NOERROR)
+ {
+ lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );
+ lprot->lpVtbl->Release(lprot);
+
+ OleDbgOut2(TEXT("IRunningObjectTable::NoteChangeTime called\r\n"));
+ }
+ }
+}
+
+
+/* OleStdNoteObjectChangeTime
+** --------------------------
+** Set the last change time of an object that is registered in the
+** RunningObjectTable. These change times are used as the basis for
+** IOleObject::IsUpToDate.
+**
+** every time the object sends out a OnDataChange notification, it
+** should update the Time of last change in the ROT.
+**
+** NOTE: this function set the change time to the current time.
+*/
+STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister)
+{
+ if (dwRegister != 0) {
+
+ LPRUNNINGOBJECTTABLE lprot;
+ FILETIME filetime;
+
+ if (GetRunningObjectTable(0,&lprot) == NOERROR)
+ {
+#ifdef OLE201
+ CoFileTimeNow( &filetime );
+ lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );
+#endif
+ lprot->lpVtbl->Release(lprot);
+
+ OleDbgOut2(TEXT("IRunningObjectTable::NoteChangeTime called\r\n"));
+ }
+ }
+}
+
+
+/* OleStdCreateTempFileMoniker
+** ---------------------------
+** return the next available FileMoniker that can be used as the
+** name of an untitled document.
+** the FileMoniker is built of the form:
+** <lpszPrefixString><number>
+** eg. "Outline1", "Outline2", etc.
+**
+** The RunningObjectTable (ROT) is consulted to determine if a
+** FileMoniker is in use. If the name is in use then the number is
+** incremented and the ROT is checked again.
+**
+** Parameters:
+** LPSTR lpszPrefixString - prefix used to build the name
+** UINT FAR* lpuUnique - (IN-OUT) last used number.
+** this number is used to make the
+** name unique. on entry, the input
+** number is incremented. on output,
+** the number used is returned. this
+** number should be passed again
+** unchanged on the next call.
+** LPSTR lpszName - (OUT) buffer used to build string.
+** caller must be sure buffer is large
+** enough to hold the generated string.
+** LPMONIKER FAR* lplpmk - (OUT) next unused FileMoniker
+**
+** Returns:
+** void
+**
+** Comments:
+** This function is similar in spirit to the Windows API
+** CreateTempFileName.
+*/
+STDAPI_(void) OleStdCreateTempFileMoniker(
+ LPTSTR lpszPrefixString,
+ UINT FAR* lpuUnique,
+ LPTSTR lpszName,
+ LPMONIKER FAR* lplpmk
+)
+{
+ LPRUNNINGOBJECTTABLE lpROT = NULL;
+ UINT i = (lpuUnique != NULL ? *lpuUnique : 1);
+ HRESULT hrErr;
+
+ wsprintf(lpszName, TEXT("%s%d"), lpszPrefixString, i++);
+
+ CreateFileMonikerA(lpszName, lplpmk);
+
+
+ OLEDBG_BEGIN2(TEXT("GetRunningObjectTable called\r\n"))
+ hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
+ OLEDBG_END2
+
+ if (hrErr == NOERROR) {
+
+ while (1) {
+ if (! *lplpmk)
+ break; // failed to create FileMoniker
+
+ OLEDBG_BEGIN2(TEXT("IRunningObjectTable::IsRunning called\r\n"))
+ hrErr = lpROT->lpVtbl->IsRunning(lpROT,*lplpmk);
+ OLEDBG_END2
+
+ if (hrErr != NOERROR)
+ break; // the Moniker is NOT running; found unused one!
+
+ OleStdVerifyRelease(
+ (LPUNKNOWN)*lplpmk,
+ TEXT("OleStdCreateTempFileMoniker: Moniker NOT released")
+ );
+
+ wsprintf(lpszName, TEXT("%s%d"), lpszPrefixString, i++);
+ CreateFileMonikerA(lpszName, lplpmk);
+ }
+
+ OleStdRelease((LPUNKNOWN)lpROT);
+ }
+
+ if (lpuUnique != NULL)
+ *lpuUnique = i;
+}
+
+
+/* OleStdGetFirstMoniker
+** ---------------------
+** return the first piece of a moniker.
+**
+** NOTE: if the given moniker is not a generic composite moniker,
+** then an AddRef'ed pointer to the given moniker is returned.
+*/
+STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk)
+{
+ LPMONIKER lpmkFirst = NULL;
+ LPENUMMONIKER lpenumMoniker;
+ DWORD dwMksys;
+ HRESULT hrErr;
+
+ if (! lpmk)
+ return NULL;
+
+ if (lpmk->lpVtbl->IsSystemMoniker(lpmk, (LPDWORD)&dwMksys) == NOERROR
+ && dwMksys == MKSYS_GENERICCOMPOSITE) {
+
+ /* OLE2NOTE: the moniker is a GenericCompositeMoniker.
+ ** enumerate the moniker to pull off the first piece.
+ */
+
+ hrErr = lpmk->lpVtbl->Enum(
+ lpmk,
+ TRUE /* fForward */,
+ (LPENUMMONIKER FAR*)&lpenumMoniker
+ );
+ if (hrErr != NOERROR)
+ return NULL; // ERROR: give up!
+
+ hrErr = lpenumMoniker->lpVtbl->Next(
+ lpenumMoniker,
+ 1,
+ (LPMONIKER FAR*)&lpmkFirst,
+ NULL
+ );
+ lpenumMoniker->lpVtbl->Release(lpenumMoniker);
+ return lpmkFirst;
+
+ } else {
+ /* OLE2NOTE: the moniker is NOT a GenericCompositeMoniker.
+ ** return an AddRef'ed pointer to the input moniker.
+ */
+ lpmk->lpVtbl->AddRef(lpmk);
+ return lpmk;
+ }
+}
+
+
+/* OleStdGetLenFilePrefixOfMoniker
+** -------------------------------
+** if the first piece of the Moniker is a FileMoniker, then return
+** the length of the filename string.
+**
+** lpmk pointer to moniker
+**
+** Returns
+** 0 if moniker does NOT start with a FileMoniker
+** uLen string length of filename prefix of the display name
+** retrieved from the given (lpmk) moniker.
+*/
+STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk)
+{
+ LPMONIKER lpmkFirst = NULL;
+ DWORD dwMksys;
+ LPTSTR lpsz = NULL;
+ LPBC lpbc = NULL;
+ ULONG uLen = 0;
+ HRESULT hrErr;
+
+ if (! lpmk)
+ return 0;
+
+ lpmkFirst = OleStdGetFirstMoniker(lpmk);
+ if (lpmkFirst) {
+ if ( (lpmkFirst->lpVtbl->IsSystemMoniker(
+ lpmkFirst, (LPDWORD)&dwMksys) == NOERROR)
+ && dwMksys == MKSYS_FILEMONIKER) {
+
+#ifdef OLE201
+ hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);
+#endif
+ if (hrErr == NOERROR) {
+ hrErr = CallIMonikerGetDisplayNameA(lpmkFirst, lpbc, NULL,
+ &lpsz);
+
+ if (hrErr == NOERROR && lpsz != NULL) {
+ uLen = lstrlen(lpsz);
+ OleStdFreeString(lpsz, NULL);
+ }
+ OleStdRelease((LPUNKNOWN)lpbc);
+ }
+ }
+ lpmkFirst->lpVtbl->Release(lpmkFirst);
+ }
+ return uLen;
+}
+
+
+/* OleStdMkParseDisplayName
+** Parse a string into a Moniker by calling the OLE API
+** MkParseDisplayName. if the original link source class was an OLE1
+** class, then attempt the parsing assuming the same class applies.
+**
+** if the class of the previous link source was an OLE1 class,
+** then first attempt to parse a string that it is qualified
+** with the progID associated with the OLE1 class. this more
+** closely matches the semantics of OLE1 where the class of
+** link sources is not expected to change. prefixing the
+** string with "@<ProgID -- OLE1 class name>!" will force the
+** parsing of the string to assume the file is of that
+** class.
+** NOTE: this trick of prepending the string with "@<ProgID>
+** only works for OLE1 classes.
+**
+** PARAMETERS:
+** REFCLSID rClsid -- original class of link source.
+** CLSID_NULL if class is unknown
+** ... other parameters the same as MkParseDisplayName API ...
+**
+** RETURNS
+** NOERROR if string parsed successfully
+** else error code returned by MkParseDisplayName
+*/
+STDAPI OleStdMkParseDisplayName(
+ REFCLSID rClsid,
+ LPBC lpbc,
+ LPTSTR lpszUserName,
+ ULONG FAR* lpchEaten,
+ LPMONIKER FAR* lplpmk
+)
+{
+ HRESULT hrErr;
+
+ if (!IsEqualCLSID(rClsid,&CLSID_NULL) && CoIsOle1Class(rClsid) &&
+ lpszUserName[0] != '@') {
+ LPTSTR lpszBuf;
+ LPTSTR lpszProgID;
+
+ // Prepend "@<ProgID>!" to the input string
+ ProgIDFromCLSIDA(rClsid, &lpszProgID);
+
+ if (lpszProgID == NULL)
+ goto Cont1;
+ lpszBuf = OleStdMalloc(
+ ((ULONG)lstrlen(lpszUserName)+
+#ifdef UNICODE
+ // OLE in Win32 is always UNICODE
+ wcslen(lpszProgID)
+#else
+ lstrlen(lpszProgID)
+#endif
+ +3)*sizeof(TCHAR));
+ if (lpszBuf == NULL) {
+ if (lpszProgID)
+ OleStdFree(lpszProgID);
+ goto Cont1;
+ }
+
+ wsprintf(lpszBuf, TEXT("@%s!%s"), lpszProgID, lpszUserName);
+
+ OLEDBG_BEGIN2(TEXT("MkParseDisplayName called\r\n"))
+
+ hrErr = MkParseDisplayNameA(lpbc, lpszBuf, lpchEaten, lplpmk);
+
+ OLEDBG_END2
+
+ if (lpszProgID)
+ OleStdFree(lpszProgID);
+ if (lpszBuf)
+ OleStdFree(lpszBuf);
+
+ if (hrErr == NOERROR)
+ return NOERROR;
+ }
+
+Cont1:
+ OLEDBG_BEGIN2(TEXT("MkParseDisplayName called\r\n"))
+
+ hrErr = MkParseDisplayNameA(lpbc, lpszUserName, lpchEaten, lplpmk);
+
+ OLEDBG_END2
+
+ return hrErr;
+}
+
+
+/*
+ * OleStdMarkPasteEntryList
+ *
+ * Purpose:
+ * Mark each entry in the PasteEntryList if its format is available from
+ * the source IDataObject*. the dwScratchSpace field of each PasteEntry
+ * is set to TRUE if available, else FALSE.
+ *
+ * Parameters:
+ * LPOLEUIPASTEENTRY array of PasteEntry structures
+ * int count of elements in PasteEntry array
+ * LPDATAOBJECT source IDataObject* pointer
+ *
+ * Return Value:
+ * none
+ */
+STDAPI_(void) OleStdMarkPasteEntryList(
+ LPDATAOBJECT lpSrcDataObj,
+ LPOLEUIPASTEENTRY lpPriorityList,
+ int cEntries
+)
+{
+ LPENUMFORMATETC lpEnumFmtEtc = NULL;
+ #define FORMATETC_MAX 20
+ FORMATETC rgfmtetc[FORMATETC_MAX];
+ int i;
+ HRESULT hrErr;
+ long j, cFetched;
+
+ // Clear all marks
+ for (i = 0; i < cEntries; i++) {
+ lpPriorityList[i].dwScratchSpace = FALSE;
+
+ if (! lpPriorityList[i].fmtetc.cfFormat) {
+ // caller wants this item always considered available
+ // (by specifying a NULL format)
+ lpPriorityList[i].dwScratchSpace = TRUE;
+ } else if (lpPriorityList[i].fmtetc.cfFormat == cfEmbeddedObject
+ || lpPriorityList[i].fmtetc.cfFormat == cfEmbedSource
+ || lpPriorityList[i].fmtetc.cfFormat == cfFileName) {
+
+ // if there is an OLE object format, then handle it
+ // specially by calling OleQueryCreateFromData. the caller
+ // need only specify one object type format.
+ OLEDBG_BEGIN2(TEXT("OleQueryCreateFromData called\r\n"))
+ hrErr = OleQueryCreateFromData(lpSrcDataObj);
+ OLEDBG_END2
+ if(NOERROR == hrErr) {
+ lpPriorityList[i].dwScratchSpace = TRUE;
+ }
+ } else if (lpPriorityList[i].fmtetc.cfFormat == cfLinkSource) {
+
+ // if there is OLE 2.0 LinkSource format, then handle it
+ // specially by calling OleQueryLinkFromData.
+ OLEDBG_BEGIN2(TEXT("OleQueryLinkFromData called\r\n"))
+ hrErr = OleQueryLinkFromData(lpSrcDataObj);
+ OLEDBG_END2
+ if(NOERROR == hrErr) {
+ lpPriorityList[i].dwScratchSpace = TRUE;
+ }
+ }
+ }
+
+ OLEDBG_BEGIN2(TEXT("IDataObject::EnumFormatEtc called\r\n"))
+ hrErr = lpSrcDataObj->lpVtbl->EnumFormatEtc(
+ lpSrcDataObj,
+ DATADIR_GET,
+ (LPENUMFORMATETC FAR*)&lpEnumFmtEtc
+ );
+ OLEDBG_END2
+
+ if (hrErr != NOERROR)
+ return; // unable to get format enumerator
+
+ // Enumerate the formats offered by the source
+ // Loop over all formats offered by the source
+ cFetched = 0;
+ _fmemset(rgfmtetc,0,sizeof(rgfmtetc[FORMATETC_MAX]) );
+ if (lpEnumFmtEtc->lpVtbl->Next(
+ lpEnumFmtEtc, FORMATETC_MAX, rgfmtetc, &cFetched) == NOERROR
+ || (cFetched > 0 && cFetched <= FORMATETC_MAX) )
+ {
+
+ for (j = 0; j < cFetched; j++)
+ {
+ for (i = 0; i < cEntries; i++)
+ {
+ if (! lpPriorityList[i].dwScratchSpace &&
+ IsCloseFormatEtc(&rgfmtetc[j], &lpPriorityList[i].fmtetc))
+ {
+ lpPriorityList[i].dwScratchSpace = TRUE;
+ }
+ }
+ }
+ } // endif
+
+ // Clean up
+ if (lpEnumFmtEtc)
+ OleStdRelease((LPUNKNOWN)lpEnumFmtEtc);
+}
+
+
+/* OleStdGetPriorityClipboardFormat
+** --------------------------------
+**
+** Retrieve the first clipboard format in a list for which data
+** exists in the source IDataObject*.
+**
+** Returns -1 if no acceptable match is found.
+** index of first acceptable match in the priority list.
+**
+*/
+STDAPI_(int) OleStdGetPriorityClipboardFormat(
+ LPDATAOBJECT lpSrcDataObj,
+ LPOLEUIPASTEENTRY lpPriorityList,
+ int cEntries
+)
+{
+ int i;
+ int nFmtEtc = -1;
+
+ // Mark all entries that the Source provides
+ OleStdMarkPasteEntryList(lpSrcDataObj, lpPriorityList, cEntries);
+
+ // Loop over the target's priority list of formats
+ for (i = 0; i < cEntries; i++)
+ {
+ if (lpPriorityList[i].dwFlags != OLEUIPASTE_PASTEONLY &&
+ !(lpPriorityList[i].dwFlags & OLEUIPASTE_PASTE))
+ continue;
+
+ // get first marked entry
+ if (lpPriorityList[i].dwScratchSpace) {
+ nFmtEtc = i;
+ break; // Found priority format; DONE
+ }
+ }
+
+ return nFmtEtc;
+}
+
+
+/* OleStdIsDuplicateFormat
+** -----------------------
+** Returns TRUE if the lpFmtEtc->cfFormat is found in the array of
+** FormatEtc structures.
+*/
+STDAPI_(BOOL) OleStdIsDuplicateFormat(
+ LPFORMATETC lpFmtEtc,
+ LPFORMATETC arrFmtEtc,
+ int nFmtEtc
+)
+{
+ int i;
+
+ for (i = 0; i < nFmtEtc; i++) {
+ if (IsEqualFORMATETC((*lpFmtEtc), arrFmtEtc[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* OleStdGetItemToken
+ * ------------------
+ *
+ * LPTSTR lpszSrc - Pointer to a source string
+ * LPTSTR lpszDst - Pointer to destination buffer
+ *
+ * Will copy one token from the lpszSrc buffer to the lpszItem buffer.
+ * It considers all alpha-numeric and white space characters as valid
+ * characters for a token. the first non-valid character delimates the
+ * token.
+ *
+ * returns the number of charaters eaten.
+ */
+STDAPI_(ULONG) OleStdGetItemToken(LPTSTR lpszSrc, LPTSTR lpszDst, int nMaxChars)
+{
+ ULONG chEaten = 0L;
+
+ // skip leading delimeter characters
+ while (*lpszSrc && --nMaxChars > 0
+ && ((*lpszSrc==TEXT('/')) || (*lpszSrc==TEXT('\\')) ||
+ (*lpszSrc==TEXT('!')) || (*lpszSrc==TEXT(':')))) {
+ *lpszSrc++;
+ chEaten++;
+ }
+
+ // Extract token string (up to first delimeter char or EOS)
+ while (*lpszSrc && --nMaxChars > 0
+ && !((*lpszSrc==TEXT('/')) || (*lpszSrc==TEXT('\\')) ||
+ (*lpszSrc==TEXT('!')) || (*lpszSrc==TEXT(':')))) {
+ *lpszDst++ = *lpszSrc++;
+ chEaten++;
+ }
+ *lpszDst = TEXT('\0');
+ return chEaten;
+}
+
+
+/*************************************************************************
+** OleStdCreateRootStorage
+** create a root level Storage given a filename that is compatible
+** to be used by a top-level OLE container. if the filename
+** specifies an existing file, then an error is returned.
+** the root storage (Docfile) that is created by this function
+** is suitable to be used to create child storages for embedings.
+** (CreateChildStorage can be used to create child storages.)
+** NOTE: the root-level storage is opened in transacted mode.
+*************************************************************************/
+
+STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPTSTR lpszStgName, DWORD grfMode)
+{
+ HRESULT hr;
+ DWORD grfCreateMode = STGM_READWRITE | STGM_TRANSACTED;
+ DWORD reserved = 0;
+ LPSTORAGE lpRootStg;
+ TCHAR szMsg[64];
+
+ // if temp file is being created, enable delete-on-release
+ if (! lpszStgName)
+ grfCreateMode |= STGM_DELETEONRELEASE;
+
+ hr = StgCreateDocfileA(
+ lpszStgName,
+ grfMode | grfCreateMode,
+ reserved,
+ (LPSTORAGE FAR*)&lpRootStg
+ );
+
+ if (hr == NOERROR)
+ return lpRootStg; // existing file successfully opened
+
+ OleDbgOutHResult(TEXT("StgCreateDocfile returned"), hr);
+
+ if (0 == LoadString(ghInst, IDS_OLESTDNOCREATEFILE, (LPTSTR)szMsg, 64))
+ return NULL;
+
+ MessageBox(NULL, (LPTSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);
+ return NULL;
+}
+
+
+/*************************************************************************
+** OleStdOpenRootStorage
+** open a root level Storage given a filename that is compatible
+** to be used by a top-level OLE container. if the file does not
+** exist then an error is returned.
+** the root storage (Docfile) that is opened by this function
+** is suitable to be used to create child storages for embedings.
+** (CreateChildStorage can be used to create child storages.)
+** NOTE: the root-level storage is opened in transacted mode.
+*************************************************************************/
+
+STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPTSTR lpszStgName, DWORD grfMode)
+{
+ HRESULT hr;
+ DWORD reserved = 0;
+ LPSTORAGE lpRootStg;
+ TCHAR szMsg[64];
+
+ if (lpszStgName) {
+ hr = StgOpenStorageA(
+ lpszStgName,
+ NULL,
+ grfMode | STGM_TRANSACTED,
+ NULL,
+ reserved,
+ (LPSTORAGE FAR*)&lpRootStg
+ );
+
+ if (hr == NOERROR)
+ return lpRootStg; // existing file successfully opened
+
+ OleDbgOutHResult(TEXT("StgOpenStorage returned"), hr);
+ }
+
+ if (0 == LoadString(ghInst, IDS_OLESTDNOOPENFILE, szMsg, 64))
+ return NULL;
+
+ MessageBox(NULL, (LPTSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);
+ return NULL;
+}
+
+
+/*************************************************************************
+** OpenOrCreateRootStorage
+** open a root level Storage given a filename that is compatible
+** to be used by a top-level OLE container. if the filename
+** specifies an existing file, then it is open, otherwise a new file
+** with the given name is created.
+** the root storage (Docfile) that is created by this function
+** is suitable to be used to create child storages for embedings.
+** (CreateChildStorage can be used to create child storages.)
+** NOTE: the root-level storage is opened in transacted mode.
+*************************************************************************/
+
+STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPTSTR lpszStgName, DWORD grfMode)
+{
+ HRESULT hrErr;
+ SCODE sc;
+ DWORD reserved = 0;
+ LPSTORAGE lpRootStg;
+ TCHAR szMsg[64];
+
+ if (lpszStgName) {
+
+ hrErr = StgOpenStorageA(
+ lpszStgName,
+ NULL,
+ grfMode | STGM_READWRITE | STGM_TRANSACTED,
+ NULL,
+ reserved,
+ (LPSTORAGE FAR*)&lpRootStg
+ );
+
+ if (hrErr == NOERROR)
+ return lpRootStg; // existing file successfully opened
+
+ OleDbgOutHResult(TEXT("StgOpenStorage returned"), hrErr);
+ sc = GetScode(hrErr);
+
+ if (sc!=STG_E_FILENOTFOUND && sc!=STG_E_FILEALREADYEXISTS) {
+ return NULL;
+ }
+ }
+
+ /* if file did not already exist, try to create a new one */
+ hrErr = StgCreateDocfileA(
+ lpszStgName,
+ grfMode | STGM_READWRITE | STGM_TRANSACTED,
+ reserved,
+ (LPSTORAGE FAR*)&lpRootStg
+ );
+
+ if (hrErr == NOERROR)
+ return lpRootStg; // existing file successfully opened
+
+ OleDbgOutHResult(TEXT("StgCreateDocfile returned"), hrErr);
+
+ if (0 == LoadString(ghInst, IDS_OLESTDNOCREATEFILE, (LPTSTR)szMsg, 64))
+ return NULL;
+
+ MessageBox(NULL, (LPTSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
+ return NULL;
+}
+
+
+/*
+** OleStdCreateChildStorage
+** create a child Storage inside the given lpStg that is compatible
+** to be used by an embedded OLE object. the return value from this
+** function can be passed to OleCreateXXX functions.
+** NOTE: the child storage is opened in transacted mode.
+*/
+STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPTSTR lpszStgName)
+{
+ if (lpStg != NULL) {
+ LPSTORAGE lpChildStg;
+ DWORD grfMode = (STGM_READWRITE | STGM_TRANSACTED |
+ STGM_SHARE_EXCLUSIVE);
+ DWORD reserved = 0;
+
+ HRESULT hrErr = CallIStorageCreateStorageA(
+ lpStg,
+ lpszStgName,
+ grfMode,
+ reserved,
+ reserved,
+ (LPSTORAGE FAR*)&lpChildStg
+ );
+
+ if (hrErr == NOERROR)
+ return lpChildStg;
+
+ OleDbgOutHResult(TEXT("lpStg->lpVtbl->CreateStorage returned"), hrErr);
+ }
+ return NULL;
+}
+
+
+/*
+** OleStdOpenChildStorage
+** open a child Storage inside the given lpStg that is compatible
+** to be used by an embedded OLE object. the return value from this
+** function can be passed to OleLoad function.
+** NOTE: the child storage is opened in transacted mode.
+*/
+STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPTSTR lpszStgName, DWORD grfMode)
+{
+ LPSTORAGE lpChildStg;
+ LPSTORAGE lpstgPriority = NULL;
+ DWORD reserved = 0;
+ HRESULT hrErr;
+
+ if (lpStg != NULL) {
+
+ hrErr = CallIStorageOpenStorageA(
+ lpStg,
+ lpszStgName,
+ lpstgPriority,
+ grfMode | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ NULL,
+ reserved,
+ (LPSTORAGE FAR*)&lpChildStg
+ );
+
+ if (hrErr == NOERROR)
+ return lpChildStg;
+
+ OleDbgOutHResult(TEXT("lpStg->lpVtbl->OpenStorage returned"), hrErr);
+ }
+ return NULL;
+}
+
+
+/* OleStdCommitStorage
+** -------------------
+** Commit the changes to the given IStorage*. This routine can be
+** called on either a root-level storage as used by an OLE-Container
+** or by a child storage as used by an embedded object.
+**
+** This routine first attempts to perform this commit in a safe
+** manner. if this fails it then attempts to do the commit in a less
+** robust manner (STGC_OVERWRITE).
+*/
+STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg)
+{
+ HRESULT hrErr;
+
+ // make the changes permanent
+ hrErr = lpStg->lpVtbl->Commit(lpStg, 0);
+
+ if (GetScode(hrErr) == STG_E_MEDIUMFULL) {
+ // try to commit changes in less robust manner.
+ OleDbgOut(TEXT("Warning: commiting with STGC_OVERWRITE specified\n"));
+ hrErr = lpStg->lpVtbl->Commit(lpStg, STGC_OVERWRITE);
+ }
+
+ if (hrErr != NOERROR)
+ {
+ TCHAR szMsg[64];
+
+ if (0 == LoadString(ghInst, IDS_OLESTDDISKFULL, (LPTSTR)szMsg, 64))
+ return FALSE;
+
+ MessageBox(NULL, (LPTSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+
+/* OleStdDestroyAllElements
+** ------------------------
+** Destroy all elements within an open storage. this is subject
+** to the current transaction.
+*/
+STDAPI OleStdDestroyAllElements(LPSTORAGE lpStg)
+{
+ IEnumSTATSTG FAR* lpEnum;
+ STATSTG sstg;
+ HRESULT hrErr;
+
+ hrErr = lpStg->lpVtbl->EnumElements(
+ lpStg, 0, NULL, 0, (IEnumSTATSTG FAR* FAR*)&lpEnum);
+
+ if (hrErr != NOERROR)
+ return hrErr;
+
+ while (1) {
+ if (lpEnum->lpVtbl->Next(lpEnum, 1, &sstg, NULL) != NOERROR)
+ break;
+ lpStg->lpVtbl->DestroyElement(lpStg, sstg.pwcsName);
+ OleStdFree(sstg.pwcsName);
+ }
+ lpEnum->lpVtbl->Release(lpEnum);
+ return NOERROR;
+}
+
+// returns 1 for a close match
+// (all fields match exactly except the tymed which simply overlaps)
+// 0 for no match
+
+int IsCloseFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight)
+{
+ if (pFetcLeft->cfFormat != pFetcRight->cfFormat)
+ return 0;
+ else if (!OleStdCompareTargetDevice (pFetcLeft->ptd, pFetcRight->ptd))
+ return 0;
+ if (pFetcLeft->dwAspect != pFetcRight->dwAspect)
+ return 0;
+ return((pFetcLeft->tymed | pFetcRight->tymed) != 0);
+}
+
+
diff --git a/private/oleutest/letest/ole2ui/olestd.h b/private/oleutest/letest/ole2ui/olestd.h
new file mode 100644
index 000000000..7ca92fcbf
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/olestd.h
@@ -0,0 +1,852 @@
+/*************************************************************************
+**
+** OLE 2.0 Standard Utilities
+**
+** olestd.h
+**
+** This file contains file contains data structure defintions,
+** function prototypes, constants, etc. for the common OLE 2.0
+** utilities.
+** These utilities include the following:
+** Debuging Assert/Verify macros
+** HIMETRIC conversion routines
+** reference counting debug support
+** OleStd API's for common compound-document app support
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#if !defined( _OLESTD_H_ )
+#define _OLESTD_H_
+
+#ifndef RC_INVOKED
+#pragma message ("INCLUDING OLESTD.H from " __FILE__)
+#endif /* RC_INVOKED */
+
+#if defined( __TURBOC__ ) || defined( WIN32 )
+#define _based(a)
+#endif
+
+#ifndef RC_INVOKED
+#include <dos.h> // needed for filetime
+#endif /* RC_INVOKED */
+
+#include <commdlg.h> // needed for LPPRINTDLG
+#include <shellapi.h> // needed for HKEY
+
+// String table defines...
+#define IDS_OLESTDNOCREATEFILE 700
+#define IDS_OLESTDNOOPENFILE 701
+#define IDS_OLESTDDISKFULL 702
+
+
+/*
+ * Some C interface declaration stuff
+ */
+
+#if ! defined(__cplusplus)
+typedef struct tagINTERFACEIMPL {
+ IUnknownVtbl FAR* lpVtbl;
+ LPVOID lpBack;
+ int cRef; // interface specific ref count.
+} INTERFACEIMPL, FAR* LPINTERFACEIMPL;
+
+#define INIT_INTERFACEIMPL(lpIFace, pVtbl, pBack) \
+ ((lpIFace)->lpVtbl = pVtbl, \
+ ((LPINTERFACEIMPL)(lpIFace))->lpBack = (LPVOID)pBack, \
+ ((LPINTERFACEIMPL)(lpIFace))->cRef = 0 \
+ )
+
+#if defined( _DEBUG )
+#define OleDbgQueryInterfaceMethod(lpUnk) \
+ ((lpUnk) != NULL ? ((LPINTERFACEIMPL)(lpUnk))->cRef++ : 0)
+#define OleDbgAddRefMethod(lpThis, iface) \
+ ((LPINTERFACEIMPL)(lpThis))->cRef++
+
+#if _DEBUGLEVEL >= 2
+#define OleDbgReleaseMethod(lpThis, iface) \
+ (--((LPINTERFACEIMPL)(lpThis))->cRef == 0 ? \
+ OleDbgOut("\t" iface "* RELEASED (cRef == 0)\r\n"),1 : \
+ (((LPINTERFACEIMPL)(lpThis))->cRef < 0) ? \
+ ( \
+ DebugBreak(), \
+ OleDbgOut( \
+ "\tERROR: " iface "* RELEASED TOO MANY TIMES\r\n") \
+ ),1 : \
+ 1)
+
+#else // if _DEBUGLEVEL < 2
+#define OleDbgReleaseMethod(lpThis, iface) \
+ (--((LPINTERFACEIMPL)(lpThis))->cRef == 0 ? \
+ 1 : \
+ (((LPINTERFACEIMPL)(lpThis))->cRef < 0) ? \
+ ( \
+ OleDbgOut( \
+ "\tERROR: " iface "* RELEASED TOO MANY TIMES\r\n") \
+ ),1 : \
+ 1)
+
+#endif // if _DEBUGLEVEL < 2
+
+#else // ! defined (_DEBUG)
+
+#define OleDbgQueryInterfaceMethod(lpUnk)
+#define OleDbgAddRefMethod(lpThis, iface)
+#define OleDbgReleaseMethod(lpThis, iface)
+
+#endif // if defined( _DEBUG )
+
+#endif // ! defined(__cplusplus)
+
+/*
+ * Some docfiles stuff
+ */
+
+#define STGM_DFRALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE)
+#define STGM_DFALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE)
+#define STGM_SALL (STGM_READWRITE | STGM_SHARE_EXCLUSIVE)
+
+/*
+ * Some moniker stuff
+ */
+
+// Delimeter used to separate ItemMoniker pieces of a composite moniker
+#if defined( _MAC )
+#define OLESTDDELIM ":"
+#else
+#define OLESTDDELIM TEXT("\\")
+#endif
+
+/*
+ * Some Concurrency stuff
+ */
+
+/* standard Delay (in msec) to wait before retrying an LRPC call.
+** this value is returned from IMessageFilter::RetryRejectedCall
+*/
+#define OLESTDRETRYDELAY (DWORD)5000
+
+/* Cancel the pending outgoing LRPC call.
+** this value is returned from IMessageFilter::RetryRejectedCall
+*/
+#define OLESTDCANCELRETRY (DWORD)-1
+
+/*
+ * Some Icon support stuff.
+ *
+ * The following API's are now OBSOLETE because equivalent API's have been
+ * added to the OLE2.DLL library
+ * GetIconOfFile superceeded by OleGetIconOfFile
+ * GetIconOfClass superceeded by OleGetIconOfClass
+ * OleUIMetafilePictFromIconAndLabel
+ * superceeded by OleMetafilePictFromIconAndLabel
+ *
+ * The following macros are defined for backward compatibility with previous
+ * versions of the OLE2UI library. It is recommended that the new Ole* API's
+ * should be used instead.
+ */
+#define GetIconOfFile(hInst, lpszFileName, fUseFileAsLabel) \
+ OleGetIconOfFileA(lpszFileName, fUseFileAsLabel)
+
+#define GetIconOfClass(hInst, rclsid, lpszLabel, fUseTypeAsLabel) \
+ OleGetIconOfClassA(rclsid, lpszLabel, fUseTypeAsLabel)
+
+#define OleUIMetafilePictFromIconAndLabel(hIcon,pszLabel,pszSourceFile,iIcon)\
+ OleMetafilePictFromIconAndLabelA(hIcon, pszLabel, pszSourceFile, iIcon)
+
+
+/*
+ * Some Clipboard Copy/Paste & Drag/Drop support stuff
+ */
+
+//Macro to set all FormatEtc fields
+#define SETFORMATETC(fe, cf, asp, td, med, li) \
+ ((fe).cfFormat=cf, \
+ (fe).dwAspect=asp, \
+ (fe).ptd=td, \
+ (fe).tymed=med, \
+ (fe).lindex=li)
+
+//Macro to set interesting FormatEtc fields defaulting the others.
+#define SETDEFAULTFORMATETC(fe, cf, med) \
+ ((fe).cfFormat=cf, \
+ (fe).dwAspect=DVASPECT_CONTENT, \
+ (fe).ptd=NULL, \
+ (fe).tymed=med, \
+ (fe).lindex=-1)
+
+// Macro to test if two FormatEtc structures are an exact match
+#define IsEqualFORMATETC(fe1, fe2) \
+ (OleStdCompareFormatEtc(&(fe1), &(fe2))==0)
+
+// Clipboard format strings
+#define CF_EMBEDSOURCE TEXT("Embed Source")
+#define CF_EMBEDDEDOBJECT TEXT("Embedded Object")
+#define CF_LINKSOURCE TEXT("Link Source")
+#define CF_CUSTOMLINKSOURCE TEXT("Custom Link Source")
+#define CF_OBJECTDESCRIPTOR TEXT("Object Descriptor")
+#define CF_LINKSRCDESCRIPTOR TEXT("Link Source Descriptor")
+#define CF_OWNERLINK TEXT("OwnerLink")
+#define CF_FILENAME TEXT("FileName")
+
+#define OleStdQueryOleObjectData(lpformatetc) \
+ (((lpformatetc)->tymed & TYMED_ISTORAGE) ? \
+ NOERROR : ResultFromScode(DV_E_FORMATETC))
+
+#define OleStdQueryLinkSourceData(lpformatetc) \
+ (((lpformatetc)->tymed & TYMED_ISTREAM) ? \
+ NOERROR : ResultFromScode(DV_E_FORMATETC))
+
+#define OleStdQueryObjectDescriptorData(lpformatetc) \
+ (((lpformatetc)->tymed & TYMED_HGLOBAL) ? \
+ NOERROR : ResultFromScode(DV_E_FORMATETC))
+
+#define OleStdQueryFormatMedium(lpformatetc, tymd) \
+ (((lpformatetc)->tymed & tymd) ? \
+ NOERROR : ResultFromScode(DV_E_FORMATETC))
+
+// Make an independent copy of a MetafilePict
+#define OleStdCopyMetafilePict(hpictin, phpictout) \
+ (*(phpictout) = OleDuplicateData(hpictin,CF_METAFILEPICT,GHND|GMEM_SHARE))
+
+
+// REVIEW: these need to be added to OLE2.H
+#if !defined( DD_DEFSCROLLINTERVAL )
+#define DD_DEFSCROLLINTERVAL 50
+#endif
+
+#if !defined( DD_DEFDRAGDELAY )
+#define DD_DEFDRAGDELAY 200
+#endif
+
+#if !defined( DD_DEFDRAGMINDIST )
+#define DD_DEFDRAGMINDIST 2
+#endif
+
+
+/* OleStdGetDropEffect
+** -------------------
+**
+** Convert a keyboard state into a DROPEFFECT.
+**
+** returns the DROPEFFECT value derived from the key state.
+** the following is the standard interpretation:
+** no modifier -- Default Drop (NULL is returned)
+** CTRL -- DROPEFFECT_COPY
+** SHIFT -- DROPEFFECT_MOVE
+** CTRL-SHIFT -- DROPEFFECT_LINK
+**
+** Default Drop: this depends on the type of the target application.
+** this is re-interpretable by each target application. a typical
+** interpretation is if the drag is local to the same document
+** (which is source of the drag) then a MOVE operation is
+** performed. if the drag is not local, then a COPY operation is
+** performed.
+*/
+#define OleStdGetDropEffect(grfKeyState) \
+ ( (grfKeyState & MK_CONTROL) ? \
+ ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ) : \
+ ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 ) )
+
+
+/* The OLEUIPASTEFLAG enumeration is used by the OLEUIPASTEENTRY structure.
+ *
+ * OLEUIPASTE_ENABLEICON If the container does not specify this flag for the entry in the
+ * OLEUIPASTEENTRY array passed as input to OleUIPasteSpecial, the DisplayAsIcon button will be
+ * unchecked and disabled when the the user selects the format that corresponds to the entry.
+ *
+ * OLEUIPASTE_PASTEONLY Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting only.
+ * OLEUIPASTE_PASTE Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting. It
+ * may also be valid for linking if any of the following linking flags are specified.
+ *
+ * If the entry in the OLEUIPASTEENTRY array is valid for linking, the following flags indicate which link
+ * types are acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values.
+ * These values correspond as follows to the array of link types passed to OleUIPasteSpecial:
+ * OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]
+ * OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]
+ * OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]
+ * OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]
+ * OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]
+ * OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]
+ * OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]
+ * OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]
+ *
+ * where,
+ * UINT arrLinkTypes[8] is an array of registered clipboard formats for linking. A maximium of 8 link
+ * types are allowed.
+ */
+
+typedef enum tagOLEUIPASTEFLAG
+{
+ OLEUIPASTE_ENABLEICON = 2048, // enable display as icon
+ OLEUIPASTE_PASTEONLY = 0,
+ OLEUIPASTE_PASTE = 512,
+ OLEUIPASTE_LINKANYTYPE = 1024,
+ OLEUIPASTE_LINKTYPE1 = 1,
+ OLEUIPASTE_LINKTYPE2 = 2,
+ OLEUIPASTE_LINKTYPE3 = 4,
+ OLEUIPASTE_LINKTYPE4 = 8,
+ OLEUIPASTE_LINKTYPE5 = 16,
+ OLEUIPASTE_LINKTYPE6 = 32,
+ OLEUIPASTE_LINKTYPE7 = 64,
+ OLEUIPASTE_LINKTYPE8 = 128
+} OLEUIPASTEFLAG;
+
+/*
+ * PasteEntry structure
+ * --------------------
+ * An array of OLEUIPASTEENTRY entries is specified for the PasteSpecial dialog
+ * box. Each entry includes a FORMATETC which specifies the formats that are
+ * acceptable, a string that is to represent the format in the dialog's list
+ * box, a string to customize the result text of the dialog and a set of flags
+ * from the OLEUIPASTEFLAG enumeration. The flags indicate if the entry is
+ * valid for pasting only, linking only or both pasting and linking. If the
+ * entry is valid for linking, the flags indicate which link types are
+ * acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values.
+ * These values correspond to the array of link types as follows:
+ * OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]
+ * OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]
+ * OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]
+ * OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]
+ * OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]
+ * OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]
+ * OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]
+ * OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]
+ * UINT arrLinkTypes[8]; is an array of registered clipboard formats
+ * for linking. A maximium of 8 link types are allowed.
+ */
+
+typedef struct tagOLEUIPASTEENTRY
+{
+ FORMATETC fmtetc; // Format that is acceptable. The paste
+ // dialog checks if this format is
+ // offered by the object on the
+ // clipboard and if so offers it for
+ // selection to the user.
+ LPCTSTR lpstrFormatName; // String that represents the format to the user. Any %s
+ // in this string is replaced by the FullUserTypeName
+ // of the object on the clipboard and the resulting string
+ // is placed in the list box of the dialog. Atmost
+ // one %s is allowed. The presence or absence of %s indicates
+ // if the result text is to indicate that data is
+ // being pasted or that an object that can be activated by
+ // an application is being pasted. If %s is
+ // present, the result-text says that an object is being pasted.
+ // Otherwise it says that data is being pasted.
+ LPCTSTR lpstrResultText; // String to customize the result text of the dialog when
+ // the user selects the format correspoding to this
+ // entry. Any %s in this string is replaced by the the application
+ // name or FullUserTypeName of the object on
+ // the clipboard. Atmost one %s is allowed.
+ DWORD dwFlags; // Values from OLEUIPASTEFLAG enum
+ DWORD dwScratchSpace; // Scratch space available to be used
+ // by routines which loop through an
+ // IEnumFORMATETC* to mark if the
+ // PasteEntry format is available.
+ // this field CAN be left uninitialized.
+} OLEUIPASTEENTRY, *POLEUIPASTEENTRY, FAR *LPOLEUIPASTEENTRY;
+
+#define OLESTDDROP_NONE 0
+#define OLESTDDROP_DEFAULT 1
+#define OLESTDDROP_NONDEFAULT 2
+
+
+/*
+ * Some misc stuff
+ */
+
+#define EMBEDDINGFLAG "Embedding" // Cmd line switch for launching a srvr
+
+#define HIMETRIC_PER_INCH 2540 // number HIMETRIC units per inch
+#define PTS_PER_INCH 72 // number points (font size) per inch
+
+#define MAP_PIX_TO_LOGHIM(x,ppli) MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
+#define MAP_LOGHIM_TO_PIX(x,ppli) MulDiv((ppli), (x), HIMETRIC_PER_INCH)
+
+// Returns TRUE if all fields of the two Rect's are equal, else FALSE.
+#define AreRectsEqual(lprc1, lprc2) \
+ (((lprc1->top == lprc2->top) && \
+ (lprc1->left == lprc2->left) && \
+ (lprc1->right == lprc2->right) && \
+ (lprc1->bottom == lprc2->bottom)) ? TRUE : FALSE)
+
+/* lstrcpyn is defined to be able to handle UNICODE string
+ * The third parameter here is the number of CHARACTERS that are
+ * to be copied.
+ */
+#define LSTRCPYN(lpdst, lpsrc, cch) \
+(\
+ (lpdst)[(cch)-1] = '\0', \
+ (cch>1 ? lstrcpyn(lpdst, lpsrc, (cch)-1) : 0)\
+)
+
+
+/****** DEBUG Stuff *****************************************************/
+
+#ifdef _DEBUG
+
+#if !defined( _DBGTRACE )
+#define _DEBUGLEVEL 2
+#else
+#define _DEBUGLEVEL _DBGTRACE
+#endif
+
+
+#if defined( NOASSERT )
+
+#define OLEDBGASSERTDATA
+#define OleDbgAssert(a)
+#define OleDbgAssertSz(a, b)
+#define OleDbgVerify(a)
+#define OleDbgVerifySz(a, b)
+
+#else // ! NOASSERT
+
+STDAPI FnAssert(LPSTR lpstrExpr, LPSTR lpstrMsg, LPSTR lpstrFileName, UINT iLine);
+
+#define OLEDBGASSERTDATA \
+ static char _based(_segname("_CODE")) _szAssertFile[]= TEXT(__FILE__);
+
+#define OleDbgAssert(a) \
+ (!(a) ? FnAssert(#a, NULL, _szAssertFile, __LINE__) : (HRESULT)1)
+
+#define OleDbgAssertSz(a, b) \
+ (!(a) ? FnAssert(#a, b, _szAssertFile, __LINE__) : (HRESULT)1)
+
+#define OleDbgVerify(a) \
+ OleDbgAssert(a)
+
+#define OleDbgVerifySz(a, b) \
+ OleDbgAssertSz(a, b)
+
+#endif // ! NOASSERT
+
+#ifdef DLL_VER
+#define OLEDBGDATA_MAIN(szPrefix) \
+ TCHAR NEAR g_szDbgPrefix[] = szPrefix; \
+ OLEDBGASSERTDATA
+#define OLEDBGDATA \
+ extern TCHAR NEAR g_szDbgPrefix[]; \
+ OLEDBGASSERTDATA
+#else
+#define OLEDBGDATA_MAIN(szPrefix) \
+ TCHAR g_szDbgPrefix[] = szPrefix; \
+ OLEDBGASSERTDATA
+#define OLEDBGDATA \
+ extern TCHAR g_szDbgPrefix[]; \
+ OLEDBGASSERTDATA
+#endif
+
+#define OLEDBG_BEGIN(lpsz) \
+ OleDbgPrintAlways(g_szDbgPrefix,lpsz,1);
+
+#define OLEDBG_END \
+ OleDbgPrintAlways(g_szDbgPrefix,TEXT("End\r\n"),-1);
+
+#define OleDbgOut(lpsz) \
+ OleDbgPrintAlways(g_szDbgPrefix,lpsz,0)
+
+#define OleDbgOutNoPrefix(lpsz) \
+ OleDbgPrintAlways(TEXT(""),lpsz,0)
+
+#define OleDbgOutRefCnt(lpsz,lpObj,refcnt) \
+ OleDbgPrintRefCntAlways(g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)
+
+#define OleDbgOutRect(lpsz,lpRect) \
+ OleDbgPrintRectAlways(g_szDbgPrefix,lpsz,lpRect)
+
+#define OleDbgOutHResult(lpsz,hr) \
+ OleDbgPrintScodeAlways(g_szDbgPrefix,lpsz,GetScode(hr))
+
+#define OleDbgOutScode(lpsz,sc) \
+ OleDbgPrintScodeAlways(g_szDbgPrefix,lpsz,sc)
+
+#define OleDbgOut1(lpsz) \
+ OleDbgPrint(1,g_szDbgPrefix,lpsz,0)
+
+#define OleDbgOutNoPrefix1(lpsz) \
+ OleDbgPrint(1,TEXT(""),lpsz,0)
+
+#define OLEDBG_BEGIN1(lpsz) \
+ OleDbgPrint(1,g_szDbgPrefix,lpsz,1);
+
+#define OLEDBG_END1 \
+ OleDbgPrint(1,g_szDbgPrefix,TEXT("End\r\n"),-1);
+
+#define OleDbgOutRefCnt1(lpsz,lpObj,refcnt) \
+ OleDbgPrintRefCnt(1,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)
+
+#define OleDbgOutRect1(lpsz,lpRect) \
+ OleDbgPrintRect(1,g_szDbgPrefix,lpsz,lpRect)
+
+#define OleDbgOut2(lpsz) \
+ OleDbgPrint(2,g_szDbgPrefix,lpsz,0)
+
+#define OleDbgOutNoPrefix2(lpsz) \
+ OleDbgPrint(2,TEXT(""),lpsz,0)
+
+#define OLEDBG_BEGIN2(lpsz) \
+ OleDbgPrint(2,g_szDbgPrefix,lpsz,1);
+
+#define OLEDBG_END2 \
+ OleDbgPrint(2,g_szDbgPrefix, TEXT("End\r\n"),-1);
+
+#define OleDbgOutRefCnt2(lpsz,lpObj,refcnt) \
+ OleDbgPrintRefCnt(2,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)
+
+#define OleDbgOutRect2(lpsz,lpRect) \
+ OleDbgPrintRect(2,g_szDbgPrefix,lpsz,lpRect)
+
+#define OleDbgOut3(lpsz) \
+ OleDbgPrint(3,g_szDbgPrefix,lpsz,0)
+
+#define OleDbgOutNoPrefix3(lpsz) \
+ OleDbgPrint(3,TEXT(""),lpsz,0)
+
+#define OLEDBG_BEGIN3(lpsz) \
+ OleDbgPrint(3,g_szDbgPrefix,lpsz,1);
+
+#define OLEDBG_END3 \
+ OleDbgPrint(3,g_szDbgPrefix,TEXT("End\r\n"),-1);
+
+#define OleDbgOutRefCnt3(lpsz,lpObj,refcnt) \
+ OleDbgPrintRefCnt(3,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)
+
+#define OleDbgOutRect3(lpsz,lpRect) \
+ OleDbgPrintRect(3,g_szDbgPrefix,lpsz,lpRect)
+
+#define OleDbgOut4(lpsz) \
+ OleDbgPrint(4,g_szDbgPrefix,lpsz,0)
+
+#define OleDbgOutNoPrefix4(lpsz) \
+ OleDbgPrint(4,TEXT(""),lpsz,0)
+
+#define OLEDBG_BEGIN4(lpsz) \
+ OleDbgPrint(4,g_szDbgPrefix,lpsz,1);
+
+#define OLEDBG_END4 \
+ OleDbgPrint(4,g_szDbgPrefix,TEXT("End\r\n"),-1);
+
+#define OleDbgOutRefCnt4(lpsz,lpObj,refcnt) \
+ OleDbgPrintRefCnt(4,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)
+
+#define OleDbgOutRect4(lpsz,lpRect) \
+ OleDbgPrintRect(4,g_szDbgPrefix,lpsz,lpRect)
+
+#else // !_DEBUG
+
+#define OLEDBGDATA_MAIN(szPrefix)
+#define OLEDBGDATA
+#define OleDbgAssert(a)
+#define OleDbgAssertSz(a, b)
+#define OleDbgVerify(a) (a)
+#define OleDbgVerifySz(a, b) (a)
+#define OleDbgOutHResult(lpsz,hr)
+#define OleDbgOutScode(lpsz,sc)
+#define OLEDBG_BEGIN(lpsz)
+#define OLEDBG_END
+#define OleDbgOut(lpsz)
+#define OleDbgOut1(lpsz)
+#define OleDbgOut2(lpsz)
+#define OleDbgOut3(lpsz)
+#define OleDbgOut4(lpsz)
+#define OleDbgOutNoPrefix(lpsz)
+#define OleDbgOutNoPrefix1(lpsz)
+#define OleDbgOutNoPrefix2(lpsz)
+#define OleDbgOutNoPrefix3(lpsz)
+#define OleDbgOutNoPrefix4(lpsz)
+#define OLEDBG_BEGIN1(lpsz)
+#define OLEDBG_BEGIN2(lpsz)
+#define OLEDBG_BEGIN3(lpsz)
+#define OLEDBG_BEGIN4(lpsz)
+#define OLEDBG_END1
+#define OLEDBG_END2
+#define OLEDBG_END3
+#define OLEDBG_END4
+#define OleDbgOutRefCnt(lpsz,lpObj,refcnt)
+#define OleDbgOutRefCnt1(lpsz,lpObj,refcnt)
+#define OleDbgOutRefCnt2(lpsz,lpObj,refcnt)
+#define OleDbgOutRefCnt3(lpsz,lpObj,refcnt)
+#define OleDbgOutRefCnt4(lpsz,lpObj,refcnt)
+#define OleDbgOutRect(lpsz,lpRect)
+#define OleDbgOutRect1(lpsz,lpRect)
+#define OleDbgOutRect2(lpsz,lpRect)
+#define OleDbgOutRect3(lpsz,lpRect)
+#define OleDbgOutRect4(lpsz,lpRect)
+
+#endif // _DEBUG
+
+
+/*************************************************************************
+** Function prototypes
+*************************************************************************/
+
+
+//OLESTD.C
+STDAPI_(int) SetDCToAnisotropic(HDC hDC, LPRECT lprcPhysical, LPRECT lprcLogical, LPRECT lprcWindowOld, LPRECT lprcViewportOld);
+STDAPI_(int) SetDCToDrawInHimetricRect(HDC, LPRECT, LPRECT, LPRECT, LPRECT);
+STDAPI_(int) ResetOrigDC(HDC, int, LPRECT, LPRECT);
+
+STDAPI_(int) XformWidthInHimetricToPixels(HDC, int);
+STDAPI_(int) XformWidthInPixelsToHimetric(HDC, int);
+STDAPI_(int) XformHeightInHimetricToPixels(HDC, int);
+STDAPI_(int) XformHeightInPixelsToHimetric(HDC, int);
+
+STDAPI_(void) XformRectInPixelsToHimetric(HDC, LPRECT, LPRECT);
+STDAPI_(void) XformRectInHimetricToPixels(HDC, LPRECT, LPRECT);
+STDAPI_(void) XformSizeInPixelsToHimetric(HDC, LPSIZEL, LPSIZEL);
+STDAPI_(void) XformSizeInHimetricToPixels(HDC, LPSIZEL, LPSIZEL);
+STDAPI_(int) XformWidthInHimetricToPixels(HDC, int);
+STDAPI_(int) XformWidthInPixelsToHimetric(HDC, int);
+STDAPI_(int) XformHeightInHimetricToPixels(HDC, int);
+STDAPI_(int) XformHeightInPixelsToHimetric(HDC, int);
+
+STDAPI_(void) ParseCmdLine(LPSTR, BOOL FAR *, LPSTR);
+
+STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk);
+STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid);
+STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPTSTR lpszStgName, DWORD grfMode);
+STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPTSTR lpszStgName, DWORD grfMode);
+STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPTSTR lpszStgName, DWORD grfMode);
+STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPTSTR lpszStgName);
+STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPTSTR lpszStgName, DWORD grfMode);
+STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg);
+STDAPI OleStdDestroyAllElements(LPSTORAGE lpStg);
+
+STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(
+ HANDLE hGlobal,
+ BOOL fDeleteOnRelease,
+ DWORD dwgrfMode
+);
+STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode);
+STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew);
+STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(
+ REFCLSID rClsidApp,
+ LPSTORAGE lpStg,
+ CLSID FAR* lpclsid,
+ CLIPFORMAT FAR* lpcfFmt,
+ LPTSTR FAR* lplpszType
+);
+STDAPI OleStdDoTreatAsClass(LPTSTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew);
+STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,
+ LPTSTR lpszContainerApp, LPTSTR lpszContainerObj,
+ LPADVISESINK lpAdviseSink, BOOL fCreate);
+STDAPI OleStdSwitchDisplayAspect(
+ LPOLEOBJECT lpOleObj,
+ LPDWORD lpdwCurAspect,
+ DWORD dwNewAspect,
+ HGLOBAL hMetaPict,
+ BOOL fDeleteOldAspect,
+ BOOL fSetupViewAdvise,
+ LPADVISESINK lpAdviseSink,
+ BOOL FAR* lpfMustUpdate
+);
+STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict);
+STDAPI_(HGLOBAL) OleStdGetData(
+ LPDATAOBJECT lpDataObj,
+ CLIPFORMAT cfFormat,
+ DVTARGETDEVICE FAR* lpTargetDevice,
+ DWORD dwAspect,
+ LPSTGMEDIUM lpMedium
+);
+STDAPI_(void) OleStdMarkPasteEntryList(
+ LPDATAOBJECT lpSrcDataObj,
+ LPOLEUIPASTEENTRY lpPriorityList,
+ int cEntries
+);
+STDAPI_(int) OleStdGetPriorityClipboardFormat(
+ LPDATAOBJECT lpSrcDataObj,
+ LPOLEUIPASTEENTRY lpPriorityList,
+ int cEntries
+);
+STDAPI_(BOOL) OleStdIsDuplicateFormat(
+ LPFORMATETC lpFmtEtc,
+ LPFORMATETC arrFmtEtc,
+ int nFmtEtc
+);
+STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister);
+STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister);
+STDAPI_(void) OleStdNoteFileChangeTime(LPTSTR lpszFileName, DWORD dwRegister);
+STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister);
+STDAPI OleStdGetOleObjectData(
+ LPPERSISTSTORAGE lpPStg,
+ LPFORMATETC lpformatetc,
+ LPSTGMEDIUM lpMedium,
+ BOOL fUseMemory
+);
+STDAPI OleStdGetLinkSourceData(
+ LPMONIKER lpmk,
+ LPCLSID lpClsID,
+ LPFORMATETC lpformatetc,
+ LPSTGMEDIUM lpMedium
+);
+STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(
+ CLSID clsid,
+ DWORD dwAspect,
+ SIZEL sizel,
+ POINTL pointl,
+ DWORD dwStatus,
+ LPTSTR lpszFullUserTypeName,
+ LPTSTR lpszSrcOfCopy
+);
+STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(
+ LPOLEOBJECT lpOleObj,
+ LPTSTR lpszSrcOfCopy,
+ DWORD dwAspect,
+ POINTL pointl,
+ LPSIZEL lpSizelHim
+);
+STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(
+ LPDATAOBJECT lpDataObject,
+ LPSTGMEDIUM lpmedium,
+ CLIPFORMAT FAR* lpcfFmt
+);
+STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(
+ LPOLEOBJECT lpOleObj,
+ DWORD dwDrawAspect,
+ LPSIZEL lpSizelHim,
+ DVTARGETDEVICE FAR* ptd
+);
+
+STDAPI_(void) OleStdCreateTempFileMoniker(LPTSTR lpszPrefixString, UINT FAR* lpuUnique, LPTSTR lpszName, LPMONIKER FAR* lplpmk);
+STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk);
+STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk);
+STDAPI OleStdMkParseDisplayName(
+ REFCLSID rClsid,
+ LPBC lpbc,
+ LPTSTR lpszUserName,
+ ULONG FAR* lpchEaten,
+ LPMONIKER FAR* lplpmk
+);
+STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize);
+STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize);
+STDAPI_(void) OleStdFree(LPVOID pmem);
+STDAPI_(ULONG) OleStdGetSize(LPVOID pmem);
+STDAPI_(void) OleStdFreeString(LPTSTR lpsz, LPMALLOC lpMalloc);
+STDAPI_(LPTSTR) OleStdCopyString(LPTSTR lpszSrc, LPMALLOC lpMalloc);
+STDAPI_(ULONG) OleStdGetItemToken(LPTSTR lpszSrc, LPTSTR lpszDst,int nMaxChars);
+
+STDAPI_(UINT) OleStdIconLabelTextOut(HDC hDC,
+ HFONT hFont,
+ int nXStart,
+ int nYStart,
+ UINT fuOptions,
+ RECT FAR * lpRect,
+ LPTSTR lpszString,
+ UINT cchString,
+ int FAR * lpDX);
+
+// registration database query functions
+STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid,
+ WORD wAuxUserType,
+ LPTSTR lpszAuxUserType,
+ int cch,
+ HKEY hKey);
+
+STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid,
+ LPTSTR lpszUserType,
+ UINT cch,
+ HKEY hKey);
+
+STDAPI_(BOOL) OleStdGetMiscStatusOfClass(REFCLSID, HKEY, DWORD FAR *);
+STDAPI_(CLIPFORMAT) OleStdGetDefaultFileFormatOfClass(
+ REFCLSID rclsid,
+ HKEY hKey
+);
+
+STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl);
+STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis);
+STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPTSTR lpszIface);
+STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPTSTR lpszMsg);
+STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk);
+
+STDAPI_(HDC) OleStdCreateDC(DVTARGETDEVICE FAR* ptd);
+STDAPI_(HDC) OleStdCreateIC(DVTARGETDEVICE FAR* ptd);
+STDAPI_(DVTARGETDEVICE FAR*) OleStdCreateTargetDevice(LPPRINTDLG lpPrintDlg);
+STDAPI_(BOOL) OleStdDeleteTargetDevice(DVTARGETDEVICE FAR* ptd);
+STDAPI_(DVTARGETDEVICE FAR*) OleStdCopyTargetDevice(DVTARGETDEVICE FAR* ptdSrc);
+STDAPI_(BOOL) OleStdCopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc);
+STDAPI_(int) OleStdCompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight);
+STDAPI_(BOOL) OleStdCompareTargetDevice
+ (DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight);
+
+
+STDAPI_(void) OleDbgPrint(
+ int nDbgLvl,
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ int nIndent
+);
+STDAPI_(void) OleDbgPrintAlways(LPTSTR lpszPrefix, LPTSTR lpszMsg, int nIndent);
+STDAPI_(void) OleDbgSetDbgLevel(int nDbgLvl);
+STDAPI_(int) OleDbgGetDbgLevel( void );
+STDAPI_(void) OleDbgIndent(int n);
+STDAPI_(void) OleDbgPrintRefCnt(
+ int nDbgLvl,
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPVOID lpObj,
+ ULONG refcnt
+);
+STDAPI_(void) OleDbgPrintRefCntAlways(
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPVOID lpObj,
+ ULONG refcnt
+);
+STDAPI_(void) OleDbgPrintRect(
+ int nDbgLvl,
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPRECT lpRect
+);
+STDAPI_(void) OleDbgPrintRectAlways(
+ LPTSTR lpszPrefix,
+ LPTSTR lpszMsg,
+ LPRECT lpRect
+);
+STDAPI_(void) OleDbgPrintScodeAlways(LPTSTR lpszPrefix, LPTSTR lpszMsg, SCODE sc);
+
+// debug implementation of the IMalloc interface.
+STDAPI OleStdCreateDbAlloc(ULONG reserved, IMalloc FAR* FAR* ppmalloc);
+
+
+STDAPI_(LPENUMFORMATETC)
+ OleStdEnumFmtEtc_Create(ULONG nCount, LPFORMATETC lpEtc);
+
+STDAPI_(LPENUMSTATDATA)
+ OleStdEnumStatData_Create(ULONG nCount, LPSTATDATA lpStat);
+
+STDAPI_(BOOL)
+ OleStdCopyStatData(LPSTATDATA pDest, LPSTATDATA pSrc);
+
+STDAPI_(HPALETTE)
+ OleStdCreateStandardPalette(void);
+
+#if defined( OBSOLETE )
+
+/*************************************************************************
+** The following API's have been converted into macros:
+** OleStdQueryOleObjectData
+** OleStdQueryLinkSourceData
+** OleStdQueryObjectDescriptorData
+** OleStdQueryFormatMedium
+** OleStdCopyMetafilePict
+** AreRectsEqual
+** OleStdGetDropEffect
+**
+** These macros are defined above
+*************************************************************************/
+STDAPI_(BOOL) AreRectsEqual(LPRECT lprc1, LPRECT lprc2);
+STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout);
+STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc);
+STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc);
+STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc);
+STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed);
+STDAPI_(DWORD) OleStdGetDropEffect ( DWORD grfKeyState );
+#endif // OBSOLETE
+
+
+#endif // _OLESTD_H_
+
diff --git a/private/oleutest/letest/ole2ui/olestr.c b/private/oleutest/letest/ole2ui/olestr.c
new file mode 100644
index 000000000..e7e8e93fa
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/olestr.c
@@ -0,0 +1,32 @@
+void CopyAndFreeOLESTR(LPOLESTR polestr, char **ppszOut)
+{
+ // See if there is any work
+ if (polestr == NULL)
+ {
+ if (ppszOut != NULL)
+ {
+ // Output string requested so set it to NULL.
+ *ppszOut = NULL;
+ }
+
+ return;
+ }
+
+ // Get the public memory allocator
+
+ if (pszOut)
+ {
+ // Copy of string converted to ANSI is requested
+ }
+
+ // Free the original string
+}
+
+LPOLESTR CreateOLESTR(char *pszIn)
+{
+ // Get the public memory allocator
+
+ // Allocate the string
+
+ // Convert the string
+}
diff --git a/private/oleutest/letest/ole2ui/olestr.h b/private/oleutest/letest/ole2ui/olestr.h
new file mode 100644
index 000000000..a9c282930
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/olestr.h
@@ -0,0 +1,21 @@
+#ifndef _OLESTR_H_
+#define _OLESTR_H_
+
+void CopyAndFreeOLESTR(LPOLESTR polestr, char **pszOut);
+
+void CopyAndFreeSTR(LPSTR polestr, LPOLESTR *pszOut);
+
+LPOLESTR CreateOLESTR(const char *pszIn);
+LPSTR CreateSTR(LPCOLESTR pszIn);
+
+#define CREATEOLESTR(x, y) LPOLESTR x = CreateOLESTR(y);
+
+#define CREATESTR(x, y) LPSTR x = CreateSTR(y);
+
+#define FREEOLESTR(x) CopyAndFreeOLESTR(x, NULL);
+
+#define FREESTR(x) CopyAndFreeSTR(x, NULL);
+
+
+
+#endif // _OLESTR_H_
diff --git a/private/oleutest/letest/ole2ui/olethunk.c b/private/oleutest/letest/ole2ui/olethunk.c
new file mode 100644
index 000000000..a69c3102d
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/olethunk.c
@@ -0,0 +1,649 @@
+#include <windows.h>
+#include <ole2.h>
+#include "olethunk.h"
+
+STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize);
+
+STDAPI_(void) OleStdFree(LPVOID pmem);
+
+
+STDAPI_(void) CopyAndFreeOLESTR(LPOLESTR polestr, LPSTR *ppszOut)
+{
+ // See if there is any work
+ if (polestr == NULL)
+ {
+ if (ppszOut != NULL)
+ {
+ // Output string requested so set it to NULL.
+ *ppszOut = NULL;
+ }
+
+ return;
+ }
+
+ if (ppszOut)
+ {
+ // Copy of string converted to ANSI is requested
+ int len = wcslen(polestr) + 1;
+ *ppszOut = OleStdMalloc(len);
+
+ if (*ppszOut)
+ {
+ wcstombs(*ppszOut, polestr, len);
+ }
+ }
+
+ // Free the original string
+ OleStdFree(polestr);
+}
+
+
+
+
+STDAPI_(void) CopyAndFreeSTR(LPSTR pstr, LPOLESTR *ppolestrOut)
+{
+ // See if there is any work
+ if (pstr == NULL)
+ {
+ if (ppolestrOut != NULL)
+ {
+ // Output string requested so set it to NULL.
+ *ppolestrOut = NULL;
+ }
+
+ return;
+ }
+
+ if (ppolestrOut)
+ {
+ // Copy of string converted to ANSI is requested
+ int len = strlen(pstr) + 1;
+ *ppolestrOut = OleStdMalloc(len * sizeof(WCHAR));
+
+ if (*ppolestrOut)
+ {
+ mbstowcs(*ppolestrOut, pstr, len);
+ }
+ }
+
+ // Free the original string
+ OleStdFree(pstr);
+}
+
+
+
+STDAPI_(LPOLESTR) CreateOLESTR(LPCSTR pszIn)
+{
+ // Return NULL if there was no string input
+ LPOLESTR polestr = NULL;
+
+ if (pszIn != NULL)
+ {
+ // Calculate size of string to allocate
+ int len = strlen(pszIn) + 1;
+
+ // Allocate the string
+ polestr = (LPOLESTR) OleStdMalloc(len * sizeof(OLECHAR));
+
+ // Convert the string
+ if (polestr)
+ {
+ mbstowcs(polestr, pszIn, len);
+ }
+ }
+
+ return polestr;
+}
+
+
+
+STDAPI_(LPSTR) CreateSTR(LPCOLESTR polestrIn)
+{
+ // Return NULL if there was no string input
+ LPSTR pstr = NULL;
+
+ if (polestrIn != NULL)
+ {
+ // Calculate size of string to allocate
+ int len = wcslen(polestrIn) + 1;
+
+ // Allocate the string
+ pstr = (PSTR) OleStdMalloc(len);
+
+ // Convert the string
+ if (pstr)
+ {
+ wcstombs(pstr, polestrIn, len);
+ }
+ }
+
+ return pstr;
+}
+
+
+
+
+STDAPI_(void) CLSIDFromStringA(LPSTR pszClass, LPCLSID pclsid)
+{
+ CREATEOLESTR(polestr, pszClass)
+
+ CLSIDFromString(polestr, pclsid);
+
+ FREEOLESTR(polestr)
+}
+
+
+
+STDAPI CreateFileMonikerA(LPSTR lpszPathName, LPMONIKER FAR* ppmk)
+{
+ CREATEOLESTR(polestr, lpszPathName)
+
+ HRESULT hr = CreateFileMoniker(polestr, ppmk);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI CreateItemMonikerA(
+ LPSTR lpszDelim,
+ LPSTR lpszItem,
+ LPMONIKER FAR* ppmk)
+{
+ CREATEOLESTR(polestrDelim, lpszDelim)
+ CREATEOLESTR(polestrItem, lpszItem)
+
+ HRESULT hr = CreateItemMoniker(polestrDelim, polestrItem, ppmk);
+
+ FREEOLESTR(polestrDelim)
+ FREEOLESTR(polestrItem)
+
+ return hr;
+}
+
+
+
+STDAPI_(HGLOBAL) OleGetIconOfClassA(
+ REFCLSID rclsid,
+ LPSTR lpszLabel,
+ BOOL fUseTypeAsLabel)
+{
+ CREATEOLESTR(polestr, lpszLabel)
+
+ HGLOBAL hglobal = OleGetIconOfClass(rclsid, polestr, fUseTypeAsLabel);
+
+ FREEOLESTR(polestr)
+
+ return hglobal;
+}
+
+
+
+STDAPI_(HGLOBAL) OleGetIconOfFileA(LPSTR lpszPath, BOOL fUseFileAsLabel)
+{
+ CREATEOLESTR(polestr, lpszPath)
+
+ HGLOBAL hMetaPict = OleGetIconOfFile(polestr, fUseFileAsLabel);
+
+ FREEOLESTR(polestr)
+
+ return hMetaPict;
+}
+
+
+
+
+STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabelA(
+ HICON hIcon,
+ LPSTR lpszLabel,
+ LPSTR lpszSourceFile,
+ UINT iIconIndex)
+{
+ CREATEOLESTR(polestrLabel, lpszLabel)
+ CREATEOLESTR(polestrSourceFile, lpszSourceFile)
+
+ HGLOBAL hglobal = OleMetafilePictFromIconAndLabel(hIcon, polestrLabel,
+ polestrSourceFile, iIconIndex);
+
+ FREEOLESTR(polestrLabel)
+ FREEOLESTR(polestrSourceFile)
+
+ return hglobal;
+}
+
+
+
+
+STDAPI GetClassFileA(LPCSTR szFilename, CLSID FAR* pclsid)
+{
+ CREATEOLESTR(polestr, szFilename)
+
+ HRESULT hr = GetClassFile(polestr, pclsid);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI CLSIDFromProgIDA(LPCSTR lpszProgID, LPCLSID lpclsid)
+{
+ CREATEOLESTR(polestr, lpszProgID)
+
+ HRESULT hr = CLSIDFromProgID(polestr, lpclsid);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+STDAPI MkParseDisplayNameA(
+ LPBC pbc,
+ LPSTR szUserName,
+ ULONG FAR * pchEaten,
+ LPMONIKER FAR * ppmk)
+{
+ CREATEOLESTR(polestr, szUserName)
+
+ HRESULT hr = MkParseDisplayName(pbc, polestr, pchEaten, ppmk);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+
+STDAPI OleCreateLinkToFileA(
+ LPCSTR lpszFileName,
+ REFIID riid,
+ DWORD renderopt,
+ LPFORMATETC lpFormatEtc,
+ LPOLECLIENTSITE pClientSite,
+ LPSTORAGE pStg,
+ LPVOID FAR* ppvObj)
+{
+ CREATEOLESTR(polestr, lpszFileName)
+
+ HRESULT hr = OleCreateLinkToFile(polestr, riid, renderopt, lpFormatEtc,
+ pClientSite, pStg, ppvObj);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+STDAPI OleCreateFromFileA(
+ REFCLSID rclsid,
+ LPCSTR lpszFileName,
+ REFIID riid,
+ DWORD renderopt,
+ LPFORMATETC lpFormatEtc,
+ LPOLECLIENTSITE pClientSite,
+ LPSTORAGE pStg,
+ LPVOID FAR* ppvObj)
+{
+ CREATEOLESTR(polestr, lpszFileName)
+
+ HRESULT hr = OleCreateFromFile(rclsid, polestr, riid, renderopt,
+ lpFormatEtc, pClientSite, pStg, ppvObj);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI OleRegGetUserTypeA(
+ REFCLSID clsid,
+ DWORD dwFormOfType,
+ LPSTR FAR* ppszUserType)
+{
+ LPOLESTR polestr;
+
+ HRESULT hr = OleRegGetUserType(clsid, dwFormOfType, &polestr);
+
+ CopyAndFreeOLESTR(polestr, ppszUserType);
+
+ return hr;
+}
+
+
+
+STDAPI ProgIDFromCLSIDA(REFCLSID clsid, LPSTR FAR* lplpszProgID)
+{
+ LPOLESTR polestr;
+
+ HRESULT hr = ProgIDFromCLSID(clsid, &polestr);
+
+ CopyAndFreeOLESTR(polestr, lplpszProgID);
+
+ return hr;
+}
+
+
+
+STDAPI ReadFmtUserTypeStgA(
+ LPSTORAGE pstg,
+ CLIPFORMAT FAR* pcf,
+ LPSTR FAR* lplpszUserType)
+{
+ LPOLESTR polestr;
+
+ HRESULT hr = ReadFmtUserTypeStg(pstg, pcf, &polestr);
+
+ CopyAndFreeOLESTR(polestr, lplpszUserType);
+
+ return hr;
+}
+
+
+
+
+
+
+STDAPI StgCreateDocfileA(
+ LPCSTR lpszName,
+ DWORD grfMode,
+ DWORD reserved,
+ IStorage FAR * FAR *ppstgOpen)
+{
+ HRESULT hr;
+ LPOLESTR polestr = NULL;
+
+ if (lpszName != NULL)
+ {
+ polestr = CreateOLESTR(lpszName);
+ }
+
+ hr = StgCreateDocfile(polestr, grfMode, reserved, ppstgOpen);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+
+STDAPI StgOpenStorageA(
+ LPCSTR lpszName,
+ IStorage FAR *pstgPriority,
+ DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ IStorage FAR * FAR *ppstgOpen)
+{
+ CREATEOLESTR(polestr, lpszName)
+
+ HRESULT hr = StgOpenStorage(polestr, pstgPriority, grfMode, snbExclude,
+ reserved, ppstgOpen);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI StgSetTimesA(
+ LPSTR lpszName,
+ FILETIME const FAR* pctime,
+ FILETIME const FAR* patime,
+ FILETIME const FAR* pmtime)
+{
+ CREATEOLESTR(polestr, lpszName)
+
+ HRESULT hr = StgSetTimes(polestr, pctime, patime, pmtime);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+
+STDAPI_(void) StringFromCLSIDA(REFCLSID rclsid, LPSTR *lplpszCLSID)
+{
+ LPOLESTR polestr;
+
+ StringFromCLSID(rclsid, &polestr);
+
+ CopyAndFreeOLESTR(polestr, lplpszCLSID);
+}
+
+
+STDAPI WriteFmtUserTypeStgA(
+ LPSTORAGE lpStg,
+ CLIPFORMAT cf,
+ LPSTR lpszUserType)
+{
+ CREATEOLESTR(polestr, lpszUserType)
+
+ HRESULT hr = WriteFmtUserTypeStg(lpStg, cf, polestr);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+
+
+
+
+STDAPI CallIMonikerGetDisplayNameA(
+ LPMONIKER lpmk,
+ IBindCtx *pbc,
+ IMoniker *pmkToLeft,
+ LPSTR *ppszDisplayName)
+{
+ LPOLESTR polestr;
+
+ HRESULT hr = lpmk->lpVtbl->GetDisplayName(lpmk, pbc, NULL,
+ &polestr);
+
+ CopyAndFreeOLESTR(polestr, ppszDisplayName);
+
+ return hr;
+}
+
+
+
+STDAPI CallIOleInPlaceUIWindowSetActiveObjectA(
+ IOleInPlaceUIWindow FAR *lpthis,
+ IOleInPlaceActiveObject *pActiveObject,
+ LPCSTR pszObjName)
+{
+ CREATEOLESTR(polestr, pszObjName)
+
+ HRESULT hr = lpthis->lpVtbl->SetActiveObject(lpthis, pActiveObject,
+ polestr);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI CallIOleInPlaceFrameSetStatusTextA(
+ IOleInPlaceFrame *poleinplc,
+ LPCSTR pszStatusText)
+{
+ CREATEOLESTR(polestr, pszStatusText)
+
+ HRESULT hr = poleinplc->lpVtbl->SetStatusText(poleinplc, polestr);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+
+STDAPI CallIOleLinkGetSourceDisplayNameA(
+ IOleLink FAR *polelink,
+ LPSTR *ppszDisplayName)
+{
+ LPOLESTR polestr;
+
+ HRESULT hr = polelink->lpVtbl->GetSourceDisplayName(polelink, &polestr);
+
+ CopyAndFreeOLESTR(polestr, ppszDisplayName);
+
+ return hr;
+}
+
+
+
+STDAPI CallIOleLinkSetSourceDisplayNameA(
+ IOleLink FAR *polelink,
+ LPCSTR pszStatusText)
+{
+ CREATEOLESTR(polestr, pszStatusText)
+
+ HRESULT hr = polelink->lpVtbl->SetSourceDisplayName(polelink, polestr);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+
+
+STDAPI CallIOleObjectGetUserTypeA(
+ LPOLEOBJECT lpOleObject,
+ DWORD dwFormOfType,
+ LPSTR *ppszUserType)
+{
+ LPOLESTR polestr;
+
+ HRESULT hr = lpOleObject->lpVtbl->GetUserType(lpOleObject,
+ dwFormOfType, &polestr);
+
+ CopyAndFreeOLESTR(polestr, ppszUserType);
+
+ return hr;
+}
+
+
+
+STDAPI CallIOleObjectSetHostNamesA(
+ LPOLEOBJECT lpOleObject,
+ LPCSTR szContainerApp,
+ LPCSTR szContainerObj)
+{
+ CREATEOLESTR(polestrApp, szContainerApp)
+ CREATEOLESTR(polestrObj, szContainerObj)
+
+ HRESULT hr = lpOleObject->lpVtbl->SetHostNames(lpOleObject, polestrApp,
+ polestrObj);
+
+ FREEOLESTR(polestrApp)
+ FREEOLESTR(polestrObj)
+
+ return hr;
+}
+
+STDAPI CallIStorageDestroyElementA(
+ LPSTORAGE lpStg,
+ LPSTR pszName)
+{
+ CREATEOLESTR(polestr, pszName)
+
+ HRESULT hr = lpStg->lpVtbl->DestroyElement(lpStg, polestr);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI CallIStorageCreateStorageA(
+ LPSTORAGE lpStg,
+ const char *pszName,
+ DWORD grfMode,
+ DWORD dwStgFmt,
+ DWORD reserved2,
+ IStorage **ppstg)
+{
+ CREATEOLESTR(polestr, pszName)
+
+ HRESULT hr = lpStg->lpVtbl->CreateStorage(lpStg, polestr, grfMode,
+ dwStgFmt, reserved2, ppstg);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+
+STDAPI CallIStorageOpenStorageA(
+ LPSTORAGE lpStg,
+ const char *pszName,
+ IStorage *pstgPriority,
+ DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ IStorage **ppstg)
+{
+ CREATEOLESTR(polestr, pszName)
+
+ HRESULT hr = lpStg->lpVtbl->OpenStorage(lpStg, polestr, pstgPriority,
+ grfMode, snbExclude, reserved, ppstg);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+
+STDAPI CallIStorageCreateStreamA(
+ LPSTORAGE lpStg,
+ LPSTR pszName,
+ DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ IStream **ppstm)
+{
+ CREATEOLESTR(polestr, pszName)
+
+ HRESULT hr = lpStg->lpVtbl->CreateStream(lpStg, polestr,
+ grfMode, reserved1, reserved2, ppstm);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
+
+STDAPI CallIStorageOpenStreamA(
+ LPSTORAGE lpStg,
+ LPSTR pszName,
+ void *reserved1,
+ DWORD grfMode,
+ DWORD reserved2,
+ IStream **ppstm)
+{
+ CREATEOLESTR(polestr, pszName)
+
+ HRESULT hr = lpStg->lpVtbl->OpenStream(lpStg, polestr, reserved1,
+ grfMode, reserved2, ppstm);
+
+ FREEOLESTR(polestr)
+
+ return hr;
+}
diff --git a/private/oleutest/letest/ole2ui/olethunk.h b/private/oleutest/letest/ole2ui/olethunk.h
new file mode 100644
index 000000000..ed47a62da
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/olethunk.h
@@ -0,0 +1,193 @@
+#ifndef _OLETHUNK_H_
+#define _OLETHUNK_H_
+
+//
+// String Conversion Helpers
+//
+STDAPI_(void) CopyAndFreeOLESTR(LPOLESTR polestr, char **pszOut);
+
+STDAPI_(void) CopyAndFreeSTR(LPSTR polestr, LPOLESTR *pszOut);
+
+STDAPI_(LPOLESTR) CreateOLESTR(const char *pszIn);
+
+STDAPI_(LPSTR) CreateSTR(LPCOLESTR pszIn);
+
+#define CREATEOLESTR(x, y) LPOLESTR x = CreateOLESTR(y);
+
+#define CREATESTR(x, y) LPSTR x = CreateSTR(y);
+
+#define FREEOLESTR(x) CopyAndFreeOLESTR(x, NULL);
+
+#define FREESTR(x) CopyAndFreeSTR(x, NULL);
+
+//
+// OLE API Thunks
+//
+STDAPI_(void) CLSIDFromStringA(LPSTR pszClass, LPCLSID pclsid);
+
+STDAPI CLSIDFromProgIDA(LPCSTR lpszProgID, LPCLSID lpclsid);
+
+STDAPI CreateFileMonikerA(LPSTR lpszPathName, LPMONIKER FAR* ppmk);
+
+STDAPI CreateItemMonikerA(
+ LPSTR lpszDelim,
+ LPSTR lpszItem,
+ LPMONIKER FAR* ppmk);
+
+STDAPI GetClassFileA(LPCSTR szFilename, CLSID FAR* pclsid);
+
+STDAPI MkParseDisplayNameA(
+ LPBC pbc,
+ LPSTR szUserName,
+ ULONG FAR * pchEaten,
+ LPMONIKER FAR * ppmk);
+
+STDAPI OleCreateFromFileA(
+ REFCLSID rclsid,
+ LPCSTR lpszFileName,
+ REFIID riid,
+ DWORD renderopt,
+ LPFORMATETC lpFormatEtc,
+ LPOLECLIENTSITE pClientSite,
+ LPSTORAGE pStg,
+ LPVOID FAR* ppvObj);
+
+STDAPI OleCreateLinkToFileA(
+ LPCSTR lpszFileName,
+ REFIID riid,
+ DWORD renderopt,
+ LPFORMATETC lpFormatEtc,
+ LPOLECLIENTSITE pClientSite,
+ LPSTORAGE pStg,
+ LPVOID FAR* ppvObj);
+
+STDAPI_(HGLOBAL) OleGetIconOfClassA(
+ REFCLSID rclsid,
+ LPSTR lpszLabel,
+ BOOL fUseTypeAsLabel);
+
+STDAPI_(HGLOBAL) OleGetIconOfFileA(LPSTR lpszPath, BOOL fUseFileAsLabel);
+
+STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabelA(
+ HICON hIcon,
+ LPSTR lpszLabel,
+ LPSTR lpszSourceFile,
+ UINT iIconIndex);
+
+STDAPI OleRegGetUserTypeA(
+ REFCLSID clsid,
+ DWORD dwFormOfType,
+ LPSTR FAR* pszUserType);
+
+STDAPI ProgIDFromCLSIDA(REFCLSID clsid, LPSTR FAR* lplpszProgID);
+
+STDAPI ReadFmtUserTypeStgA(
+ LPSTORAGE pstg,
+ CLIPFORMAT FAR* pcf,
+ LPSTR FAR* lplpszUserType);
+
+STDAPI StgCreateDocfileA(
+ LPCSTR pwcsName,
+ DWORD grfMode,
+ DWORD reserved,
+ IStorage FAR * FAR *ppstgOpen);
+
+STDAPI StgOpenStorageA(
+ LPCSTR pwcsName,
+ IStorage FAR *pstgPriority,
+ DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ IStorage FAR * FAR *ppstgOpen);
+
+STDAPI StgSetTimesA(
+ LPSTR lpszName,
+ FILETIME const FAR* pctime,
+ FILETIME const FAR* patime,
+ FILETIME const FAR* pmtime);
+
+
+STDAPI_(void) StringFromCLSIDA(REFCLSID rclsid, LPSTR *lplpszCLSID);
+
+STDAPI WriteFmtUserTypeStgA(
+ LPSTORAGE pstg,
+ CLIPFORMAT cf,
+ LPSTR lpszUserType);
+
+
+
+//
+// Method Thunks
+//
+STDAPI CallIMonikerGetDisplayNameA(
+ LPMONIKER lpmk,
+ IBindCtx *pbc,
+ IMoniker *pmkToLeft,
+ LPSTR *ppszDisplayName);
+
+STDAPI CallIOleLinkGetSourceDisplayNameA(
+ IOleLink FAR *polelink,
+ LPSTR *ppszDisplayName);
+
+STDAPI CallIOleLinkSetSourceDisplayNameA(
+ IOleLink FAR *polelink,
+ LPCSTR pszStatusText);
+
+STDAPI CallIOleInPlaceFrameSetStatusTextA(
+ IOleInPlaceFrame *poleinplc,
+ LPCSTR pszStatusText);
+
+STDAPI CallIOleInPlaceUIWindowSetActiveObjectA(
+ IOleInPlaceUIWindow FAR *lpthis,
+ IOleInPlaceActiveObject *pActiveObject,
+ LPCSTR pszObjName);
+
+STDAPI CallIOleObjectGetUserTypeA(
+ LPOLEOBJECT lpOleObject,
+ DWORD dwFormOfType,
+ LPSTR *pszUserType);
+
+STDAPI CallIOleObjectSetHostNamesA(
+ LPOLEOBJECT lpOleObject,
+ LPCSTR szContainerApp,
+ LPCSTR szContainerObj);
+
+STDAPI CallIStorageCreateStorageA(
+ LPSTORAGE lpStg,
+ const char *pwcsName,
+ DWORD grfMode,
+ DWORD dwStgFmt,
+ DWORD reserved2,
+ IStorage **ppstg);
+
+STDAPI CallIStorageDestroyElementA(
+ LPSTORAGE lpStg,
+ LPSTR pszName);
+
+STDAPI CallIStorageOpenStorageA(
+ LPSTORAGE lpStg,
+ const char *pszName,
+ IStorage *pstgPriority,
+ DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ IStorage **ppstg);
+
+STDAPI CallIStorageCreateStreamA(
+ LPSTORAGE lpStg,
+ LPSTR pszName,
+ DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ IStream **ppstm);
+
+STDAPI CallIStorageOpenStreamA(
+ LPSTORAGE lpStg,
+ LPSTR pszName,
+ void *reserved1,
+ DWORD grfMode,
+ DWORD reserved2,
+ IStream **ppstm);
+
+
+#endif // _OLETHUNK_H_
diff --git a/private/oleutest/letest/ole2ui/oleutl.c b/private/oleutest/letest/ole2ui/oleutl.c
new file mode 100644
index 000000000..9c968cefd
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/oleutl.c
@@ -0,0 +1,660 @@
+/*
+ * OLEUTL.C
+ *
+ * Miscellaneous utility functions for OLE 2.0 Applications:
+ *
+ * Function Purpose
+ * -------------------------------------------------------------------
+ * SetDCToDrawInHimetricRect Sets up an HIMETRIC mapping mode in a DC.
+ * ResetOrigDC Performs the opposite of
+ * SetDCToDrawInHimetricRect
+ * XformWidthInPixelsToHimetric Converts an int width into HiMetric units
+ * XformWidthInHimetricToPixels Converts an int width from HiMetric units
+ * XformHeightInPixelsToHimetric Converts an int height into HiMetric units
+ * XformHeightInHimetricToPixels Converts an int height from HiMetric units
+ * XformRectInPixelsToHimetric Converts a rect into HiMetric units
+ * XformRectInHimetricToPixels Converts a rect from HiMetric units
+ * XformSizeInPixelsToHimetric Converts a SIZEL into HiMetric units
+ * XformSizeInHimetricToPixels Converts a SIZEL from HiMetric units
+ * AreRectsEqual Compares to Rect's
+ *
+ * ParseCmdLine Determines if -Embedding exists
+ * OpenOrCreateRootStorage Creates a root docfile for OLE storage
+ * CommitStorage Commits all changes in a docfile
+ * CreateChildStorage Creates child storage in another storage
+ * OpenChildStorage Opens child storage in another storage
+ *
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#define STRICT 1
+#include "ole2ui.h"
+#include <stdlib.h>
+#include <ctype.h>
+
+//Internal function to this module. No need for UNICODE in this function
+static LPSTR GetWord(LPSTR lpszSrc, LPSTR lpszDst);
+
+
+/*
+ * SetDCToAnisotropic
+ *
+ * Purpose:
+ * Setup the correspondence between the rect in device unit (Viewport) and
+ * the rect in logical unit (Window) so that the proper scaling of
+ * coordinate systems will be calculated. set up both the Viewport and
+ * the window as follows:
+ *
+ * 1) ------------------ ( 2
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * 3) ------------------ ( 4
+ *
+ * Origin = P3
+ * X extent = P2x - P3x
+ * Y extent = P2y - P3y
+ *
+ * Parameters:
+ * hDC HDC to affect
+ * lprcPhysical LPRECT containing the physical (device) extents of DC
+ * lprcLogical LPRECT containing the logical extents
+ * lprcWindowOld LPRECT in which to preserve the window for ResetOrigDC
+ * lprcViewportOld LPRECT in which to preserver the viewport for ResetOrigDC
+ *
+ * Return Value:
+ * int The original mapping mode of the DC.
+ */
+
+STDAPI_(int) SetDCToAnisotropic(
+ HDC hDC,
+ LPRECT lprcPhysical, LPRECT lprcLogical,
+ LPRECT lprcWindowOld, LPRECT lprcViewportOld)
+{
+ int nMapModeOld=SetMapMode(hDC, MM_ANISOTROPIC);
+
+ SetWindowOrgEx(hDC, lprcLogical->left, lprcLogical->bottom, (LPPOINT)&lprcWindowOld->left);
+ SetWindowExtEx(hDC, (lprcLogical->right-lprcLogical->left), (lprcLogical->top-lprcLogical->bottom), (LPSIZE)&lprcWindowOld->right);
+ SetViewportOrgEx(hDC, lprcPhysical->left, lprcPhysical->bottom, (LPPOINT)&lprcViewportOld->left);
+ SetViewportExtEx(hDC, (lprcPhysical->right-lprcPhysical->left), (lprcPhysical->top-lprcPhysical->bottom), (LPSIZE)&lprcViewportOld->right);
+
+ return nMapModeOld;
+}
+
+
+/*
+ * SetDCToDrawInHimetricRect
+ *
+ * Purpose:
+ * Setup the correspondence between the rect in pixels (Viewport) and
+ * the rect in HIMETRIC (Window) so that the proper scaling of
+ * coordinate systems will be calculated. set up both the Viewport and
+ * the window as follows:
+ *
+ * 1) ------------------ ( 2
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * 3) ------------------ ( 4
+ *
+ * Origin = P3
+ * X extent = P2x - P3x
+ * Y extent = P2y - P3y
+ *
+ * Parameters:
+ * hDC HDC to affect
+ * lprcPix LPRECT containing the pixel extents of DC
+ * lprcHiMetric LPRECT to receive the himetric extents
+ * lprcWindowOld LPRECT in which to preserve the window for ResetOrigDC
+ * lprcViewportOld LPRECT in which to preserver the viewport for ResetOrigDC
+ *
+ * Return Value:
+ * int The original mapping mode of the DC.
+ */
+STDAPI_(int) SetDCToDrawInHimetricRect(
+ HDC hDC,
+ LPRECT lprcPix, LPRECT lprcHiMetric,
+ LPRECT lprcWindowOld, LPRECT lprcViewportOld)
+ {
+ int nMapModeOld=SetMapMode(hDC, MM_ANISOTROPIC);
+ BOOL fSystemDC =FALSE;
+
+ if (NULL==hDC)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ XformRectInPixelsToHimetric(hDC, lprcPix, lprcHiMetric);
+
+ SetWindowOrgEx(hDC, lprcHiMetric->left, lprcHiMetric->bottom, (LPPOINT)&lprcWindowOld->left);
+ SetWindowExtEx(hDC, (lprcHiMetric->right-lprcHiMetric->left), (lprcHiMetric->top-lprcHiMetric->bottom), (LPSIZE)&lprcWindowOld->right);
+ SetViewportOrgEx(hDC, lprcPix->left, lprcPix->bottom, (LPPOINT)&lprcViewportOld->left);
+ SetViewportExtEx(hDC, (lprcPix->right-lprcPix->left), (lprcPix->top-lprcPix->bottom), (LPSIZE)&lprcViewportOld->right);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return nMapModeOld;
+ }
+
+
+
+/*
+ * ResetOrigDC
+ *
+ * Purpose:
+ * Restores a DC set to draw in himetric from SetDCToDrawInHimetricRect.
+ *
+ * Parameters:
+ * hDC HDC to restore
+ * nMapModeOld int original mapping mode of hDC
+ * lprcWindowOld LPRECT filled in SetDCToDrawInHimetricRect
+ * lprcViewportOld LPRECT filled in SetDCToDrawInHimetricRect
+ *
+ * Return Value:
+ * int Same as nMapModeOld.
+ */
+
+STDAPI_(int) ResetOrigDC(
+ HDC hDC, int nMapModeOld,
+ LPRECT lprcWindowOld, LPRECT lprcViewportOld)
+ {
+ POINT pOld;
+
+ SetMapMode(hDC, nMapModeOld);
+
+ SetWindowOrgEx(hDC, lprcWindowOld->left, lprcWindowOld->top, (LPPOINT)&pOld);
+ SetWindowExtEx(hDC, lprcWindowOld->right, lprcWindowOld->bottom, (LPSIZE)&pOld);
+ SetViewportOrgEx(hDC, lprcViewportOld->left, lprcViewportOld->top, (LPPOINT)&pOld);
+ SetViewportExtEx(hDC, lprcViewportOld->right, lprcViewportOld->bottom, (LPSIZE)&pOld);
+
+ return nMapModeOld;
+ }
+
+
+
+/*
+ * XformWidthInPixelsToHimetric
+ * XformWidthInHimetricToPixels
+ * XformHeightInPixelsToHimetric
+ * XformHeightInHimetricToPixels
+ *
+ * Functions to convert an int between a device coordinate system and
+ * logical HiMetric units.
+ *
+ * Parameters:
+ * hDC HDC providing reference to the pixel mapping. If
+ * NULL, a screen DC is used.
+ *
+ * Size Functions:
+ * lpSizeSrc LPSIZEL providing the structure to convert. This
+ * contains pixels in XformSizeInPixelsToHimetric and
+ * logical HiMetric units in the complement function.
+ * lpSizeDst LPSIZEL providing the structure to receive converted
+ * units. This contains pixels in
+ * XformSizeInPixelsToHimetric and logical HiMetric
+ * units in the complement function.
+ *
+ * Width Functions:
+ * iWidth int containing the value to convert.
+ *
+ * Return Value:
+ * Size Functions: None
+ * Width Functions: Converted value of the input parameters.
+ *
+ * NOTE:
+ * When displaying on the screen, Window apps display everything enlarged
+ * from its actual size so that it is easier to read. For example, if an
+ * app wants to display a 1in. horizontal line, that when printed is
+ * actually a 1in. line on the printed page, then it will display the line
+ * on the screen physically larger than 1in. This is described as a line
+ * that is "logically" 1in. along the display width. Windows maintains as
+ * part of the device-specific information about a given display device:
+ * LOGPIXELSX -- no. of pixels per logical in along the display width
+ * LOGPIXELSY -- no. of pixels per logical in along the display height
+ *
+ * The following formula converts a distance in pixels into its equivalent
+ * logical HIMETRIC units:
+ *
+ * DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)
+ * -------------------------------
+ * PIXELS_PER_LOGICAL_IN
+ *
+ */
+STDAPI_(int) XformWidthInPixelsToHimetric(HDC hDC, int iWidthInPix)
+ {
+ int iXppli; //Pixels per logical inch along width
+ int iWidthInHiMetric;
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+
+ //We got pixel units, convert them to logical HIMETRIC along the display
+ iWidthInHiMetric = MAP_PIX_TO_LOGHIM(iWidthInPix, iXppli);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return iWidthInHiMetric;
+ }
+
+
+STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric)
+ {
+ int iXppli; //Pixels per logical inch along width
+ int iWidthInPix;
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+
+ //We got logical HIMETRIC along the display, convert them to pixel units
+ iWidthInPix = MAP_LOGHIM_TO_PIX(iWidthInHiMetric, iXppli);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return iWidthInPix;
+ }
+
+
+STDAPI_(int) XformHeightInPixelsToHimetric(HDC hDC, int iHeightInPix)
+ {
+ int iYppli; //Pixels per logical inch along height
+ int iHeightInHiMetric;
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+
+ //* We got pixel units, convert them to logical HIMETRIC along the display
+ iHeightInHiMetric = MAP_PIX_TO_LOGHIM(iHeightInPix, iYppli);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return iHeightInHiMetric;
+ }
+
+
+STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric)
+ {
+ int iYppli; //Pixels per logical inch along height
+ int iHeightInPix;
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+
+ //* We got logical HIMETRIC along the display, convert them to pixel units
+ iHeightInPix = MAP_LOGHIM_TO_PIX(iHeightInHiMetric, iYppli);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return iHeightInPix;
+ }
+
+
+
+/*
+ * XformRectInPixelsToHimetric
+ * XformRectInHimetricToPixels
+ *
+ * Purpose:
+ * Convert a rectangle between pixels of a given hDC and HIMETRIC units
+ * as manipulated in OLE. If the hDC is NULL, then a screen DC is used
+ * and assumes the MM_TEXT mapping mode.
+ *
+ * Parameters:
+ * hDC HDC providing reference to the pixel mapping. If
+ * NULL, a screen DC is used.
+ * lprcSrc LPRECT providing the rectangle to convert. This
+ * contains pixels in XformRectInPixelsToHimetric and
+ * logical HiMetric units in the complement function.
+ * lprcDst LPRECT providing the rectangle to receive converted units.
+ * This contains pixels in XformRectInPixelsToHimetric and
+ * logical HiMetric units in the complement function.
+ *
+ * Return Value:
+ * None
+ *
+ * NOTE:
+ * When displaying on the screen, Window apps display everything enlarged
+ * from its actual size so that it is easier to read. For example, if an
+ * app wants to display a 1in. horizontal line, that when printed is
+ * actually a 1in. line on the printed page, then it will display the line
+ * on the screen physically larger than 1in. This is described as a line
+ * that is "logically" 1in. along the display width. Windows maintains as
+ * part of the device-specific information about a given display device:
+ * LOGPIXELSX -- no. of pixels per logical in along the display width
+ * LOGPIXELSY -- no. of pixels per logical in along the display height
+ *
+ * The following formula converts a distance in pixels into its equivalent
+ * logical HIMETRIC units:
+ *
+ * DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)
+ * -------------------------------
+ * PIXELS_PER_LOGICAL_IN
+ *
+ * Rect in Pixels (MM_TEXT):
+ *
+ * 0---------- X
+ * |
+ * | 1) ------------------ ( 2 P1 = (rc.left, rc.top)
+ * | | | P2 = (rc.right, rc.top)
+ * | | | P3 = (rc.left, rc.bottom)
+ * | | | P4 = (rc.right, rc.bottom)
+ * | |
+ * Y | |
+ * 3) ------------------ ( 4
+ *
+ * NOTE: Origin = (P1x, P1y)
+ * X extent = P4x - P1x
+ * Y extent = P4y - P1y
+ *
+ *
+ * Rect in Himetric (MM_HIMETRIC):
+ *
+ *
+ * 1) ------------------ ( 2 P1 = (rc.left, rc.top)
+ * Y | | P2 = (rc.right, rc.top)
+ * | | P3 = (rc.left, rc.bottom)
+ * | | | P4 = (rc.right, rc.bottom)
+ * | | |
+ * | | |
+ * | 3) ------------------ ( 4
+ * |
+ * 0---------- X
+ *
+ * NOTE: Origin = (P3x, P3y)
+ * X extent = P2x - P3x
+ * Y extent = P2y - P3y
+ *
+ *
+ */
+
+STDAPI_(void) XformRectInPixelsToHimetric(
+ HDC hDC, LPRECT lprcPix, LPRECT lprcHiMetric)
+ {
+ int iXppli; //Pixels per logical inch along width
+ int iYppli; //Pixels per logical inch along height
+ int iXextInPix=(lprcPix->right-lprcPix->left);
+ int iYextInPix=(lprcPix->bottom-lprcPix->top);
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC || GetDeviceCaps(hDC, LOGPIXELSX) == 0)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+ iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+
+ //We got pixel units, convert them to logical HIMETRIC along the display
+ lprcHiMetric->right = MAP_PIX_TO_LOGHIM(iXextInPix, iXppli);
+ lprcHiMetric->top = MAP_PIX_TO_LOGHIM(iYextInPix, iYppli);
+
+ lprcHiMetric->left = 0;
+ lprcHiMetric->bottom = 0;
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return;
+ }
+
+
+
+STDAPI_(void) XformRectInHimetricToPixels(
+ HDC hDC, LPRECT lprcHiMetric, LPRECT lprcPix)
+ {
+ int iXppli; //Pixels per logical inch along width
+ int iYppli; //Pixels per logical inch along height
+ int iXextInHiMetric=(lprcHiMetric->right-lprcHiMetric->left);
+ int iYextInHiMetric=(lprcHiMetric->bottom-lprcHiMetric->top);
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC || GetDeviceCaps(hDC, LOGPIXELSX) == 0)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+ iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+
+ //We got pixel units, convert them to logical HIMETRIC along the display
+ lprcPix->right = MAP_LOGHIM_TO_PIX(iXextInHiMetric, iXppli);
+ lprcPix->top = MAP_LOGHIM_TO_PIX(iYextInHiMetric, iYppli);
+
+ lprcPix->left = 0;
+ lprcPix->bottom= 0;
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return;
+ }
+
+
+
+
+/*
+ * XformSizeInPixelsToHimetric
+ * XformSizeInHimetricToPixels
+ *
+ * Functions to convert a SIZEL structure (Size functions) or
+ * an int (Width functions) between a device coordinate system and
+ * logical HiMetric units.
+ *
+ * Parameters:
+ * hDC HDC providing reference to the pixel mapping. If
+ * NULL, a screen DC is used.
+ *
+ * Size Functions:
+ * lpSizeSrc LPSIZEL providing the structure to convert. This
+ * contains pixels in XformSizeInPixelsToHimetric and
+ * logical HiMetric units in the complement function.
+ * lpSizeDst LPSIZEL providing the structure to receive converted
+ * units. This contains pixels in
+ * XformSizeInPixelsToHimetric and logical HiMetric
+ * units in the complement function.
+ *
+ * Width Functions:
+ * iWidth int containing the value to convert.
+ *
+ * Return Value:
+ * Size Functions: None
+ * Width Functions: Converted value of the input parameters.
+ *
+ * NOTE:
+ * When displaying on the screen, Window apps display everything enlarged
+ * from its actual size so that it is easier to read. For example, if an
+ * app wants to display a 1in. horizontal line, that when printed is
+ * actually a 1in. line on the printed page, then it will display the line
+ * on the screen physically larger than 1in. This is described as a line
+ * that is "logically" 1in. along the display width. Windows maintains as
+ * part of the device-specific information about a given display device:
+ * LOGPIXELSX -- no. of pixels per logical in along the display width
+ * LOGPIXELSY -- no. of pixels per logical in along the display height
+ *
+ * The following formula converts a distance in pixels into its equivalent
+ * logical HIMETRIC units:
+ *
+ * DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)
+ * -------------------------------
+ * PIXELS_PER_LOGICAL_IN
+ *
+ */
+
+STDAPI_(void) XformSizeInPixelsToHimetric(
+ HDC hDC, LPSIZEL lpSizeInPix, LPSIZEL lpSizeInHiMetric)
+ {
+ int iXppli; //Pixels per logical inch along width
+ int iYppli; //Pixels per logical inch along height
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC || GetDeviceCaps(hDC, LOGPIXELSX) == 0)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+ iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+
+ //We got pixel units, convert them to logical HIMETRIC along the display
+ lpSizeInHiMetric->cx = (long)MAP_PIX_TO_LOGHIM((int)lpSizeInPix->cx, iXppli);
+ lpSizeInHiMetric->cy = (long)MAP_PIX_TO_LOGHIM((int)lpSizeInPix->cy, iYppli);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return;
+ }
+
+
+STDAPI_(void) XformSizeInHimetricToPixels(
+ HDC hDC, LPSIZEL lpSizeInHiMetric, LPSIZEL lpSizeInPix)
+ {
+ int iXppli; //Pixels per logical inch along width
+ int iYppli; //Pixels per logical inch along height
+ BOOL fSystemDC=FALSE;
+
+ if (NULL==hDC || GetDeviceCaps(hDC, LOGPIXELSX) == 0)
+ {
+ hDC=GetDC(NULL);
+ fSystemDC=TRUE;
+ }
+
+ iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+ iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+
+ //We got logical HIMETRIC along the display, convert them to pixel units
+ lpSizeInPix->cx = (long)MAP_LOGHIM_TO_PIX((int)lpSizeInHiMetric->cx, iXppli);
+ lpSizeInPix->cy = (long)MAP_LOGHIM_TO_PIX((int)lpSizeInHiMetric->cy, iYppli);
+
+ if (fSystemDC)
+ ReleaseDC(NULL, hDC);
+
+ return;
+ }
+
+
+#if defined( OBSOLETE )
+// This function has been converted to a macro
+
+/* AreRectsEqual
+** -------------
+*/
+STDAPI_(BOOL) AreRectsEqual(LPRECT lprc1, LPRECT lprc2)
+{
+ if ((lprc1->top == lprc2->top) &&
+ (lprc1->left == lprc2->left) &&
+ (lprc1->right == lprc2->right) &&
+ (lprc1->bottom == lprc2->bottom))
+ return TRUE;
+
+ return FALSE;
+}
+#endif // OBSOLETE
+
+
+/*
+ * ParseCmdLine
+ *
+ * Parses the Windows command line which was passed to WinMain.
+ * This function determines if the -Embedding switch has been given.
+ *
+ */
+
+STDAPI_(void) ParseCmdLine(
+ LPSTR lpszLine,
+ BOOL FAR* lpfEmbedFlag,
+ LPSTR szFileName)
+{
+ int i=0;
+ CHAR szBuf[256];
+
+ if(lpfEmbedFlag)
+ *lpfEmbedFlag = FALSE;
+ szFileName[0]='\0'; // NULL string
+
+ // skip blanks
+ while(isspace(*lpszLine)) lpszLine++;
+
+ if(!*lpszLine) // No filename or options, so start a fresh document.
+ return;
+
+ // Check for "-Embedding" or "/Embedding" and set fEmbedding.
+ if(lpfEmbedFlag && (*lpszLine == '-' || *lpszLine == '/')) {
+ lpszLine++;
+ lpszLine = GetWord(lpszLine, szBuf);
+ *lpfEmbedFlag = (BOOL) !strcmp(szBuf, EMBEDDINGFLAG);
+ }
+
+ // skip blanks
+ while(isspace(*lpszLine)) lpszLine++;
+
+ // set szFileName to argument
+ while(lpszLine[i]) {
+ szFileName[i]=lpszLine[i];
+ i++;
+ }
+ szFileName[i]='\0';
+}
+
+
+/* GetWord
+ * -------
+ *
+ * LPSTR lpszSrc - Pointer to a source string
+ * LPSTR lpszDst - Pointer to destination buffer
+ *
+ * Will copy one space-terminated or null-terminated word from the source
+ * string to the destination buffer.
+ * returns: pointer to next character following the word.
+ */
+static LPSTR GetWord(LPSTR lpszSrc, LPSTR lpszDst)
+{
+ while (*lpszSrc && !isspace(*lpszSrc))
+ *lpszDst++ = *lpszSrc++;
+
+ *lpszDst = '\0';
+ return lpszSrc;
+}
+
+
+
+
+
diff --git a/private/oleutest/letest/ole2ui/outlui.d32 b/private/oleutest/letest/ole2ui/outlui.d32
new file mode 100644
index 000000000..502d0b598
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/outlui.d32
@@ -0,0 +1,138 @@
+;;
+;; ole2ui.def
+;;
+;; Definition file for ole2ui.dll
+;;
+;; (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
+;;
+;;
+
+CODE MOVEABLE DISCARDABLE
+DATA MOVEABLE SINGLE
+
+HEAPSIZE 16392
+
+EXPORTS WEP @1 RESIDENTNAME
+;;
+;; NOTE: DO NOT PLACE ANY EXPORTS HERE -- USE THE
+;; __export KEYWORD INSTEAD.
+
+SetDCToAnisotropic
+SetDCToDrawInHimetricRect
+ResetOrigDC
+XformRectInPixelsToHimetric
+XformRectInHimetricToPixels
+XformSizeInPixelsToHimetric
+XformSizeInHimetricToPixels
+XformWidthInHimetricToPixels
+XformWidthInPixelsToHimetric
+XformHeightInHimetricToPixels
+XformHeightInPixelsToHimetric
+AreRectsEqual
+ParseCmdLine
+OleStdIsOleLink
+OleStdQueryInterface
+OleStdCreateRootStorage
+OleStdOpenRootStorage
+OleStdOpenOrCreateRootStorage
+OleStdCreateChildStorage
+OleStdOpenChildStorage
+OleStdCommitStorage
+OleStdCreateStorageOnHGlobal
+OleStdCreateTempStorage
+OleStdDoConvert
+OleStdGetTreatAsFmtUserType
+OleStdDoTreatAsClass
+OleStdSetupAdvises
+OleStdSwitchDisplayAspect
+OleStdSetIconInCache
+OleStdGetData
+OleStdMarkPasteEntryList
+OleStdGetPriorityClipboardFormat
+OleStdIsDuplicateFormat
+OleStdRegisterAsRunning
+OleStdRevokeAsRunning
+OleStdNoteFileChangeTime
+OleStdNoteObjectChangeTime
+OleStdGetOleObjectData
+OleStdGetLinkSourceData
+OleStdGetObjectDescriptorData
+OleStdGetObjectDescriptorDataFromOleObject
+OleStdFillObjectDescriptorFromData
+OleStdCopyMetafilePict
+OleStdGetMetafilePictFromOleObject
+OleStdQueryOleObjectData
+OleStdQueryLinkSourceData
+OleStdQueryObjectDescriptorData
+OleStdQueryFormatMedium
+OleStdGetDropEffect
+OleStdCreateTempFileMoniker
+OleStdGetFirstMoniker
+OleStdGetLenFilePrefixOfMoniker
+OleStdMalloc
+OleStdRealloc
+OleStdFree
+OleStdGetSize
+OleStdFreeString
+OleStdCopyString
+OleStdGetItemToken
+OleStdInitVtbl
+OleStdCheckVtbl
+OleStdVerifyRelease
+OleStdRelease
+OleStdCreateDC
+OleStdCreateIC
+OleStdCreateTargetDevice
+OleStdDeleteTargetDevice
+OleStdCopyTargetDevice
+OleStdCopyFormatEtc
+OleDbgPrint
+OleDbgPrintAlways
+OleDbgSetDbgLevel
+OleDbgGetDbgLevel
+OleDbgIndent
+OleDbgPrintRefCnt
+OleDbgPrintRefCntAlways
+OleDbgPrintRect
+OleDbgPrintRectAlways
+OleDbgPrintScodeAlways
+OleUIInitialize
+OleUIUnInitialize
+OleUIAddVerbMenu
+OleUIMetafilePictFromIconAndLabel
+OleUIMetafilePictIconFree
+OleUIMetafilePictIconDraw
+OleUIMetafilePictExtractLabel
+OleUIMetafilePictExtractIcon
+OleUIMetafilePictExtractIconSource
+OleUIInsertObject
+OleUIPasteSpecial
+OleUIEditLinks
+OleUIChangeIcon
+OleUIConvert
+OleUIBusy
+OleUIUpdateLinks
+OleUIDrawHandles
+OleUIDrawShading
+OleUIShowObject
+RegisterHatchWindowClass
+CreateHatchWindow
+GetHatchWidth
+GetHatchRect
+SetHatchRect
+SetHatchWindowSize
+OleUIPromptUser
+OleStdEnumFmtEtc_Create
+GetIconOfFile
+GetIconOfClass
+OleStdGetAuxUserType
+OleStdGetUserTypeOfClass
+OleStdIconLabelTextOut
+OleStdMsgFilter_Create
+OleStdMsgFilter_SetInComingCallStatus
+OleStdMsgFilter_GetInComingCallStatus
+OleStdMsgFilter_EnableBusyDialog
+OleStdMsgFilter_EnableNotRespondingDialog
+OleStdMsgFilter_SetParentWindow
+OleStdGetMiscStatusOfClass
+OleStdGetDefaultFileFormatOfClass
diff --git a/private/oleutest/letest/ole2ui/pastespl.c b/private/oleutest/letest/ole2ui/pastespl.c
new file mode 100644
index 000000000..0cf086cf1
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/pastespl.c
@@ -0,0 +1,1713 @@
+/*
+ * PASTESPL.C
+ *
+ * Implements the OleUIPasteSpecial function which invokes the complete
+ * Paste Special dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Rights Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "pastespl.h"
+#include "common.h"
+#include "utility.h"
+#include "resimage.h"
+#include "iconbox.h"
+#include "geticon.h"
+#include "icon.h"
+#include "regdb.h"
+#include <stdlib.h>
+
+OLEDBGDATA
+
+/*
+ * OleUIPasteSpecial
+ *
+ * Purpose:
+ * Invokes the standard OLE Paste Special dialog box which allows the user
+ * to select the format of the clipboard object to be pasted or paste linked.
+ *
+ * Parameters:
+ * lpPS LPOLEUIPasteSpecial pointing to the in-out structure
+ * for this dialog.
+ *
+ * Return Value:
+ * UINT One of the following codes or one of the standard error codes (OLEUI_ERR_*)
+ * defined in OLE2UI.H, indicating success or error:
+ * OLEUI_OK User selected OK
+ * OLEUI_CANCEL User cancelled the dialog
+ * OLEUI_IOERR_SRCDATAOBJECTINVALID lpSrcDataObject field of OLEUIPASTESPECIAL invalid
+ * OLEUI_IOERR_ARRPASTEENTRIESINVALID arrPasteEntries field of OLEUIPASTESPECIAL invalid
+ * OLEUI_IOERR_ARRLINKTYPESINVALID arrLinkTypes field of OLEUIPASTESPECIAL invalid
+ * OLEUI_PSERR_CLIPBOARDCHANGED Clipboard contents changed while dialog was up
+ */
+
+STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL lpPS)
+{
+ UINT uRet;
+ HGLOBAL hMemDlg=NULL;
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lpPS, sizeof(OLEUIPASTESPECIAL)
+ , &hMemDlg);
+
+ if (uRet != OLEUI_SUCCESS)
+ return uRet;
+
+ //Validate PasteSpecial specific fields
+ if (NULL == lpPS->lpSrcDataObj || IsBadReadPtr(lpPS->lpSrcDataObj, sizeof(IDataObject)))
+ uRet = OLEUI_IOERR_SRCDATAOBJECTINVALID;
+ if (NULL == lpPS->arrPasteEntries || IsBadReadPtr(lpPS->arrPasteEntries, sizeof(OLEUIPASTEENTRY)))
+ uRet = OLEUI_IOERR_ARRPASTEENTRIESINVALID;
+ if (NULL != lpPS->arrLinkTypes && IsBadReadPtr(lpPS->arrLinkTypes, sizeof(UINT)))
+ uRet = OLEUI_IOERR_ARRLINKTYPESINVALID;
+
+ if (0!=lpPS->cClsidExclude)
+ {
+ if (NULL!=lpPS->lpClsidExclude && IsBadReadPtr(lpPS->lpClsidExclude
+ , lpPS->cClsidExclude*sizeof(CLSID)))
+ uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;
+ }
+
+ if (uRet >= OLEUI_ERR_STANDARDMIN)
+ {
+ if (NULL != hMemDlg)
+ FreeResource(hMemDlg);
+ return uRet;
+ }
+
+ //Now that we've validated everything, we can invoke the dialog.
+ uRet = UStandardInvocation(PasteSpecialDialogProc, (LPOLEUISTANDARD)lpPS
+ , hMemDlg, MAKEINTRESOURCE(IDD_PASTESPECIAL));
+
+ /*
+ * IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.
+ */
+
+ return uRet;
+}
+
+
+/*
+ * PasteSpecialDialogProc
+ *
+ * Purpose:
+ * Implements the OLE Paste Special dialog as invoked through the
+ * OleUIPasteSpecial function.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+BOOL CALLBACK EXPORT PasteSpecialDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ LPOLEUIPASTESPECIAL lpOPS;
+ LPPASTESPECIAL lpPS;
+ BOOL fHook=FALSE;
+ HCURSOR hCursorOld;
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ lpPS=(LPPASTESPECIAL)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &fHook);
+
+ //If the hook processed the message, we're done.
+ if (0!=fHook)
+ return fHook;
+
+ // Process help message from Change Icon
+ if (iMsg == uMsgHelp)
+ {
+ PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp, wParam, lParam);
+ return FALSE;
+ }
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ HWND hwndNextViewer;
+
+ // Free the icon/icon-title metafile corresponding to Paste/PasteList option which is not selected
+ if (lpPS->fLink)
+ OleUIMetafilePictIconFree(lpPS->hMetaPictOD);
+ else OleUIMetafilePictIconFree(lpPS->hMetaPictLSD);
+
+ // Free data associated with each list box entry
+ FreeListData(GetDlgItem(hDlg, ID_PS_PASTELIST));
+ FreeListData(GetDlgItem(hDlg, ID_PS_PASTELINKLIST));
+
+ //Free any specific allocations before calling StandardCleanup
+ if (lpPS->hObjDesc) GlobalFree(lpPS->hObjDesc);
+ if (lpPS->hLinkSrcDesc) GlobalFree(lpPS->hLinkSrcDesc);
+ if (lpPS->hBuff) GlobalFree(lpPS->hBuff);
+
+ // Change the clipboard notification chain
+ hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
+ if (hwndNextViewer != HWND_BROADCAST)
+ {
+ SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);
+ ChangeClipboardChain(hDlg, hwndNextViewer);
+ }
+ RemoveProp(hDlg, NEXTCBVIEWER);
+
+ StandardCleanup(lpPS, hDlg);
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ switch (iMsg)
+ {
+ case WM_INITDIALOG:
+ hCursorOld = HourGlassOn();
+ FPasteSpecialInit(hDlg, wParam, lParam);
+ HourGlassOff(hCursorOld);
+ return FALSE;
+
+ case WM_DRAWCLIPBOARD:
+ {
+ HWND hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
+ HWND hDlg_ChgIcon;
+
+ if (hwndNextViewer == HWND_BROADCAST)
+ break;
+
+ if (hwndNextViewer)
+ {
+ SendMessage(hwndNextViewer, iMsg, wParam, lParam);
+ // Refresh next viewer in case it got modified
+ // by the SendMessage() (likely if multiple
+ // PasteSpecial dialogs are up simultaneously)
+ hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
+ }
+ SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);
+ ChangeClipboardChain(hDlg, hwndNextViewer);
+
+ /* OLE2NOTE: if the ChangeIcon dialog is currently up, then
+ ** we need to defer bringing down PasteSpecial dialog
+ ** until after ChangeIcon dialog returns. if the
+ ** ChangeIcon dialog is NOT up, then we can bring down
+ ** the PasteSpecial dialog immediately.
+ */
+ if ((hDlg_ChgIcon=(HWND)GetProp(hDlg,PROP_HWND_CHGICONDLG))!=NULL)
+ {
+ // ChangeIcon dialog is UP
+ lpPS->fClipboardChanged = TRUE;
+ } else {
+ // ChangeIcon dialog is NOT up
+
+ // Free icon and icon title metafile
+ SendDlgItemMessage(
+ hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L);
+
+ SendMessage(
+ hDlg, uMsgEndDialog, OLEUI_PSERR_CLIPBOARDCHANGED,0L);
+ }
+ break;
+ }
+
+ case WM_CHANGECBCHAIN:
+ {
+ HWND hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
+
+ if (wParam == (WORD)hwndNextViewer)
+ SetProp(hDlg, NEXTCBVIEWER, (hwndNextViewer = (HWND)LOWORD(lParam)));
+ else if (hwndNextViewer && hwndNextViewer != HWND_BROADCAST)
+ SendMessage(hwndNextViewer, iMsg, wParam, lParam);
+ break;
+ }
+
+ case WM_COMMAND:
+ switch (wID)
+ {
+ case ID_PS_PASTE:
+ FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE);
+ break;
+
+ case ID_PS_PASTELINK:
+ FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK);
+ break;
+
+ case ID_PS_DISPLAYLIST:
+ switch (wCode)
+ {
+ case LBN_SELCHANGE:
+ ChangeListSelection(hDlg, lpPS, hWndMsg);
+ break;
+
+ case LBN_DBLCLK:
+ // Same as pressing OK
+ SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
+ break;
+ }
+ break;
+
+ case ID_PS_DISPLAYASICON:
+ ToggleDisplayAsIcon(hDlg, lpPS);
+ break;
+
+ case ID_PS_CHANGEICON:
+ ChangeIcon(hDlg, lpPS);
+ if (lpPS->fClipboardChanged) {
+ // Free icon and icon title metafile
+ SendDlgItemMessage(
+ hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE,0,0L);
+ SendMessage(
+ hDlg, uMsgEndDialog,
+ OLEUI_PSERR_CLIPBOARDCHANGED, 0L);
+ }
+ break;
+
+ case IDOK:
+ {
+ BOOL fDestAspectIcon =
+ ((lpPS->dwFlags & PSF_CHECKDISPLAYASICON) ?
+ TRUE : FALSE);
+ lpOPS = lpPS->lpOPS;
+ // Return current flags
+ lpOPS->dwFlags = lpPS->dwFlags;
+ // Return index of arrPasteEntries[] corresponding to format selected by user
+ lpOPS->nSelectedIndex = lpPS->nSelectedIndex;
+ // Return if user selected Paste or PasteLink
+ lpOPS->fLink = lpPS->fLink;
+
+ /* if user selected same ASPECT as displayed in the
+ ** source, then sizel passed in the
+ ** ObjectDescriptor/LinkSrcDescriptor is
+ ** applicable. otherwise, the sizel does not apply.
+ */
+ if (lpPS->fLink) {
+ if (lpPS->fSrcAspectIconLSD == fDestAspectIcon)
+ lpOPS->sizel = lpPS->sizelLSD;
+ else
+ lpOPS->sizel.cx = lpOPS->sizel.cy = 0;
+ } else {
+ if (lpPS->fSrcAspectIconOD == fDestAspectIcon)
+ lpOPS->sizel = lpPS->sizelOD;
+ else
+ lpOPS->sizel.cx = lpOPS->sizel.cy = 0;
+ }
+ // Return metafile with icon and icon title that the user selected
+ lpOPS->hMetaPict=(HGLOBAL)SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY,
+ IBXM_IMAGEGET, 0, 0L);
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ break;
+ }
+ case IDCANCEL:
+ // Free icon and icon title metafile
+ SendDlgItemMessage(
+ hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L);
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ break;
+
+ case ID_OLEUIHELP:
+ PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp,
+ (WPARAM)hDlg, MAKELPARAM(IDD_PASTESPECIAL, 0));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+/*
+ * FPasteSpecialInit
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the Paste Special dialog box.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL FPasteSpecialInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
+{
+ LPPASTESPECIAL lpPS;
+ LPOLEUIPASTESPECIAL lpOPS;
+ HFONT hFont;
+ BOOL fPasteAvailable, fPasteLinkAvailable;
+ STGMEDIUM medium;
+ LPOBJECTDESCRIPTOR lpOD;
+ LPLINKSRCDESCRIPTOR lpLSD;
+ int n;
+ CLIPFORMAT cfFormat;
+
+ // Copy the structure at lParam into our instance memory.
+ lpPS = (LPPASTESPECIAL)LpvStandardInit(hDlg, sizeof(PASTESPECIAL), TRUE, &hFont);
+
+ // PvStandardInit sent a termination to us already.
+ if (NULL == lpPS)
+ return FALSE;
+
+ lpOPS=(LPOLEUIPASTESPECIAL)lParam;
+
+ // Copy other information from lpOPS that we might modify.
+ lpPS->lpOPS = lpOPS;
+ lpPS->dwFlags = lpOPS->dwFlags;
+
+ // Initialize user selections in the Paste and PasteLink listboxes
+ lpPS->nPasteListCurSel = 0;
+ lpPS->nPasteLinkListCurSel = 0;
+
+ // If we got a font, send it to the necessary controls.
+ if (NULL!=hFont)
+ {
+ SendDlgItemMessage(hDlg, ID_PS_SOURCETEXT, WM_SETFONT, (WPARAM)hFont, 0L);
+ SendDlgItemMessage(hDlg, ID_PS_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L);
+ }
+
+ // Hide the help button if required
+ if (!(lpPS->lpOPS->dwFlags & PSF_SHOWHELP))
+ StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
+
+ // Hide all DisplayAsIcon related controls if it should be disabled
+ if ( lpPS->dwFlags & PSF_DISABLEDISPLAYASICON ) {
+ StandardShowDlgItem(hDlg, ID_PS_DISPLAYASICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
+ }
+
+ // PSF_CHECKDISPLAYASICON is an OUT flag. Clear it if has been set on the way in.
+ lpPS->dwFlags = lpPS->dwFlags & ~PSF_CHECKDISPLAYASICON;
+
+ // Change the caption if required
+ if (NULL != lpOPS->lpszCaption)
+ SetWindowText(hDlg, lpOPS->lpszCaption);
+
+ // Load 'Unknown Source' and 'Unknown Type' strings
+ n = LoadString(ghInst, IDS_PSUNKNOWNTYPE, lpPS->szUnknownType, PS_UNKNOWNSTRLEN);
+ if (n)
+ n = LoadString(ghInst, IDS_PSUNKNOWNSRC, lpPS->szUnknownSource, PS_UNKNOWNSTRLEN);
+ if (!n)
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
+ return FALSE;
+ }
+ lpPS->szAppName[0]=TEXT('\0');
+
+ // GetData CF_OBJECTDESCRIPTOR. If the object on the clipboard in an OLE1 object (offering CF_OWNERLINK)
+ // or has been copied to clipboard by FileMaager (offering CF_FILENAME), an OBJECTDESCRIPTOR will be
+ // created will be created from CF_OWNERLINK or CF_FILENAME. See OBJECTDESCRIPTOR for more info.
+
+ if (lpPS->hObjDesc = OleStdFillObjectDescriptorFromData(lpOPS->lpSrcDataObj, &medium, &cfFormat))
+ {
+ lpOD = GlobalLock(lpPS->hObjDesc);
+
+ // Get FullUserTypeName, SourceOfCopy and CLSID
+ if (lpOD->dwFullUserTypeName)
+ lpPS->szFullUserTypeNameOD = (LPTSTR)lpOD+lpOD->dwFullUserTypeName;
+ else lpPS->szFullUserTypeNameOD = lpPS->szUnknownType;
+
+ if (lpOD->dwSrcOfCopy)
+ {
+ lpPS->szSourceOfDataOD = (LPTSTR)lpOD+lpOD->dwSrcOfCopy;
+ // If CF_FILENAME was offered, source of copy is a path name. Fit the path to the
+ // static control that will display it.
+ if (cfFormat == cfFileName)
+ lpPS->szSourceOfDataOD = ChopText(GetDlgItem(hDlg, ID_PS_SOURCETEXT), 0, lpPS->szSourceOfDataOD);
+ }
+ else lpPS->szSourceOfDataOD = lpPS->szUnknownSource;
+
+ lpPS->clsidOD = lpOD->clsid;
+ lpPS->sizelOD = lpOD->sizel;
+
+ // Does source specify DVASPECT_ICON?
+ if (lpOD->dwDrawAspect & DVASPECT_ICON)
+ lpPS->fSrcAspectIconOD = TRUE;
+ else lpPS->fSrcAspectIconOD = FALSE;
+
+ // Does source specify OLEMISC_ONLYICONIC?
+ if (lpOD->dwStatus & OLEMISC_ONLYICONIC)
+ lpPS->fSrcOnlyIconicOD = TRUE;
+ else lpPS->fSrcOnlyIconicOD = FALSE;
+
+ // Get application name of source from auxusertype3 in the registration database
+ if (0==OleStdGetAuxUserType(&lpPS->clsidOD, 3, lpPS->szAppName, OLEUI_CCHKEYMAX_SIZE, NULL))
+ {
+ // Use "the application which created it" as the name of the application
+ if (0==LoadString(ghInst, IDS_PSUNKNOWNAPP, lpPS->szAppName, PS_UNKNOWNSTRLEN))
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
+ return FALSE;
+ }
+ }
+
+ // Retrieve an icon from the object
+ if (lpPS->fSrcAspectIconOD)
+ {
+ lpPS->hMetaPictOD = OleStdGetData(
+ lpOPS->lpSrcDataObj,
+ (CLIPFORMAT) CF_METAFILEPICT,
+ NULL,
+ DVASPECT_ICON,
+ &medium
+ );
+
+ }
+ // If object does not offer icon, obtain it from the CLSID
+ if (NULL == lpPS->hMetaPictOD)
+ {
+#ifdef OLE201
+ lpPS->hMetaPictOD = GetIconOfClass(
+ ghInst,
+ &lpPS->clsidOD,
+ NULL,
+ TRUE); // Use the short user type name (auxusertype3)
+#endif
+ lpPS->hMetaPictOD = NULL;
+
+
+ }
+ }
+
+ // Does object offer CF_LINKSRCDESCRIPTOR?
+ if (lpPS->hLinkSrcDesc = OleStdGetData(
+ lpOPS->lpSrcDataObj,
+ (CLIPFORMAT) cfLinkSrcDescriptor,
+ NULL,
+ DVASPECT_CONTENT,
+ &medium))
+ {
+ // Get FullUserTypeName, SourceOfCopy and CLSID
+ lpLSD = GlobalLock(lpPS->hLinkSrcDesc);
+ if (lpLSD->dwFullUserTypeName)
+ lpPS->szFullUserTypeNameLSD = (LPTSTR)lpLSD+lpLSD->dwFullUserTypeName;
+ else lpPS->szFullUserTypeNameLSD = lpPS->szUnknownType;
+
+ if (lpLSD->dwSrcOfCopy)
+ lpPS->szSourceOfDataLSD = (LPTSTR)lpLSD+lpLSD->dwSrcOfCopy;
+ else lpPS->szSourceOfDataLSD = lpPS->szUnknownSource;
+
+ // if no ObjectDescriptor, then use LinkSourceDescriptor source string
+ if (!lpPS->hObjDesc)
+ lpPS->szSourceOfDataOD = lpPS->szSourceOfDataLSD;
+
+ lpPS->clsidLSD = lpLSD->clsid;
+ lpPS->sizelLSD = lpLSD->sizel;
+
+ // Does source specify DVASPECT_ICON?
+ if (lpLSD->dwDrawAspect & DVASPECT_ICON)
+ lpPS->fSrcAspectIconLSD = TRUE;
+ else lpPS->fSrcAspectIconLSD = FALSE;
+
+ // Does source specify OLEMISC_ONLYICONIC?
+ if (lpLSD->dwStatus & OLEMISC_ONLYICONIC)
+ lpPS->fSrcOnlyIconicLSD = TRUE;
+ else lpPS->fSrcOnlyIconicLSD = FALSE;
+
+ // Retrieve an icon from the object
+ if (lpPS->fSrcAspectIconLSD)
+ {
+ lpPS->hMetaPictLSD = OleStdGetData(
+ lpOPS->lpSrcDataObj,
+ CF_METAFILEPICT,
+ NULL,
+ DVASPECT_ICON,
+ &medium
+ );
+
+ }
+ // If object does not offer icon, obtain it from the CLSID
+ if (NULL == lpPS->hMetaPictLSD)
+ {
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ HWND hIconWnd;
+ RECT IconRect;
+ int nWidth;
+ LPTSTR lpszLabel;
+
+ hIconWnd = GetDlgItem(hDlg, ID_PS_ICONDISPLAY);
+
+ GetClientRect(hIconWnd, &IconRect);
+
+ nWidth = ((IconRect.right-IconRect.left) * 3) / 2; // width is 1.5 times width of iconbox
+
+ LSTRCPYN(szLabel, lpPS->szSourceOfDataLSD, OLEUI_CCHLABELMAX);
+ szLabel[OLEUI_CCHLABELMAX-1] = TEXT('\0');
+
+ lpszLabel = ChopText(hIconWnd, nWidth, (LPTSTR)szLabel);
+
+#ifdef OLE201
+ lpPS->hMetaPictLSD = GetIconOfClass(
+ ghInst,
+ &lpPS->clsidLSD,
+ lpszLabel, /* use chopped source string as label */
+ FALSE /* not applicable */
+ );
+#endif
+ lpPS->hMetaPictLSD = NULL;
+
+ }
+ }
+ else if (lpPS->hObjDesc) // Does not offer CF_LINKSRCDESCRIPTOR but offers CF_OBJECTDESCRIPTOR
+ {
+ // Copy the values of OBJECTDESCRIPTOR
+ lpPS->szFullUserTypeNameLSD = lpPS->szFullUserTypeNameOD;
+ lpPS->szSourceOfDataLSD = lpPS->szSourceOfDataOD;
+ lpPS->clsidLSD = lpPS->clsidOD;
+ lpPS->sizelLSD = lpPS->sizelOD;
+ lpPS->fSrcAspectIconLSD = lpPS->fSrcAspectIconOD;
+ lpPS->fSrcOnlyIconicLSD = lpPS->fSrcOnlyIconicOD;
+
+ // Don't copy the hMetaPict; instead get a separate copy
+ if (lpPS->fSrcAspectIconLSD)
+ {
+ lpPS->hMetaPictLSD = OleStdGetData(
+ lpOPS->lpSrcDataObj,
+ CF_METAFILEPICT,
+ NULL,
+ DVASPECT_ICON,
+ &medium
+ );
+ }
+ if (NULL == lpPS->hMetaPictLSD)
+ {
+ TCHAR szLabel[OLEUI_CCHLABELMAX];
+ HWND hIconWnd;
+ RECT IconRect;
+ int nWidth;
+ LPTSTR lpszLabel;
+
+ hIconWnd = GetDlgItem(hDlg, ID_PS_ICONDISPLAY);
+
+ GetClientRect(hIconWnd, &IconRect);
+
+ nWidth = ((IconRect.right-IconRect.left) * 3) / 2; // width is 1.5 times width of iconbox
+
+ LSTRCPYN(szLabel, lpPS->szSourceOfDataLSD, OLEUI_CCHLABELMAX);
+ szLabel[OLEUI_CCHLABELMAX-1] = TEXT('\0');
+
+ lpszLabel = ChopText(hIconWnd, nWidth, (LPTSTR)szLabel);
+
+#ifdef OLE201
+ lpPS->hMetaPictLSD = GetIconOfClass(
+ ghInst,
+ &lpPS->clsidLSD,
+ lpszLabel, /* Use chopped source string as label */
+ FALSE /* Not applicable */
+ );
+#endif
+ lpPS->hMetaPictLSD = NULL;
+
+ }
+ }
+
+ // Not an OLE object
+ if (lpPS->hObjDesc == NULL && lpPS->hLinkSrcDesc == NULL)
+ {
+ lpPS->szFullUserTypeNameLSD = lpPS->szFullUserTypeNameOD = lpPS->szUnknownType;
+ lpPS->szSourceOfDataLSD = lpPS->szSourceOfDataOD = lpPS->szUnknownSource;
+ lpPS->hMetaPictLSD = lpPS->hMetaPictOD = NULL;
+ }
+
+ // Allocate scratch memory to construct item names in the paste and pastelink listboxes
+ lpPS->hBuff = AllocateScratchMem(lpPS);
+ if (lpPS->hBuff == NULL)
+ {
+ PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);
+ return FALSE;
+ }
+
+ // Select the Paste Link Button if specified. Otherwise select
+ // Paste Button by default
+ if (lpPS->dwFlags & PSF_SELECTPASTELINK)
+ lpPS->dwFlags = (lpPS->dwFlags & ~PSF_SELECTPASTE) | PSF_SELECTPASTELINK;
+ else
+ lpPS->dwFlags =(lpPS->dwFlags & ~PSF_SELECTPASTELINK) | PSF_SELECTPASTE;
+
+ // Mark which PasteEntry formats are available from source data object
+ OleStdMarkPasteEntryList(
+ lpOPS->lpSrcDataObj,lpOPS->arrPasteEntries,lpOPS->cPasteEntries);
+
+ // Check if items are available to be pasted
+ fPasteAvailable = FFillPasteList(hDlg, lpPS);
+ if (!fPasteAvailable)
+ {
+ lpPS->dwFlags &= ~PSF_SELECTPASTE;
+ EnableWindow(GetDlgItem(hDlg, ID_PS_PASTE), FALSE);
+ }
+
+ // Check if items are available to be paste-linked
+ fPasteLinkAvailable = FFillPasteLinkList(hDlg, lpPS);
+ if (!fPasteLinkAvailable)
+ {
+ lpPS->dwFlags &= ~PSF_SELECTPASTELINK;
+ EnableWindow(GetDlgItem(hDlg, ID_PS_PASTELINK), FALSE);
+ }
+
+ // If one of Paste or PasteLink is disabled, select the other one
+ // regardless of what the input flags say
+ if (fPasteAvailable && !fPasteLinkAvailable)
+ lpPS->dwFlags |= PSF_SELECTPASTE;
+ if (fPasteLinkAvailable && !fPasteAvailable)
+ lpPS->dwFlags |= PSF_SELECTPASTELINK;
+
+ if (lpPS->dwFlags & PSF_SELECTPASTE)
+ {
+ // FTogglePaste will set the PSF_SELECTPASTE flag, so clear it.
+ lpPS->dwFlags &= ~PSF_SELECTPASTE;
+ CheckRadioButton(hDlg, ID_PS_PASTE, ID_PS_PASTELINK, ID_PS_PASTE);
+ FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE);
+ }
+ else if (lpPS->dwFlags & PSF_SELECTPASTELINK)
+ {
+ // FTogglePaste will set the PSF_SELECTPASTELINK flag, so clear it.
+ lpPS->dwFlags &= ~PSF_SELECTPASTELINK;
+ CheckRadioButton(hDlg, ID_PS_PASTE, ID_PS_PASTELINK, ID_PS_PASTELINK);
+ FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK);
+ }
+ else // Items are not available to be be Pasted or Paste-Linked
+ {
+ // Enable or disable DisplayAsIcon and set the result text and image
+ EnableDisplayAsIcon(hDlg, lpPS);
+ SetPasteSpecialHelpResults(hDlg, lpPS);
+ }
+
+ // Give initial focus to the list box
+ SetFocus(GetDlgItem(hDlg, ID_PS_DISPLAYLIST));
+
+ // Set property to handle clipboard change notifications
+ SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);
+ SetProp(hDlg, NEXTCBVIEWER, SetClipboardViewer(hDlg));
+
+ lpPS->fClipboardChanged = FALSE;
+
+ /*
+ * PERFORM OTHER INITIALIZATION HERE.
+ */
+
+ // Call the hook with lCustData in lParam
+ UStandardHook(lpPS, hDlg, WM_INITDIALOG, wParam, lpOPS->lCustData);
+ return TRUE;
+}
+
+/*
+ * FTogglePasteType
+ *
+ * Purpose:
+ * Toggles between Paste and Paste Link. The Paste list and PasteLink
+ * list are always invisible. The Display List is filled from either
+ * the Paste list or the PasteLink list depending on which Paste radio
+ * button is selected.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ * dwOption Paste or PasteSpecial option
+ *
+ * Return Value:
+ * BOOL Returns TRUE if the option has already been selected.
+ * Otherwise the option is selected and FALSE is returned
+ */
+
+BOOL FTogglePasteType(HWND hDlg, LPPASTESPECIAL lpPS, DWORD dwOption)
+{
+ DWORD dwTemp;
+ HWND hList, hListDisplay;
+ DWORD dwData;
+ int i, nItems;
+ LPTSTR lpsz;
+
+ // Skip all this if the button is already selected
+ if (lpPS->dwFlags & dwOption)
+ return TRUE;
+
+ dwTemp = PSF_SELECTPASTE | PSF_SELECTPASTELINK;
+ lpPS->dwFlags = (lpPS->dwFlags & ~dwTemp) | dwOption;
+
+ // Hide IconDisplay. This prevents flashing if the icon display is changed
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
+
+ hListDisplay = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);
+
+ // If Paste was selected
+ if (lpPS->dwFlags & PSF_SELECTPASTE)
+ {
+ // Set the Source of the object in the clipboard
+ SetDlgItemText(hDlg, ID_PS_SOURCETEXT, lpPS->szSourceOfDataOD);
+
+ // If an icon is available
+ if (lpPS->hMetaPictOD)
+ // Set the icon display
+ SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET,
+ (WPARAM)lpPS->hMetaPictOD, 0L);
+
+
+ hList = GetDlgItem(hDlg, ID_PS_PASTELIST);
+ // We are switching from PasteLink to Paste. Remember current selection
+ // in PasteLink list so it can be restored.
+ lpPS->nPasteLinkListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L);
+ if (lpPS->nPasteLinkListCurSel == LB_ERR)
+ lpPS->nPasteLinkListCurSel = 0;
+ // Remember if user selected Paste or PasteLink
+ lpPS->fLink = FALSE;
+ }
+ else // If PasteLink was selected
+ {
+ // Set the Source of the object in the clipboard
+ SetDlgItemText(hDlg, ID_PS_SOURCETEXT, lpPS->szSourceOfDataLSD);
+
+ // If an icon is available
+ if (lpPS->hMetaPictLSD)
+ // Set the icon display
+ SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET,
+ (WPARAM)lpPS->hMetaPictLSD, 0L);
+
+
+ hList = GetDlgItem(hDlg, ID_PS_PASTELINKLIST);
+ // We are switching from Paste to PasteLink. Remember current selection
+ // in Paste list so it can be restored.
+ lpPS->nPasteListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L);
+ if (lpPS->nPasteListCurSel == LB_ERR)
+ lpPS->nPasteListCurSel = 0;
+ // Remember if user selected Paste or PasteLink
+ lpPS->fLink = TRUE;
+ }
+
+ // Turn drawing off while the Display List is being filled
+ SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)FALSE, 0L);
+
+ // Move data to Display list box
+ SendMessage(hListDisplay, LB_RESETCONTENT, 0, 0L);
+ nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L);
+ lpsz = (LPTSTR)GlobalLock(lpPS->hBuff);
+ for (i = 0; i < nItems; i++)
+ {
+ SendMessage(hList, LB_GETTEXT, (WPARAM)i, (LPARAM)lpsz);
+ dwData = SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);
+ SendMessage(hListDisplay, LB_INSERTSTRING, (WPARAM)i, (LPARAM)lpsz);
+ SendMessage(hListDisplay, LB_SETITEMDATA, (WPARAM)i, dwData);
+ }
+ GlobalUnlock(lpPS->hBuff);
+
+ // Restore the selection in the Display List from user's last selection
+ if (lpPS->dwFlags & PSF_SELECTPASTE)
+ SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteListCurSel, 0L);
+ else
+ SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteLinkListCurSel, 0L);
+
+ // Paint Display List
+ SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)TRUE, 0L);
+ InvalidateRect(hListDisplay, NULL, TRUE);
+ UpdateWindow(hListDisplay);
+
+ // Auto give the focus to the Display List
+ SetFocus(hListDisplay);
+
+ // Enable/Disable DisplayAsIcon and set the help result text and bitmap corresponding to
+ // the current selection
+ ChangeListSelection(hDlg, lpPS, hListDisplay);
+
+ return FALSE;
+}
+
+
+/*
+ * ChangeListSelection
+ *
+ * Purpose:
+ * When the user changes the selection in the list, DisplayAsIcon is enabled or disabled,
+ * Result text and bitmap are updated and the index of the arrPasteEntries[] corresponding
+ * to the current format selection is saved.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ * hList HWND of the List
+ *
+ * Return Value:
+ * No return value
+ */
+
+void ChangeListSelection(HWND hDlg, LPPASTESPECIAL lpPS, HWND hList)
+{
+ LPPASTELISTITEMDATA lpItemData;
+ int nCurSel;
+
+ EnableDisplayAsIcon(hDlg, lpPS);
+ SetPasteSpecialHelpResults(hDlg, lpPS);
+
+ // Remember index of arrPasteEntries[] corresponding to the current selection
+ nCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+ if (nCurSel == LB_ERR) return;
+ lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA,
+ (WPARAM)nCurSel, 0L);
+ if ((LRESULT)lpItemData == LB_ERR) return;
+ lpPS->nSelectedIndex = lpItemData->nPasteEntriesIndex;
+}
+
+/*
+ * EnableDisplayAsIcon
+ *
+ * Purpose:
+ * Enable or disable the DisplayAsIcon button depending on whether
+ * the current selection can be displayed as an icon or not. The following table describes
+ * the state of DisplayAsIcon. The calling application is termed CONTAINER, the source
+ * of data on the clipboard is termed SOURCE.
+ * Y = Yes; N = No; Blank = State does not matter;
+ * =====================================================================
+ * SOURCE SOURCE CONTAINER DisplayAsIcon
+ * specifies specifies specifies Initial State
+ * DVASPECT_ICON OLEMISC_ONLYICONIC OLEUIPASTE_ENABLEICON
+ *
+ * N Unchecked&Disabled
+ * Y Y Checked&Disabled
+ * Y N Y Checked&Enabled
+ * N N Y Unchecked&Enabled
+ * =====================================================================
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * No return value
+ */
+
+void EnableDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS)
+{
+ int nIndex;
+ BOOL fCntrEnableIcon;
+ BOOL fSrcOnlyIconic = (lpPS->fLink) ? lpPS->fSrcOnlyIconicLSD : lpPS->fSrcOnlyIconicOD;
+ BOOL fSrcAspectIcon = (lpPS->fLink) ? lpPS->fSrcAspectIconLSD : lpPS->fSrcAspectIconOD;
+ HWND hList;
+ LPPASTELISTITEMDATA lpItemData;
+ HGLOBAL hMetaPict = (lpPS->fLink) ? lpPS->hMetaPictLSD : lpPS->hMetaPictOD;
+
+ hList = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);
+
+ // Get data corresponding to the current selection in the listbox
+ nIndex = (int)SendMessage(hList, LB_GETCURSEL, 0, 0);
+ if (nIndex != LB_ERR)
+ {
+ lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA, (WPARAM)nIndex, 0L);
+ if ((LRESULT)lpItemData != LB_ERR)
+ fCntrEnableIcon = lpItemData->fCntrEnableIcon;
+ else fCntrEnableIcon = FALSE;
+ }
+ else fCntrEnableIcon = FALSE;
+
+ // If there is an icon available
+ if (hMetaPict != NULL)
+ {
+ if (!fCntrEnableIcon) // Does CONTAINER specify OLEUIPASTE_ENABLEICON?
+ {
+ // Uncheck & Disable DisplayAsIcon
+ lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
+ CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);
+ EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);
+
+ // Hide IconDisplay and ChangeIcon button
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
+ }
+ else if (fSrcOnlyIconic) // Does SOURCE specify OLEMISC_ONLYICONIC?
+ {
+ // Check & Disable DisplayAsIcon
+ lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;
+ CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, TRUE);
+ EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);
+
+ // Show IconDisplay and ChangeIcon button
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_SHOWNORMAL);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_SHOWNORMAL);
+ }
+ else if (fSrcAspectIcon) // Does SOURCE specify DVASPECT_ICON?
+ {
+ // Check & Enable DisplayAsIcon
+ lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;
+ CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, TRUE);
+ EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), TRUE);
+
+ // Show IconDisplay and ChangeIcon button
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_SHOWNORMAL);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_SHOWNORMAL);
+ }
+ else
+ {
+ //Uncheck and Enable DisplayAsIcon
+ lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
+ CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);
+ EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), TRUE);
+
+ // Hide IconDisplay and ChangeIcon button
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
+
+ }
+ }
+ else // No icon available
+ {
+ // Unchecked & Disabled
+ lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
+ CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);
+ EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);
+
+ // Hide IconDisplay and ChangeIcon button
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
+ }
+}
+
+/*
+ * ToggleDisplayAsIcon
+ *
+ * Purpose:
+ * Toggles the DisplayAsIcon button. Hides or shows the Icon Display and
+ * the ChangeIcon button and changes the help result text and bitmap.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * None
+ *
+ */
+
+void ToggleDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS)
+{
+ BOOL fCheck;
+ int i;
+
+ fCheck = IsDlgButtonChecked(hDlg, ID_PS_DISPLAYASICON);
+
+ if (fCheck)
+ lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;
+ else lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
+
+ // Set the help result text and bitmap
+ SetPasteSpecialHelpResults(hDlg, lpPS);
+
+ // Show or hide the Icon Display and ChangeIcon button depending
+ // on the check state
+ i = (fCheck) ? SW_SHOWNORMAL : SW_HIDE;
+ StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, i);
+ StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, i);
+}
+
+/*
+ * ChangeIcon
+ *
+ * Purpose:
+ * Brings up the ChangeIcon dialog which allows the user to change
+ * the icon and label.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * None
+ *
+ */
+
+void ChangeIcon(HWND hDlg, LPPASTESPECIAL lpPS)
+{
+ OLEUICHANGEICON ci;
+ UINT uRet;
+ CLSID clsid = (lpPS->fLink) ? lpPS->clsidLSD : lpPS->clsidOD;
+
+ //Initialize the structure
+ _fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));
+
+ ci.hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);
+ ci.cbStruct = sizeof(ci);
+ ci.hWndOwner = hDlg;
+ ci.clsid = clsid;
+ ci.dwFlags = CIF_SELECTCURRENT;
+
+ // Only show help in the ChangeIcon dialog if we're showing it in this dialog.
+ if (lpPS->dwFlags & PSF_SHOWHELP)
+ ci.dwFlags |= CIF_SHOWHELP;
+
+ // Let the hook in to customize Change Icon if desired.
+ uRet = UStandardHook(lpPS, hDlg, uMsgChangeIcon, 0, (LONG)(LPSTR)&ci);
+
+ if (0 == uRet)
+ uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci));
+
+ // Update the display if necessary.
+ if (0!=uRet)
+ {
+ /*
+ * OleUIChangeIcon will have already freed our
+ * current hMetaPict that we passed in when OK is
+ * pressed in that dialog. So we use 0L as lParam
+ * here so the IconBox doesn't try to free the
+ * metafilepict again.
+ */
+ SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)ci.hMetaPict, 0L);
+ // Remember the new icon chosen by the user. Note that Paste and PasteLink have separate
+ // icons - changing one does not change the other.
+ if (lpPS->fLink)
+ lpPS->hMetaPictLSD = ci.hMetaPict;
+ else lpPS->hMetaPictOD = ci.hMetaPict;
+ }
+}
+
+/*
+ *SetPasteSpecialHelpResults
+ *
+ * Purpose:
+ * Sets the help result text and bitmap according to the current
+ * list selection. The following state table indicates which ResultText
+ * and ResultImage are selected. If %s in the lpstrFormatName is present,
+ * it is assumed that an object is being pasted/paste-linked, otherwise it
+ * is assumed that data is being pasted/paste-linked.
+ * Y = Yes; N = No; Blank = State does not matter;
+ * The numbers in the the ResultText and ResultImage columns refer to the table
+ * entries that follow.
+ * =====================================================================
+ * Paste/ lpstrFormatName in DisplayAsIcon Result Result
+ * PasteLink arrPasteEntry[]contains %s checked Text Image
+ * (Is Object == Y, Is Data == N)
+ * Paste N 1 1
+ * Paste Y N 2 2
+ * Paste Y Y 3 3
+ * PasteLink N 4 4
+ * PasteLink Y N 5 4
+ * PasteLink Y Y 6 5
+ * =====================================================================
+ * Result Text:
+ *
+ * 1. "Inserts the contents of the Clipboard into your document as <native type name,
+ * and optionally an additional help sentence>"
+ * 2. "Inserts the contents of the Clipboard into your document so that you may
+ * activate it using <object app name>"
+ * 3. "Inserts the contents of the Clipboard into your document so that you may
+ * activate it using <object app name>. It will be displayed as an icon."
+ * 4. "Inserts the contents of the Clipboard into your document as <native type name>.
+ * Paste Link creates a link to the source file so that changes to the source file
+ * will be reflected in your document."
+ * 5. "Inserts a picture of the Clipboard contents into your document. Paste Link
+ * creates a link to the source file so that changes to the source file will be
+ * reflected in your document."
+ * 6. "Inserts an icon into your document which represents the Clipboard contents.
+ * Paste Link creates a link to the source file so that changes to the source file
+ * will be reflected in your document."
+ * =====================================================================
+ * Result Image:
+ *
+ * 1. Clipboard Image
+ * 2. Paste image, non-iconic.
+ * 3. Paste image, iconic.
+ * 4. Paste Link image, non-iconic
+ * 5. Paste Link image, iconic
+ * ====================================================================
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * No return value
+ */
+void SetPasteSpecialHelpResults(HWND hDlg, LPPASTESPECIAL lpPS)
+{
+ LPTSTR psz1, psz2, psz3, psz4;
+ UINT i, iString, iImage, cch;
+ int nPasteEntriesIndex;
+ BOOL fDisplayAsIcon;
+ BOOL fIsObject;
+ HWND hList;
+ LPPASTELISTITEMDATA lpItemData;
+ LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
+ LPTSTR szFullUserTypeName = (lpPS->fLink) ?
+ lpPS->szFullUserTypeNameLSD : lpPS->szFullUserTypeNameOD;
+ LPTSTR szInsert;
+
+ hList = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);
+
+ i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
+ if (i != LB_ERR)
+ {
+ lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, i, 0L);
+ if ((LRESULT)lpItemData == LB_ERR) return;
+ nPasteEntriesIndex = lpItemData->nPasteEntriesIndex;
+ // Check if there is a '%s' in the lpstrFormatName, then an object is being
+ // pasted/pastelinked. Otherwise Data is being pasted-pastelinked.
+ fIsObject = FHasPercentS(lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName,
+ lpPS);
+ }
+ else return;
+
+ // Is DisplayAsIcon checked?
+ fDisplayAsIcon=(0L!=(lpPS->dwFlags & PSF_CHECKDISPLAYASICON));
+
+ szInsert = szFullUserTypeName;
+
+ if (lpPS->dwFlags & PSF_SELECTPASTE) // If user selected Paste
+ {
+ if (fIsObject)
+ {
+ iString = fDisplayAsIcon ? IDS_PSPASTEOBJECTASICON : IDS_PSPASTEOBJECT;
+ iImage = fDisplayAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED;
+ szInsert = lpPS->szAppName;
+ }
+ else
+ {
+ iString = IDS_PSPASTEDATA;
+ iImage = RESULTIMAGE_PASTE;
+ }
+ }
+ else if (lpPS->dwFlags & PSF_SELECTPASTELINK) // User selected PasteLink
+ {
+ if (fIsObject)
+ {
+ iString = fDisplayAsIcon ? IDS_PSPASTELINKOBJECTASICON : IDS_PSPASTELINKOBJECT;
+ iImage = fDisplayAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK;
+ }
+ else
+ {
+ iString = IDS_PSPASTELINKDATA;
+ iImage = RESULTIMAGE_LINK;
+ }
+
+ }
+ else // Should never occur.
+ {
+ iString = IDS_PSNONOLE;
+ iImage = RESULTIMAGE_PASTE;
+ }
+
+ // hBuff contains enough space for the 4 buffers required to build up the help
+ // result text.
+ cch = (UINT)GlobalSize(lpPS->hBuff)/4;
+
+ psz1=(LPTSTR)GlobalLock(lpPS->hBuff);
+ psz2=psz1+cch;
+ psz3=psz2+cch;
+ psz4=psz3+cch;
+
+ // Default is an empty string.
+ *psz1=0;
+
+ if (0!=LoadString(ghInst, iString, psz1, cch))
+ {
+ // Insert the FullUserTypeName of the source object into the partial result text
+ // specified by the container.
+ wsprintf(psz3, lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrResultText,
+ (LPTSTR)szInsert);
+ // Insert the above partial result text into the standard result text.
+ wsprintf(psz4, psz1, (LPTSTR)psz3);
+ psz1=psz4;
+ }
+
+ // If LoadString failed, we simply clear out the results (*psz1=0 above)
+ SetDlgItemText(hDlg, ID_PS_RESULTTEXT, psz1);
+
+ // Change the result bitmap
+ SendDlgItemMessage(hDlg, ID_PS_RESULTIMAGE, RIM_IMAGESET, iImage, 0L);
+
+ GlobalUnlock(lpPS->hBuff);
+}
+
+/*
+ * FAddPasteListItem
+ *
+ * Purpose:
+ * Adds an item to the list box
+ *
+ * Parameters:
+ * hList HWND List into which item is to be added
+ * fInsertFirst BOOL Insert in the beginning of the list?
+ * nPasteEntriesIndex int Index of Paste Entry array this list item corresponsds to
+ * lpPS Paste Special Dialog Structure
+ * pIMalloc LPMALLOC Memory Allocator
+ * lpszBuf LPSTR Scratch buffer to build up string for list entry
+ * lpszFullUserTypeName LPSTR full user type name for object entry
+ *
+ * Return Value:
+ * BOOL TRUE if sucessful.
+ * FALSE if unsucessful.
+ */
+BOOL FAddPasteListItem(
+ HWND hList, BOOL fInsertFirst, int nPasteEntriesIndex,
+ LPPASTESPECIAL lpPS,
+ LPMALLOC pIMalloc, LPTSTR lpszBuf, LPTSTR lpszFullUserTypeName)
+{
+ LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
+ LPPASTELISTITEMDATA lpItemData;
+ int nIndex;
+
+ // Allocate memory for each list box item
+ lpItemData = (LPPASTELISTITEMDATA)pIMalloc->lpVtbl->Alloc(
+ pIMalloc, (DWORD)sizeof(PASTELISTITEMDATA));
+ if (NULL == lpItemData)
+ return FALSE;
+
+ // Fill data associated with each list box item
+ lpItemData->nPasteEntriesIndex = nPasteEntriesIndex;
+ lpItemData->fCntrEnableIcon = ((lpOPS->arrPasteEntries[nPasteEntriesIndex].dwFlags &
+ OLEUIPASTE_ENABLEICON) ? TRUE : FALSE);
+
+ // Build list box entry string, insert the string and add the data the corresponds to it
+ wsprintf(
+ (LPTSTR)lpszBuf,
+ lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName,
+ (LPTSTR)lpszFullUserTypeName
+ );
+
+ // only add to listbox if not a duplicate
+ if (LB_ERR!=SendMessage(hList,LB_FINDSTRING, 0, (LPARAM)(LPTSTR)lpszBuf)) {
+ // item is already in list; SKIP this one
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpItemData);
+ return TRUE; // this is NOT an error
+ }
+
+ nIndex = (int)SendMessage(
+ hList,
+ (fInsertFirst ? LB_INSERTSTRING : LB_ADDSTRING),
+ 0,
+ (LPARAM)(LPTSTR)lpszBuf
+ );
+ SendMessage(
+ hList,
+ LB_SETITEMDATA,
+ nIndex,
+ (LPARAM)(LPPASTELISTITEMDATA)lpItemData
+ );
+ return TRUE;
+}
+
+
+/*
+ * FFillPasteList
+ *
+ * Purpose:
+ * Fills the invisible paste list with the formats offered by the clipboard object and
+ * asked for by the container.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * BOOL TRUE if sucessful and if formats could be found.
+ * FALSE if unsucessful or if no formats could be found.
+ */
+BOOL FFillPasteList(HWND hDlg, LPPASTESPECIAL lpPS)
+{
+ LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
+ LPMALLOC pIMalloc = NULL;
+ LPTSTR lpszBuf = (LPTSTR)GlobalLock(lpPS->hBuff);
+ HWND hList;
+ int i, j;
+ int nItems = 0;
+ int nDefFormat = -1;
+ BOOL fTryObjFmt = FALSE;
+ BOOL fInsertFirst;
+ BOOL fExclude;
+ HRESULT hrErr;
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+ if (hrErr != NOERROR)
+ goto error;
+
+ hList = GetDlgItem(hDlg, ID_PS_PASTELIST);
+
+ // Loop over the target's priority list of formats
+ for (i = 0; i < lpOPS->cPasteEntries; i++)
+ {
+ if (lpOPS->arrPasteEntries[i].dwFlags != OLEUIPASTE_PASTEONLY &&
+ !(lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_PASTE))
+ continue;
+
+ fInsertFirst = FALSE;
+
+ if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfFileName
+ || lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfEmbeddedObject
+ || lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfEmbedSource) {
+ if (! fTryObjFmt) {
+ fTryObjFmt = TRUE; // only use 1st object format
+ fInsertFirst = TRUE; // OLE obj format should always be 1st
+
+ //Check if this CLSID is in the exclusion list.
+ fExclude=FALSE;
+
+ for (j=0; j < (int)lpOPS->cClsidExclude; j++)
+ {
+ if (IsEqualCLSID(&lpPS->clsidOD,
+ (LPCLSID)(lpOPS->lpClsidExclude+j)))
+ {
+ fExclude=TRUE;
+ break;
+ }
+ }
+
+ if (fExclude)
+ continue; // don't add the object entry to list
+
+ } else {
+ continue; // already added an object format to list
+ }
+ }
+
+ // add to list if entry is marked TRUE
+ if (lpOPS->arrPasteEntries[i].dwScratchSpace) {
+ if (nDefFormat < 0)
+ nDefFormat = (fInsertFirst ? 0 : nItems);
+ else if (fInsertFirst)
+ nDefFormat++; // adjust for obj fmt inserted 1st in list
+
+ if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, pIMalloc,
+ lpszBuf, lpPS->szFullUserTypeNameOD))
+ goto error;
+ nItems++;
+ }
+ }
+
+ // initialize selection to first format matched in list
+ if (nDefFormat >= 0)
+ lpPS->nPasteListCurSel = nDefFormat;
+
+ // Clean up
+ if (pIMalloc)
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ if (lpszBuf)
+ GlobalUnlock(lpPS->hBuff);
+
+ // If no items have been added to the list box (none of the formats
+ // offered by the source matched those acceptable to the container),
+ // return FALSE
+ if (nItems > 0)
+ return TRUE;
+ else
+ return FALSE;
+
+error:
+ if (pIMalloc)
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ if (lpszBuf)
+ GlobalUnlock(lpPS->hBuff);
+ FreeListData(hList);
+
+ return FALSE;
+}
+
+
+/*
+ * FFillPasteLinkList
+ *
+ * Purpose:
+ * Fills the invisible paste link list with the formats offered by the clipboard object and
+ * asked for by the container.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * BOOL TRUE if sucessful and if formats could be found.
+ * FALSE if unsucessful or if no formats could be found.
+ */
+BOOL FFillPasteLinkList(HWND hDlg, LPPASTESPECIAL lpPS)
+{
+ LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
+ LPDATAOBJECT lpSrcDataObj = lpOPS->lpSrcDataObj;
+ LPENUMFORMATETC lpEnumFmtEtc = NULL;
+ LPMALLOC pIMalloc = NULL;
+ LPTSTR lpszBuf = (LPTSTR)GlobalLock(lpPS->hBuff);
+ OLEUIPASTEFLAG pasteFlag;
+ UINT arrLinkTypesSupported[PS_MAXLINKTYPES]; // Array of flags that
+ // indicate which link types
+ // are supported by source.
+ FORMATETC fmtetc;
+ int i, j;
+ int nItems = 0;
+ BOOL fLinkTypeSupported = FALSE;
+ HWND hList;
+ int nDefFormat = -1;
+ BOOL fTryObjFmt = FALSE;
+ BOOL fInsertFirst;
+ HRESULT hrErr;
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+ if (hrErr != NOERROR)
+ goto error;
+
+ // Remember which link type formats are offered by lpSrcDataObj.
+ _fmemset(&fmtetc, 0, sizeof(FORMATETC));
+ for (i = 0; i < lpOPS->cLinkTypes; i++)
+ {
+ if (lpOPS->arrLinkTypes[i] = cfLinkSource) {
+ OLEDBG_BEGIN2(TEXT("OleQueryLinkFromData called\r\n"))
+ hrErr = OleQueryLinkFromData(lpSrcDataObj);
+ OLEDBG_END2
+ if(NOERROR == hrErr)
+ {
+ arrLinkTypesSupported[i] = 1;
+ fLinkTypeSupported = TRUE;
+ }
+ else arrLinkTypesSupported[i] = 0;
+ }
+ else {
+ fmtetc.cfFormat = lpOPS->arrLinkTypes[i];
+ fmtetc.dwAspect = DVASPECT_CONTENT;
+ fmtetc.tymed = 0xFFFFFFFF; // All tymed values
+ fmtetc.lindex = -1;
+ OLEDBG_BEGIN2(TEXT("IDataObject::QueryGetData called\r\n"))
+ hrErr = lpSrcDataObj->lpVtbl->QueryGetData(lpSrcDataObj,&fmtetc);
+ OLEDBG_END2
+ if(NOERROR == hrErr)
+ {
+ arrLinkTypesSupported[i] = 1;
+ fLinkTypeSupported = TRUE;
+ }
+ else arrLinkTypesSupported[i] = 0;
+ }
+ }
+ // No link types are offered by lpSrcDataObj
+ if (! fLinkTypeSupported) {
+ nItems = 0;
+ goto cleanup;
+ }
+
+ hList = GetDlgItem(hDlg, ID_PS_PASTELINKLIST);
+
+ // Enumerate the formats acceptable to container
+ for (i = 0; i < lpOPS->cPasteEntries; i++)
+ {
+ fLinkTypeSupported = FALSE;
+
+ // If container will accept any link type offered by source object
+ if (lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_LINKANYTYPE)
+ fLinkTypeSupported = TRUE;
+ else
+ {
+ // Check if any of the link types offered by the source
+ // object are acceptable to the container
+ // This code depends on the LINKTYPE enum values being powers of 2
+ for (pasteFlag = OLEUIPASTE_LINKTYPE1, j = 0;
+ j < lpOPS->cLinkTypes;
+ pasteFlag*=2, j++)
+ {
+ if ((lpOPS->arrPasteEntries[i].dwFlags & pasteFlag) &&
+ arrLinkTypesSupported[j])
+ {
+ fLinkTypeSupported = TRUE;
+ break;
+ }
+ }
+ }
+
+ fInsertFirst = FALSE;
+
+ if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfFileName
+ || lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfLinkSource) {
+ if (! fTryObjFmt) {
+ fTryObjFmt = TRUE; // only use 1st object format
+ fInsertFirst = TRUE; // OLE obj format should always be 1st
+ } else {
+ continue; // already added an object format to list
+ }
+ }
+
+ // add to list if entry is marked TRUE
+ if (fLinkTypeSupported && lpOPS->arrPasteEntries[i].dwScratchSpace) {
+ if (nDefFormat < 0)
+ nDefFormat = (fInsertFirst ? 0 : nItems);
+ else if (fInsertFirst)
+ nDefFormat++; // adjust for obj fmt inserted 1st in list
+
+ if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, pIMalloc,
+ lpszBuf, lpPS->szFullUserTypeNameLSD))
+ goto error;
+ nItems++;
+ }
+ } // end FOR
+
+ nItems = (int)SendMessage(hList, LB_GETCOUNT, 0, 0L);
+
+ // initialize selection to first format matched in list
+ if (nDefFormat >= 0)
+ lpPS->nPasteLinkListCurSel = nDefFormat;
+
+cleanup:
+ // Clean up
+ if (pIMalloc)
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ if (lpszBuf)
+ GlobalUnlock(lpPS->hBuff);
+
+ // If no items have been added to the list box (none of the formats
+ // offered by the source matched those acceptable to the destination),
+ // return FALSE
+ if (nItems > 0)
+ return TRUE;
+ else
+ return FALSE;
+
+error:
+ if (pIMalloc)
+ pIMalloc->lpVtbl->Release(pIMalloc);
+ if (lpszBuf)
+ GlobalUnlock(lpPS->hBuff);
+ FreeListData(hList);
+
+ return FALSE;
+}
+
+
+/*
+ * FreeListData
+ *
+ * Purpose:
+ * Free the local memory associated with each list box item
+ *
+ * Parameters:
+ * hList HWND of the list
+ *
+ * Return Value:
+ * None
+ */
+void FreeListData(HWND hList)
+{
+ int nItems, i;
+ LPPASTELISTITEMDATA lpItemData;
+ LPMALLOC pIMalloc;
+ HRESULT hrErr;
+
+ hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+ if (hrErr != NOERROR)
+ return;
+
+ nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L);
+ for (i = 0; i < nItems; i++)
+ {
+ lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);
+ if ((LRESULT)lpItemData != LB_ERR)
+ pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpItemData);
+ }
+ pIMalloc->lpVtbl->Release(pIMalloc);
+}
+
+/*
+ * FHasPercentS
+ *
+ * Purpose:
+ * Determines if string contains %s.
+ *
+ * Parameters:
+ * lpsz LPCSTR string in which occurence of '%s' is looked for
+ *
+ * Return Value:
+ * BOOL TRUE if %s is found, else FALSE.
+ */
+
+BOOL FHasPercentS(LPCTSTR lpsz, LPPASTESPECIAL lpPS)
+{
+ int n = 0;
+ LPTSTR lpszTmp;
+
+ if (!lpsz) return FALSE;
+ // Copy input string to buffer. This allows caller to pass a
+ // code-based string. Code segments may be swapped out in low memory situations
+ // and so code-based strings need to be copied before string elements can be accessed.
+ lpszTmp = (LPTSTR)GlobalLock(lpPS->hBuff);
+ lstrcpy(lpszTmp, lpsz);
+
+ while (*lpszTmp)
+ {
+ if (*lpszTmp == TEXT('%'))
+ {
+#ifdef WIN32
+ // AnsiNext is obsolete in Win32
+ lpszTmp = CharNext(lpszTmp);
+#else
+ lpszTmp = AnsiNext(lpszTmp);
+#endif
+ if (*lpszTmp == TEXT('s')) // If %s, return
+ {
+ GlobalUnlock(lpPS->hBuff);
+ return TRUE;
+ }
+ else if (*lpszTmp == TEXT('%')) // if %%, skip to next character
+#ifdef WIN32
+ // AnsiNext is obsolete in Win32
+ lpszTmp = CharNext(lpszTmp);
+#else
+ lpszTmp = AnsiNext(lpszTmp);
+#endif
+ }
+ else
+#ifdef WIN32
+ lpszTmp = CharNext(lpszTmp);
+#else
+ lpszTmp = AnsiNext(lpszTmp);
+#endif
+ }
+
+ GlobalUnlock(lpPS->hBuff);
+ return FALSE;
+}
+
+/*
+ * AllocateScratchMem
+ *
+ * Purpose:
+ * Allocates scratch memory for use by the PasteSpecial dialog. The memory is
+ * is used as the buffer for building up strings using wsprintf. Strings are built up
+ * using the buffer while inserting items into the Paste & PasteLink lists and while
+ * setting the help result text. It must be big enough to handle the string that results after
+ * replacing the %s in the lpstrFormatName and lpstrResultText in arrPasteEntries[]
+ * by the FullUserTypeName. It must also be big enough to build the dialog's result text
+ * after %s substitutions by the FullUserTypeName or the ApplicationName.
+ *
+ * Parameters:
+ * lpPS Paste Special Dialog Structure
+ *
+ * Return Value:
+ * HGLOBAL Handle to allocated global memory
+ */
+
+HGLOBAL AllocateScratchMem(LPPASTESPECIAL lpPS)
+{
+ LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
+ int nLen, i;
+ int nSubstitutedText = 0;
+ int nAlloc = 0;
+
+ // Get the maximum length of the FullUserTypeNames specified by OBJECTDESCRIPTOR
+ // and the LINKSRCDESCRIPTOR and the Application Name. Any of these may be substituted
+ // for %s in the result-text/list entries.
+ if (lpPS->szFullUserTypeNameOD)
+ nSubstitutedText = lstrlen(lpPS->szFullUserTypeNameOD);
+ if (lpPS->szFullUserTypeNameLSD)
+ nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szFullUserTypeNameLSD));
+ if (lpPS->szAppName)
+ nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szAppName));
+
+ // Get the maximum length of lpstrFormatNames & lpstrResultText in arrPasteEntries
+ nLen = 0;
+ for (i = 0; i < lpOPS->cPasteEntries; i++)
+ {
+ nLen = __max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrFormatName));
+ nLen = __max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrResultText));
+ }
+
+ // Get the maximum length of lpstrFormatNames and lpstrResultText after %s has
+ // been substituted (At most one %s can appear in each string).
+ // Add 1 to hold NULL terminator.
+ nAlloc = (nLen+nSubstitutedText+1)*sizeof(TCHAR);
+
+ // Allocate scratch memory to be used to build strings
+ // nAlloc is big enough to hold any of the lpstrResultText or lpstrFormatName in arrPasteEntries[]
+ // after %s substitution.
+ // We also need space to build up the help result text. 512 is the maximum length of the
+ // standard dialog help text before substitutions. 512+nAlloc is the maximum length
+ // after %s substition.
+ // SetPasteSpecialHelpResults() requires 4 such buffers to build up the result text
+ return GlobalAlloc(GHND, (DWORD)4*(512+nAlloc));
+}
+
diff --git a/private/oleutest/letest/ole2ui/pastespl.dlg b/private/oleutest/letest/ole2ui/pastespl.dlg
new file mode 100644
index 000000000..d64f5e45c
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/pastespl.dlg
@@ -0,0 +1,40 @@
+// DLGINCLUDE RCDATA DISCARDABLE
+// BEGIN
+// "PASTESPL.H\0"
+// END
+
+IDD_PASTESPECIAL DIALOG 3, 15, 293, 140
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Paste Special"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Source:", ID_PS_STXSOURCE, 6, 9, 30, 8
+ LTEXT "", ID_PS_SOURCETEXT, 37, 9, 180, 8, SS_NOPREFIX | NOT
+ WS_GROUP
+ CONTROL "&Paste", ID_PS_PASTE, "Button", BS_AUTORADIOBUTTON |
+ WS_GROUP | WS_TABSTOP, 6, 38, 55, 10
+ CONTROL "Paste &Link", ID_PS_PASTELINK, "Button",
+ BS_AUTORADIOBUTTON, 6, 63, 55, 10
+ LTEXT "&As:", ID_PS_STXAS, 65, 25, 16, 8
+ LISTBOX ID_PS_PASTELIST, 65, 36, 153, 57, LBS_USETABSTOPS |
+ WS_VSCROLL | WS_GROUP | WS_TABSTOP | NOT WS_VISIBLE
+ LISTBOX ID_PS_PASTELINKLIST, 65, 36, 153, 57, LBS_USETABSTOPS |
+ WS_VSCROLL | WS_GROUP | WS_TABSTOP | NOT WS_VISIBLE
+ LISTBOX ID_PS_DISPLAYLIST, 65, 36, 153, 57, LBS_USETABSTOPS |
+ WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 224, 6, 66, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 224, 23, 66, 14
+ PUSHBUTTON "&Help", ID_OLEUIHELP, 224, 42, 66, 14
+ CONTROL "&Display As Icon", ID_PS_DISPLAYASICON, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 224, 59, 66, 14
+// CONTROL "", ID_PS_ICONDISPLAY, SZCLASSICONBOX, 0, 224, 75, 66, 44
+ PUSHBUTTON "Change &Icon...", ID_PS_CHANGEICON, 224, 123, 66, 14
+// CONTROL "", ID_PS_RESULTIMAGE, SZCLASSRESULTIMAGE, 0, 8, 101,
+// 42, 34
+ LTEXT "Result", ID_PS_RESULTTEXT, 54, 100, 159, 35,
+ SS_NOPREFIX | NOT WS_GROUP
+ GROUPBOX "Result", ID_PS_RESULTGROUP, 6, 90, 212, 48, WS_GROUP
+END
+
+
+
diff --git a/private/oleutest/letest/ole2ui/pastespl.h b/private/oleutest/letest/ole2ui/pastespl.h
new file mode 100644
index 000000000..526462f36
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/pastespl.h
@@ -0,0 +1,110 @@
+/*
+ * PASTESPL.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI Paste Special dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#ifndef _PASTESPL_H_
+#define _PASTESPL_H_
+
+#ifndef RC_INVOKED
+#pragma message ("INCLUDING PASTESPL.H from " __FILE__)
+#endif /* RC_INVOKED */
+
+
+// Length of buffers to hold the strings 'Unknown Type', Unknown Source'
+// and 'the application which created it'
+#define PS_UNKNOWNSTRLEN 100
+
+//Property label used to store clipboard viewer chain information
+#define NEXTCBVIEWER TEXT("NextCBViewer")
+
+//Internally used structure
+typedef struct tagPASTESPECIAL
+{
+ //Keep this item first as the Standard* functions depend on it here.
+ LPOLEUIPASTESPECIAL lpOPS; //Original structure passed.
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog but that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+
+ DWORD dwFlags; // Local copy of paste special flags
+
+ int nPasteListCurSel; // Save the selection the user made last
+ int nPasteLinkListCurSel; // in the paste and pastelink lists
+ int nSelectedIndex; // Index in arrPasteEntries[] corresponding to user selection
+ BOOL fLink; // Indicates if Paste or PasteLink was selected by user
+
+ HGLOBAL hBuff; // Scratch Buffer for building up strings
+ TCHAR szUnknownType[PS_UNKNOWNSTRLEN]; // Buffer for 'Unknown Type' string
+ TCHAR szUnknownSource[PS_UNKNOWNSTRLEN]; // Buffer for 'Unknown Source' string
+ TCHAR szAppName[OLEUI_CCHKEYMAX]; // Application name of Source. Used in the result text
+ // when Paste is selected. Obtained using clsidOD.
+
+ // Information obtained from OBJECTDESCRIPTOR. This information is accessed when the Paste
+ // radio button is selected.
+ CLSID clsidOD; // ClassID of source
+ SIZEL sizelOD; // sizel transfered in
+ // ObjectDescriptor
+ LPTSTR szFullUserTypeNameOD; // Full User Type Name
+ LPTSTR szSourceOfDataOD; // Source of Data
+ BOOL fSrcAspectIconOD; // Does Source specify DVASPECT_ICON?
+ BOOL fSrcOnlyIconicOD; // Does Source specify OLEMISC_ONLYICONIC?
+ HGLOBAL hMetaPictOD; // Metafile containing icon and icon title
+ HGLOBAL hObjDesc; // Handle to OBJECTDESCRIPTOR structure from which the
+ // above information is obtained
+
+ // Information obtained from LINKSRCDESCRIPTOR. This infomation is accessed when the PasteLink
+ // radio button is selected.
+ CLSID clsidLSD; // ClassID of source
+ SIZEL sizelLSD; // sizel transfered in
+ // LinkSrcDescriptor
+ LPTSTR szFullUserTypeNameLSD;// Full User Type Name
+ LPTSTR szSourceOfDataLSD; // Source of Data
+ BOOL fSrcAspectIconLSD; // Does Source specify DVASPECT_ICON?
+ BOOL fSrcOnlyIconicLSD; // Does Source specify OLEMISC_ONLYICONIC?
+ HGLOBAL hMetaPictLSD; // Metafile containing icon and icon title
+ HGLOBAL hLinkSrcDesc; // Handle to LINKSRCDESCRIPTOR structure from which the
+ // above information is obtained
+
+ BOOL fClipboardChanged; // Has clipboard content changed
+ // if so bring down dlg after
+ // ChangeIcon dlg returns.
+} PASTESPECIAL, *PPASTESPECIAL, FAR *LPPASTESPECIAL;
+
+// Data corresponding to each list item. A pointer to this structure is attached to each
+// Paste\PasteLink list box item using LB_SETITEMDATA
+typedef struct tagPASTELISTITEMDATA
+{
+ int nPasteEntriesIndex; // Index of arrPasteEntries[] corresponding to list item
+ BOOL fCntrEnableIcon; // Does calling application (called container here)
+ // specify OLEUIPASTE_ENABLEICON for this item?
+} PASTELISTITEMDATA, *PPASTELISTITEMDATA, FAR *LPPASTELISTITEMDATA;
+
+
+//Internal function prototypes
+//PASTESPL.C
+BOOL CALLBACK EXPORT PasteSpecialDialogProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FPasteSpecialInit(HWND hDlg, WPARAM, LPARAM);
+BOOL FTogglePasteType(HWND, LPPASTESPECIAL, DWORD);
+void ChangeListSelection(HWND, LPPASTESPECIAL, HWND);
+void EnableDisplayAsIcon(HWND, LPPASTESPECIAL);
+void ToggleDisplayAsIcon(HWND, LPPASTESPECIAL);
+void ChangeIcon(HWND, LPPASTESPECIAL);
+void SetPasteSpecialHelpResults(HWND, LPPASTESPECIAL);
+BOOL FAddPasteListItem(HWND, BOOL, int, LPPASTESPECIAL, LPMALLOC, LPTSTR, LPTSTR);
+BOOL FFillPasteList(HWND, LPPASTESPECIAL);
+BOOL FFillPasteLinkList(HWND, LPPASTESPECIAL);
+BOOL FHasPercentS(LPCTSTR, LPPASTESPECIAL);
+HGLOBAL AllocateScratchMem(LPPASTESPECIAL);
+void FreeListData(HWND);
+
+#endif //_PASTESPL_H_
+
diff --git a/private/oleutest/letest/ole2ui/precomp.c b/private/oleutest/letest/ole2ui/precomp.c
new file mode 100644
index 000000000..1385d8a41
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/precomp.c
@@ -0,0 +1,23 @@
+/*
+ * PRECOMP.C
+ *
+ * This file is used to precompile the OLE2UI.H header file
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+
+// This dummy function is needed in order for the static link version
+// of this library to work correctly. When we include PRECOMP.OBJ
+// in our library (.LIB file), it will only get linked into our
+// application IFF at least one function in precomp.c is called from
+// either our EXE or LIB. Therefore, we will use a function
+// here called OleUIStaticLibDummy(). You need to call it from
+// your application.
+
+void FAR PASCAL OleUIStaticLibDummy(void)
+{
+
+}
diff --git a/private/oleutest/letest/ole2ui/prompt.dlg b/private/oleutest/letest/ole2ui/prompt.dlg
new file mode 100644
index 000000000..fc8474315
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/prompt.dlg
@@ -0,0 +1,80 @@
+Exclamation ICON bang.ico
+
+
+IDD_LINKSOURCEUNAVAILABLE DIALOG 21, 34, 175, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION ""
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON "Exclamation", ID_DUMMY, 8, 8, 0, 0, SS_ICON
+ LTEXT "This action cannot be completed because the selected link's source is presently unavailable.", ID_PU_TEXT, 48, 8, 117, 32
+ DEFPUSHBUTTON "OK", IDOK, 39, 58, 40, 14
+ PUSHBUTTON "Links...", ID_PU_LINKS, 95, 58, 40, 14
+END
+
+
+IDD_CANNOTUPDATELINK DIALOG 21, 34, 175, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION ""
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON "Exclamation", ID_DUMMY, 8, 8, 0, 0, SS_ICON
+ LTEXT "Some links could not be updated because their sources are presently unavailable.", ID_PU_TEXT, 48, 8, 117, 32
+ DEFPUSHBUTTON "OK", IDOK, 39, 58, 40, 14
+ PUSHBUTTON "Links...", ID_PU_LINKS, 95, 58, 40, 14
+END
+
+
+IDD_SERVERNOTREG DIALOG 39, 30, 198, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON "Exclamation", ID_DUMMY, 8, 8, 0, 0, SS_ICON
+ LTEXT "The application necessary to activate this %s is unavailable. You may convert it to or activate it as another type of object using Convert...", ID_PU_TEXT, 39, 8, 152, 36
+ DEFPUSHBUTTON "Convert...", ID_PU_CONVERT, 23, 58, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 79, 58, 40, 14
+ PUSHBUTTON "Help", ID_OLEUIHELP, 135, 58, 40, 14
+END
+
+
+IDD_LINKTYPECHANGED DIALOG 39, 30, 198, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON "Exclamation", ID_DUMMY, 8, 8, 0, 0, SS_ICON
+ LTEXT "The link is no longer a %s. Please choose a different command offered by the new type.",
+ ID_PU_TEXT, 39, 8, 152, 36
+ PUSHBUTTON "OK", IDOK, 79, 58, 40, 14
+END
+
+
+IDD_SERVERNOTFOUND DIALOG 36, 39, 183, 90
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON "Exclamation", ID_DUMMY, 8, 8, 0, 0, SS_ICON
+ LTEXT "The server application cannot be found.\n\nMake sure the application is properly installed, or exists in your DOS path, and that is has not been deleted, moved, or renamed.",
+ ID_PU_TEXT, 38, 8, 136, 52
+ DEFPUSHBUTTON "OK", IDOK, 71, 70, 40, 14
+END
+
+
+IDD_UPDATELINKS DIALOG 50, 57, 179, 55
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", ID_PU_METER, "Static", SS_BLACKFRAME, 5, 40, 122, 9
+ DEFPUSHBUTTON "Stop", ID_PU_STOP, 134, 37, 40, 14
+ LTEXT "Update links...", ID_DUMMY, 5, 7, 56, 8
+ LTEXT "", ID_PU_PERCENT, 56, 26, 20, 8
+END
+
+
+IDD_OUTOFMEMORY DIALOG 36, 39, 107, 73
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON "Exclamation", ID_DUMMY, 8, 8, 0, 0, SS_ICON
+ LTEXT "Out of memory!", ID_PU_TEXT, 41, 13, 57, 12
+ DEFPUSHBUTTON "OK", IDOK, 33, 53, 40, 14
+END
diff --git a/private/oleutest/letest/ole2ui/regdb.c b/private/oleutest/letest/ole2ui/regdb.c
new file mode 100644
index 000000000..b6922b260
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/regdb.c
@@ -0,0 +1,401 @@
+/*
+ * REGDB.C
+ *
+ * Functions to query the registration database
+ *
+ * OleStdGetMiscStatusOfClass
+ * OleStdGetDefaultFileFormatOfClass
+ * OleStdGetAuxUserType
+ * OleStdGetUserTypeOfClass
+ *
+ * (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved
+ *
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "common.h"
+#include <ctype.h>
+
+OLEDBGDATA
+
+// Replacement for stdlib atol,
+// which didn't work and doesn't take far pointers.
+// Must be tolerant of leading spaces.
+//
+//
+static LONG Atol(LPTSTR lpsz)
+{
+ signed int sign = +1;
+ UINT base = 10;
+ LONG l = 0;
+
+ if (NULL==lpsz)
+ {
+ OleDbgAssert (0);
+ return 0;
+ }
+ while (isspace(*lpsz))
+ lpsz++;
+
+ if (*lpsz=='-')
+ {
+ lpsz++;
+ sign = -1;
+ }
+ if (lpsz[0]==TEXT('0') && lpsz[1]==TEXT('x'))
+ {
+ base = 16;
+ lpsz+=2;
+ }
+
+ if (base==10)
+ {
+ while (isdigit(*lpsz))
+ {
+ l = l * base + *lpsz - '0';
+ lpsz++;
+ }
+ }
+ else
+ {
+ OleDbgAssert (base==16);
+ while (isxdigit(*lpsz))
+ {
+ l = l * base + isdigit(*lpsz) ? *lpsz - '0' : toupper(*lpsz) - 'A' + 10;
+ lpsz++;
+ }
+ }
+ return l * sign;
+}
+
+
+
+/*
+ * OleStdGetUserTypeOfClass(REFCLSID, LPSTR, UINT, HKEY)
+ *
+ * Purpose:
+ * Returns the user type (human readable class name) of the specified class.
+ *
+ * Parameters:
+ * rclsid pointer to the clsid to retrieve user type of.
+ * lpszUserType pointer to buffer to return user type in.
+ * cch length of buffer pointed to by lpszUserType
+ * hKey hKey for reg db - if this is NULL, then we
+ * open and close the reg db within this function. If it
+ * is non-NULL, then we assume it's a valid key to the
+ * \ root and use it without closing it. (useful
+ * if you're doing lots of reg db stuff).
+ *
+ * Return Value:
+ * UINT Number of characters in returned string. 0 on error.
+ *
+ */
+STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid, LPTSTR lpszUserType, UINT cch, HKEY hKey)
+{
+
+ LONG dw;
+ LONG lRet;
+ LPSTR lpszCLSID, lpszProgID;
+ BOOL fFreeProgID = FALSE;
+ BOOL bCloseRegDB = FALSE;
+ TCHAR szKey[128];
+ LPMALLOC lpIMalloc;
+
+ if (!lpszUserType)
+ return 0;
+
+ *lpszUserType = TEXT('\0');
+ if (hKey == NULL)
+ {
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return (UINT)FALSE;
+
+ bCloseRegDB = TRUE;
+ }
+
+ // Get a string containing the class name
+ StringFromCLSIDA(rclsid, &lpszCLSID);
+
+ wsprintf(szKey, TEXT("CLSID\\%s"), lpszCLSID);
+
+ dw=cch;
+ lRet = RegQueryValue(hKey, szKey, lpszUserType, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet) {
+ // Load 'Unknown Source' and 'Unknown Type' strings
+ dw = (LONG)LoadString(ghInst, IDS_PSUNKNOWNTYPE, lpszUserType, cch);
+ }
+
+ if ( ((LONG)ERROR_SUCCESS!=lRet) && (CoIsOle1Class(rclsid)) )
+ {
+ // We've got an OLE 1.0 class, so let's try to get the user type
+ // name from the ProgID entry.
+
+ ProgIDFromCLSIDA(rclsid, &lpszProgID);
+ fFreeProgID = TRUE;
+
+ dw = cch;
+ lRet = RegQueryValue(hKey, lpszProgID, lpszUserType, &dw);
+
+ if ((LONG)ERROR_SUCCESS != lRet)
+ dw = 0;
+ }
+
+
+ if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc))
+ {
+ if (fFreeProgID)
+ lpIMalloc->lpVtbl->Free(lpIMalloc, (LPVOID)lpszProgID);
+
+ lpIMalloc->lpVtbl->Free(lpIMalloc, (LPVOID)lpszCLSID);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ }
+
+ if (bCloseRegDB)
+ RegCloseKey(hKey);
+
+ return (UINT)dw;
+
+}
+
+
+
+/*
+ * OleStdGetAuxUserType(RCLSID, WORD, LPSTR, int, HKEY)
+ *
+ * Purpose:
+ * Returns the specified AuxUserType from the reg db.
+ *
+ * Parameters:
+ * rclsid pointer to the clsid to retrieve aux user type of.
+ * hKey hKey for reg db - if this is NULL, then we
+ * open and close the reg db within this function. If it
+ * is non-NULL, then we assume it's a valid key to the
+ * \ root and use it without closing it. (useful
+ * if you're doing lots of reg db stuff).
+ * wAuxUserType which aux user type field to look for. In 4/93 release
+ * 2 is short name and 3 is exe name.
+ * lpszUserType pointer to buffer to return user type in.
+ * cch length of buffer pointed to by lpszUserType
+ *
+ * Return Value:
+ * UINT Number of characters in returned string. 0 on error.
+ *
+ */
+STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid,
+ WORD wAuxUserType,
+ LPTSTR lpszAuxUserType,
+ int cch,
+ HKEY hKey)
+{
+ HKEY hThisKey;
+ BOOL fCloseRegDB = FALSE;
+ LONG dw;
+ LRESULT lRet;
+ LPTSTR lpszCLSID;
+ LPMALLOC lpIMalloc;
+ TCHAR szKey[OLEUI_CCHKEYMAX];
+ TCHAR szTemp[32];
+
+ lpszAuxUserType[0] = TEXT('\0');
+
+ if (NULL == hKey)
+ {
+ lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hThisKey);
+
+ if (ERROR_SUCCESS != lRet)
+ return 0;
+ }
+ else
+ hThisKey = hKey;
+
+ StringFromCLSIDA(rclsid, &lpszCLSID);
+
+ lstrcpy(szKey, TEXT("CLSID\\"));
+ lstrcat(szKey, lpszCLSID);
+ wsprintf(szTemp, TEXT("\\AuxUserType\\%d"), wAuxUserType);
+ lstrcat(szKey, szTemp);
+
+ dw = cch;
+
+ lRet = RegQueryValue(hThisKey, szKey, lpszAuxUserType, &dw);
+
+ if (ERROR_SUCCESS != lRet) {
+ dw = 0;
+ lpszAuxUserType[0] = TEXT('\0');
+ }
+
+
+ if (fCloseRegDB)
+ RegCloseKey(hThisKey);
+
+ if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc))
+ {
+ lpIMalloc->lpVtbl->Free(lpIMalloc, (LPVOID)lpszCLSID);
+ lpIMalloc->lpVtbl->Release(lpIMalloc);
+ }
+
+ return (UINT)dw;
+}
+
+
+
+/*
+ * OleStdGetMiscStatusOfClass(REFCLSID, HKEY)
+ *
+ * Purpose:
+ * Returns the value of the misc status for the given clsid.
+ *
+ * Parameters:
+ * rclsid pointer to the clsid to retrieve user type of.
+ * hKey hKey for reg db - if this is NULL, then we
+ * open and close the reg db within this function. If it
+ * is non-NULL, then we assume it's a valid key to the
+ * \\CLSID root and use it without closing it. (useful
+ * if you're doing lots of reg db stuff).
+ *
+ * Return Value:
+ * BOOL TRUE on success, FALSE on failure.
+ *
+ */
+STDAPI_(BOOL) OleStdGetMiscStatusOfClass(REFCLSID rclsid, HKEY hKey, DWORD FAR * lpdwValue)
+{
+ DWORD dw;
+ LONG lRet;
+ LPTSTR lpszCLSID;
+ TCHAR szKey[64];
+ TCHAR szMiscStatus[OLEUI_CCHKEYMAX];
+ BOOL bCloseRegDB = FALSE;
+
+ if (hKey == NULL)
+ {
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return FALSE;
+
+ bCloseRegDB = TRUE;
+ }
+
+ // Get a string containing the class name
+ StringFromCLSIDA(rclsid, &lpszCLSID);
+
+ // Construct key
+ lstrcpy(szKey, lpszCLSID);
+
+ lstrcat(szKey, TEXT("\\MiscStatus"));
+
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet = RegQueryValue(hKey, szKey, (LPTSTR)szMiscStatus, &dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ {
+ OleStdFreeString(lpszCLSID, NULL);
+
+ if (bCloseRegDB)
+ RegCloseKey(hKey);
+
+ return FALSE;
+
+ }
+
+ *lpdwValue = Atol((LPTSTR)szMiscStatus);
+
+ OleStdFreeString(lpszCLSID, NULL);
+
+ if (bCloseRegDB)
+ RegCloseKey(hKey);
+
+ return TRUE;
+
+
+}
+
+
+/*
+ * CLIPFORMAT OleStdGetDefaultFileFormatOfClass(REFCLSID, HKEY)
+ *
+ * Purpose:
+ * Returns the default file format of the specified class.
+ * this is entered in REGDB as follows:
+ * CLSID\{...}\DataFormats\DefaultFile = <cfFmt>
+ *
+ * Parameters:
+ * rclsid pointer to the clsid to retrieve user type of.
+ * hKey hKey for reg db- if this is NULL, then we
+ * open and close the reg db within this function. If it
+ * is non-NULL, then we assume it's a valid key to the
+ * \ root and use it without closing it. (useful
+ * if you're doing lots of reg db stuff).
+ *
+ * Return Value:
+ * cfFmt -- DefaultFile format
+ * NULL -- failed to get default file format
+ *
+ */
+STDAPI_(CLIPFORMAT) OleStdGetDefaultFileFormatOfClass(
+ REFCLSID rclsid,
+ HKEY hKey
+)
+{
+ CLIPFORMAT cfFmt = 0;
+ DWORD dw;
+ LONG lRet;
+ LPTSTR lpszCLSID;
+ BOOL bCloseRegDB = FALSE;
+ TCHAR szKey[128];
+ TCHAR szDefaultFile[OLEUI_CCHKEYMAX];
+ BOOL bStatus = TRUE;
+
+
+ if (hKey == NULL)
+ {
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return 0;
+
+ bCloseRegDB = TRUE;
+ }
+
+
+ // Get a string containing the class name
+ StringFromCLSIDA(rclsid, &lpszCLSID);
+
+ // Construct key
+ wsprintf(szKey, TEXT("CLSID\\%s\\DataFormats\\DefaultFile"), lpszCLSID);
+
+ OleStdFreeString(lpszCLSID, NULL);
+
+ dw=OLEUI_CCHKEYMAX_SIZE;
+ lRet = RegQueryValue(hKey, szKey, (LPTSTR)szDefaultFile, (LONG FAR *)&dw);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ bStatus = FALSE;
+ else {
+ /* if the format is a number, then it should refer to one of the
+ ** standard Windows formats.
+ */
+ if (isdigit(szDefaultFile[0]))
+ cfFmt = (CLIPFORMAT)Atol(szDefaultFile);
+ else
+ cfFmt = RegisterClipboardFormat(szDefaultFile);
+ }
+
+ if (bCloseRegDB)
+ RegCloseKey(hKey);
+
+ return cfFmt;
+}
+
+
diff --git a/private/oleutest/letest/ole2ui/regdb.h b/private/oleutest/letest/ole2ui/regdb.h
new file mode 100644
index 000000000..d05bc93b2
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/regdb.h
@@ -0,0 +1,8 @@
+// This file is now OBSOLETE (include olestd.h instead)
+/*
+ * Regdb.h
+ *
+ * (c) Copyright Microsoft Corp. 1992 All Rights Reserved
+ */
+
+// Function prototypes moved to olestd.h
diff --git a/private/oleutest/letest/ole2ui/resimage.c b/private/oleutest/letest/ole2ui/resimage.c
new file mode 100644
index 000000000..8a95f4c71
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/resimage.c
@@ -0,0 +1,363 @@
+/*
+ * RESIMAGE.C
+ *
+ * Implementation of the Results Image control for OLE 2.0 UI dialogs.
+ * We need a separate control for dialogs in order to control the repaints
+ * properly and to provide a clean message interface for the dialog
+ * implementations.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "resimage.h"
+
+OLEDBGDATA
+
+//Flag indicating if we've registered the class
+static BOOL fRegistered=FALSE;
+
+//Bitmap and image dimensions for result images.
+static HBITMAP hBmpResults=NULL;
+static UINT cxBmpResult=0;
+static UINT cyBmpResult=0;
+
+/*
+ * FResultImageInitialize
+ *
+ * Purpose:
+ * Attempts to load result bitmaps for the current display driver
+ * for use in OLE 2.0 UI dialogs. Also registers the ResultImage
+ * control class.
+ *
+ * Parameters:
+ * hInst HINSTANCE instance of the DLL.
+ *
+ * hPrevInst HINSTANCE of the previous instance. Used to
+ * determine whether to register window classes or not.
+ *
+ * lpszClassName LPSTR containing the class name to register the
+ * ResultImage control class with.
+ *
+ * Return Value:
+ * BOOL TRUE if all initialization succeeded, FALSE otherwise.
+ */
+
+BOOL FResultImageInitialize(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpszClassName)
+ {
+ int cx, iBmp;
+ HDC hDC;
+ BITMAP bm;
+
+ WNDCLASS wc;
+
+
+ /*
+ * Determine the aspect ratio of the display we're currently
+ * running on and load the appropriate bitmap into the global
+ * hBmpResults (used from the ResultImage control only).
+ *
+ * By retrieving the logical Y extent of the display driver, you
+ * only have limited possibilities:
+ * LOGPIXELSY Display
+ * ----------------------------------------
+ * 48 CGA (unsupported)
+ * 72 EGA
+ * 96 VGA
+ * 120 8514/a (i.e. HiRes VGA)
+ */
+
+ hDC=GetDC(NULL);
+
+ if (NULL==hDC)
+ return FALSE;
+
+ cx=GetDeviceCaps(hDC, LOGPIXELSY);
+ ReleaseDC(NULL, hDC);
+
+ /*
+ * Instead of single comparisons, check ranges instead, so in case
+ * we get something funky, we'll act reasonable.
+ */
+ if (72 >=cx) iBmp=IDB_RESULTSEGA;
+ if (72 < cx && 120 > cx) iBmp=IDB_RESULTSVGA;
+ if (120 <=cx) iBmp=IDB_RESULTSHIRESVGA;
+
+ hBmpResults=LoadBitmap(hInst, MAKEINTRESOURCE(iBmp));
+
+ if (NULL==hBmpResults)
+ {
+ //On error, fail loading the DLL
+ OleDbgOut1(TEXT("FResultImageInitialize: Failed LoadBitmap.\r\n"));
+ return FALSE;
+ }
+
+ OleDbgOut4(TEXT("FResultImageInitialize: Loaded hBmpResults\r\n"));
+
+ //Now that we have the bitmap, calculate image dimensions
+ GetObject(hBmpResults, sizeof(BITMAP), &bm);
+ cxBmpResult=bm.bmWidth;
+ cyBmpResult=bm.bmHeight/CIMAGESY;
+
+
+ // Only register class if we're the first instance
+ if (hPrevInst)
+ fRegistered = TRUE;
+ else
+ {
+ // Static flag fRegistered guards against calling this function more
+ // than once in the same instance
+
+ if (!fRegistered)
+ {
+ wc.lpfnWndProc =ResultImageWndProc;
+ wc.cbClsExtra =0;
+ wc.cbWndExtra =CBRESULTIMAGEWNDEXTRA;
+ wc.hInstance =hInst;
+ wc.hIcon =NULL;
+ wc.hCursor =LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground =NULL;
+ wc.lpszMenuName =NULL;
+ wc.lpszClassName =lpszClassName;
+ wc.style =CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
+
+ fRegistered = RegisterClass(&wc);
+ }
+ }
+
+ return fRegistered;
+}
+
+
+
+
+
+/*
+ * ResultImageUninitialize
+ *
+ * Purpose:
+ * Cleans up anything done in FResultImageInitialize, such as freeing
+ * the bitmaps. Call from WEP.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * None
+ */
+
+void ResultImageUninitialize(void)
+ {
+ if (NULL!=hBmpResults)
+ {
+ DeleteObject(hBmpResults);
+ }
+
+ return;
+ }
+
+
+
+
+
+
+/*
+ * ResultImageWndProc
+ *
+ * Purpose:
+ * Window Procedure for the ResultImage custom control. Only handles
+ * WM_CREATE, WM_PAINT, and private messages to manipulate the bitmap.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+LONG CALLBACK EXPORT ResultImageWndProc(HWND hWnd, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ UINT iBmp;
+ PAINTSTRUCT ps;
+ HDC hDC;
+
+ //Handle standard Windows messages.
+ switch (iMsg)
+ {
+ case WM_CREATE:
+ SetWindowWord(hWnd, RIWW_IMAGEINDEX, RESULTIMAGE_NONE);
+ return 0L;
+
+ case WM_PAINT:
+ iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX);
+
+ hDC=BeginPaint(hWnd, &ps);
+
+ if (RESULTIMAGE_NONE!=iBmp)
+ {
+ RECT rc;
+ UINT x, y;
+ HDC hDCDlg;
+ HBRUSH hBr;
+ LOGBRUSH lb;
+ HWND hDlg;
+
+ /*
+ * Our job before using TransparentBlt is to figure out
+ * where to position the result image. We place it centered
+ * on this control, so get our rect's center and subtract
+ * half of the image dimensions.
+ */
+ GetClientRect(hWnd, &rc);
+ x=(rc.right+rc.left-cxBmpResult)/2;
+ y=(rc.bottom+rc.top-cyBmpResult)/2;
+
+ //Get the backgroup color the dialog is using.
+ hDlg=GetParent(hWnd);
+ hDCDlg=GetDC(hDlg);
+#if defined( WIN32 )
+ hBr = (HBRUSH)SendMessage(hDlg,
+ WM_CTLCOLORDLG,
+ (WPARAM)hDCDlg,
+ (LPARAM)hDlg);
+#else
+ hBr = (HBRUSH)SendMessage(hDlg,
+ WM_CTLCOLOR,
+ (WPARAM)hDCDlg,
+ MAKELPARAM(hDlg, CTLCOLOR_DLG));
+#endif
+ ReleaseDC(hDlg, hDCDlg);
+
+ GetObject(hBr, sizeof(LOGBRUSH), &lb);
+ SetBkColor(hDC, lb.lbColor);
+
+ TransparentBlt(hDC, x, y, hBmpResults, 0, iBmp*cyBmpResult
+ , cxBmpResult, cyBmpResult, RGBTRANSPARENT);
+ }
+
+ EndPaint(hWnd, &ps);
+ break;
+
+ case RIM_IMAGESET:
+ //wParam contains the new index.
+ iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX);
+
+ //Validate the index before changing it and repainting
+ if (RESULTIMAGE_NONE==wParam ||
+ ((RESULTIMAGE_MIN <= wParam) && (RESULTIMAGE_MAX >= wParam)))
+ {
+ SetWindowWord(hWnd, RIWW_IMAGEINDEX, (WORD)wParam);
+ InvalidateRect(hWnd, NULL, FALSE);
+ UpdateWindow(hWnd);
+ }
+
+ //Return the previous index.
+ return iBmp;
+
+ case RIM_IMAGEGET:
+ //Return the current index.
+ iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX);
+ return (LONG)iBmp;
+
+ default:
+ return DefWindowProc(hWnd, iMsg, wParam, lParam);
+ }
+
+ return 0L;
+ }
+
+
+
+
+
+
+/*
+ * TransparentBlt
+ *
+ * Purpose:
+ * Given a DC, a bitmap, and a color to assume as transparent in that
+ * bitmap, BitBlts the bitmap to the DC letting the existing background
+ * show in place of the transparent color.
+ *
+ * Parameters:
+ * hDC HDC on which to draw.
+ * x, y UINT location at which to draw the bitmap
+ * hBmp HBITMIP to draw from
+ * xOrg, yOrg UINT coordinates from which to draw the bitamp
+ * cx, cy UINT dimensions of the bitmap to Blt.
+ * cr COLORREF to consider as transparent.
+ *
+ * Return Value:
+ * None
+ */
+
+void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, UINT xOrg, UINT yOrg
+ , UINT cx, UINT cy, COLORREF cr)
+ {
+ HDC hDCSrc, hDCMid, hMemDC;
+ HBITMAP hBmpMono, hBmpT;
+ HBRUSH hBr, hBrT;
+ COLORREF crBack, crText;
+
+ if (NULL==hBmp)
+ return;
+
+ //Get three intermediate DC's
+ hDCSrc=CreateCompatibleDC(hDC);
+ hDCMid=CreateCompatibleDC(hDC);
+ hMemDC=CreateCompatibleDC(hDC);
+
+ SelectObject(hDCSrc, hBmp);
+
+ //Create a monochrome bitmap for masking
+ hBmpMono=CreateCompatibleBitmap(hDCMid, cx, cy);
+ SelectObject(hDCMid, hBmpMono);
+
+ //Create a middle bitmap
+ hBmpT=CreateCompatibleBitmap(hDC, cx, cy);
+ SelectObject(hMemDC, hBmpT);
+
+
+ //Create a monochrome mask where we have 0's in the image, 1's elsewhere.
+ crBack=SetBkColor(hDCSrc, cr);
+ BitBlt(hDCMid, 0, 0, cx, cy, hDCSrc, xOrg, yOrg, SRCCOPY);
+ SetBkColor(hDCSrc, crBack);
+
+ //Put the unmodified image in the temporary bitmap
+ BitBlt(hMemDC, 0, 0, cx, cy, hDCSrc, xOrg, yOrg, SRCCOPY);
+
+ //Create an select a brush of the background color
+ hBr=CreateSolidBrush(GetBkColor(hDC));
+ hBrT=SelectObject(hMemDC, hBr);
+
+ //Force conversion of the monochrome to stay black and white.
+ crText=SetTextColor(hMemDC, 0L);
+ crBack=SetBkColor(hMemDC, RGB(255, 255, 255));
+
+ /*
+ * Where the monochrome mask is 1, Blt the brush; where the mono mask
+ * is 0, leave the destination untouches. This results in painting
+ * around the image with the background brush. We do this first
+ * in the temporary bitmap, then put the whole thing to the screen.
+ */
+ BitBlt(hMemDC, 0, 0, cx, cy, hDCMid, 0, 0, ROP_DSPDxax);
+ BitBlt(hDC, x, y, cx, cy, hMemDC, 0, 0, SRCCOPY);
+
+
+ SetTextColor(hMemDC, crText);
+ SetBkColor(hMemDC, crBack);
+
+ SelectObject(hMemDC, hBrT);
+ DeleteObject(hBr);
+
+ DeleteDC(hMemDC);
+ DeleteDC(hDCSrc);
+ DeleteDC(hDCMid);
+ DeleteObject(hBmpT);
+ DeleteObject(hBmpMono);
+
+ return;
+ }
diff --git a/private/oleutest/letest/ole2ui/resimage.h b/private/oleutest/letest/ole2ui/resimage.h
new file mode 100644
index 000000000..31640be91
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/resimage.h
@@ -0,0 +1,61 @@
+/*
+ * RESIMAGE.H
+ *
+ * Structures and definitions for the ResultImage control.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _RESIMAGE_H_
+#define _RESIMAGE_H_
+
+
+/*
+ * Indices into the bitmaps to extract the right image. Each bitmap
+ * contains five images arranged vertically, so the offset to the correct
+ * image is (iImage*cy)
+ */
+
+#define RESULTIMAGE_NONE 0xFFFF
+#define RESULTIMAGE_PASTE 0
+#define RESULTIMAGE_EMBED 1
+#define RESULTIMAGE_EMBEDICON 2
+#define RESULTIMAGE_LINK 3
+#define RESULTIMAGE_LINKICON 4
+#define RESULTIMAGE_LINKTOLINK 5
+#define RESULTIMAGE_LINKTOLINKICON 6
+
+#define RESULTIMAGE_MIN 0
+#define RESULTIMAGE_MAX 6
+
+
+//Total number of images in each bitmap.
+#define CIMAGESY (RESULTIMAGE_MAX+1)
+
+//The color to use for transparancy (cyan)
+#define RGBTRANSPARENT RGB(0, 255, 255)
+
+
+//Function prototypes
+BOOL FResultImageInitialize(HINSTANCE, HINSTANCE, LPTSTR);
+void ResultImageUninitialize(void);
+LONG CALLBACK EXPORT ResultImageWndProc(HWND, UINT, WPARAM, LPARAM);
+void TransparentBlt(HDC, UINT, UINT, HBITMAP, UINT, UINT, UINT, UINT, COLORREF);
+
+
+//Window extra bytes contain the bitmap index we deal with currently.
+#define CBRESULTIMAGEWNDEXTRA sizeof(UINT)
+#define RIWW_IMAGEINDEX 0
+
+
+//Control messages
+#define RIM_IMAGESET (WM_USER+0)
+#define RIM_IMAGEGET (WM_USER+1)
+
+
+//Special ROP code for TransparentBlt.
+#define ROP_DSPDxax 0x00E20746
+
+
+#endif //_RESIMAGE_H_
diff --git a/private/oleutest/letest/ole2ui/stdpal.c b/private/oleutest/letest/ole2ui/stdpal.c
new file mode 100644
index 000000000..abe3e82ac
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/stdpal.c
@@ -0,0 +1,94 @@
+/*-----------------------------------------------------------------------
+| stdpal.c
+|
+| Standard App Palette useful for OLE applications. v 1.01
+|
+| NOTE: Palette MUST be created with OleStdCreateStandardPalette
+|
+| Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+|
+-----------------------------------------------------------------------*/
+
+#ifndef PC_RESERVED
+#ifndef INC_OLE2
+ #define INC_OLE2
+#endif
+
+#undef UNICODE
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#include "stdpal.h"
+
+#define cpeAppPal 256 // number of colors in our apps palette
+typedef struct
+ {
+ WORD wVersion;
+ WORD cpe;
+ PALETTEENTRY rgpe[cpeAppPal];
+ } LOGPAL;
+
+
+/*-----------------------------------------------------------------------
+| OleStdCreateStandardPalette
+|
+| Creates the standard Apps palette. Create one of these for your
+| app, and select/realize it into each DC.
+|
+| Arguments:
+| void:
+|
+| Returns:
+|
+| Keywords:
+-----------------------------------------------------------------------*/
+STDAPI_(HPALETTE) OleStdCreateStandardPalette(void)
+ {
+ HDC hdc;
+ HPALETTE hpal;
+
+ hpal = (HPALETTE) NULL;
+ hdc = GetDC(NULL);
+ if (hdc != NULL && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
+ {
+ int cpeSysPal;
+ int cpeReserved;
+
+ cpeSysPal = GetDeviceCaps(hdc, SIZEPALETTE);
+ cpeReserved = GetDeviceCaps(hdc, NUMRESERVED);
+ if (cpeSysPal > cpeReserved)
+ {
+ int cpeReserved2;
+ unsigned char FAR* lpb;
+ PALETTEENTRY FAR* ppe;
+ PALETTEENTRY FAR* ppeMac;
+ LOGPAL logpal;
+
+ cpeReserved2 = cpeReserved/2;
+
+ // Get the system palette entries at the beginning and end.
+ GetSystemPaletteEntries(hdc, 0, cpeReserved2, logpal.rgpe);
+ GetSystemPaletteEntries(hdc, cpeSysPal - cpeReserved2, cpeReserved2,
+ &logpal.rgpe[cpeAppPal-cpeReserved2]);
+
+ logpal.cpe = cpeAppPal;
+ logpal.wVersion = 0x300;
+
+ lpb = (BYTE FAR *) &palSVGA[10];
+ ppe = (PALETTEENTRY FAR*)&logpal.rgpe[cpeReserved2];
+ ppeMac = (PALETTEENTRY FAR*)&logpal.rgpe[cpeAppPal-cpeReserved2];
+ while (ppe < ppeMac)
+ {
+ ppe->peFlags = PC_NOCOLLAPSE;
+ ppe->peRed = *lpb++;
+ ppe->peGreen = *lpb++;
+ ppe->peBlue = *lpb++;
+ ppe++;
+ }
+ hpal = CreatePalette((LOGPALETTE FAR *)&logpal);
+ }
+ }
+ ReleaseDC(NULL, hdc);
+ return hpal;
+ }
diff --git a/private/oleutest/letest/ole2ui/stdpal.h b/private/oleutest/letest/ole2ui/stdpal.h
new file mode 100644
index 000000000..59162ed78
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/stdpal.h
@@ -0,0 +1,292 @@
+/*-----------------------------------------------------------------------
+| stdpal.h
+|
+| Standard App Palette useful for OLE applications. v 1.01
+|
+| #include this file in the same file as HpalCreateAppPalette
+|
+| NOTE: Palette MUST be created with HpalCreateAppPalette
+|
+| Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+|
+-----------------------------------------------------------------------*/
+
+#include <commdlg.h> // needed for LPPRINTDLG
+#include <shellapi.h> // needed for HKEY
+
+#ifdef WIN32
+#define _based(A)
+#define _segname(A)
+#endif
+
+#ifndef CSCONST
+#ifdef FLAT
+#define CSCONST(type) type const
+#else
+#define CSCONST(type) type _based(_segname("_CODE")) const
+#endif
+#endif
+
+CSCONST(unsigned char) palSVGA[256][3] =
+ {
+ // R G B
+ {0x00, 0x00, 0x00}, // 0 Sys Black gray 0
+ {0x80, 0x00, 0x00}, // 1 Sys Dk Red
+ {0x00, 0x80, 0x00}, // 2 Sys Dk Green
+ {0x80, 0x80, 0x00}, // 3 Sys Dk Yellow
+ {0x00, 0x00, 0x80}, // 4 Sys Dk Blue
+ {0x80, 0x00, 0x80}, // 5 Sys Dk Violet
+ {0x00, 0x80, 0x80}, // 6 Sys Dk Cyan
+ {0xc0, 0xc0, 0xc0}, // 7 Sys Lt Grey gray 192
+ {0xc0, 0xdc, 0xc0}, // 8 Sys 8
+ {0xa6, 0xca, 0xf0}, // 9 Sys 9 (the first 10 are fixed by Windows)
+
+ {0x80, 0x00, 0x00}, // 10 Sys Dk Red repeat
+ {0x00, 0x80, 0x00}, // 11 Sys Dk Green repeat
+ {0x80, 0x80, 0x00}, // 12 Sys Dk Yellow repeat
+ {0x00, 0x00, 0x80}, // 13 Sys Dk Blue repeat
+ {0x80, 0x00, 0x80}, // 14 Sys Dk Violet repeat
+ {0x00, 0x80, 0x80}, // 15 Sys Dk Cyan repeat
+ {0x80, 0x80, 0x80}, // 16 Sys Dk Grey repeat gray 128
+ {0x80, 0x80, 0xff}, // 17 Excel Chart Fill 1
+ {0x80, 0x20, 0x60}, // 18 Excel Chart Fill 2
+ {0xff, 0xff, 0xc0}, // 19 Excel Chart Fill 3
+ {0xa0, 0xe0, 0xe0}, // 20 Excel Chart Fill 4
+ {0x60, 0x00, 0x80}, // 21 Excel Chart Fill 4
+ {0xff, 0x80, 0x80}, // 22 Excel Chart Fill 6
+ {0x00, 0x80, 0xc0}, // 23 Excel Chart Fill 7
+ {0xc0, 0xc0, 0xff}, // 24 Excel Chart Fill 8
+ {0x00, 0xcf, 0xff}, // 25 Excel clrt entry
+ {0x69, 0xff, 0xff}, // 26 Excel clrt entry
+ {0xe0, 0xff, 0xe0}, // 27 Excel clrt entry
+ {0xdd, 0x9c, 0xb3}, // 28 Excel clrt entry
+ {0xb3, 0x8f, 0xee}, // 29 Excel clrt entry
+ {0x2a, 0x6f, 0xf9}, // 30 Excel clrt entry
+ {0x3f, 0xb8, 0xcd}, // 31 Excel clrt entry
+ {0x48, 0x84, 0x36}, // 32 Excel clrt entry
+ {0x95, 0x8c, 0x41}, // 33 Excel clrt entry
+ {0x8e, 0x5e, 0x42}, // 34 Excel clrt entry
+ {0xa0, 0x62, 0x7a}, // 35 Excel clrt entry
+ {0x62, 0x4f, 0xac}, // 36 Excel clrt entry
+ {0x1d, 0x2f, 0xbe}, // 37 Excel clrt entry
+ {0x28, 0x66, 0x76}, // 38 Excel clrt entry
+ {0x00, 0x45, 0x00}, // 39 Excel clrt entry
+ {0x45, 0x3e, 0x01}, // 40 Excel clrt entry
+ {0x6a, 0x28, 0x13}, // 41 Excel clrt entry
+ {0x85, 0x39, 0x6a}, // 42 Excel clrt entry
+ {0x4a, 0x32, 0x85}, // 43 Excel clrt entry
+ {0x04, 0x04, 0x04}, // 44 gray 4
+ {0x08, 0x08, 0x08}, // 45 gray 8
+ {0x0c, 0x0c, 0x0c}, // 46 gray 12
+ {0x11, 0x11, 0x11}, // 47 gray 17
+ {0x16, 0x16, 0x16}, // 48 gray 22
+ {0x1c, 0x1c, 0x1c}, // 49 gray 28
+ {0x22, 0x22, 0x22}, // 50 gray 34
+ {0x29, 0x29, 0x29}, // 51 gray 41
+ {0x30, 0x30, 0x30}, // 52 gray 48
+ {0x5f, 0x5f, 0x5f}, // 53 swapped so inversions look good gray 95
+ {0x55, 0x55, 0x55}, // 54 swapped so inversions look good gray 85
+ {0x4d, 0x4d, 0x4d}, // 55 swapped so inversions look good gray 77
+ {0x42, 0x42, 0x42}, // 56 swapped so inversions look good gray 66
+ {0x39, 0x39, 0x39}, // 57 swapped so inversions look good gray 57
+ {0x00, 0x07, 0x00}, // 58
+ {0x0d, 0x00, 0x00}, // 59
+ {0xb7, 0x99, 0x81}, // 60
+ {0x84, 0x99, 0xb4}, // 61
+ {0xbd, 0xbd, 0x90}, // 62
+ {0x7f, 0x7f, 0x60}, // 63
+ {0x60, 0x60, 0x7f}, // 64
+ {0x00, 0x0e, 0x00}, // 65
+ {0x1b, 0x00, 0x00}, // 66
+ {0x28, 0x00, 0x00}, // 67
+ {0x08, 0x09, 0x2b}, // 68
+ {0x00, 0x1d, 0x00}, // 69
+ {0x39, 0x00, 0x00}, // 70
+ {0x00, 0x00, 0x9b}, // 71
+ {0x00, 0x25, 0x00}, // 72
+ {0x49, 0x00, 0x00}, // 73
+ {0x11, 0x11, 0x3b}, // 74
+ {0x00, 0x2f, 0x00}, // 75
+ {0x5d, 0x00, 0x00}, // 76
+ {0x17, 0x17, 0x45}, // 77
+ {0x00, 0x3a, 0x00}, // 78
+ {0x49, 0x11, 0x11}, // 79
+ {0x1c, 0x1c, 0x53}, // 80
+ {0x00, 0x16, 0xff}, // 81
+ {0x2b, 0x00, 0xff}, // 82
+ {0x21, 0x21, 0x6c}, // 83
+ {0x59, 0x14, 0x14}, // 84
+ {0x00, 0x51, 0x00}, // 85
+ {0x47, 0x1a, 0x6a}, // 86
+ {0x19, 0x32, 0x67}, // 87
+ {0x00, 0x61, 0x00}, // 88
+ {0x00, 0x31, 0xff}, // 89
+ {0x61, 0x00, 0xff}, // 90
+ {0x53, 0x20, 0x7b}, // 91
+ {0x16, 0x43, 0x67}, // 92
+ {0x2e, 0x2e, 0xe2}, // 93
+ {0x26, 0x59, 0x16}, // 94
+ {0x51, 0x46, 0x04}, // 95
+ {0x68, 0x2e, 0x49}, // 96
+ {0x07, 0x52, 0x8f}, // 97
+ {0x6a, 0x18, 0xb8}, // 98
+ {0x90, 0x23, 0x15}, // 99
+ {0x00, 0x53, 0xff}, // 100
+ {0xa3, 0x00, 0xff}, // 101
+ {0x6a, 0x4a, 0x12}, // 102
+ {0x75, 0x33, 0x6c}, // 103
+ {0x4a, 0x41, 0x9a}, // 104
+ {0x37, 0x65, 0x0b}, // 105
+ {0xa4, 0x2c, 0x15}, // 106
+ {0x83, 0x1f, 0xb1}, // 107
+ {0x4e, 0x2c, 0xff}, // 108
+ {0x20, 0x51, 0xb6}, // 109
+ {0x08, 0x64, 0x92}, // 110
+ {0x6f, 0x56, 0x0b}, // 111
+ {0x59, 0x43, 0xad}, // 112
+ {0x36, 0x72, 0x12}, // 113
+ {0xb0, 0x33, 0x17}, // 114
+ {0x00, 0xa1, 0x00}, // 115
+ {0x77, 0x5f, 0x1f}, // 116
+ {0x89, 0x47, 0x71}, // 117
+ {0xb0, 0x43, 0x1c}, // 118
+ {0xb7, 0x2d, 0x7d}, // 119
+ {0x00, 0x86, 0x95}, // 120
+ {0x7a, 0x6e, 0x23}, // 121
+ {0x26, 0x9f, 0x00}, // 122
+ {0x73, 0xa9, 0x01}, // 123
+ {0x00, 0x00, 0x00}, // 124 free 0 gray 0
+ {0x00, 0x00, 0x00}, // 125 free 2 gray 0
+ {0x00, 0x00, 0x00}, // 126 free 4 gray 0
+ {0x00, 0x00, 0x00}, // 127 free 6 gray 0
+ {0x00, 0x00, 0x00}, // 128 free 7 gray 0
+ {0x00, 0x00, 0x00}, // 129 free 5 gray 0
+ {0x00, 0x00, 0x00}, // 130 free 3 gray 0
+ {0x00, 0x00, 0x00}, // 131 free 1 gray 0
+ {0x00, 0xca, 0x00}, // 132
+ {0xac, 0x5b, 0x01}, // 133
+ {0x20, 0x1d, 0xc2}, // 134
+ {0x94, 0x52, 0x70}, // 135
+ {0x24, 0xaa, 0x4c}, // 136
+ {0x0a, 0x94, 0x89}, // 137
+ {0x36, 0x6e, 0x7b}, // 138
+ {0x44, 0x75, 0x90}, // 139
+ {0xff, 0x00, 0xa8}, // 140
+ {0x00, 0x71, 0xff}, // 141
+ {0xdf, 0x00, 0xff}, // 142
+ {0x56, 0x91, 0x4a}, // 143
+ {0x34, 0x48, 0xf8}, // 144
+ {0xcc, 0x32, 0x82}, // 145
+ {0xe4, 0x41, 0x70}, // 146
+ {0x68, 0xca, 0x01}, // 147
+ {0x36, 0xbc, 0x42}, // 148
+ {0x00, 0x9a, 0xff}, // 149
+ {0x96, 0x22, 0xb7}, // 150
+ {0x85, 0x7d, 0x33}, // 151
+ {0x25, 0xb7, 0x8c}, // 152
+ {0x36, 0x5a, 0xed}, // 153
+ {0x5c, 0xff, 0x00}, // 154
+ {0xff, 0x48, 0x00}, // 155
+ {0x22, 0x9b, 0xa2}, // 156
+ {0x42, 0xcf, 0x4d}, // 157
+ {0xc2, 0x58, 0x52}, // 158
+ {0x20, 0xd3, 0x95}, // 159
+ {0xa5, 0x24, 0xe0}, // 160
+ {0x73, 0x56, 0xb5}, // 161
+ {0xa9, 0xa9, 0x00}, // 162
+ {0xd0, 0x6f, 0x3c}, // 163
+ {0x67, 0x9f, 0x58}, // 164
+ {0x89, 0xcf, 0x0b}, // 165
+ {0xff, 0xac, 0x00}, // 166
+ {0xa7, 0x2e, 0xfe}, // 167
+ {0xe2, 0x59, 0x7f}, // 168
+ {0x4c, 0xdc, 0x67}, // 169
+ {0xff, 0x18, 0xff}, // 170
+ {0x3a, 0x7d, 0xff}, // 171
+ {0xb1, 0xd0, 0x18}, // 172
+ {0xc7, 0xff, 0x00}, // 173
+ {0xff, 0xe2, 0x00}, // 174
+ {0xdf, 0x9a, 0x3d}, // 175
+ {0x56, 0x81, 0x9f}, // 176
+ {0xc6, 0x43, 0xba}, // 177
+ {0xaf, 0x71, 0x8b}, // 178
+ {0x38, 0xa2, 0xc9}, // 179
+ {0xd1, 0x53, 0xce}, // 180
+ {0xff, 0x9a, 0x65}, // 181
+ {0x46, 0xca, 0xdb}, // 182
+ {0xff, 0x4d, 0xff}, // 183
+ {0xc8, 0xe9, 0x6a}, // 184
+ {0x4c, 0xde, 0xe0}, // 185
+ {0xff, 0x98, 0xff}, // 186
+ {0xdf, 0xc0, 0x82}, // 187
+ {0xe9, 0xec, 0xa5}, // 188
+ {0xf5, 0xf6, 0xcd}, // 189
+ {0xff, 0xd0, 0xff}, // 190
+ {0xb1, 0xac, 0x5a}, // 191
+ {0x63, 0x91, 0xae}, // 192
+ {0x22, 0x4c, 0x65}, // 193
+ {0x8d, 0x4e, 0x3f}, // 194
+ {0x50, 0x70, 0x70}, // 195
+ {0xd0, 0xff, 0xff}, // 196
+ {0xff, 0xe7, 0xff}, // 197
+ {0x69, 0x69, 0x69}, // 198 gray 105
+ {0x77, 0x77, 0x77}, // 199 gray 119
+ {0x86, 0x86, 0x86}, // 200 gray 134
+ {0x96, 0x96, 0x96}, // 201 gray 150
+ {0x9d, 0x9d, 0x9d}, // 202 gray 157
+ {0xa4, 0xa4, 0xa4}, // 203 gray 164
+ {0xb2, 0xb2, 0xb2}, // 204 gray 178
+ {0xcb, 0xcb, 0xcb}, // 205 gray 203
+ {0xd7, 0xd7, 0xd7}, // 206 gray 215
+ {0xdd, 0xdd, 0xdd}, // 207 gray 221
+ {0xe3, 0xe3, 0xe3}, // 208 gray 227
+ {0xea, 0xea, 0xea}, // 209 gray 234
+ {0xf1, 0xf1, 0xf1}, // 210 gray 241
+ {0xf8, 0xf8, 0xf8}, // 211 gray 248
+ {0xb2, 0xc1, 0x66}, // 212
+ {0x80, 0xbf, 0x78}, // 213
+ {0xc6, 0xf0, 0xf0}, // 214
+ {0xb2, 0xa4, 0xff}, // 215
+ {0xff, 0xb3, 0xff}, // 216
+ {0xd1, 0x8e, 0xa3}, // 217
+ {0xc3, 0xdc, 0x37}, // 218
+ {0xa0, 0x9e, 0x54}, // 219
+ {0x76, 0xae, 0x70}, // 220
+ {0x78, 0x9e, 0xc1}, // 221
+ {0x83, 0x64, 0xbf}, // 222
+ {0xa4, 0x83, 0xd3}, // 223
+ {0xd1, 0x3f, 0x32}, // 224
+ {0xff, 0x7d, 0x00}, // 225
+ {0x44, 0x78, 0x23}, // 226
+ {0x24, 0x5f, 0x60}, // 227
+ {0x0e, 0x0e, 0x2c}, // 228
+ {0xbe, 0x00, 0x00}, // 229
+ {0xff, 0x1f, 0x00}, // 230
+ {0x31, 0x39, 0x00}, // 231
+ {0xd9, 0x85, 0x3e}, // 232
+ {0x02, 0x77, 0x85}, // 233
+ {0xb0, 0xd8, 0x81}, // 234
+ {0x56, 0x21, 0x1d}, // 235
+ {0x00, 0x00, 0x30}, // 236
+ {0x88, 0xc8, 0xb3}, // 237
+ {0xa0, 0x79, 0x00}, // 238
+ {0xc0, 0xc0, 0xc0}, // 239 Sys Dk Grey repeat inversion gray 192
+ {0xea, 0x70, 0x81}, // 240
+ {0x51, 0xf1, 0x69}, // 241
+ {0xff, 0xff, 0x80}, // 242
+ {0x91, 0x74, 0xcd}, // 243
+ {0xff, 0x7c, 0xff}, // 244
+ {0xa2, 0xff, 0xff}, // 245
+
+ {0xff, 0xfb, 0xf0}, // 246 Sys Reserved
+ {0xa0, 0xa0, 0xa4}, // 247 Sys Reserved
+ {0x80, 0x80, 0x80}, // 248 Sys Lt Gray gray 128
+ {0xff, 0x00, 0x00}, // 249 Sys Red
+ {0x00, 0xff, 0x00}, // 250 Sys Green
+ {0xff, 0xff, 0x00}, // 251 Sys Yellow
+ {0x00, 0x00, 0xff}, // 252 Sys Blue
+ {0xff, 0x00, 0xff}, // 253 Sys Violet
+ {0x00, 0xff, 0xff}, // 254 Sys Cyan
+ {0xff, 0xff, 0xff} // 255 Sys White gray 255
+ };
+
diff --git a/private/oleutest/letest/ole2ui/strings.rc b/private/oleutest/letest/ole2ui/strings.rc
new file mode 100644
index 000000000..f3f8c415a
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/strings.rc
@@ -0,0 +1,124 @@
+/*
+ * STRINGS.RC
+ *
+ * strings for the OLE 2.0 UI Support Library.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#include "ole2ui.h"
+
+
+//Stringtable common for all dialogs.
+STRINGTABLE
+ BEGIN
+ IDS_FILTERS, "All Files (*.*)|*.*|"
+ IDS_ICONFILTERS, "Icon Files|*.exe;*.dll;*.ico|Programs (*.exe)|*.exe|Libraries (*.dll)|Icons (*.ico)|All Files (*.*)|*.*|"
+ END
+
+// browse dialog
+STRINGTABLE
+ BEGIN
+ IDS_BROWSE "Browse"
+ END
+
+
+//Insert Object stringtable.
+STRINGTABLE
+ BEGIN
+ IDS_IORESULTNEW, "Inserts a new %s object into your document."
+ IDS_IORESULTNEWICON, "Inserts a new %s object into your document. It will be displayed as an icon."
+ IDS_IORESULTFROMFILE1, "Inserts the contents of the file as an object into your document so that you may activate it using the "
+ IDS_IORESULTFROMFILE2, "application which created it."
+ IDS_IORESULTFROMFILEICON2, "application which created it. It will be displayed as an icon."
+ IDS_IORESULTLINKFILE1, "Inserts a picture of the file contents into your document. The picture will be linked to "
+ IDS_IORESULTLINKFILE2, "the file so that changes to the file will be reflected in your document."
+ IDS_IORESULTLINKFILEICON1, "Inserts an icon into your document which represents the file. The icon will be linked to "
+ IDS_IORESULTLINKFILEICON2, "the file so that changes to the file will be reflected in your document."
+ END
+
+//Change Icon stringtable
+STRINGTABLE
+ BEGIN
+ IDS_CINOICONSINFILE, "There are no icons in %s."
+ IDS_CIINVALIDFILE, "File %s does not exist."
+ IDS_CIFILEACCESS, "Unable to open file %s. Access denied."
+ IDS_CIFILESHARE, "Unable to open file %s. Sharing violation."
+ IDS_CIFILEOPENFAIL, "Unable to open file %s. General failure."
+ END
+
+// Convert stringtable.
+STRINGTABLE
+ BEGIN
+ IDS_CVRESULTCONVERTLINK, "A linked object must be converted at the source."
+ IDS_CVRESULTCONVERTTO, "Permanently changes the selected %s object to a %s object."
+ IDS_CVRESULTNOCHANGE, "The selected %s object will not be converted."
+ IDS_CVRESULTDISPLAYASICON, " It will be displayed as an icon."
+ IDS_CVRESULTACTIVATEAS, "Every %s object will be activated as a %s object"
+ IDS_CVRESULTACTIVATEDIFF, ", but it will not be converted."
+ END
+
+//Paste Special stringtable
+STRINGTABLE
+ BEGIN
+ IDS_PSPASTEDATA, "Inserts the contents of the Clipboard into your document as %s."
+ IDS_PSPASTEOBJECT, "Inserts the contents of the Clipboard into your document so that you may activate it using %s."
+ IDS_PSPASTEOBJECTASICON, "Inserts the contents of the Clipboard into your document so that you may activate it using %s. It will be displayed as an icon."
+ IDS_PSPASTELINKDATA, "Inserts the contents of the Clipboard into your document as %s. Paste Link creates a link to the source file so that changes to the source file will be reflected in your document."
+ IDS_PSPASTELINKOBJECT, "Inserts a picture of the Clipboard contents into your document. Paste Link creates a link to the source file so that changes to the source file will be reflected in your document."
+ IDS_PSPASTELINKOBJECTASICON, "Inserts an icon into your document which represents the Clipboard contents. Paste Link creates a link to the source file so that changes to the source file will be reflected in your document."
+ IDS_PSNONOLE, "Inserts the contents of the Clipboard into your document."
+ IDS_PSUNKNOWNTYPE, "Unknown Type"
+ IDS_PSUNKNOWNSRC, "Unknown Source"
+ IDS_PSUNKNOWNAPP, "the application which created it"
+ END
+
+// Busy/Blocked dialog stringtable
+STRINGTABLE
+ BEGIN
+ IDS_BZRESULTTEXTBUSY "This action cannot be completed because the %s application (%s) is busy. Choose ""Switch To"" to activate %s and correct the problem."
+ IDS_BZRESULTTEXTNOTRESPONDING "This action cannot be completed because the %s application (%s) is not responding. Choose ""Switch To"" to activate %s and correct the problem."
+ END
+
+// OLESTD stringtable
+STRINGTABLE
+ BEGIN
+ IDS_OLESTDNOCREATEFILE, "Could not create file!"
+ IDS_OLESTDNOOPENFILE, "Could not open file!"
+ IDS_OLESTDDISKFULL, "Disk full--unable to complete save operation"
+ END
+
+// OLE2UI stringtable
+STRINGTABLE
+ BEGIN
+ IDS_OLE2UIEDITNOOBJCMD, "&Object"
+ IDS_OLE2UIEDITLINKCMD_1VERB, "0%s Linked %s &Object"
+ IDS_OLE2UIEDITOBJECTCMD_1VERB, "0%s %s &Object"
+ IDS_OLE2UIEDITLINKCMD_NVERB, "Linked %s &Object"
+ IDS_OLE2UIEDITOBJECTCMD_NVERB, "%s &Object"
+ IDS_OLE2UIUNKNOWN, "Unknown"
+ IDS_OLE2UILINK, "Link"
+ IDS_OLE2UIOBJECT, "Object"
+ IDS_OLE2UIEDIT, "&Edit"
+ IDS_OLE2UICONVERT, "&Convert..."
+ IDS_DEFICONLABEL, "Document"
+ IDS_OLE2UIPASTELINKEDTYPE, "Linked %s"
+ END
+
+// LINKS stringtable
+STRINGTABLE
+ BEGIN
+ IDS_LINK_AUTO "Automatic"
+ IDS_LINK_MANUAL "Manual"
+ IDS_LINK_UNKNOWN "Unavail"
+ IDS_LINKS "Links"
+ IDS_FAILED "Operation failed!"
+ IDS_CHANGESOURCE "Change Source"
+ IDS_INVALIDSOURCE "Invalid Source : Do you want to correct it?"
+ IDS_CHANGEADDITIONALLINKS "The selected link has been changed.\nThis document contains additional links to\n%s.\n\nChange additional links?"
+ IDS_ERR_GETLINKSOURCE "Fail to get source of the link!"
+ IDS_ERR_GETLINKUPDATEOPTIONS "Fail to get update option of the link!"
+ IDS_ERR_ADDSTRING "Fail to add item to ListBox!"
+ IDS_CLOSE "Close"
+ END
diff --git a/private/oleutest/letest/ole2ui/suminfo.cpp b/private/oleutest/letest/ole2ui/suminfo.cpp
new file mode 100644
index 000000000..528fe2540
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/suminfo.cpp
@@ -0,0 +1,1371 @@
+/*************************************************************************
+**
+** OLE 2.0 Property Set Utilities
+**
+** suminfo.cpp
+**
+** This file contains functions that are useful for the manipulation
+** of OLE 2.0 Property Sets particularly to manage the Summary Info
+** property set.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+// Note: this file is designed to be stand-alone; it includes a
+// carefully chosen, minimal set of headers.
+//
+// For conditional compilation we use the ole2 conventions,
+// _MAC = mac
+// WIN32 = Win32 (NT really)
+// <nothing> = defaults to Win16
+
+// REVIEW: the following needs to modified to handle _MAC
+#define STRICT
+#ifndef INC_OLE2
+ #define INC_OLE2
+#endif
+
+#include <windows.h>
+#include <string.h>
+#include <ole2.h>
+#include "ole2ui.h"
+
+OLEDBGDATA
+
+/* A LPSUMINFO variable is a pointer to an instance of an abstract data
+** type. There can be an arbitrary number of SummaryInfo streams open
+** simultaneously (subject to available memory); each must have its
+** own LPSUMINFO instance. Each LPSUMINFO instance must
+** be initialized prior to use by calling Init and freed after its
+** last use by calling Free. The param argument to Init is reserved
+** for future expansion and should be zero initially. Once a LPSUMINFO
+** instance is allocated (by Init), the user can call the Set
+** procedures to initialize fields. A copy of the arguments is made
+** in every case except SetThumbnail where control of the storage
+** occupied by the METAFILEPICT is merely transferred. When the
+** Free routine is called, all storage will be deallocated including
+** that of the thumbnail. The arguments to SetThumbNail and the
+** return values from GetThumbNail correspond to the OLE2.0 spec.
+** Note that on input, the thumbnail is read on demand but all the
+** other properties are pre-loaded. The thumbnail is manipulated as
+** a windows handle to a METAFILEPICT structure, which in turn
+** contains a handle to the METAFILE. The transferClip argument on
+** GetThumbNail, when set to true, transfers responsibility for
+** storage management of the thumbnail to the caller; that is, after
+** Free has been called, the handle is still valid. Clear can be
+** used to free storage for all the properties but then you must
+** call Read to load them again. All the code is based on FAR
+** pointers.
+** CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.
+** Memory is allocated using the currently active IMalloc*
+** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
+**
+** Common scenarios:
+** Read SummaryInfo
+** ----------------
+** OleStdInitSummaryInfo()
+** OleStdReadSummaryInfo()
+** . . . . .
+** call different Get routines
+** . . . . .
+** OleStdFreeSummaryInfo()
+**
+** Create SummaryInfo
+** ------------------
+** OleStdInitSummaryInfo()
+** call different Set routines
+** OleStdWriteSummaryInfo()
+** OleStdFreeSummaryInfo()
+**
+** Update SummaryInfo
+** ------------------
+** OleStdInitSummaryInfo()
+** OleStdReadSummaryInfo()
+** OleStdGetThumbNailProperty(necessary only if no SetThumb)
+** call different Set routines
+** OleStdWriteSummaryInfo()
+** OleStdFreeSummaryInfo()
+*/
+
+#ifdef WIN32
+#define CHAR TCHAR
+#else
+#define CHAR unsigned char
+#endif
+#define fTrue 1
+#define fFalse 0
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned long
+#define LPVOID void FAR *
+#define uchar unsigned char
+#define ulong unsigned long
+#define BOOL unsigned char
+#define BF unsigned int
+
+#include "suminfo.h"
+#include "wn_dos.h"
+
+#if defined( _DEBUG )
+ #ifndef NOASSERT
+ // following is from compobj.dll (ole2)
+ #ifdef UNICODE
+ #define ASSERT(x) (!(x) ? FnAssert(TEXT(#x), NULL, \
+ TEXT(__FILE__), __LINE__) : 0)
+ #else
+ #define ASSERT(x) (!(x) ? \
+ { \
+ WCHAR wsz[255]; \
+ wcscpy(wsz, (#x)); \
+ FnAssert(wsz, NULL, TEXT(__FILE__), __LINE__) \
+ } \
+ : 0)
+ #endif
+ #else
+ #define ASSERT(x)
+ #endif
+#else
+#define ASSERT(x)
+#endif
+
+
+typedef struct _RSUMINFO
+ {
+ WORD byteOrder;
+ WORD formatVersion;
+ WORD getOSVersion;
+ WORD osVersion;
+ CLSID classId; //from compobj.h
+ DWORD cSections;
+ PROPSETLIST rgPropSet[1/*cSections*/]; //one section in standard summary info
+ STANDARDSECINMEM section;
+ ULONG fileOffset; //offset for thumbnail to support demand read
+ } RSUMINFO;
+
+typedef RSUMINFO FAR * LPRSI;
+
+ typedef union _foo{
+ ULARGE_INTEGER uli;
+ struct {
+ DWORD dw;
+ DWORD dwh;
+ };
+ struct {
+ WORD w0;
+ WORD w1;
+ WORD w2;
+ WORD w3;
+ };
+ } Foo;
+
+
+
+/* MemAlloc
+** ---------
+** allocate memory using the currently active IMalloc* allocator
+*/
+static LPVOID MemAlloc(ULONG ulSize)
+{
+ LPVOID pout;
+ LPMALLOC pmalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
+ OleDbgAssert(pmalloc);
+ return NULL;
+ }
+
+ pout = (LPVOID)pmalloc->Alloc(ulSize);
+
+ if (pmalloc != NULL) {
+ ULONG refs = pmalloc->Release();
+ }
+
+ return pout;
+}
+
+
+/* MemFree
+** -------
+** free memory using the currently active IMalloc* allocator
+*/
+static void MemFree(LPVOID pmem)
+{
+ LPMALLOC pmalloc;
+
+ if (pmem == NULL)
+ return;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
+ OleDbgAssert(pmalloc);
+ return;
+ }
+
+ pmalloc->Free(pmem);
+
+ if (pmalloc != NULL) {
+ ULONG refs = pmalloc->Release();
+ }
+}
+
+// Replace the first argument with the product of itself and the multiplier
+static void ulargeMultiply(ULARGE_INTEGER FAR *ul, USHORT m)
+{
+ Foo out, in;
+ in.uli = *ul;
+ out.dw = (ULONG)m * in.w0; in.w0 = out.w0;
+ out.dw = (ULONG)m * in.w1 + out.w1; in.w1 = out.w0;
+ out.dw = (ULONG)m * in.w2 + out.w1; in.w2 = out.w0;
+ out.dw = (ULONG)m * in.w3 + out.w1; in.w3 = out.w0;
+ *ul = in.uli;
+}
+
+// Replace the first argument with the product of itself and the multiplier
+static void ulargeDivide(ULARGE_INTEGER FAR *ul, USHORT m)
+{
+ Foo out, in;
+ DWORD i;
+ in.uli = *ul;
+ out.dwh = in.dwh/(ULONG)m;
+ i = in.dwh%(ULONG)m;
+ in.w2 = in.w1;
+ in.w3 = (WORD)i;
+ out.w1 = (WORD)(in.dwh/(ULONG)m);
+ in.w1 = (WORD)(in.dwh%(ULONG)m);
+ out.w0 = (WORD)(in.dw/(ULONG)m);
+ *ul = out.uli;
+}
+
+
+static void setStandard(LPRSI lprsi)
+{
+ int i;
+ lprsi->cSections = 1;
+ SetSumInfFMTID(&lprsi->rgPropSet[0].formatID);
+ _fmemcpy(&lprsi->classId, &lprsi->rgPropSet[0].formatID, sizeof(FMTID));
+ lprsi->rgPropSet[0].byteOffset = cbNewSummaryInfo(1);
+ for (i=0; i<cPID_STANDARD; i++)
+ lprsi->section.rgPropId[i].propertyID = PID_TITLE+i;
+ lprsi->section.cProperties = cPID_STANDARD; //always; do null test to check validity
+}
+
+extern "C" {
+
+/*************************************************************************
+**
+** OleStdInitSummaryInfo
+**
+** Purpose:
+** Initialize a Summary Info structure.
+**
+** Parameters:
+** int reserved - reserverd for future use. must be 0.
+**
+** Return Value:
+** LPSUMINFO
+**
+** Comments:
+** CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.
+** Memory is allocated using the currently active IMalloc*
+** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
+** Each LPSUMINFO instance must be initialized prior to use by
+** calling OleStdInitSummaryInfo. Once a LPSUMINFO instance is allocated
+** (by OleStdInitSummaryInfo), the user can call the Set procedures to
+** initialize fields.
+*************************************************************************/
+
+STDAPI_(LPSUMINFO) OleStdInitSummaryInfo(int reserved)
+{
+ LPRSI lprsi;
+
+ if ((lprsi = (LPRSI)MemAlloc(sizeof(RSUMINFO))) != NULL)
+ {
+ ClearSumInf(lprsi, sizeof(RSUMINFO));
+ } else return NULL;
+
+ setStandard(lprsi);
+ return (LPSUMINFO)lprsi;
+}
+
+
+/*************************************************************************
+**
+** OleStdFreeSummaryInfo
+**
+** Purpose:
+** Free a Summary Info structure.
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+**
+** Return Value:
+** void
+**
+** Comments:
+** Memory is freed using the currently active IMalloc*
+** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
+** Every LPSUMINFO struct must be freed after its last use.
+** When the OleStdFreeSummaryInfo routine is called, all storage will be
+** deallocated including that of the thumbnail (unless ownership of
+** the thumbnail has been transfered to the caller -- see
+** description of transferClip in GetThumbnail API).
+**
+*************************************************************************/
+
+STDAPI_(void) OleStdFreeSummaryInfo(LPSUMINFO FAR *lplp)
+{
+ if (lplp==NULL||*lplp==NULL) return;
+ OleStdClearSummaryInfo(*lplp);
+ MemFree(*lplp);
+ *lplp = NULL;
+}
+
+
+/*************************************************************************
+**
+** OleStdClearSummaryInfo
+**
+** Purpose:
+** Free storage (memory) for all the properties of the LPSUMINFO.
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+**
+** Return Value:
+** void
+**
+** Comments:
+** After calling OleStdClearSummaryInfo you must call OleStdReadSummaryInfo to
+** load them again.
+**
+*************************************************************************/
+
+STDAPI_(void) OleStdClearSummaryInfo(LPSUMINFO lp)
+{
+ OleStdSetStringProperty(lp, PID_TITLE, NULL);
+ OleStdSetStringProperty(lp, PID_SUBJECT, NULL);
+ OleStdSetStringProperty(lp, PID_AUTHOR, NULL);
+ OleStdSetStringProperty(lp, PID_KEYWORDS, NULL);
+ OleStdSetStringProperty(lp, PID_COMMENTS, NULL);
+ OleStdSetStringProperty(lp, PID_TEMPLATE, NULL);
+ OleStdSetStringProperty(lp, PID_REVNUMBER, NULL);
+ OleStdSetStringProperty(lp, PID_APPNAME, NULL);
+ OleStdSetThumbNailProperty(NULL, lp, VT_CF_EMPTY, 0, NULL, NULL, 0);
+ ClearSumInf((LPRSI)lp, sizeof(RSUMINFO));
+}
+
+
+/*************************************************************************
+**
+** OleStdReadSummaryInfo
+**
+** Purpose:
+** Read all Summary Info properties into memory (except thumbnail
+** which is demand loaded).
+**
+** Parameters:
+** LPSTREAM lps - open SummaryInfo IStream*
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+**
+** Return Value:
+** int - 1 for success
+** - 0 if error occurs
+** Comments:
+**
+*************************************************************************/
+
+STDAPI_(int) OleStdReadSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp)
+{
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ LPRSI lpSumInfo = (LPRSI)lp;
+ SCODE sc;
+ ULONG cbRead,i,sectionOffset;
+ LARGE_INTEGER a;
+ ULARGE_INTEGER b;
+ int j,k,l;
+ union {
+ RSUMINFO rsi;
+ STDZ stdz;
+ };
+ OleStdClearSummaryInfo(lp);
+ LISet32(a, 0);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ sectionOffset = cbNewSummaryInfo(1);
+ sc = GetScode(lpStream->Read(&rsi, sectionOffset, &cbRead));
+ if (FAILED(sc)||cbRead<sectionOffset) goto fail;
+ if (!FIntelOrder(&rsi)||rsi.formatVersion!=0) goto fail;
+ j = (int)rsi.cSections;
+ while (j-->0) {
+ if (FEqSumInfFMTID(&rsi.rgPropSet[0].formatID)) {
+ sectionOffset = rsi.rgPropSet[0].byteOffset;
+ break;
+ } else {
+ sc = GetScode(lpStream->Read(&rsi.rgPropSet[0].formatID, sizeof(PROPSETLIST), &cbRead));
+ if (FAILED(sc)||cbRead!=sizeof(PROPSETLIST)) goto fail;
+ }
+ if (j<=0) goto fail;
+ }
+
+ LISet32(a, sectionOffset);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ sc = GetScode(lpStream->Read(&rsi.section, cbNewSection(1), &cbRead));
+ if (FAILED(sc)||cbRead!=cbNewSection(1)) goto fail;
+ i = rsi.section.cBytes+sectionOffset;
+ j = (int)rsi.section.cProperties;
+ if (j>cPID_STANDARD) goto fail;
+ k = 0;
+ while (j-->0) {
+ k++;
+ switch (l=(int)rsi.section.rgPropId[0].propertyID) {
+ case PID_PAGECOUNT:
+ case PID_WORDCOUNT:
+ case PID_CHARCOUNT:
+ case PID_SECURITY:
+ if (l==PID_SECURITY) l=3; else l-=PID_PAGECOUNT;
+ cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
+ if (cbRead>=i) goto fail;
+ LISet32(a, cbRead);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ sc = GetScode(lpStream->Read(&lpSSIM->rgInts[l], sizeof(INTS), &cbRead));
+ if (FAILED(sc)||cbRead!=sizeof(INTS)) goto fail;
+ if (lpSSIM->rgInts[l].vtType==VT_EMPTY) break;
+ if (lpSSIM->rgInts[l].vtType!=VT_I4) goto fail;
+ break;
+ case PID_EDITTIME:
+ case PID_LASTPRINTED:
+ case PID_CREATE_DTM_RO:
+ case PID_LASTSAVE_DTM:
+ l-=PID_EDITTIME;
+ cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
+ if (cbRead>=i) goto fail;
+ LISet32(a, cbRead);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ sc = GetScode(lpStream->Read(&lpSSIM->rgTime[l], sizeof(TIME), &cbRead));
+ if (FAILED(sc)||cbRead!=sizeof(TIME)) goto fail;
+ if (lpSSIM->rgTime[l].vtType==VT_EMPTY) break;
+ if (lpSSIM->rgTime[l].vtType!=VT_FILETIME) goto fail;
+ break;
+ case PID_TITLE:
+ case PID_SUBJECT:
+ case PID_AUTHOR:
+ case PID_KEYWORDS:
+ case PID_COMMENTS:
+ case PID_TEMPLATE:
+ case PID_LASTAUTHOR:
+ case PID_REVNUMBER:
+ case PID_APPNAME:
+ cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
+ if (cbRead>=i) goto fail;
+ LISet32(a, cbRead);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ sc = GetScode(lpStream->Read(&stdz, sizeof(STDZ), &cbRead));
+ if (FAILED(sc)||cbRead<sizeof(DWORD)*2) goto fail;
+ if (stdz.vtType==VT_EMPTY||stdz.vtByteCount<=1) break;
+ if (stdz.vtType!=VT_LPSTR||stdz.vtByteCount>WORDMAX) goto fail;
+ stdz.rgchars[(int)stdz.vtByteCount-1] = TEXT('\0');
+ OleStdSetStringProperty(lp, (DWORD)l, (LPTSTR)&stdz.rgchars[0]);
+ break;
+ case PID_THUMBNAIL:
+ cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
+ if (cbRead>=i) goto fail;
+ LISet32(a, cbRead);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ lpSumInfo->fileOffset = cbRead+sizeof(DWORD)*3;
+ sc = GetScode(lpStream->Read(&lpSSIM->thumb, sizeof(DWORD)*4, &cbRead));
+ if (FAILED(sc)||cbRead!=sizeof(DWORD)*4) {
+ lpSSIM->thumb.vtType = VT_EMPTY;
+ goto fail;
+ }
+ if (lpSSIM->thumb.vtType == VT_EMPTY) {
+ lpSSIM->thumb.cBytes = 0;
+ break;
+ }
+ if (lpSSIM->thumb.vtType != VT_CF) {
+ lpSSIM->thumb.vtType = VT_EMPTY;
+ goto fail;
+ }
+ lpSSIM->thumb.cBytes -= sizeof(DWORD); //for selector
+ if (lpSSIM->thumb.selector==VT_CF_WIN||lpSSIM->thumb.selector==VT_CF_MAC) {
+ lpSumInfo->fileOffset += sizeof(DWORD);
+ lpSSIM->thumb.cBytes -= sizeof(DWORD); //for format val
+ }
+ break;
+ default: ;
+ }
+ if (j<=0)
+ {
+ // We should fail if the document is password-protected.
+ if(OleStdGetSecurityProperty(lp)==fSecurityPassworded)
+ goto fail;
+ return 1;
+ }
+ LISet32(a, sectionOffset+sizeof(DWORD)*2+k*sizeof(PROPIDLIST));
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) goto fail;
+ sc = GetScode(lpStream->Read(&rsi.section.rgPropId[0], sizeof(PROPIDLIST), &cbRead));
+ if (FAILED(sc)||cbRead!=sizeof(PROPIDLIST)) goto fail;
+ }
+
+fail:
+ OleStdClearSummaryInfo(lpSumInfo);
+
+ return 0;
+}
+
+
+/*************************************************************************
+**
+** OleStdWriteSummaryInfo
+**
+** Purpose:
+** Write all Summary Info properties to a IStream*
+**
+** Parameters:
+** LPSTREAM lps - open SummaryInfo IStream*
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+**
+** Return Value:
+** int - 1 for success
+** - 0 if error occurs
+** Comments:
+**
+*************************************************************************/
+
+STDAPI_(int) OleStdWriteSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp)
+{
+
+
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ // REVIEW: localization issues for propert sets
+ // do we need to include a code page and dictionary?
+
+ LPRSI lpSumInfo = (LPRSI)lp;
+ SCODE sc;
+ ULONG cbWritten;
+ ULONG cBytes, oBytes, k,l,m,n;
+ LARGE_INTEGER a;
+ ULARGE_INTEGER b;
+ CHAR FAR *lps;
+ LPMETAFILEPICT lpmfp;
+ int i,j,s;
+
+ setStandard(lpSumInfo);
+ oBytes = cbNewSection(cPID_STANDARD); //offsets are relative to the section
+ cBytes = cbNewSection(cPID_STANDARD)+(sizeof(TIME)*MAXTIME)+(sizeof(INTS)*MAXINTS);
+
+ lpSSIM->rgPropId[PID_EDITTIME-2].byteOffset = oBytes;
+ lpSSIM->rgPropId[PID_LASTPRINTED-2].byteOffset = oBytes+sizeof(TIME);
+ lpSSIM->rgPropId[PID_CREATE_DTM_RO-2].byteOffset = oBytes+sizeof(TIME)*2;
+ lpSSIM->rgPropId[PID_LASTSAVE_DTM-2].byteOffset = oBytes+sizeof(TIME)*3;
+
+ lpSSIM->rgPropId[PID_PAGECOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME);
+ lpSSIM->rgPropId[PID_WORDCOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS));
+ lpSSIM->rgPropId[PID_CHARCOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS)*2);
+ lpSSIM->rgPropId[PID_SECURITY-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS)*3);
+ oBytes += sizeof(TIME)*MAXTIME + sizeof(INTS)*MAXINTS;
+
+ lpSSIM->rgPropId[PID_THUMBNAIL-2].byteOffset = oBytes;
+ l = 0;
+ if (lpSSIM->thumb.vtType==VT_EMPTY) k = sizeof(DWORD);
+ else {
+ l = ((lpSSIM->thumb.cBytes+4-1)>>2)<<2;
+ if (lpSSIM->thumb.selector==VT_CF_BYTES) k = sizeof(DWORD)*3;
+ else if (lpSSIM->thumb.selector==VT_CF_FMTID) {k = sizeof(DWORD)*3; l += sizeof(FMTID); }
+ else if (lpSSIM->thumb.selector==VT_CF_NAME) {k = sizeof(DWORD)*3; l += (((*lpSSIM->thumb.lpstzName+1+3)>>2)<<2);}
+ else k = sizeof(DWORD)*4;
+ }
+ cBytes += k+l;
+ oBytes += k+l;
+
+ for (i=0; i<MAXSTDZ; i++) {
+ j = 0;
+ if (lpSSIM->rglpsz[i]!=NULL) {
+ j = lpSSIM->rglpsz[i]->VTCB+1/*null*/;
+ lpSSIM->rglpsz[i]->vtByteCount = j;
+ j = (((j+4-1)>>2)<<2)+sizeof(DWORD);
+ cBytes += j;
+ }
+ if (i!=MAXSTDZ-1) lpSSIM->rgPropId[i].byteOffset = oBytes;
+ else lpSSIM->rgPropId[PID_APPNAME-2].byteOffset = oBytes;
+ oBytes += j+sizeof(DWORD);
+ cBytes += sizeof(DWORD); //type
+ }
+ lpSSIM->cBytes = cBytes;
+
+
+ LISet32(a, 0);
+ sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) return 0;
+ sc = GetScode(lpStream->Write(lpSumInfo, cbNewSummaryInfo(1), &cbWritten));
+ if (FAILED(sc)||cbWritten!=cbNewSummaryInfo(1)) return 0;
+ sc = GetScode(lpStream->Write(lpSSIM, cbNewSection(cPID_STANDARD)+sizeof(TIME)*MAXTIME+sizeof(INTS)*MAXINTS, &cbWritten));
+ if (FAILED(sc)||cbWritten!=cbNewSection(cPID_STANDARD)+sizeof(TIME)*MAXTIME+sizeof(INTS)*MAXINTS) return 0;
+
+ m = lpSSIM->thumb.cBytes;
+ if (lpSSIM->thumb.lpstzName!=NULL) s = *lpSSIM->thumb.lpstzName;
+ else s = 0;
+ if (m!=0) {
+ lpSSIM->thumb.cBytes = (k-sizeof(DWORD)*2)+
+ (((lpSSIM->thumb.cBytes+4-1)>>2)<<2)+(((s+4-1)>>2)<<2);
+ n = lpSSIM->thumb.selector;
+ lps = lpSSIM->thumb.lpByte;
+ OleDbgAssert(lps!=NULL); //maybe a GetThumbNail here
+ OleDbgAssert(n!=VT_CF_NAME);
+ if (n==VT_CF_WIN) { //bytes are in global memory
+ lpmfp = (LPMETAFILEPICT)GlobalLock((HANDLE)(DWORD)lps);
+ if (lpmfp==NULL) goto fail;
+ lps = (CHAR FAR*)GlobalLock(lpmfp->hMF);
+ }
+ if (n==VT_CF_NAME) lpSSIM->thumb.selector = *lpSSIM->thumb.lpstzName+1/*null*/;
+ }
+ sc = GetScode(lpStream->Write(&lpSSIM->thumb, k, &cbWritten));
+ if (FAILED(sc)||cbWritten!=k) goto fail;
+ if (s!=0) {
+ k = ((s+1+4-1)>>2)<<2;
+ sc = GetScode(lpStream->Write(lpSSIM->thumb.lpstzName+1, k, &cbWritten));
+ if (FAILED(sc)||cbWritten!=k) goto fail;
+ }
+ if (m!=0) {
+ k = ((m+3)>>2)<<2;
+ if (n==VT_CF_WIN||VT_CF_NAME) { //bytes are in global memory
+ sc = GetScode(lpStream->Write(lpmfp, sizeof(METAFILEPICT), &cbWritten));
+ k -= sizeof(METAFILEPICT);
+ }
+ sc = GetScode(lpStream->Write(lps, k, &cbWritten));
+ if (FAILED(sc)||cbWritten!=k) goto fail;
+ if (n==VT_CF_WIN||VT_CF_NAME) { //bytes are in global memory
+ GlobalUnlock(lpmfp->hMF);
+ GlobalUnlock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
+ }
+ }
+ lpSSIM->thumb.cBytes = m; //restore in mem value
+ lpSSIM->thumb.selector = n;
+
+ k = VT_EMPTY;
+ for (i=0; i<MAXSTDZ; i++) {
+ if (lpSSIM->rglpsz[i]!=NULL) {
+ l = lpSSIM->rglpsz[i]->vtByteCount;
+ j = ((((int)l+4-1)/4)*4)+sizeof(DWORD)*2;
+ sc = GetScode(lpStream->Write(lpSSIM->rglpsz[i], j, &cbWritten));
+ if (FAILED(sc)||cbWritten!=(ULONG)j) return 0;
+ lpSSIM->rglpsz[i]->vtByteCount = 0; //restore stz count convention
+ lpSSIM->rglpsz[i]->VTCB = (int)l;
+ } else {
+ sc = GetScode(lpStream->Write(&k, sizeof(DWORD), &cbWritten));
+ if (FAILED(sc)||cbWritten!=sizeof(DWORD)) return 0;
+ }
+ }
+ return 1;
+fail:
+ lpSSIM->thumb.cBytes = m; //restore in mem value
+ lpSSIM->thumb.selector = n;
+ if (m!=0&&(n==VT_CF_WIN||VT_CF_NAME)) { //bytes are in global memory
+ GlobalUnlock((HANDLE)(DWORD)lps);
+ }
+
+ return 0;
+}
+
+
+/*************************************************************************
+**
+** OleStdGetSecurityProperty
+**
+** Purpose:
+** Retrieve the Security Property
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+**
+** Return Value:
+** DWORD - security level
+** AllSecurityFlagsEqNone 0 - no security
+** fSecurityPassworded 1 - password required
+** fSecurityRORecommended 2 - read-only is recommended
+** fSecurityRO 4 - read-only is required
+** fSecurityLockedForAnnotations 8 - locked for annotations
+**
+** Comments:
+** by noting the (suggested; that is, application-enforced) security
+** level on the document, an application other than the originator
+** of the document can adjust its user interface to the properties
+** appropriately. An application should not display any of the
+** information about a password protected document, and should not
+** allow modifications to enforced read-only or locked for
+** annotations documents. It should warn the user about read-only
+** recommended if the user attempts to modify properties.
+**
+*************************************************************************/
+
+STDAPI_(DWORD) OleStdGetSecurityProperty(LPSUMINFO lp)
+{
+STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ if (lpSSIM->rgInts[3].vtType == VT_I4) return lpSSIM->rgInts[3].value;
+
+ return 0;
+}
+
+
+/*************************************************************************
+**
+** OleStdSetSecurityProperty
+**
+** Purpose:
+** Set the Security Property
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD security - security level
+** AllSecurityFlagsEqNone 0 - no security
+** fSecurityPassworded 1 - password required
+** fSecurityRORecommended 2 - read-only is recommended
+** fSecurityRO 4 - read-only is required
+** fSecurityLockedForAnnotations 8 - locked for annotations
+**
+** Return Value:
+** int - 1 for success
+** - 0 if error occurs
+** (there are no errors)
+**
+** Comments:
+** by noting the (suggested; that is, application-enforced) security
+** level on the document, an application other than the originator
+** of the document can adjust its user interface to the properties
+** appropriately. An application should not display any of the
+** information about a password protected document, and should not
+** allow modifications to enforced read-only or locked for
+** annotations documents. It should warn the user about read-only
+** recommended if the user attempts to modify properties.
+**
+*************************************************************************/
+
+STDAPI_(int) OleStdSetSecurityProperty(LPSUMINFO lp, DWORD security)
+{
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+
+ // REVIEW: check valid transitions; how do we know APP called us?
+
+ if (security==0) {
+ lpSSIM->rgInts[3].vtType = VT_EMPTY;
+ return 1;
+ }
+ lpSSIM->rgInts[3].vtType = VT_I4;
+ lpSSIM->rgInts[3].value = security;
+ return 1;
+}
+
+
+/*************************************************************************
+**
+** OleStdGetStringProperty
+**
+** Purpose:
+** Retrieve a String Propety.
+** (returns zero terminated string -- C string)
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD pid - ID of String Property
+**
+** Return Value:
+** LPTSTR - value of String Property
+** (zero terminated string--C string)
+**
+** Comments:
+** String should NOT be freed by caller. Memory for string will be
+** freed when OleStdFreeSummaryInfo is called.
+*************************************************************************/
+
+STDAPI_(LPTSTR) OleStdGetStringProperty(LPSUMINFO lp, DWORD pid)
+{
+ LPTSTR l = OleStdGetStringZProperty(lp,pid);
+ if (l==NULL) return NULL; else return l+1;
+}
+
+
+/*************************************************************************
+**
+** OleStdSetStringProperty
+**
+** Purpose:
+** Set a String Propety
+** (takes zero terminated string -- C string)
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD pid - ID of String Property
+** LPTSTR lpsz - new value for String Property.
+** zero terminated string -- C string.
+** May be NULL, in which case the
+** propery is cleared.
+**
+** Return Value:
+** int - 1 if successful
+** - 0 invalid property id
+**
+** Comments:
+** The input string is copied.
+**
+*************************************************************************/
+
+STDAPI_(int) OleStdSetStringProperty(LPSUMINFO lp, DWORD pid, LPTSTR lpsz)
+{
+ LPRSI lprsi=(LPRSI)lp;
+ STANDARDSECINMEM FAR* lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ int i;
+ if (pid==PID_APPNAME) {
+ pid = MAXSTDZ-1;
+ } else if (pid<PID_TITLE || pid>PID_REVNUMBER) return 0; else pid -= 2;
+ OleDbgAssert(lpSSIM);
+ if (lpSSIM->rglpsz[pid]) MemFree(lpSSIM->rglpsz[pid]);
+ if ((lpsz==NULL)||(*lpsz==0)) {
+ lpSSIM->rglpsz[pid] = NULL;
+ return (1);
+ }
+ i = _fstrlen(lpsz);
+ lpSSIM->rglpsz[pid] = (STDZ FAR*)MemAlloc((i+1/*null*/)*sizeof(TCHAR)+
+ sizeof(DWORD)*2);
+ if (lpSSIM->rglpsz[pid]==NULL) return 0;
+ _fstrcpy((LPTSTR)&lpSSIM->rglpsz[pid]->rgchars, lpsz);
+ lpSSIM->rglpsz[pid]->vtType = VT_LPSTR;
+ lpSSIM->rglpsz[pid]->vtByteCount = 0;
+ lpSSIM->rglpsz[pid]->VTCB = i;
+ return (1);
+}
+
+
+/*************************************************************************
+**
+** OleStdGetStringZProperty
+**
+** Purpose:
+** Retrieve a String Propety.
+** (returns zero-terminated with leading byte count string)
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD pid - ID of Property
+**
+** Return Value:
+** LPSTZR - value of String Property
+** (zero-terminated with leading
+** byte count)
+**
+** Comments:
+** String should NOT be freed by caller. Memory for string will be
+** freed when OleStdFreeSummaryInfo is called.
+*************************************************************************/
+
+STDAPI_(LPSTZR) OleStdGetStringZProperty(LPSUMINFO lp, DWORD pid)
+{
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ if (pid==PID_APPNAME) {
+ pid = MAXSTDZ-1;
+ } else if (pid<PID_TITLE || pid>PID_REVNUMBER) return NULL; else pid -= 2;
+ if (lpSSIM->rglpsz[pid]!=NULL) {
+ return (LPTSTR)&lpSSIM->rglpsz[pid]->VTCB;
+ }
+ return NULL;
+}
+
+
+/*************************************************************************
+**
+** OleStdGetDocProperty
+**
+** Purpose:
+** Retrieve document properties (no. pages, no. words, no. characters)
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD FAR *nPage - (OUT) number of pages in document
+** DWORD FAR *nWords - (OUT) number of words in document
+** DWORD FAR *nChars - (OUT) number of charactrs in doc
+**
+** Return Value:
+** void
+**
+** Comments:
+**
+*************************************************************************/
+
+STDAPI_(void) OleStdGetDocProperty(
+ LPSUMINFO lp,
+ DWORD FAR* nPage,
+ DWORD FAR* nWords,
+ DWORD FAR* nChars
+)
+{
+STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ *nPage=0; *nWords=0; *nChars=0;
+ if (lpSSIM->rgInts[0].vtType == VT_I4) *nPage = lpSSIM->rgInts[0].value;
+ if (lpSSIM->rgInts[1].vtType == VT_I4) *nWords = lpSSIM->rgInts[1].value;
+ if (lpSSIM->rgInts[2].vtType == VT_I4) *nChars = lpSSIM->rgInts[2].value;
+}
+
+
+/*************************************************************************
+**
+** OleStdSetDocProperty
+**
+** Purpose:
+** Set document properties (no. pages, no. words, no. characters)
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD nPage - number of pages in document
+** DWORD nWords - number of words in document
+** DWORD nChars - number of charactrs in doc
+**
+** Return Value:
+** int - 1 for success
+** - 0 if error occurs
+** (there are no errors)
+**
+** Comments:
+**
+*************************************************************************/
+
+STDAPI_(int) OleStdSetDocProperty(
+ LPSUMINFO lp,
+ DWORD nPage,
+ DWORD nWords,
+ DWORD nChars
+)
+{
+DWORD vttype=VT_I4;
+STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ if ((nPage|nWords|nChars)==0) {
+ vttype = VT_EMPTY;
+ nPage=0; nWords=0; nChars=0;
+ }
+ lpSSIM->rgInts[0].vtType = vttype;
+ lpSSIM->rgInts[1].vtType = vttype;
+ lpSSIM->rgInts[2].vtType = vttype;
+ lpSSIM->rgInts[0].value = nPage;
+ lpSSIM->rgInts[1].value = nWords;
+ lpSSIM->rgInts[2].value = nChars;
+ return 1;
+}
+
+
+/*************************************************************************
+**
+** OleStdGetThumbNailProperty
+**
+** Purpose:
+** Retrieve a Thumbnail Property
+**
+** Parameters:
+** LPSTREAM lps
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD FAR* clipFormatNo - clipboard format for thumbnail
+** (type of value depends on vtcf
+** return value.)
+** NOTE: ONLY VT_CF_WIN is
+** implemented, so clipFormatNo
+** will be CF_METAFILEPICT
+** LPTSTR FAR* lpszName - format name if VT_CF_NAME is
+** returned
+** NOTE: NOT IMPLEMENTED
+** THUMBNAIL FAR* clip - handle to thumbnail
+** for VT_CF_WIN clip will be
+** handle to MetafilePict
+** NOTE: only VT_CF_WIN IMPLEMENTED
+** DWORD FAR* byteCount - size of thumbnail stream
+** for VT_CF_WIN case this should
+** be combined size of both the
+** Metafile as well as the
+** MetafilePict structure.
+** BOOL transferClip - transfer ownership of thumbnail
+** to caller. (see comment)
+**
+** Return Value:
+** int vtcfNo - OLE thumbnail selector value
+** VT_CF_WIN - Windows thumbnail
+** (interpret clipFormatNo as
+** Windows clipboard format)
+** VT_CF_FMTID - (NOT IMPLEMENTED)
+** thumbnail format is specified
+** by ID. use clipFormatNo.
+** (but NOT a Windows format ID)
+**
+** VT_CF_NAME - (NOT IMPLEMENTED)
+** thumbnail format is specified
+** by name. use lpszName.
+** VT_CF_EMPTY - blank thumbnail
+** (clip will be NULL)
+** VT_CF_OOM - Memory allocation failure
+**
+** Comments:
+** NOTE: Currently there is only proper support for VT_CF_WIN.
+** OleStdSetThumbNailProperty does implement VT_CF_FMTID and VT_CF_NAME,
+** however, OleStdGetThumbNailProperty, OleStdReadSummaryInfo and
+** OleStdWriteSummaryInfo only support VT_CF_WIN.
+**
+** Note that on input, the thumbnail is read on demand while all the
+** other properties are pre-loaded. The thumbnail is manipulated as
+** a windows handle to a METAFILEPICT structure, which in turn
+** contains a handle to the METAFILE. The transferClip argument on
+** GetThumbNail, when set to true, transfers responsibility for
+** storage management of the thumbnail to the caller; that is, after
+** OleStdFreeSummaryInfo has been called, the handle is still valid.
+*************************************************************************/
+
+STDAPI_(int) OleStdGetThumbNailProperty(
+ LPSTREAM lps,
+ LPSUMINFO lp,
+ DWORD FAR* clipFormatNo,
+ LPTSTR FAR* lpszName,
+ THUMBNAIL FAR* clip,
+ DWORD FAR* byteCount,
+ BOOL transferClip
+)
+{
+ int i;
+ LPRSI lprsi=(LPRSI)lp;
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ ULONG cbRead, cbToRead;
+ LARGE_INTEGER a;
+ ULARGE_INTEGER b;
+ CHAR FAR *lpst;
+ LPMETAFILEPICT lpmfp;
+ HANDLE hst, hmfp;
+ SCODE sc;
+ *byteCount = 0;
+ if (lpSSIM->thumb.cBytes==0) return VT_CF_EMPTY;
+ if (lpSSIM->thumb.lpByte==NULL) {
+ LISet32(a, lprsi->fileOffset);
+ sc = GetScode(lps->Seek(a, STREAM_SEEK_SET, &b));
+ if (FAILED(sc)) return VT_CF_EMPTY;
+ i = (int) lpSSIM->thumb.selector;
+ if (i>0||i==VT_CF_FMTID) {
+ if (i>255) return VT_CF_EMPTY;
+ else if (i==VT_CF_FMTID) i = sizeof(FMTID);
+ else lpSSIM->thumb.selector = VT_CF_NAME;
+ cbToRead = ((i+3)>>2)<<2;
+ lpSSIM->thumb.lpstzName=(CHAR FAR*)MemAlloc(i+1/*n*/+1);
+ if (lpSSIM->thumb.lpstzName==NULL) return VT_CF_OOM;
+ sc = GetScode(lps->Read(lpSSIM->thumb.lpstzName+1, cbToRead, &cbRead));
+ if (FAILED(sc)||cbRead!=cbToRead) return VT_CF_EMPTY;
+ *lpSSIM->thumb.lpstzName = i;
+ *(lpSSIM->thumb.lpstzName+i) = 0;
+ lpSSIM->thumb.cBytes -= cbToRead+sizeof(DWORD);
+ }
+ i = (int) lpSSIM->thumb.selector;
+ cbToRead = lpSSIM->thumb.cBytes;
+ if (cbToRead>65535) return VT_CF_OOM;
+ OleDbgAssert(i!=VT_CF_NAME);
+ if (i==VT_CF_WIN) {
+ cbToRead -= sizeof(METAFILEPICT);
+ hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
+ if (hmfp==NULL) return VT_CF_OOM;
+ hst = GlobalAlloc(GMEM_MOVEABLE, cbToRead);
+ if (hst==NULL) {
+ GlobalFree(hmfp);
+ return VT_CF_OOM;
+ }
+ lpmfp = (LPMETAFILEPICT)GlobalLock(hmfp);
+ sc = GetScode(lps->Read(lpmfp, sizeof(METAFILEPICT), &cbRead));
+ if (FAILED(sc)||cbRead!=sizeof(METAFILEPICT)) {
+ GlobalUnlock(hmfp);
+ GlobalFree(hmfp);
+ GlobalFree(hst);
+ return VT_CF_EMPTY;
+ }
+ lpst = (CHAR FAR*)GlobalLock(hst);
+ lpmfp->hMF = (HMETAFILE)hst;
+ lpSSIM->thumb.lpByte = (CHAR FAR*)hmfp;
+ } else {
+ lpst =(CHAR FAR*)MemAlloc((int)cbToRead);
+ if (lpst==NULL) return VT_CF_OOM;
+ lpSSIM->thumb.lpByte = lpst;
+ }
+ sc = GetScode(lps->Read(lpst, cbToRead, &cbRead));
+ if (i==VT_CF_WIN) {
+ GlobalUnlock(hst);
+ GlobalUnlock(hmfp);
+ }
+ if (FAILED(sc)||cbRead!=cbToRead) {
+ if (i==VT_CF_WIN) {
+ GlobalFree(hst);
+ GlobalFree(hmfp);
+ } else MemFree(lpst);
+ lpSSIM->thumb.lpByte = NULL;
+ if ((i==VT_CF_NAME||i==VT_CF_FMTID)&&(lpSSIM->thumb.lpstzName!=NULL))
+ MemFree(lpSSIM->thumb.lpstzName);
+ return VT_CF_EMPTY;
+ }
+ }
+ *clipFormatNo = lpSSIM->thumb.clipFormat;
+ *byteCount = lpSSIM->thumb.cBytes;
+ if(lpszName!=NULL)
+ *lpszName = (TCHAR FAR*)lpSSIM->thumb.lpstzName+1;
+ *clip = (TCHAR FAR*)lpSSIM->thumb.lpByte;
+ if (transferClip) lpSSIM->thumb.lpByte=NULL;
+ return (int)lpSSIM->thumb.selector;
+}
+
+
+/*************************************************************************
+**
+** OleStdSetThumbNailProperty
+**
+** Purpose:
+** Set a Thumbnail Property
+**
+** Parameters:
+** LPSTREAM lps - open SummaryInfo IStream*
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** int vtcfNo - OLE thumbnail selector value
+** VT_CF_WIN - Windows thumbnail
+** (interpret clipFormatNo as
+** Windows clipboard format)
+** VT_CF_FMTID - thumbnail format is specified
+** by ID. use clipFormatNo.
+** (but NOT a Windows format ID)
+**
+** VT_CF_NAME - thumbnail format is specified
+** by name. use lpszName.
+** VT_CF_EMPTY - blank thumbnail
+** (clip will be NULL)
+**
+** DWORD FAR* clipFormatNo - clipboard format for thumbnail
+** used if vtcfNo is VT_CF_WIN or
+** VT_CF_FMTID. interpretation of
+** value depends on vtcfNo specified.
+** (normally vtcfNo==VT_CF_WIN and
+** clipFormatNo==CF_METAFILEPICT)
+** LPSTR FAR* lpszName - format name if vtcfNo is VT_CF_NAME
+** THUMBNAIL clip - handle to thumbnail
+** for VT_CF_WIN clip will be
+** handle to MetafilePict
+** DWORD FAR* byteCount - size of thumbnail stream
+** for VT_CF_WIN case this should
+** be combined size of both the
+** Metafile as well as the
+** MetafilePict structure.
+**
+** Return Value:
+** int - 1 for success
+** - 0 if error occurs
+**
+** Comments:
+** NOTE: Currently there is only proper support for VT_CF_WIN.
+** OleStdSetThumbNailProperty does implement VT_CF_FMTID and VT_CF_NAME,
+** however, OleStdGetThumbNailProperty, OleStdReadSummaryInfo and
+** OleStdWriteSummaryInfo only support VT_CF_WIN.
+**
+** This function copies lpszName but saves the "clip" handle passed.
+**
+** NOTE: overwriting or emptying frees space for clip and name.
+** The thumbnail is manipulated as a windows handle to a
+** METAFILEPICT structure, which in turn contains a handle to the
+** METAFILE.
+*************************************************************************/
+
+STDAPI_(int) OleStdSetThumbNailProperty(
+ LPSTREAM lps,
+ LPSUMINFO lp,
+ int vtcfNo,
+ DWORD clipFormatNo,
+ LPTSTR lpszName,
+ THUMBNAIL clip,
+ DWORD byteCount
+)
+{
+ int i;
+ LPRSI lprsi=(LPRSI)lp;
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ LPMETAFILEPICT lpmfp;
+ if (lpSSIM==NULL||vtcfNo>0||vtcfNo<VT_CF_EMPTY||(vtcfNo==VT_CF_NAME&&(lpszName==NULL||*lpszName==0))) {
+ return 0;
+ }
+ if (vtcfNo!=VT_CF_EMPTY&&(clip==0||byteCount==0)) return 0;
+ i = (int) lpSSIM->thumb.vtType;
+ if (i!=VT_EMPTY) {
+ i = (int) lpSSIM->thumb.selector;
+ OleDbgAssert(i!=VT_CF_NAME);
+ if (i==VT_CF_WIN) {
+ if (lpSSIM->thumb.lpByte!=NULL) {
+ lpmfp = (LPMETAFILEPICT)GlobalLock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
+ GlobalFree(lpmfp->hMF);
+ GlobalUnlock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
+ GlobalFree((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
+ }
+ } else {
+ MemFree(lpSSIM->thumb.lpByte);
+ }
+ if ((i==VT_CF_NAME||i==VT_CF_FMTID)&&(lpSSIM->thumb.lpstzName!=NULL))
+ MemFree(lpSSIM->thumb.lpstzName);
+ lpSSIM->thumb.lpstzName = NULL;
+ lpSSIM->thumb.lpByte = NULL;
+ }
+ if (vtcfNo==VT_CF_EMPTY) {
+ lpSSIM->thumb.vtType = VT_EMPTY;
+ lpSSIM->thumb.cBytes = 0;
+ } else {
+ lpSSIM->thumb.vtType = VT_CF;
+ lpSSIM->thumb.selector = vtcfNo;
+ lpSSIM->thumb.cBytes = byteCount;
+ lpSSIM->thumb.clipFormat = clipFormatNo;
+ lpSSIM->thumb.lpByte = (CHAR FAR*)clip; //just save the hnadle
+ if (vtcfNo==VT_CF_NAME||vtcfNo==VT_CF_FMTID) {
+ i = _fstrlen(lpszName);
+ if (vtcfNo==VT_CF_FMTID) OleDbgAssert(i*sizeof(TCHAR)==sizeof(FMTID));
+ lpSSIM->thumb.lpstzName =
+ (CHAR FAR*)MemAlloc((i+1/*n*/+1/*null*/)*sizeof(TCHAR));
+ if (lpSSIM->thumb.lpstzName==NULL) {
+ lpSSIM->thumb.vtType = VT_EMPTY;
+ return 0;
+ }
+ _fstrcpy((TCHAR FAR*)lpSSIM->thumb.lpstzName+1, lpszName);
+ *lpSSIM->thumb.lpstzName = i;
+ }
+ }
+ return 1;
+}
+
+
+/*************************************************************************
+**
+** OleStdGetDateProperty
+**
+** Purpose:
+** Retrieve Data Property
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD pid - ID of Property
+** int FAR *yr - (OUT) year
+** int FAR *mo - (OUT) month
+** int FAR *dy - (OUT) day
+** DWORD FAR *sc - (OUT) seconds
+**
+** Return Value:
+** void
+**
+** Comments:
+**
+*************************************************************************/
+
+STDAPI_(void) OleStdGetDateProperty(
+ LPSUMINFO lp,
+ DWORD pid,
+ int FAR* yr,
+ int FAR* mo,
+ int FAR* dy,
+ DWORD FAR* sc
+)
+{
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ SFFS sffs;
+ pid -= PID_EDITTIME;
+ *yr = 0; *mo = 0; *dy = 0; *sc = 0;
+ if (pid<0||pid>=MAXTIME) return;
+ if (lpSSIM->rgTime[pid].vtType == VT_FILETIME) {
+ if (pid==0) {
+ //convert from 100ns to seconds
+ ulargeDivide((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 10000);
+ ulargeDivide((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 1000);
+ pid = lpSSIM->rgTime[0].time.dwLowDateTime;
+ *sc = pid%((DWORD)60*60*24);
+ pid /= (DWORD)60*60*24;
+ *dy = (int)(pid%(DWORD)30);
+ pid /= (DWORD)30;
+ *mo = (int)(pid%(DWORD)12);
+ *yr = (int)(pid/(DWORD)12);
+ } else {
+ if (CoFileTimeToDosDateTime(&lpSSIM->rgTime[pid].time,
+ &sffs.dateVariable, &sffs.timeVariable)) {
+ *yr = sffs.yr+1980;
+ *mo = sffs.mon;
+ *dy = sffs.dom;
+ *sc = (DWORD)sffs.hr*3600+sffs.mint*60+sffs.sec*2;
+ }
+ }
+ }
+ return;
+}
+
+
+
+/*************************************************************************
+**
+** OleStdSetDateProperty
+**
+** Purpose:
+** Set Data Property
+**
+** Parameters:
+** LPSUMINFO FAR *lp - pointer to open Summary Info struct
+** DWORD pid - ID of Property
+** int yr - year
+** int mo - month
+** int dy - day
+** DWORD sc - seconds
+**
+** Return Value:
+** int - 1 for success
+** - 0 if error occurs
+**
+** Comments:
+** Use all zeros to clear.
+** The following is an example of valid input:
+** yr=1993 mo=1(Jan) dy=1(1st) hr=12(noon) mn=30 sc=23
+** for PID_EDITTIME property, the values are a zero-origin duration
+** of time.
+**
+*************************************************************************/
+
+STDAPI_(int) OleStdSetDateProperty(
+ LPSUMINFO lp,
+ DWORD pid,
+ int yr,
+ int mo,
+ int dy,
+ int hr,
+ int mn,
+ int sc
+)
+{
+ STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
+ SFFS sffs;
+ pid -= PID_EDITTIME;
+ if (pid<0||pid>=MAXTIME) return 0;
+ if ((yr|mo|dy|hr|mn|sc)==0) { //all must be zero
+ lpSSIM->rgTime[pid].vtType = VT_EMPTY;
+ return 1;
+ }
+ lpSSIM->rgTime[pid].vtType = VT_FILETIME;
+ if (pid==0) {
+ lpSSIM->rgTime[0].time.dwLowDateTime =
+ (((((DWORD)yr*365+mo*30)+dy)*24+hr)*60+mn)*60+sc;
+ lpSSIM->rgTime[0].time.dwHighDateTime = 0;
+ //10^7 nanoseconds/second
+ ulargeMultiply((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 10000);
+ //convert to units of 100 ns
+ ulargeMultiply((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 1000);
+ } else {
+ sffs.yr = max(yr-1980,0);
+ sffs.mon = mo;
+ sffs.dom = dy;
+ sffs.hr = hr;
+ sffs.mint= mn;
+ sffs.sec = sc/2; //dos is 2 second intervals
+ if (!CoDosDateTimeToFileTime(sffs.date, sffs.time,
+ &lpSSIM->rgTime[pid].time)) {
+ lpSSIM->rgTime[pid].vtType = VT_EMPTY;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+} //END C
diff --git a/private/oleutest/letest/ole2ui/suminfo.h b/private/oleutest/letest/ole2ui/suminfo.h
new file mode 100644
index 000000000..ef803ab65
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/suminfo.h
@@ -0,0 +1,331 @@
+/*************************************************************************
+**
+** OLE 2.0 Property Set Utilities
+**
+** suminfo.h
+**
+** This file contains file contains data structure defintions,
+** function prototypes, constants, etc. for OLE 2.0 Property Set
+** utilities used to manage the Summary Info property set.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#ifndef SUMINFO_H
+#define SUMINFO_H
+
+#include <ole2.h>
+
+/* A SUMINFO variable is an instance of an abstract data type. Thus,
+** there can be an arbitrary number of SummaryInfo streams open
+** simultaneously (subject to available memory). Each variable must
+** be initialized prior to use by calling Init and freed after its
+** last use by calling Free. The param argument to Init is reserved
+** for future expansion and should be zero initially. Once a SUMINFO
+** variable is allocated (by Init), the user can call the Set
+** procedures to initialize fields. A copy of the arguments is made
+** in every case except SetThumbnail where control of the storage
+** occupied by the METAFILEPICT is merely transferred. When the
+** Free routine is called, all storage will be deallocated including
+** that of the thumbnail. The arguments to SetThumbNail and the
+** return values from GetThumbNail correspond to the OLE2.0 spec.
+** Note that on input, the thumbnail is read on demand but all the
+** other properties are pre-loaded. The thumbnail is manipulated as
+** a windows handle to a METAFILEPICT structure, which in turn
+** contains a handle to the METAFILE. The transferClip argument on
+** GetThumbNail, when set to true, transfers responsibility for
+** storage management of the thumbnail to the caller; that is, after
+** Free has been called, the handle is still valid. Clear can be
+** used to free storage for all the properties but then you must
+** call Read to load them again. All the code is based on FAR
+** pointers.
+** CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.
+** Memory is allocated using the currently active IMalloc*
+** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
+**
+** Common scenarios:
+** Read SummaryInfo
+** ----------------
+** OleStdInitSummaryInfo()
+** OleStdReadSummaryInfo()
+** . . . . .
+** call different Get routines
+** . . . . .
+** OleStdFreeSummaryInfo()
+**
+** Create SummaryInfo
+** ------------------
+** OleStdInitSummaryInfo()
+** call different Set routines
+** OleStdWriteSummaryInfo()
+** OleStdFreeSummaryInfo()
+**
+** Update SummaryInfo
+** ------------------
+** OleStdInitSummaryInfo()
+** OleStdReadSummaryInfo()
+** OleStdGetThumbNailProperty(necessary only if no SetThumb)
+** call different Set routines
+** OleStdWriteSummaryInfo()
+** OleStdFreeSummaryInfo()
+*/
+
+#define WORDMAX 256 //current string max for APPS; 255 + null terminator
+
+
+typedef union {
+ short iVal; /* VT_I2 */
+ long lVal; /* VT_I4 */
+ float fltVal; /* VT_R4 */
+ double dblVal; /* VT_R8 */
+ DWORD bool; /* VT_BOOL */
+ SCODE scodeVal; /* VT_ERROR */
+ DWORD systimeVal; /* VT_SYSTIME */
+#ifdef UNICODE
+ TCHAR bstrVal[WORDMAX]; /* VT_BSTR */
+#else
+ unsigned char bstrVal[WORDMAX]; /* VT_BSTR */
+#endif
+ } VTUNION;
+
+#if 0
+typedef struct _FMTID
+ {
+ DWORD dword;
+ WORD words[2];
+ BYTE bytes[8];
+ } FMTID;
+#endif
+
+typedef struct _PROPSETLIST
+ {
+ FMTID formatID;
+ DWORD byteOffset;
+ } PROPSETLIST;
+
+typedef struct _PROPIDLIST
+ {
+ DWORD propertyID;
+ DWORD byteOffset;
+ } PROPIDLIST;
+
+typedef struct _PROPVALUE
+ {
+ DWORD vtType;
+ VTUNION vtValue;
+ } PROPVALUE;
+
+typedef struct _SECTION
+ {
+ DWORD cBytes;
+ DWORD cProperties;
+ PROPIDLIST rgPropId[1/*cProperties*/]; //variable-length array
+ PROPVALUE rgPropValue[1]; //CANNOT BE ACCESSED BY NAME; ONLY BY POINTER
+ } SECTION;
+
+typedef struct _SUMMARYINFO
+ {
+ WORD byteOrder;
+ WORD formatVersion;
+ WORD getOSVersion;
+ WORD osVersion;
+ CLSID classId; //from compobj.h
+ DWORD cSections;
+ PROPSETLIST rgPropSet[1/*cSections*/]; //variable-length array
+ SECTION rgSections[1/*cSections*/]; //CANNOT BE ACCESSED BY NAME; ONLY BY POINTER
+ } SUMMARYINFO;
+
+#define osWinOnDos 0
+#define osMac 1
+#define osWinNT 2
+
+#define PID_DICTIONARY 0X00000000
+#define PID_CODEPAGE 0X00000001
+#define PID_TITLE 0X00000002
+#define PID_SUBJECT 0X00000003
+#define PID_AUTHOR 0X00000004
+#define PID_KEYWORDS 0X00000005
+#define PID_COMMENTS 0X00000006
+#define PID_TEMPLATE 0X00000007
+#define PID_LASTAUTHOR 0X00000008
+#define PID_REVNUMBER 0X00000009
+#define PID_EDITTIME 0X0000000A
+#define PID_LASTPRINTED 0X0000000B
+#define PID_CREATE_DTM_RO 0X0000000C
+#define PID_LASTSAVE_DTM 0X0000000D
+#define PID_PAGECOUNT 0X0000000E
+#define PID_WORDCOUNT 0X0000000F
+#define PID_CHARCOUNT 0X00000010
+#define PID_THUMBNAIL 0X00000011
+#define PID_APPNAME 0X00000012
+#define PID_SECURITY 0X00000013
+#define cPID_STANDARD (PID_SECURITY+1-2)
+
+#define MAXWORD 256 //maximum string size for APPS at present
+
+typedef struct _STDZ
+ {
+ DWORD vtType;
+ union {
+ DWORD vtByteCount;
+#ifdef UNICODE
+ TCHAR fill[4]; //use last byte as byte count for stz requests
+#else
+ unsigned char fill[4]; //use last byte as byte count for stz requests
+#endif
+ };
+
+#ifdef UNICODE
+ TCHAR rgchars[MAXWORD];
+#else
+ unsigned char rgchars[MAXWORD];
+#endif
+ } STDZ;
+#define VTCB fill[3] //used to set/get the count byte when in memory
+
+typedef struct _THUMB
+ {
+ DWORD vtType;
+ DWORD cBytes; //clip size in memory
+ DWORD selector; //on disk -1,win clip no. -2,mac clip no. -3,ole FMTID 0,bytes nameLength, format name
+ DWORD clipFormat;
+ char FAR *lpstzName;
+ char FAR *lpByte;
+ } THUMB;
+
+#define VT_CF_BYTES 0
+#define VT_CF_WIN ((DWORD)(-1))
+#define VT_CF_MAC ((DWORD)(-2))
+#define VT_CF_FMTID ((DWORD)(-3))
+#define VT_CF_NAME ((DWORD)(-4))
+#define VT_CF_EMPTY ((DWORD)(-5))
+#define VT_CF_OOM ((DWORD)(-6)) // Out of memory
+typedef THUMB FAR *LPTHUMB;
+
+typedef STDZ FAR *LPSTDZ;
+
+typedef struct _TIME
+ {
+ DWORD vtType;
+ FILETIME time;
+ } TIME;
+
+typedef struct _INTS
+ {
+ DWORD vtType;
+ DWORD value;
+ } INTS;
+
+#define MAXTIME (PID_LASTSAVE_DTM-PID_EDITTIME+1)
+#define MAXINTS (PID_CHARCOUNT-PID_PAGECOUNT+1+1)
+#define MAXSTDZ (PID_REVNUMBER-PID_TITLE+1+1)
+
+typedef struct _STANDARDSECINMEM
+ {
+ DWORD cBytes;
+ DWORD cProperties;
+ PROPIDLIST rgPropId[cPID_STANDARD/*cProperties*/]; //variable-length array
+ TIME rgTime[MAXTIME];
+ INTS rgInts[MAXINTS];
+ LPSTDZ rglpsz[MAXSTDZ];
+ THUMB thumb;
+ } STANDARDSECINMEM;
+
+
+#define OFFSET_NIL 0X00000000
+
+#define AllSecurityFlagsEqNone 0
+#define fSecurityPassworded 1
+#define fSecurityRORecommended 2
+#define fSecurityRO 4
+#define fSecurityLockedForAnnotations 8
+
+#define PropStreamNamePrefixByte '\005'
+#define PropStreamName "\005SummaryInformation"
+#define cbNewSummaryInfo(nSection) (sizeof(SUMMARYINFO)-sizeof(SECTION)+sizeof(PROPSETLIST)*((nSection)-1))
+#define cbNewSection(nPropIds) (sizeof(SECTION)-sizeof(PROPVALUE)+sizeof(PROPIDLIST)*((nPropIds)-1))
+
+#define FIntelOrder(prop) ((prop)->byteOrder==0xfffe)
+#define SetOs(prop, os) {(prop)->osVersion=os; (prop)->getOSVersion=LOWORD(GetVersion());}
+#define SetSumInfFMTID(fmtId) {(fmtId)->Data1=0XF29F85E0; *(long FAR *)&(fmtId)->Data2=0X10684FF9;\
+ *(long FAR *)&(fmtId)->Data4[0]=0X000891AB; *(long FAR *)&(fmtId)->Data4[4]=0XD9B3272B;}
+#define FEqSumInfFMTID(fmtId) ((fmtId)->Data1==0XF29F85E0&&*((long FAR *)&(fmtId)->Data2)==0X10684FF9&&\
+ *((long FAR *)&(fmtId)->Data4[0])==0X000891AB&&*((long FAR *)&(fmtId)->Data4[4])==0XD9B3272B)
+#define FSzEqPropStreamName(sz) _fstricmp(sz, PropStreamName)
+#define ClearSumInf(lpsuminf, cb) {_fmemset(lpsuminf,0,cb); (lpsuminf)->byteOrder=0xfffe;\
+ SetOs(lpsuminf, osWinOnDos);}
+
+typedef void FAR *LPSUMINFO;
+typedef LPTSTR LPSTZR;
+typedef void FAR *THUMBNAIL; //for VT_CF_WIN this is an unlocked global handle
+#define API __far __pascal
+
+
+/*************************************************************************
+** Public Summary Info Property Set Management API
+*************************************************************************/
+
+extern "C" {
+STDAPI_(LPSUMINFO) OleStdInitSummaryInfo(int reserved);
+STDAPI_(void) OleStdFreeSummaryInfo(LPSUMINFO FAR *lplp);
+STDAPI_(void) OleStdClearSummaryInfo(LPSUMINFO lp);
+STDAPI_(int) OleStdReadSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp);
+STDAPI_(int) OleStdWriteSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp);
+STDAPI_(DWORD) OleStdGetSecurityProperty(LPSUMINFO lp);
+STDAPI_(int) OleStdSetSecurityProperty(LPSUMINFO lp, DWORD security);
+STDAPI_(LPTSTR) OleStdGetStringProperty(LPSUMINFO lp, DWORD pid);
+STDAPI_(int) OleStdSetStringProperty(LPSUMINFO lp, DWORD pid, LPTSTR lpsz);
+STDAPI_(LPSTZR) OleStdGetStringZProperty(LPSUMINFO lp, DWORD pid);
+STDAPI_(void) OleStdGetDocProperty(
+ LPSUMINFO lp,
+ DWORD FAR* nPage,
+ DWORD FAR* nWords,
+ DWORD FAR* nChars
+);
+STDAPI_(int) OleStdSetDocProperty(
+ LPSUMINFO lp,
+ DWORD nPage,
+ DWORD nWords,
+ DWORD nChars
+);
+STDAPI_(int) OleStdGetThumbNailProperty(
+ LPSTREAM lps,
+ LPSUMINFO lp,
+ DWORD FAR* clipFormatNo,
+ LPTSTR FAR* lpszName,
+ THUMBNAIL FAR* clip,
+ DWORD FAR* byteCount,
+ BOOL transferClip
+);
+STDAPI_(int) OleStdSetThumbNailProperty(
+ LPSTREAM lps,
+ LPSUMINFO lp,
+ int vtcfNo,
+ DWORD clipFormatNo,
+ LPTSTR lpszName,
+ THUMBNAIL clip,
+ DWORD byteCount
+);
+STDAPI_(void) OleStdGetDateProperty(
+ LPSUMINFO lp,
+ DWORD pid,
+ int FAR* yr,
+ int FAR* mo,
+ int FAR* dy,
+ DWORD FAR* sc
+);
+STDAPI_(int) OleStdSetDateProperty(
+ LPSUMINFO lp,
+ DWORD pid,
+ int yr,
+ int mo,
+ int dy,
+ int hr,
+ int mn,
+ int sc
+);
+
+} //END C
+
+#endif // SUMINFO_H
diff --git a/private/oleutest/letest/ole2ui/targtdev.c b/private/oleutest/letest/ole2ui/targtdev.c
new file mode 100644
index 000000000..55b6b0886
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/targtdev.c
@@ -0,0 +1,328 @@
+/*************************************************************************
+**
+** OLE 2 Standard Utilities
+**
+** olestd.c
+**
+** This file contains utilities that are useful for dealing with
+** target devices.
+**
+** (c) Copyright Microsoft Corp. 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#define STRICT 1
+#include "ole2ui.h"
+#ifndef WIN32
+#include <print.h>
+#endif
+
+/*
+ * OleStdCreateDC()
+ *
+ * Purpose:
+ *
+ * Parameters:
+ *
+ * Return Value:
+ * SCODE - S_OK if successful
+ */
+STDAPI_(HDC) OleStdCreateDC(DVTARGETDEVICE FAR* ptd)
+{
+ HDC hdc=NULL;
+ LPDEVNAMES lpDevNames;
+ LPDEVMODE lpDevMode;
+ LPTSTR lpszDriverName;
+ LPTSTR lpszDeviceName;
+ LPTSTR lpszPortName;
+
+ if (ptd == NULL) {
+ hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
+ goto errReturn;
+ }
+
+ lpDevNames = (LPDEVNAMES) ptd; // offset for size field
+
+ if (ptd->tdExtDevmodeOffset == 0) {
+ lpDevMode = NULL;
+ }else{
+ lpDevMode = (LPDEVMODE) ((LPSTR)ptd + ptd->tdExtDevmodeOffset);
+ }
+
+ lpszDriverName = (LPTSTR) lpDevNames + ptd->tdDriverNameOffset;
+ lpszDeviceName = (LPTSTR) lpDevNames + ptd->tdDeviceNameOffset;
+ lpszPortName = (LPTSTR) lpDevNames + ptd->tdPortNameOffset;
+
+ hdc = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);
+
+errReturn:
+ return hdc;
+}
+
+
+/*
+ * OleStdCreateIC()
+ *
+ * Purpose: Same as OleStdCreateDC, except that information context is
+ * created, rather than a whole device context. (CreateIC is
+ * used rather than CreateDC).
+ * OleStdDeleteDC is still used to delete the information context.
+ *
+ * Parameters:
+ *
+ * Return Value:
+ * SCODE - S_OK if successful
+ */
+STDAPI_(HDC) OleStdCreateIC(DVTARGETDEVICE FAR* ptd)
+{
+ HDC hdcIC=NULL;
+ LPDEVNAMES lpDevNames;
+ LPDEVMODE lpDevMode;
+ LPTSTR lpszDriverName;
+ LPTSTR lpszDeviceName;
+ LPTSTR lpszPortName;
+
+ if (ptd == NULL) {
+ hdcIC = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
+ goto errReturn;
+ }
+
+ lpDevNames = (LPDEVNAMES) ptd; // offset for size field
+
+ lpDevMode = (LPDEVMODE) ((LPTSTR)ptd + ptd->tdExtDevmodeOffset);
+
+ lpszDriverName = (LPTSTR) lpDevNames + ptd->tdDriverNameOffset;
+ lpszDeviceName = (LPTSTR) lpDevNames + ptd->tdDeviceNameOffset;
+ lpszPortName = (LPTSTR) lpDevNames + ptd->tdPortNameOffset;
+
+ hdcIC = CreateIC(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);
+
+errReturn:
+ return hdcIC;
+}
+
+
+#ifdef NEVER
+// This code is wrong
+/*
+ * OleStdCreateTargetDevice()
+ *
+ * Purpose:
+ *
+ * Parameters:
+ *
+ * Return Value:
+ * SCODE - S_OK if successful
+ */
+STDAPI_(DVTARGETDEVICE FAR*) OleStdCreateTargetDevice(LPPRINTDLG lpPrintDlg)
+{
+ DVTARGETDEVICE FAR* ptd=NULL;
+ LPDEVNAMES lpDevNames, pDN;
+ LPDEVMODE lpDevMode, pDM;
+ UINT nMaxOffset;
+ LPTSTR pszName;
+ DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;
+
+ if ((pDN = (LPDEVNAMES)GlobalLock(lpPrintDlg->hDevNames)) == NULL) {
+ goto errReturn;
+ }
+
+ if ((pDM = (LPDEVMODE)GlobalLock(lpPrintDlg->hDevMode)) == NULL) {
+ goto errReturn;
+ }
+
+ nMaxOffset = (pDN->wDriverOffset > pDN->wDeviceOffset) ?
+ pDN->wDriverOffset : pDN->wDeviceOffset ;
+
+ nMaxOffset = (pDN->wOutputOffset > nMaxOffset) ?
+ pDN->wOutputOffset : nMaxOffset ;
+
+ pszName = (LPTSTR)pDN + nMaxOffset;
+
+ dwDevNamesSize = (DWORD)((nMaxOffset+lstrlen(pszName) + 1/* NULL term */)*sizeof(TCHAR));
+ dwDevModeSize = (DWORD) (pDM->dmSize + pDM->dmDriverExtra);
+
+ dwPtdSize = sizeof(DWORD) + dwDevNamesSize + dwDevModeSize;
+
+ if ((ptd = (DVTARGETDEVICE FAR*)OleStdMalloc(dwPtdSize)) != NULL) {
+
+ // copy in the info
+ ptd->tdSize = (UINT)dwPtdSize;
+
+ lpDevNames = (LPDEVNAMES) &ptd->tdDriverNameOffset;
+ _fmemcpy(lpDevNames, pDN, (size_t)dwDevNamesSize);
+
+ lpDevMode=(LPDEVMODE)((LPTSTR)&ptd->tdDriverNameOffset+dwDevNamesSize);
+ _fmemcpy(lpDevMode, pDM, (size_t)dwDevModeSize);
+
+ ptd->tdDriverNameOffset += 4 ;
+ ptd->tdDeviceNameOffset += 4 ;
+ ptd->tdPortNameOffset += 4 ;
+ ptd->tdExtDevmodeOffset = (UINT)dwDevNamesSize + 4 ;
+ }
+
+errReturn:
+ GlobalUnlock(lpPrintDlg->hDevNames);
+ GlobalUnlock(lpPrintDlg->hDevMode);
+
+ return ptd;
+}
+#endif // NEVER
+
+
+
+/*
+ * OleStdDeleteTargetDevice()
+ *
+ * Purpose:
+ *
+ * Parameters:
+ *
+ * Return Value:
+ * SCODE - S_OK if successful
+ */
+STDAPI_(BOOL) OleStdDeleteTargetDevice(DVTARGETDEVICE FAR* ptd)
+{
+ BOOL res=TRUE;
+
+ if (ptd != NULL) {
+ OleStdFree(ptd);
+ }
+
+ return res;
+}
+
+
+
+/*
+ * OleStdCopyTargetDevice()
+ *
+ * Purpose:
+ * duplicate a TARGETDEVICE struct. this function allocates memory for
+ * the copy. the caller MUST free the allocated copy when done with it
+ * using the standard allocator returned from CoGetMalloc.
+ * (OleStdFree can be used to free the copy).
+ *
+ * Parameters:
+ * ptdSrc pointer to source TARGETDEVICE
+ *
+ * Return Value:
+ * pointer to allocated copy of ptdSrc
+ * if ptdSrc==NULL then retuns NULL is returned.
+ * if ptdSrc!=NULL and memory allocation fails, then NULL is returned
+ */
+STDAPI_(DVTARGETDEVICE FAR*) OleStdCopyTargetDevice(DVTARGETDEVICE FAR* ptdSrc)
+{
+ DVTARGETDEVICE FAR* ptdDest = NULL;
+
+ if (ptdSrc == NULL) {
+ return NULL;
+ }
+
+ if ((ptdDest = (DVTARGETDEVICE FAR*)OleStdMalloc(ptdSrc->tdSize)) != NULL) {
+ _fmemcpy(ptdDest, ptdSrc, (size_t)ptdSrc->tdSize);
+ }
+
+ return ptdDest;
+}
+
+
+/*
+ * OleStdCopyFormatEtc()
+ *
+ * Purpose:
+ * Copies the contents of a FORMATETC structure. this function takes
+ * special care to copy correctly copying the pointer to the TARGETDEVICE
+ * contained within the source FORMATETC structure.
+ * if the source FORMATETC has a non-NULL TARGETDEVICE, then a copy
+ * of the TARGETDEVICE will be allocated for the destination of the
+ * FORMATETC (petcDest).
+ *
+ * OLE2NOTE: the caller MUST free the allocated copy of the TARGETDEVICE
+ * within the destination FORMATETC when done with it
+ * using the standard allocator returned from CoGetMalloc.
+ * (OleStdFree can be used to free the copy).
+ *
+ * Parameters:
+ * petcDest pointer to destination FORMATETC
+ * petcSrc pointer to source FORMATETC
+ *
+ * Return Value:
+ * returns TRUE is copy is successful; retuns FALSE if not successful
+ */
+STDAPI_(BOOL) OleStdCopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc)
+{
+ if ((petcDest == NULL) || (petcSrc == NULL)) {
+ return FALSE;
+ }
+
+ petcDest->cfFormat = petcSrc->cfFormat;
+ petcDest->ptd = OleStdCopyTargetDevice(petcSrc->ptd);
+ petcDest->dwAspect = petcSrc->dwAspect;
+ petcDest->lindex = petcSrc->lindex;
+ petcDest->tymed = petcSrc->tymed;
+
+ return TRUE;
+
+}
+
+
+// returns 0 for exact match, 1 for no match, -1 for partial match (which is
+// defined to mean the left is a subset of the right: fewer aspects, null target
+// device, fewer medium).
+
+STDAPI_(int) OleStdCompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight)
+{
+ BOOL bExact = TRUE;
+
+ if (pFetcLeft->cfFormat != pFetcRight->cfFormat)
+ return 1;
+ else if (!OleStdCompareTargetDevice (pFetcLeft->ptd, pFetcRight->ptd))
+ return 1;
+ if (pFetcLeft->dwAspect == pFetcRight->dwAspect)
+ // same aspects; equal
+ ;
+ else if ((pFetcLeft->dwAspect & ~pFetcRight->dwAspect) != 0)
+ // left not subset of aspects of right; not equal
+ return 1;
+ else
+ // left subset of right
+ bExact = FALSE;
+
+ if (pFetcLeft->tymed == pFetcRight->tymed)
+ // same medium flags; equal
+ ;
+ else if ((pFetcLeft->tymed & ~pFetcRight->tymed) != 0)
+ // left not subset of medium flags of right; not equal
+ return 1;
+ else
+ // left subset of right
+ bExact = FALSE;
+
+ return bExact ? 0 : -1;
+}
+
+
+
+STDAPI_(BOOL) OleStdCompareTargetDevice
+ (DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight)
+{
+ if (ptdLeft == ptdRight)
+ // same address of td; must be same (handles NULL case)
+ return TRUE;
+ else if ((ptdRight == NULL) || (ptdLeft == NULL))
+ return FALSE;
+ else if (ptdLeft->tdSize != ptdRight->tdSize)
+ // different sizes, not equal
+ return FALSE;
+#ifdef WIN32
+ else if (memcmp(ptdLeft, ptdRight, ptdLeft->tdSize) != 0)
+#else
+ else if (_fmemcmp(ptdLeft, ptdRight, (int)ptdLeft->tdSize) != 0)
+#endif
+ // not same target device, not equal
+ return FALSE;
+
+ return TRUE;
+}
+
diff --git a/private/oleutest/letest/ole2ui/template.c b/private/oleutest/letest/ole2ui/template.c
new file mode 100644
index 000000000..9c35b4c2f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/template.c
@@ -0,0 +1,243 @@
+/*
+ * TEMPLATE.C
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ *
+ *
+ * CUSTOMIZATION INSTRUCTIONS:
+ *
+ * 1. Replace <FILE> with the uppercased filename for this file.
+ * Lowercase the <FILE>.h entry
+ *
+ * 2. Replace <NAME> with the mixed case dialog name in one word,
+ * such as InsertObject
+ *
+ * 3. Replace <FULLNAME> with the mixed case dialog name in multiple
+ * words, such as Insert Object
+ *
+ * 4. Replace <ABBREV> with the suffix for pointer variables, such
+ * as the IO in InsertObject's pIO or the CI in ChangeIcon's pCI.
+ * Check the alignment of the first variable declaration in the
+ * Dialog Proc after this. I will probably be misaligned with the
+ * rest of the variables.
+ *
+ * 5. Replace <STRUCT> with the uppercase structure name for this
+ * dialog sans OLEUI, such as INSERTOBJECT. Changes OLEUI<STRUCT>
+ * in most cases, but we also use this for IDD_<STRUCT> as the
+ * standard template resource ID.
+ *
+ * 6. Find <UFILL> fields and fill them out with whatever is appropriate.
+ *
+ * 7. Delete this header up to the start of the next comment.
+ */
+
+
+/*
+ * <FILE>.C
+ *
+ * Implements the OleUI<NAME> function which invokes the complete
+ * <FULLNAME> dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include "common.h"
+
+#ifndef WIN32
+#include "<FILE>.h"
+#else
+ #include "template.h"
+#endif
+
+
+
+
+/*
+ * OleUI<NAME>
+ *
+ * Purpose:
+ * Invokes the standard OLE <FULLNAME> dialog box allowing the user
+ * to <UFILL>
+ *
+ * Parameters:
+ * lp<ABBREV> LPOLEUI<NAME> pointing to the in-out structure
+ * for this dialog.
+ *
+ * Return Value:
+ * UINT One of the following codes, indicating success or error:
+ * OLEUI_SUCCESS Success
+ * OLEUI_ERR_STRUCTSIZE The dwStructSize value is wrong
+ */
+
+STDAPI_(UINT) OleUI<NAME>(LPOLEUI<STRUCT> lp<ABBREV>)
+ {
+ UINT uRet;
+ HGLOBAL hMemDlg=NULL;
+
+ uRet=UStandardValidation((LPOLEUISTANDARD)lp<ABBREV>, sizeof(OLEUI<STRUCT>)
+ , &hMemDlg);
+
+ if (OLEUI_SUCCESS!=uRet)
+ return uRet;
+
+ /*
+ * PERFORM ANY STRUCTURE-SPECIFIC VALIDATION HERE!
+ * ON FAILURE:
+ * {
+ * if (NULL!=hMemDlg)
+ * FreeResource(hMemDlg)
+ *
+ * return OLEUI_<ABBREV>ERR_<ERROR>
+ * }
+ */
+
+ //Now that we've validated everything, we can invoke the dialog.
+ uRet=UStandardInvocation(<NAME>DialogProc, (LPOLEUISTANDARD)lp<ABBREV>
+ , hMemDlg, MAKEINTRESOURCE(IDD_<STRUCT>));
+
+ /*
+ * IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.
+ */
+ <UFILL>
+
+ return uRet;
+ }
+
+
+
+
+
+/*
+ * <NAME>DialogProc
+ *
+ * Purpose:
+ * Implements the OLE <FULLNAME> dialog as invoked through the
+ * OleUI<NAME> function.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+BOOL CALLBACK EXPORT <NAME>DialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+ {
+ P<STRUCT> p<ABBREV>;
+ BOOL fHook=FALSE;
+
+ //Declare Win16/Win32 compatible WM_COMMAND parameters.
+ COMMANDPARAMS(wID, wCode, hWndMsg);
+
+ //This will fail under WM_INITDIALOG, where we allocate it.
+ p<ABBREV>=(<STRUCT>)PvStandardEntry(hDlg, iMsg, wParam, lParam, &uHook);
+
+ //If the hook processed the message, we're done.
+ if (0!=uHook)
+ return (BOOL)uHook;
+
+ //Process the temination message
+ if (iMsg==uMsgEndDialog)
+ {
+ //Free any specific allocations before calling StandardCleanup
+ StandardCleanup((PVOID)p<ABBREV>, hDlg);
+ EndDialog(hDlg, wParam);
+ return TRUE;
+ }
+
+ switch (iMsg)
+ {
+ case WM_INITDIALOG:
+ F<NAME>Init(hDlg, wParam, lParam);
+ return TRUE;
+
+
+ case WM_COMMAND:
+ switch (wID)
+ {
+ case IDOK:
+ /*
+ * PERFORM WHATEVER FUNCTIONS ARE DEFAULT HERE.
+ */
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
+ break;
+
+ case IDCANCEL:
+ /*
+ * PERFORM ANY UNDOs HERE, BUT NOT CLEANUP THAT WILL
+ * ALWAYS HAPPEN WHICH SHOULD BE IN uMsgEndDialog.
+ */
+ SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
+ break;
+
+ case ID_OLEUIHELP:
+ PostMessage(p<ABBREV>->lpO<ABBREV>->hWndOwner, uMsgHelp
+ , (WPARAM)hDlg, MAKELPARAM(IDD_<STRUCT>, 0));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+ }
+
+
+
+
+/*
+ * F<NAME>Init
+ *
+ * Purpose:
+ * WM_INITIDIALOG handler for the <FULLNAME> dialog box.
+ *
+ * Parameters:
+ * hDlg HWND of the dialog
+ * wParam WPARAM of the message
+ * lParam LPARAM of the message
+ *
+ * Return Value:
+ * BOOL Value to return for WM_INITDIALOG.
+ */
+
+BOOL F<NAME>Init(HWND hDlg, WPARAM wParam, LPARAM lParam)
+ {
+ P<STRUCT> p<ABBREV>;
+ LPOLEUI<STRUCT> lpO<ABBREV>;
+ HFONT hFont;
+
+ //1. Copy the structure at lParam into our instance memory.
+ p<ABBREV>=(PSTRUCT)PvStandardInit(hDlg, sizeof(<STRUCT>), TRUE, &hFont);
+
+ //PvStandardInit send a termination to us already.
+ if (NULL==p<ABBREV>)
+ return FALSE;
+
+ lpO<ABBREV>=(LPOLEUI<STRUCT>)lParam);
+
+ p<ABBREV>->lpO<ABBREV>=lpO<ABBREV>;
+
+ //Copy other information from lpO<ABBREV> that we might modify.
+ <UFILL>
+
+ //2. If we got a font, send it to the necessary controls.
+ if (NULL!=hFont)
+ {
+ //Do this for as many controls as you need it for.
+ SendDlgItemMessage(hDlg, ID_<UFILL>, WM_SETFONT, (WPARAM)hFont, 0L);
+ }
+
+
+ //3. Show or hide the help button
+ if (!(p<ABBREV>->lpO<ABBREV>->dwFlags & <ABBREV>F_SHOWHELP))
+ StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
+
+ /*
+ * PERFORM OTHER INITIALIZATION HERE. ON ANY LoadString
+ * FAILURE POST OLEUI_MSG_ENDDIALOG WITH OLEUI_ERR_LOADSTRING.
+ */
+
+ //n. Call the hook with lCustData in lParam
+ UStandardHook((PVOID)p<ABBREV>, hDlg, WM_INITDIALOG, wParam, lpO<ABBREV>->lCustData);
+ return TRUE;
+ }
diff --git a/private/oleutest/letest/ole2ui/template.h b/private/oleutest/letest/ole2ui/template.h
new file mode 100644
index 000000000..3f277aec1
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/template.h
@@ -0,0 +1,119 @@
+/*
+ * TEMPLATE.H
+ *
+ * CUSTOMIZATION INSTRUCTIONS:
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ *
+ *
+ * 1. Replace <FILE> with the uppercased filename for this file.
+ * Lowercase the <FILE>.h entry
+ *
+ * 2. Replace <NAME> with the mixed case dialog name in one word,
+ * such as InsertObject
+ *
+ * 3. Replace <FULLNAME> with the mixed case dialog name in multiple
+ * words, such as Insert Object
+ *
+ * 4. Replace <ABBREV> with the suffix for pointer variables, such
+ * as the IO in InsertObject's pIO or the CI in ChangeIcon's pCI.
+ * Check the alignment of the first variable declaration in the
+ * Dialog Proc after this. I will probably be misaligned with the
+ * rest of the variables.
+ *
+ * 5. Replace <STRUCT> with the uppercase structure name for this
+ * dialog sans OLEUI, such as INSERTOBJECT. Changes OLEUI<STRUCT>
+ * in most cases, but we also use this for IDD_<STRUCT> as the
+ * standard template resource ID.
+ *
+ * 6. Find <UFILL> fields and fill them out with whatever is appropriate.
+ *
+ * 7. Delete this header up to the start of the next comment.
+ *
+ */
+
+
+/*
+ * <FILE>.H
+ *
+ * Internal definitions, structures, and function prototypes for the
+ * OLE 2.0 UI <FULLNAME> dialog.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef <UFILL>
+#define <UFILL>
+
+//UFILL> Move from here to INTERNAL to to OLE2UI.H
+
+
+typedef struct tagOLEUI<STRUCT>
+ {
+ //These IN fields are standard across all OLEUI dialog functions.
+ DWORD cbStruct; //Structure Size
+ DWORD dwFlags; //IN-OUT: Flags
+ HWND hWndOwner; //Owning window
+ LPCTSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCTSTR lpszTemplate; //Customized template name
+ HRSRC hResource; //Customized template handle
+
+ //Specifics for OLEUI<STRUCT>. All are IN-OUT unless otherwise spec.
+ } OLEUI<STRUCT>, *POLEUI<STRUCT>, FAR *LPOLEUI<STRUCT>;
+
+
+//API Prototype
+UINT FAR PASCAL OleUI<NAME>(LPOLEUI<STRUCT>);
+
+
+//<FULLNAME> flags
+#define <ABBREV>F_SHOWHELP 0x00000001L
+<UFILL>
+
+
+//<FULLNAME> specific error codes
+//DEFINE AS OLEUI_<ABBREV>ERR_<ERROR> (OLEUI_ERR_STANDARDMAX+n)
+<UFILL>
+
+
+//<FULLNAME> Dialog identifiers
+//FILL IN DIALOG IDs HERE
+<UFILL>
+
+
+
+
+
+//INTERNAL INFORMATION STARTS HERE
+
+//Internally used structure
+typedef struct tag<STRUCT>
+ {
+ //Keep this item first as the Standard* functions depend on it here.
+ LPOLEUI<STRUCT> lpO<ABBREV>; //Original structure passed.
+
+ /*
+ * What we store extra in this structure besides the original caller's
+ * pointer are those fields that we need to modify during the life of
+ * the dialog but that we don't want to change in the original structure
+ * until the user presses OK.
+ */
+
+ <UFILL>
+ } <STRUCT>, *P<STRUCT>;
+
+
+
+//Internal function prototypes
+//<FILE>.C
+BOOL FAR PASCAL <NAME>DialogProc(HWND, UINT, WPARAM, LPARAM);
+BOOL F<NAME>Init(HWND hDlg, WPARAM, LPARAM);
+<UFILL>
+
+
+
+#endif //<UFILL>
diff --git a/private/oleutest/letest/ole2ui/uiclass.h b/private/oleutest/letest/ole2ui/uiclass.h
new file mode 100644
index 000000000..801819141
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/uiclass.h
@@ -0,0 +1,2 @@
+#define SZCLASSICONBOX TEXT("OLE2UIIBClass")
+#define SZCLASSRESULTIMAGE TEXT("OLE2UIRIClass")
diff --git a/private/oleutest/letest/ole2ui/uimake.cmd b/private/oleutest/letest/ole2ui/uimake.cmd
new file mode 100644
index 000000000..b6bd1f6c7
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/uimake.cmd
@@ -0,0 +1 @@
+nmake -f ole2ui.mak %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/private/oleutest/letest/ole2ui/uimake.ini b/private/oleutest/letest/ole2ui/uimake.ini
new file mode 100644
index 000000000..a7d847908
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/uimake.ini
@@ -0,0 +1,24 @@
+# This is the DEBUG static .LIB UILibrary INI file
+MSG=DEBUG Static LIB Version ($(LANG))
+DEBUG=1
+MODEL=M
+# Make a static library called OLE2UI.LIB
+LIBNAME=OLE2UI
+REL_DIR=d:\cairo\cairole\h\export
+OLEREL_DIR=d:\cairo\cairole\h\export
+OBJ=DEBUGLIB
+BUILD=LIB
+RESOURCE=RESOURCE
+
+# 16 bit CFLAGS=-c -Od -GA2s -W3 -Zpei -AM -D_DEBUG -DWIN32 -DUNICODE
+
+CFLAGS=-c -Od -Gs -W3 -Zpei -D_DEBUG -DWIN32 -DUNICODE
+RFLAGS=-D DEBUG
+LFLAGS=/MAP:FULL /CO /LINE /NOD /NOE /SE:300 /NOPACKCODE
+UILIBS=mlibcew libw ole2 storage shell commdlg toolhelp
+CC=cl
+AS=masm
+RS=rc
+LK=link
+LANG=USA
+LIBOBJS = $(UI_COBJS:D^\=DEBUGLIB^\) $(UI_NOPCOBJS:D^\=DEBUGLIB\NOPC^\)
diff --git a/private/oleutest/letest/ole2ui/utility.c b/private/oleutest/letest/ole2ui/utility.c
new file mode 100644
index 000000000..98deecc25
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/utility.c
@@ -0,0 +1,1039 @@
+/*
+ * UTILITY.C
+ *
+ * Utility routines for functions inside OLE2UI.DLL
+ *
+ * General:
+ * ----------------------
+ * HourGlassOn Displays the hourglass
+ * HourGlassOff Hides the hourglass
+ *
+ * Misc Tools:
+ * ----------------------
+ * Browse Displays the "File..." or "Browse..." dialog.
+ * ReplaceCharWithNull Used to form filter strings for Browse.
+ * ErrorWithFile Creates an error message with embedded filename
+ * OpenFileError Give error message for OpenFile error return
+ * ChopText Chop a file path to fit within a specified width
+ * DoesFileExist Checks if file is valid
+ *
+ * Registration Database:
+ * ----------------------
+ * HIconFromClass Extracts the first icon in a class's server path
+ * FServerFromClass Retrieves the server path for a class name (fast)
+ * UClassFromDescription Finds the classname given a description (slow)
+ * UDescriptionFromClass Retrieves the description for a class name (fast)
+ * FGetVerb Retrieves a specific verb for a class (fast)
+ *
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+#define STRICT 1
+#include "ole2ui.h"
+#include <stdlib.h>
+#include <commdlg.h>
+#include <memory.h>
+#include <cderr.h>
+#include "common.h"
+#include "utility.h"
+#include "geticon.h"
+
+OLEDBGDATA
+
+/*
+ * HourGlassOn
+ *
+ * Purpose:
+ * Shows the hourglass cursor returning the last cursor in use.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * HCURSOR Cursor in use prior to showing the hourglass.
+ */
+
+HCURSOR WINAPI HourGlassOn(void)
+ {
+ HCURSOR hCur;
+
+ hCur=SetCursor(LoadCursor(NULL, IDC_WAIT));
+ ShowCursor(TRUE);
+
+ return hCur;
+ }
+
+
+
+/*
+ * HourGlassOff
+ *
+ * Purpose:
+ * Turns off the hourglass restoring it to a previous cursor.
+ *
+ * Parameters:
+ * hCur HCURSOR as returned from HourGlassOn
+ *
+ * Return Value:
+ * None
+ */
+
+void WINAPI HourGlassOff(HCURSOR hCur)
+ {
+ ShowCursor(FALSE);
+ SetCursor(hCur);
+ return;
+ }
+
+
+
+
+/*
+ * Browse
+ *
+ * Purpose:
+ * Displays the standard GetOpenFileName dialog with the title of
+ * "Browse." The types listed in this dialog are controlled through
+ * iFilterString. If it's zero, then the types are filled with "*.*"
+ * Otherwise that string is loaded from resources and used.
+ *
+ * Parameters:
+ * hWndOwner HWND owning the dialog
+ * lpszFile LPSTR specifying the initial file and the buffer in
+ * which to return the selected file. If there is no
+ * initial file the first character of this string should
+ * be NULL.
+ * lpszInitialDir LPSTR specifying the initial directory. If none is to
+ * set (ie, the cwd should be used), then this parameter
+ * should be NULL.
+ * cchFile UINT length of pszFile
+ * iFilterString UINT index into the stringtable for the filter string.
+ * dwOfnFlags DWORD flags to OR with OFN_HIDEREADONLY
+ *
+ * Return Value:
+ * BOOL TRUE if the user selected a file and pressed OK.
+ * FALSE otherwise, such as on pressing Cancel.
+ */
+
+BOOL WINAPI Browse(HWND hWndOwner, LPTSTR lpszFile, LPTSTR lpszInitialDir, UINT cchFile, UINT iFilterString, DWORD dwOfnFlags)
+ {
+ UINT cch;
+ TCHAR szFilters[256];
+ OPENFILENAME ofn;
+ BOOL fStatus;
+ DWORD dwError;
+ TCHAR szDlgTitle[128]; // that should be big enough
+
+ if (NULL==lpszFile || 0==cchFile)
+ return FALSE;
+
+ /*
+ * REVIEW: Exact contents of the filter combobox is TBD. One idea
+ * is to take all the extensions in the RegDB and place them in here
+ * with the descriptive class name associate with them. This has the
+ * extra step of finding all extensions of the same class handler and
+ * building one extension string for all of them. Can get messy quick.
+ * UI demo has only *.* which we do for now.
+ */
+
+ if (0!=iFilterString)
+ cch=LoadString(ghInst, iFilterString, (LPTSTR)szFilters, sizeof(szFilters)/sizeof(TCHAR));
+ else
+ {
+ szFilters[0]=0;
+ cch=1;
+ }
+
+ if (0==cch)
+ return FALSE;
+
+ ReplaceCharWithNull(szFilters, szFilters[cch-1]);
+
+ //Prior string must also be initialized, if there is one.
+ _fmemset((LPOPENFILENAME)&ofn, 0, sizeof(ofn));
+ ofn.lStructSize =sizeof(ofn);
+ ofn.hwndOwner =hWndOwner;
+ ofn.lpstrFile =lpszFile;
+ ofn.nMaxFile =cchFile;
+ ofn.lpstrFilter =(LPTSTR)szFilters;
+ ofn.nFilterIndex=1;
+ if (LoadString(ghInst, IDS_BROWSE, (LPTSTR)szDlgTitle, sizeof(szDlgTitle)/sizeof(TCHAR)))
+ ofn.lpstrTitle =(LPTSTR)szDlgTitle;
+ ofn.hInstance = ghInst;
+ ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEOPEN);
+ if (NULL != lpszInitialDir)
+ ofn.lpstrInitialDir = lpszInitialDir;
+
+ ofn.Flags= OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | (dwOfnFlags) ;
+
+ //On success, copy the chosen filename to the static display
+ fStatus = GetOpenFileName((LPOPENFILENAME)&ofn);
+ dwError = CommDlgExtendedError();
+ return fStatus;
+
+ }
+
+
+
+
+
+/*
+ * ReplaceCharWithNull
+ *
+ * Purpose:
+ * Walks a null-terminated string and replaces a given character
+ * with a zero. Used to turn a single string for file open/save
+ * filters into the appropriate filter string as required by the
+ * common dialog API.
+ *
+ * Parameters:
+ * psz LPTSTR to the string to process.
+ * ch int character to replace.
+ *
+ * Return Value:
+ * int Number of characters replaced. -1 if psz is NULL.
+ */
+
+int WINAPI ReplaceCharWithNull(LPTSTR psz, int ch)
+ {
+ int cChanged=-1;
+
+ if (NULL!=psz)
+ {
+ while (0!=*psz)
+ {
+ if (ch==*psz)
+ {
+ *psz=TEXT('\0');
+ cChanged++;
+ }
+ psz++;
+ }
+ }
+ return cChanged;
+ }
+
+
+
+
+
+
+/*
+ * ErrorWithFile
+ *
+ * Purpose:
+ * Displays a message box built from a stringtable string containing
+ * one %s as a placeholder for a filename and from a string of the
+ * filename to place there.
+ *
+ * Parameters:
+ * hWnd HWND owning the message box. The caption of this
+ * window is the caption of the message box.
+ * hInst HINSTANCE from which to draw the idsErr string.
+ * idsErr UINT identifier of a stringtable string containing
+ * the error message with a %s.
+ * lpszFile LPSTR to the filename to include in the message.
+ * uFlags UINT flags to pass to MessageBox, like MB_OK.
+ *
+ * Return Value:
+ * int Return value from MessageBox.
+ */
+
+int WINAPI ErrorWithFile(HWND hWnd, HINSTANCE hInst, UINT idsErr
+ , LPTSTR pszFile, UINT uFlags)
+ {
+ int iRet=0;
+ HANDLE hMem;
+ const UINT cb=(2*OLEUI_CCHPATHMAX_SIZE);
+ LPTSTR psz1, psz2, psz3;
+
+ if (NULL==hInst || NULL==pszFile)
+ return iRet;
+
+ //Allocate three 2*OLEUI_CCHPATHMAX byte work buffers
+ hMem=GlobalAlloc(GHND, (DWORD)(3*cb));
+
+ if (NULL==hMem)
+ return iRet;
+
+ psz1=GlobalLock(hMem);
+ psz2=psz1+cb;
+ psz3=psz2+cb;
+
+ if (0!=LoadString(hInst, idsErr, psz1, cb))
+ {
+ wsprintf(psz2, psz1, pszFile);
+
+ //Steal the caption of the dialog
+ GetWindowText(hWnd, psz3, cb);
+ iRet=MessageBox(hWnd, psz2, psz3, uFlags);
+ }
+
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ return iRet;
+ }
+
+
+
+
+
+
+
+
+
+/*
+ * HIconFromClass
+ *
+ * Purpose:
+ * Given an object class name, finds an associated executable in the
+ * registration database and extracts the first icon from that
+ * executable. If none is available or the class has no associated
+ * executable, this function returns NULL.
+ *
+ * Parameters:
+ * pszClass LPSTR giving the object class to look up.
+ *
+ * Return Value:
+ * HICON Handle to the extracted icon if there is a module
+ * associated to pszClass. NULL on failure to either
+ * find the executable or extract and icon.
+ */
+
+HICON WINAPI HIconFromClass(LPTSTR pszClass)
+ {
+ HICON hIcon;
+ TCHAR szEXE[OLEUI_CCHPATHMAX];
+ UINT Index;
+ CLSID clsid;
+
+ if (NULL==pszClass)
+ return NULL;
+
+ CLSIDFromStringA(pszClass, &clsid);
+
+ if (!FIconFileFromClass((REFCLSID)&clsid, szEXE, OLEUI_CCHPATHMAX_SIZE, &Index))
+ return NULL;
+
+ hIcon=ExtractIcon(ghInst, szEXE, Index);
+
+ if ((HICON)32 > hIcon)
+ hIcon=NULL;
+
+ return hIcon;
+ }
+
+
+
+
+
+/*
+ * FServerFromClass
+ *
+ * Purpose:
+ * Looks up the classname in the registration database and retrieves
+ * the name undet protocol\StdFileEditing\server.
+ *
+ * Parameters:
+ * pszClass LPSTR to the classname to look up.
+ * pszEXE LPSTR at which to store the server name
+ * cch UINT size of pszEXE
+ *
+ * Return Value:
+ * BOOL TRUE if one or more characters were loaded into pszEXE.
+ * FALSE otherwise.
+ */
+
+BOOL WINAPI FServerFromClass(LPTSTR pszClass, LPTSTR pszEXE, UINT cch)
+{
+
+ DWORD dw;
+ LONG lRet;
+ HKEY hKey;
+
+ if (NULL==pszClass || NULL==pszEXE || 0==cch)
+ return FALSE;
+
+ /*
+ * We have to go walking in the registration database under the
+ * classname, so we first open the classname key and then check
+ * under "\\LocalServer" to get the .EXE.
+ */
+
+ //Open up the class key
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, pszClass, &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return FALSE;
+
+ //Get the executable path.
+ dw=(DWORD)cch;
+ lRet=RegQueryValue(hKey, TEXT("LocalServer"), pszEXE, &dw);
+
+ RegCloseKey(hKey);
+
+ return ((ERROR_SUCCESS == lRet) && (dw > 0));
+}
+
+
+
+/*
+ * UClassFromDescription
+ *
+ * Purpose:
+ * Looks up the actual OLE class name in the registration database
+ * for the given descriptive name chosen from a listbox.
+ *
+ * Parameters:
+ * psz LPSTR to the descriptive name.
+ * pszClass LPSTR in which to store the class name.
+ * cb UINT maximum length of pszClass.
+ *
+ * Return Value:
+ * UINT Number of characters copied to pszClass. 0 on failure.
+ */
+
+UINT WINAPI UClassFromDescription(LPTSTR psz, LPTSTR pszClass, UINT cb)
+ {
+ DWORD dw;
+ HKEY hKey;
+ TCHAR szClass[OLEUI_CCHKEYMAX];
+ LONG lRet;
+ UINT i;
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return 0;
+
+ i=0;
+ lRet=RegEnumKey(hKey, i++, szClass, OLEUI_CCHKEYMAX_SIZE);
+
+ //Walk the available keys
+ while ((LONG)ERROR_SUCCESS==lRet)
+ {
+ dw=(DWORD)cb;
+ lRet=RegQueryValue(hKey, szClass, pszClass, &dw);
+
+ //Check if the description matches the one just enumerated
+ if ((LONG)ERROR_SUCCESS==lRet)
+ {
+ if (!lstrcmp(pszClass, psz))
+ break;
+ }
+
+ //Continue with the next key.
+ lRet=RegEnumKey(hKey, i++, szClass, OLEUI_CCHKEYMAX_SIZE);
+ }
+
+ //If we found it, copy to the return buffer
+ if ((LONG)ERROR_SUCCESS==lRet)
+ lstrcpy(pszClass, szClass);
+ else
+ dw=0L;
+
+ RegCloseKey(hKey);
+ return (UINT)dw;
+ }
+
+
+
+
+
+
+
+
+/*
+ * UDescriptionFromClass
+ *
+ * Purpose:
+ * Looks up the actual OLE descriptive name name in the registration
+ * database for the given class name.
+ *
+ * Parameters:
+ * pszClass LPSTR to the class name.
+ * psz LPSTR in which to store the descriptive name.
+ * cb UINT maximum length of psz.
+ *
+ * Return Value:
+ * UINT Number of characters copied to pszClass. 0 on failure.
+ */
+
+UINT WINAPI UDescriptionFromClass(LPTSTR pszClass, LPTSTR psz, UINT cb)
+ {
+ DWORD dw;
+ HKEY hKey;
+ LONG lRet;
+
+ if (NULL==pszClass || NULL==psz)
+ return 0;
+
+ //Open up the root key.
+ lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return 0;
+
+ //Get the descriptive name using the class name.
+ dw=(DWORD)cb;
+ lRet=RegQueryValue(hKey, pszClass, psz, &dw);
+
+ RegCloseKey(hKey);
+
+ psz+=lstrlen(psz)+1;
+ *psz=0;
+
+ if ((LONG)ERROR_SUCCESS!=lRet)
+ return 0;
+
+ return (UINT)dw;
+ }
+
+
+
+// returns width of line of text. this is a support routine for ChopText
+static LONG GetTextWSize(HDC hDC, LPTSTR lpsz)
+{
+ SIZE size;
+
+ if (GetTextExtentPoint(hDC, lpsz, lstrlen(lpsz), (LPSIZE)&size))
+ return size.cx;
+ else {
+ return 0;
+ }
+}
+
+
+/*
+ * ChopText
+ *
+ * Purpose:
+ * Parse a string (pathname) and convert it to be within a specified
+ * length by chopping the least significant part
+ *
+ * Parameters:
+ * hWnd window handle in which the string resides
+ * nWidth max width of string in pixels
+ * use width of hWnd if zero
+ * lpch pointer to beginning of the string
+ *
+ * Return Value:
+ * pointer to the modified string
+ */
+LPTSTR WINAPI ChopText(HWND hWnd, int nWidth, LPTSTR lpch)
+{
+#define PREFIX_SIZE 7 + 1
+#define PREFIX_FORMAT TEXT("%c%c%c...\\")
+
+ TCHAR szPrefix[PREFIX_SIZE];
+ BOOL fDone = FALSE;
+ int i;
+ RECT rc;
+ HDC hdc;
+ HFONT hfont;
+ HFONT hfontOld = NULL;
+
+ if (!hWnd || !lpch)
+ return NULL;
+
+ /* Get length of static field. */
+ if (!nWidth) {
+ GetClientRect(hWnd, (LPRECT)&rc);
+ nWidth = rc.right - rc.left;
+ }
+
+ /* Set up DC appropriately for the static control */
+ hdc = GetDC(hWnd);
+ hfont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);
+
+ if (NULL != hfont) // WM_GETFONT returns NULL if window uses system font
+ hfontOld = SelectObject(hdc, hfont);
+
+ /* check horizontal extent of string */
+ if (GetTextWSize(hdc, lpch) > nWidth) {
+
+ /* string is too long to fit in static control; chop it */
+ /* set up new prefix & determine remaining space in control */
+ wsprintf((LPTSTR) szPrefix, PREFIX_FORMAT, lpch[0], lpch[1], lpch[2]);
+ nWidth -= (int)GetTextWSize(hdc, (LPTSTR) szPrefix);
+
+ /*
+ ** advance a directory at a time until the remainder of the
+ ** string fits into the static control after the "x:\...\" prefix
+ */
+ while (!fDone) {
+
+#ifdef DBCS
+ while (*lpch && (*lpch != TEXT('\\')))
+#ifdef WIN32
+ lpch = CharNext(lpch);
+#else
+ lpch = AnsiNext(lpch);
+#endif
+ if (*lpch)
+#ifdef WIN32
+ lpch = CharNext(lpch);
+#else
+ lpch = AnsiNext(lpch);
+#endif
+#else
+ while (*lpch && (*lpch++ != TEXT('\\')));
+#endif
+
+ if (!*lpch || GetTextWSize(hdc, lpch) <= nWidth) {
+ if (!*lpch)
+ /*
+ ** Nothing could fit after the prefix; remove the
+ ** final "\" from the prefix
+ */
+ szPrefix[lstrlen((LPTSTR) szPrefix) - 1] = 0;
+
+ /* rest or string fits -- stick prefix on front */
+ for (i = lstrlen((LPTSTR) szPrefix) - 1; i >= 0; --i)
+ *--lpch = szPrefix[i];
+ fDone = TRUE;
+ }
+ }
+ }
+
+ if (NULL != hfont)
+ SelectObject(hdc, hfontOld);
+ ReleaseDC(hWnd, hdc);
+
+ return(lpch);
+
+#undef PREFIX_SIZE
+#undef PREFIX_FORMAT
+}
+
+
+/*
+ * OpenFileError
+ *
+ * Purpose:
+ * display message for error returned from OpenFile
+ *
+ * Parameters:
+ * hDlg HWND of the dialog.
+ * nErrCode UINT error code returned in OFSTRUCT passed to OpenFile
+ * lpszFile LPSTR file name passed to OpenFile
+ *
+ * Return Value:
+ * None
+ */
+void WINAPI OpenFileError(HWND hDlg, UINT nErrCode, LPTSTR lpszFile)
+{
+ switch (nErrCode) {
+ case 0x0005: // Access denied
+ ErrorWithFile(hDlg, ghInst, IDS_CIFILEACCESS, lpszFile, MB_OK);
+ break;
+
+ case 0x0020: // Sharing violation
+ ErrorWithFile(hDlg, ghInst, IDS_CIFILESHARE, lpszFile, MB_OK);
+ break;
+
+ case 0x0002: // File not found
+ case 0x0003: // Path not found
+ ErrorWithFile(hDlg, ghInst, IDS_CIINVALIDFILE, lpszFile, MB_OK);
+ break;
+
+ default:
+ ErrorWithFile(hDlg, ghInst, IDS_CIFILEOPENFAIL, lpszFile, MB_OK);
+ break;
+ }
+}
+
+#define chSpace TEXT(' ')
+#define chPeriod TEXT('.')
+#define PARSE_EMPTYSTRING -1
+#define PARSE_INVALIDDRIVE -2
+#define PARSE_INVALIDPERIOD -3
+#define PARSE_INVALIDDIRCHAR -4
+#define PARSE_INVALIDCHAR -5
+#define PARSE_WILDCARDINDIR -6
+#define PARSE_INVALIDNETPATH -7
+#define PARSE_INVALIDSPACE -8
+#define PARSE_EXTENTIONTOOLONG -9
+#define PARSE_DIRECTORYNAME -10
+#define PARSE_FILETOOLONG -11
+
+/*---------------------------------------------------------------------------
+ * ParseFile
+ * Purpose: Determine if the filename is a legal DOS name
+ * Input: Long pointer to a SINGLE file name
+ * Circumstance checked:
+ * 1) Valid as directory name, but not as file name
+ * 2) Empty String
+ * 3) Illegal Drive label
+ * 4) Period in invalid location (in extention, 1st in file name)
+ * 5) Missing directory character
+ * 6) Illegal character
+ * 7) Wildcard in directory name
+ * 8) Double slash beyond 1st 2 characters
+ * 9) Space character in the middle of the name (trailing spaces OK)
+ * 10) Filename greater than 8 characters
+ * 11) Extention greater than 3 characters
+ * Notes:
+ * Filename length is NOT checked.
+ * Valid filenames will have leading spaces, trailing spaces and
+ * terminating period stripped in place.
+ *
+ * Returns: If valid, LOWORD is byte offset to filename
+ * HIWORD is byte offset to extention
+ * if string ends with period, 0
+ * if no extention is given, string length
+ * If invalid, LOWORD is error code suggesting problem (< 0)
+ * HIWORD is approximate offset where problem found
+ * Note that this may be beyond the offending character
+ *--------------------------------------------------------------------------*/
+
+static long ParseFile(LPTSTR lpstrFileName)
+{
+ short nFile, nExt, nFileOffset, nExtOffset;
+ BOOL bExt;
+ BOOL bWildcard;
+ short nNetwork = 0;
+ BOOL bUNCPath = FALSE;
+ LPTSTR lpstr = lpstrFileName;
+
+/* Strip off initial white space. Note that TAB is not checked */
+/* because it cannot be received out of a standard edit control */
+/* 30 January 1991 clarkc */
+ while (*lpstr == chSpace)
+ lpstr++;
+
+ if (!*lpstr)
+ {
+ nFileOffset = PARSE_EMPTYSTRING;
+ goto FAILURE;
+ }
+
+ if (lpstr != lpstrFileName)
+ {
+ lstrcpy(lpstrFileName, lpstr);
+ lpstr = lpstrFileName;
+ }
+
+ if (
+
+#ifdef WIN32
+ *CharNext(lpstr)
+#else
+ *AnsiNext(lpstr)
+#endif
+ == TEXT(':')
+ )
+
+ {
+ TCHAR cDrive = (*lpstr | (BYTE) 0x20); /* make lowercase */
+
+/* This does not test if the drive exists, only if it's legal */
+ if ((cDrive < TEXT('a')) || (cDrive > TEXT('z')))
+ {
+ nFileOffset = PARSE_INVALIDDRIVE;
+ goto FAILURE;
+ }
+#ifdef WIN32
+ lpstr = CharNext(CharNext(lpstr));
+#else
+ lpstr = AnsiNext(AnsiNext(lpstr));
+#endif
+ }
+
+ if ((*lpstr == TEXT('\\')) || (*lpstr == TEXT('/')))
+ {
+ if (*++lpstr == chPeriod) /* cannot have c:\. */
+ {
+ if ((*++lpstr != TEXT('\\')) && (*lpstr != TEXT('/'))) /* unless it's stupid */
+ {
+ if (!*lpstr) /* it's the root directory */
+ goto MustBeDir;
+
+ nFileOffset = PARSE_INVALIDPERIOD;
+ goto FAILURE;
+ }
+ else
+ ++lpstr; /* it's saying top directory (again), thus allowed */
+ }
+ else if ((*lpstr == TEXT('\\')) && (*(lpstr-1) == TEXT('\\')))
+ {
+/* It seems that for a full network path, whether a drive is declared or
+ * not is insignificant, though if a drive is given, it must be valid
+ * (hence the code above should remain there).
+ * 13 February 1991 clarkc
+ */
+ ++lpstr; /* ...since it's the first slash, 2 are allowed */
+ nNetwork = -1; /* Must receive server and share to be real */
+ bUNCPath = TRUE; /* No wildcards allowed if UNC name */
+ }
+ else if (*lpstr == TEXT('/'))
+ {
+ nFileOffset = PARSE_INVALIDDIRCHAR;
+ goto FAILURE;
+ }
+ }
+ else if (*lpstr == chPeriod)
+ {
+ if (*++lpstr == chPeriod) /* Is this up one directory? */
+ ++lpstr;
+ if (!*lpstr)
+ goto MustBeDir;
+ if ((*lpstr != TEXT('\\')) && (*lpstr != TEXT('/')))
+ {
+ nFileOffset = PARSE_INVALIDPERIOD;
+ goto FAILURE;
+ }
+ else
+ ++lpstr; /* it's saying directory, thus allowed */
+ }
+
+ if (!*lpstr)
+ {
+ goto MustBeDir;
+ }
+
+/* Should point to first char in 8.3 filename by now */
+ nFileOffset = nExtOffset = nFile = nExt = 0;
+ bWildcard = bExt = FALSE;
+ while (*lpstr)
+ {
+/*
+ * The next comparison MUST be unsigned to allow for extended characters!
+ * 21 Feb 1991 clarkc
+ */
+ if (*lpstr < chSpace)
+ {
+ nFileOffset = PARSE_INVALIDCHAR;
+ goto FAILURE;
+ }
+ switch (*lpstr)
+ {
+ case TEXT('"'): /* All invalid */
+ case TEXT('+'):
+ case TEXT(','):
+ case TEXT(':'):
+ case TEXT(';'):
+ case TEXT('<'):
+ case TEXT('='):
+ case TEXT('>'):
+ case TEXT('['):
+ case TEXT(']'):
+ case TEXT('|'):
+ {
+ nFileOffset = PARSE_INVALIDCHAR;
+ goto FAILURE;
+ }
+
+ case TEXT('\\'): /* Subdirectory indicators */
+ case TEXT('/'):
+ nNetwork++;
+ if (bWildcard)
+ {
+ nFileOffset = PARSE_WILDCARDINDIR;
+ goto FAILURE;
+ }
+
+ else if (nFile == 0) /* can't have 2 in a row */
+ {
+ nFileOffset = PARSE_INVALIDDIRCHAR;
+ goto FAILURE;
+ }
+ else
+ { /* reset flags */
+ ++lpstr;
+ if (!nNetwork && !*lpstr)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ nFile = nExt = 0;
+ bExt = FALSE;
+ }
+ break;
+
+ case chSpace:
+ {
+ LPTSTR lpSpace = lpstr;
+
+ *lpSpace = TEXT('\0');
+ while (*++lpSpace)
+ {
+ if (*lpSpace != chSpace)
+ {
+ *lpstr = chSpace; /* Reset string, abandon ship */
+ nFileOffset = PARSE_INVALIDSPACE;
+ goto FAILURE;
+ }
+ }
+ }
+ break;
+
+ case chPeriod:
+ if (nFile == 0)
+ {
+ if (*++lpstr == chPeriod)
+ ++lpstr;
+ if (!*lpstr)
+ goto MustBeDir;
+
+ if ((*lpstr != TEXT('\\')) && (*lpstr != TEXT('/')))
+ {
+ nFileOffset = PARSE_INVALIDPERIOD;
+ goto FAILURE;
+ }
+
+ ++lpstr; /* Flags are already set */
+ }
+ else if (bExt)
+ {
+ nFileOffset = PARSE_INVALIDPERIOD; /* can't have one in ext */
+ goto FAILURE;
+ }
+ else
+ {
+ nExtOffset = 0;
+ ++lpstr;
+ bExt = TRUE;
+ }
+ break;
+
+ case TEXT('*'):
+ case TEXT('?'):
+ if (bUNCPath)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ bWildcard = TRUE;
+/* Fall through to normal character processing */
+
+ default:
+ if (bExt)
+ {
+ if (++nExt == 1)
+ nExtOffset = lpstr - lpstrFileName;
+ else if (nExt > 3)
+ {
+ nFileOffset = PARSE_EXTENTIONTOOLONG;
+ goto FAILURE;
+ }
+ if ((nNetwork == -1) && (nFile + nExt > 11))
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ }
+ else if (++nFile == 1)
+ nFileOffset = lpstr - lpstrFileName;
+ else if (nFile > 8)
+ {
+ /* If it's a server name, it can have 11 characters */
+ if (nNetwork != -1)
+ {
+ nFileOffset = PARSE_FILETOOLONG;
+ goto FAILURE;
+ }
+ else if (nFile > 11)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ }
+
+#ifdef WIN32
+ lpstr = CharNext(lpstr);
+#else
+ lpstr = AnsiNext(lpstr);
+#endif
+ break;
+ }
+ }
+
+/* Did we start with a double backslash but not have any more slashes? */
+ if (nNetwork == -1)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+
+ if (!nFile)
+ {
+MustBeDir:
+ nFileOffset = PARSE_DIRECTORYNAME;
+ goto FAILURE;
+ }
+
+ if ((*(lpstr - 1) == chPeriod) && /* if true, no extention wanted */
+ (
+#ifdef WIN32
+ *CharNext(lpstr-2)
+#else
+ *AnsiNext(lpstr-2)
+#endif
+ == chPeriod
+ ))
+ *(lpstr - 1) = TEXT('\0'); /* Remove terminating period */
+ else if (!nExt)
+FAILURE:
+ nExtOffset = lpstr - lpstrFileName;
+
+ return(MAKELONG(nFileOffset, nExtOffset));
+}
+
+
+/*
+ * DoesFileExist
+ *
+ * Purpose:
+ * Determines if a file path exists
+ *
+ * Parameters:
+ * lpszFile LPTSTR - file name
+ * lpOpenBuf OFSTRUCT FAR* - points to the OFSTRUCT structure that
+ * will receive information about the file when the
+ * file is first opened. this field is filled by the
+ * Windows OpenFile API.
+ *
+ * Return Value:
+ * HFILE HFILE_ERROR - file does NOT exist
+ * file handle (as returned from OpenFile) - file exists
+ */
+HFILE WINAPI DoesFileExist(LPTSTR lpszFile, OFSTRUCT FAR* lpOpenBuf)
+{
+ long nRet;
+ int i;
+ static TCHAR *arrIllegalNames[] = {
+ TEXT("LPT1"),
+ TEXT("LPT2"),
+ TEXT("LPT3"),
+ TEXT("COM1"),
+ TEXT("COM2"),
+ TEXT("COM3"),
+ TEXT("COM4"),
+ TEXT("CON"),
+ TEXT("AUX"),
+ TEXT("PRN")
+ };
+
+ // Check if file name is syntactically correct.
+ // (OpenFile sometimes crashes if path is not syntactically correct)
+ nRet = ParseFile(lpszFile);
+ if (LOWORD(nRet) < 0)
+ goto error;
+
+ // Check is the name is an illegal name (eg. the name of a device)
+ for (i=0; i < (sizeof(arrIllegalNames)/sizeof(arrIllegalNames[0])); i++) {
+ if (lstrcmpi(lpszFile, arrIllegalNames[i])==0)
+ goto error; // illegal name FOUND
+ }
+
+ return OpenFile(lpszFile, lpOpenBuf, OF_EXIST);
+
+error:
+ _fmemset(lpOpenBuf, 0, sizeof(OFSTRUCT));
+ lpOpenBuf->nErrCode = 0x0002; // File not found
+ return HFILE_ERROR;
+}
+
diff --git a/private/oleutest/letest/ole2ui/utility.h b/private/oleutest/letest/ole2ui/utility.h
new file mode 100644
index 000000000..10b295cd5
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/utility.h
@@ -0,0 +1,37 @@
+/*
+ * UTILITY.H
+ *
+ * Miscellaneous prototypes and definitions for OLE UI dialogs.
+ *
+ * Copyright (c)1992 Microsoft Corporation, All Right Reserved
+ */
+
+
+#ifndef _UTILITY_H_
+#define _UTILITY_H_
+
+//Function prototypes
+//UTILITY.C
+HCURSOR WINAPI HourGlassOn(void);
+void WINAPI HourGlassOff(HCURSOR);
+
+BOOL WINAPI Browse(HWND, LPTSTR, LPTSTR, UINT, UINT, DWORD);
+int WINAPI ReplaceCharWithNull(LPTSTR, int);
+int WINAPI ErrorWithFile(HWND, HINSTANCE, UINT, LPTSTR, UINT);
+HFILE WINAPI DoesFileExist(LPTSTR lpszFile, OFSTRUCT FAR* lpOpenBuf);
+
+
+HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID, LPTSTR, UINT FAR *);
+BOOL FAR PASCAL FIconFileFromClass(REFCLSID, LPTSTR, UINT, UINT FAR *);
+LPTSTR FAR PASCAL PointerToNthField(LPTSTR, int, TCHAR);
+BOOL FAR PASCAL GetAssociatedExecutable(LPTSTR, LPTSTR);
+HICON WINAPI HIconFromClass(LPTSTR);
+BOOL WINAPI FServerFromClass(LPTSTR, LPTSTR, UINT);
+UINT WINAPI UClassFromDescription(LPTSTR, LPTSTR, UINT);
+UINT WINAPI UDescriptionFromClass(LPTSTR, LPTSTR, UINT);
+BOOL WINAPI FVerbGet(LPTSTR, UINT, LPTSTR);
+LPTSTR WINAPI ChopText(HWND hwndStatic, int nWidth, LPTSTR lpch);
+void WINAPI OpenFileError(HWND hDlg, UINT nErrCode, LPTSTR lpszFile);
+
+
+#endif //_UTILITY_H_
diff --git a/private/oleutest/letest/ole2ui/verlocal.h b/private/oleutest/letest/ole2ui/verlocal.h
new file mode 100644
index 000000000..92b7000c8
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/verlocal.h
@@ -0,0 +1,54 @@
+/*
+ * VERLOCAL.H
+ *
+ * Version resource file for the OLE 2.0 UI Support DLL.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved.
+ *
+ * This file contains the text that needs to be translated in the version
+ * resource. All of the following variables must be localized:
+ *
+ * wLanguage
+ * szTranslation
+ * szzCompanyName
+ * szzProductName
+ * szzLegalCopyright
+ */
+
+/* wLanguage comes from the table of "langID" values on page 218 of
+ the Windows 3.1 SDK Programmer's Reference, Volume 4: Resources.
+ This page is in Chapter 13, "Resource-Definition Statements", in the
+ description of the "VERSIONINFO" statment.
+
+ For example,
+ 0x0407 German
+ 0x0409 U.S. English
+ 0x0809 U.K. English
+ 0x040C French
+ 0x040A Castilian Spanish
+*/
+#define wLanguage 0x0409 /* U.S. English */
+
+/* The first 4 characters of szTranslation must be the same as wLanguage,
+ without the "0x". The last 4 characters of szTranslation MUST be
+ 04E4. Note that any alphabetic characters in szTranslation must
+ be capitalized. */
+#define szTranslation "040904E4" /* U.S. English */
+
+
+/* The following szz strings must all end with the two characters "\0" */
+/* Note that the "\251" in szzLegalCopyright stands for the "circle c"
+ copyright symbol, and it should be left as \251 rather than
+ substituting the actual ANSI copyright character in the string. */
+#define szzCompanyName "Microsoft Corporation\0"
+#define szzFileDescription "Microsoft Windows(TM) OLE 2.0 User Interface Support\0"
+#define szzLegalCopyright "Copyright \251 1992-1993 Microsoft Corp. All rights reserved.\0"
+
+#ifdef PUBLISHER
+#define szzProductName "Microsoft Publisher for Windows 2.0\0"
+#else
+#define szzProductName szzFileDescription
+#endif
+
+
+/* DO NOT CHANGE ANY LINES BELOW THIS POINT */
diff --git a/private/oleutest/letest/ole2ui/vgares.bmp b/private/oleutest/letest/ole2ui/vgares.bmp
new file mode 100644
index 000000000..496902f9f
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/vgares.bmp
Binary files differ
diff --git a/private/oleutest/letest/ole2ui/wn_dos.h b/private/oleutest/letest/ole2ui/wn_dos.h
new file mode 100644
index 000000000..dbc75a643
--- /dev/null
+++ b/private/oleutest/letest/ole2ui/wn_dos.h
@@ -0,0 +1,174 @@
+/*************************************************************************
+**
+** OLE 2.0 Property Set Utilities
+**
+** wn_dos.h
+**
+** This file contains file contains data structure defintions,
+** function prototypes, constants, etc. for Windows 3.x form of
+** DOS calls. This is used by the SUMINFO OLE 2.0 Property Set
+** utilities used to manage the Summary Info property set.
+**
+** (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+**
+*************************************************************************/
+
+#ifndef WN_DOS_H
+#define WN_DOS_H
+
+#include <dos.h>
+
+#define WIN 1
+
+#define cbMaxFile 146 //from inc\path.h
+#define SEEK_FROM_BEGINNING 0
+#define SEEK_FROM_END 2
+#define chDOSPath ('\\') // FUTURE: not used all places it could be
+#define chDOSWildAll '*' /* DOS File name wild card. */
+#define chDOSWildSingle '?'
+
+
+
+// Close, seek, delete, rename, flush, get attributes, read, write
+/* RPC TEMP
+int FCloseOsfnWin(WORD);
+#define FCloseOsfn(osfn) FCloseOsfnWin(osfn)
+long DwSeekDwWin(WORD,LONG,WORD);
+#define DwSeekDw(osfn, dwSeek, bSeekFrom) DwSeekDwWin(osfn, dwSeek, bSeekFrom)
+EC EcDeleteSzFfnameWin(char *);
+#define EcDeleteSzFfname(szFile) EcDeleteSzFfnameWin(szFile)
+EC EcRenameSzFfnameWin(char *,char *);
+#define EcRenameSzFfname(szFileCur,szFileNew) EcRenameSzFfnameWin(szFileCur,szFileNew)
+int FFlushOsfnWin(int);
+#define FFlushOsfn(osfn) FFlushOsfnWin(osfn)
+WORD DaGetFileModeSzWin(char *);
+#define DaGetFileModeSz(szFile) DaGetFileModeSzWin(szFile)
+int CbReadOsfnWin(int, void far *, UINT);
+int CbWriteOsfnWin(int, void far *, UINT);
+#define CbWriteOsfn(osfn,lpch,cbWrite) CbWriteOsfnWin(osfn,lpch,cbWrite)
+*/
+#define WinOpenFile(sz,ofs,n) OpenFile(sz,ofs,n)
+#define SeekHfile(f,off,kind) _llseek(f,off,kind)
+#define CbReadOsfn(osfn,lpch,cbRead) CbReadOsfnWin(osfn,lpch,cbRead)
+#define CbReadHfile(f,buf,n) _lread(f,buf,n)
+#define CbReadOsfnWin(f,buf,n) CbReadHfile(f,buf,n)
+#define EcFindFirst4dm(a,b,c) _dos_findfirst((const char *)(b),c,(struct find_t*)a)
+#define EcFindNext4dm(a) _dos_findnext((struct find_t*)a)
+#define FHfileToSffsDate(handle,date,time) _dos_getftime(handle, (unsigned *)(date), (unsigned *)(time))
+#define SeekHfile(f, off, kind) _llseek(f,off,kind)
+
+/* buffer structure to be used with EcFindFirst() and EcFindNext() */
+typedef struct _SFFS
+ { /* Search Find File Structure */
+ uchar buff[21]; // dos search info
+ uchar wAttr;
+ union
+ {
+ unsigned short timeVariable; /*RPC47*/
+ BF time:16;
+ struct
+ {
+ BF sec : 5;
+ BF mint: 6;
+ BF hr : 5;
+ };
+ };
+ union
+ {
+ unsigned short dateVariable;
+ BF date:16;
+ struct
+ {
+ BF dom : 5;
+ BF mon : 4;
+ BF yr : 7;
+ };
+ };
+ ulong cbFile;
+ uchar szFileName[13];
+ } SFFS;
+
+// find first file/find next file
+#define PszFromPsffs(psffs) ((psffs)->szFileName)
+#define CopySzFilePsffs(psffs,sz) OemToAnsi((char HUGE *)&((psffs)->szFileName[0]),(char HUGE *)(sz))
+#define CbSzFilePsffs(psffs) CbSz((psffs)->szFileName)
+#define CbFileSizePsffs(psffs) (psffs)->cbFile
+#define AttribPsffs(psffs) (psffs)->wAttr
+#define EcFindFirstCore(psffs, sz, wAttr) EcFindFirst(psffs, sz, wAttr) /*RPC22*/
+#define FDotPsffs(psffs) ((psffs)->szFileName[0]=='.') /*RPC23*/
+#define AppendSzWild(sz) {int i=_fstrlen((char FAR *)(sz)); sz[i]='*'; sz[i+1]='.'; sz[i+2]='*'; sz[i+3]='\0';}
+// disk free space
+
+unsigned long LcbDiskFreeSpaceWin(int);
+#define LcbDiskFreeSpace(chDrive) LcbDiskFreeSpaceWin(chDrive)
+
+// date and time /*RPC39*/
+/*
+typedef struct _TIM { // Time structure returned by OsTime
+ CHAR minutes, hour, hsec, sec;
+ } TIM;
+
+typedef struct _DAT { // Date structure returned by OsDate
+ int year;
+ CHAR month, day, dayOfWeek;
+ } DAT;
+*/
+#define TIM dostime_t /*RPC39*/
+#define DAT dosdate_t
+#define OsTimeWin(TIM) _dos_gettime(TIM)
+#define OsDateWin(DAT) _dos_getdate(DAT)
+
+
+/* DOS File Attributes */
+#define DA_NORMAL 0x00
+#define DA_READONLY 0x01
+#define DA_HIDDEN 0x02
+#define DA_SYSTEM 0x04
+#define DA_VOLUME 0x08
+#define DA_SUBDIR 0x10
+#define DA_ARCHIVE 0x20
+#define DA_NIL 0xFFFF /* Error DA */
+#define dosxSharing 32 /* Extended error code for sharing viol. */
+#define nErrNoAcc 5 /* OpenFile error code for Access Denied */
+#define nErrFnf 2 /* OpenFile error code for File Not Found */
+
+/* Components of the Open mode for OpenSzFfname (DOS FUNC 3DH) */
+#define MASK_fINH 0x80
+#define MASK_bSHARE 0x70
+#define MASK_bACCESS 0x07
+
+#define bSHARE_DENYRDWR 0x10
+#define bSHARE_DENYWR 0x20
+#define bSHARE_DENYNONE 0x40
+
+/* Seek-from type codes passed to DOS function 42H */
+
+#define SF_BEGINNING 0 /* Seek from beginning of file */
+#define SF_CURRENT 1 /* Seek from current file pointer */
+#define SF_END 2 /* Seek from end of file */
+
+
+typedef struct _DOSDTTM /* DOS DaTe TiMe */
+ {
+ union
+ {
+ long lDOSDttm;
+ struct
+ {
+ BF day: 5;
+ BF month: 4;
+ BF year: 7;
+ BF sec: 5;
+ BF mint: 6;
+ BF hours: 5;
+ } S1;
+ } U1;
+ } DOSDTTM;
+
+int FOsfnIsFile(int);
+
+void DateStamp(int, LONG *, int);
+int DosxError(void);
+int ShellExec(int, int);
+
+#endif //WN_DOS_H
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);
+}
+
diff --git a/private/oleutest/letest/readme.txt b/private/oleutest/letest/readme.txt
new file mode 100644
index 000000000..a273023d7
--- /dev/null
+++ b/private/oleutest/letest/readme.txt
@@ -0,0 +1,11 @@
+Author: Kennethm
+Date: 3-10-94
+
+There are four applications made from this directory. These four apps
+are made from one common source base. The master files are found in the
+cntroutl subdirectory. If you make any of the apps their source code
+will be copied into the proper subdirectory.
+
+Do not modify any source files other than those in the cntroutl directory!
+
+ \ No newline at end of file